1363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/* 2363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * Copyright 2012 Google Inc. 3363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * 4363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * Use of this source code is governed by a BSD-style license that can be 5363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * found in the LICENSE file. 6363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger */ 7363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 8363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "skdiff.h" 9363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "skdiff_html.h" 10363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkStream.h" 11363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkTime.h" 12363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 13363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/// Make layout more consistent by scaling image to 240 height, 360 width, 14363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/// or natural size, whichever is smallest. 15363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic int compute_image_height(int height, int width) { 16363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int retval = 240; 17363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (height < retval) { 18363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger retval = height; 19363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 20363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger float scale = (float) retval / height; 21363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (width * scale > 360) { 22363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger scale = (float) 360 / width; 23363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger retval = static_cast<int>(height * scale); 24363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 25363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return retval; 26363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 27363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 28363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic void print_table_header(SkFILEWStream* stream, 29363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const int matchCount, 30363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const int colorThreshold, 31363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const RecordArray& differences, 32363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const SkString &baseDir, 33363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const SkString &comparisonDir, 34363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool doOutputDate = false) { 35363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("<table>\n"); 36363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("<tr><th>"); 37363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("select image</th>\n<th>"); 38363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (doOutputDate) { 39363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkTime::DateTime dt; 40363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkTime::GetDateTime(&dt); 41363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("SkDiff run at "); 42363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeDecAsText(dt.fHour); 43363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(":"); 44363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (dt.fMinute < 10) { 45363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("0"); 46363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 47363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeDecAsText(dt.fMinute); 48363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(":"); 49363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (dt.fSecond < 10) { 50363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("0"); 51363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 52363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeDecAsText(dt.fSecond); 53363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("<br>"); 54363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 55363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeDecAsText(matchCount); 56363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(" of "); 57363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeDecAsText(differences.count()); 58363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(" diffs matched "); 59363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (colorThreshold == 0) { 60363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("exactly"); 61363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else { 62363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("within "); 63363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeDecAsText(colorThreshold); 64363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(" color units per component"); 65363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 66363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(".<br>"); 67363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("</th>\n<th>"); 68363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("every different pixel shown in white"); 69363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("</th>\n<th>"); 70363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("color difference at each pixel"); 71363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("</th>\n<th>baseDir: "); 72363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(baseDir.c_str()); 73363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("</th>\n<th>comparisonDir: "); 74363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(comparisonDir.c_str()); 75363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("</th>\n"); 76363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("</tr>\n"); 77363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 78363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 79363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic void print_pixel_count(SkFILEWStream* stream, const DiffRecord& diff) { 80363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("<br>("); 81363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeDecAsText(static_cast<int>(diff.fFractionDifference * 82363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger diff.fBase.fBitmap.width() * 83363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger diff.fBase.fBitmap.height())); 84363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(" pixels)"); 85363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/* 86363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeDecAsText(diff.fWeightedFraction * 87363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger diff.fBaseWidth * 88363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger diff.fBaseHeight); 89363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(" weighted pixels)"); 90363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger*/ 91363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 92363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 93363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic void print_checkbox_cell(SkFILEWStream* stream, const DiffRecord& diff) { 94363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("<td><input type=\"checkbox\" name=\""); 95363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(diff.fBase.fFilename.c_str()); 96363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("\" checked=\"yes\"></td>"); 97363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 98363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 99363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic void print_label_cell(SkFILEWStream* stream, const DiffRecord& diff) { 100363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger char metricBuf [20]; 101363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 102363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("<td><b>"); 103363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(diff.fBase.fFilename.c_str()); 104363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("</b><br>"); 105363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger switch (diff.fResult) { 106363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kEqualBits_Result: 107363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDEBUGFAIL("should not encounter DiffRecord with kEqualBits here"); 108363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 109363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kEqualPixels_Result: 110363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDEBUGFAIL("should not encounter DiffRecord with kEqualPixels here"); 111363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 112363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kDifferentSizes_Result: 113363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("Image sizes differ</td>"); 114363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 115363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kDifferentPixels_Result: 116363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger sprintf(metricBuf, "%.4f%%", 100 * diff.fFractionDifference); 117363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(metricBuf); 118363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(" of pixels differ"); 119363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("\n ("); 120363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger sprintf(metricBuf, "%.4f%%", 100 * diff.fWeightedFraction); 121363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(metricBuf); 122363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(" weighted)"); 123363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // Write the actual number of pixels that differ if it's < 1% 124363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (diff.fFractionDifference < 0.01) { 125363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger print_pixel_count(stream, diff); 126363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 127d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger stream->writeText("<br>"); 128d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger if (SkScalarRoundToInt(diff.fAverageMismatchA) > 0) { 129d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger stream->writeText("<br>Average alpha channel mismatch "); 130d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger stream->writeDecAsText(SkScalarRoundToInt(diff.fAverageMismatchA)); 131d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger } 132d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger 133d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger stream->writeText("<br>Max alpha channel mismatch "); 134d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger stream->writeDecAsText(SkScalarRoundToInt(diff.fMaxMismatchA)); 135d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger 136d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger stream->writeText("<br>Total alpha channel mismatch "); 137d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger stream->writeDecAsText(static_cast<int>(diff.fTotalMismatchA)); 138d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger 139d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger stream->writeText("<br>"); 140363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("<br>Average color mismatch "); 141d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger stream->writeDecAsText(SkScalarRoundToInt(MAX3(diff.fAverageMismatchR, 142d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger diff.fAverageMismatchG, 143d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger diff.fAverageMismatchB))); 144363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("<br>Max color mismatch "); 145363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeDecAsText(MAX3(diff.fMaxMismatchR, 146363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger diff.fMaxMismatchG, 147363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger diff.fMaxMismatchB)); 148363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("</td>"); 149363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger break; 150363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kCouldNotCompare_Result: 151363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("Could not compare.<br>base: "); 152363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(DiffResource::getStatusDescription(diff.fBase.fStatus)); 153363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("<br>comparison: "); 154363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(DiffResource::getStatusDescription(diff.fComparison.fStatus)); 155363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("</td>"); 156363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 157363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger default: 158363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDEBUGFAIL("encountered DiffRecord with unknown result type"); 159363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 160363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 161363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 162363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 163363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic void print_image_cell(SkFILEWStream* stream, const SkString& path, int height) { 164363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("<td><a href=\""); 165363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(path.c_str()); 166363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("\"><img src=\""); 167363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(path.c_str()); 168363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("\" height=\""); 169363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeDecAsText(height); 170363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("px\"></a></td>"); 171363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 172363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 173363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic void print_link_cell(SkFILEWStream* stream, const SkString& path, const char* text) { 174363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("<td><a href=\""); 175363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(path.c_str()); 176363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("\">"); 177363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText(text); 178363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("</a></td>"); 179363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 180363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 181363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic void print_diff_resource_cell(SkFILEWStream* stream, DiffResource& resource, 182363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const SkString& relativePath, bool local) { 183363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (resource.fBitmap.empty()) { 184363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (DiffResource::kCouldNotDecode_Status == resource.fStatus) { 185363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (local && !resource.fFilename.isEmpty()) { 186363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger print_link_cell(stream, resource.fFilename, "N/A"); 187363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 188363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 189363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (!resource.fFullPath.isEmpty()) { 190363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (!resource.fFullPath.startsWith(PATH_DIV_STR)) { 191363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger resource.fFullPath.prepend(relativePath); 192363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 193363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger print_link_cell(stream, resource.fFullPath, "N/A"); 194363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 195363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 196363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 197363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("<td>N/A</td>"); 198363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 199363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 200363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 201363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int height = compute_image_height(resource.fBitmap.height(), resource.fBitmap.width()); 202363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (local) { 203363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger print_image_cell(stream, resource.fFilename, height); 204363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 205363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 206363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (!resource.fFullPath.startsWith(PATH_DIV_STR)) { 207363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger resource.fFullPath.prepend(relativePath); 208363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 209363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger print_image_cell(stream, resource.fFullPath, height); 210363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 211363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 212363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic void print_diff_row(SkFILEWStream* stream, DiffRecord& diff, const SkString& relativePath) { 213363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("<tr>\n"); 214363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger print_checkbox_cell(stream, diff); 215363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger print_label_cell(stream, diff); 216363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger print_diff_resource_cell(stream, diff.fWhite, relativePath, true); 217363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger print_diff_resource_cell(stream, diff.fDifference, relativePath, true); 218363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger print_diff_resource_cell(stream, diff.fBase, relativePath, false); 219363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger print_diff_resource_cell(stream, diff.fComparison, relativePath, false); 220363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->writeText("</tr>\n"); 221363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger stream->flush(); 222363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 223363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 224363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid print_diff_page(const int matchCount, 225363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const int colorThreshold, 226363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const RecordArray& differences, 227363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const SkString& baseDir, 228363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const SkString& comparisonDir, 229363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const SkString& outputDir) { 230363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 231363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(!baseDir.isEmpty()); 232363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(!comparisonDir.isEmpty()); 233363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(!outputDir.isEmpty()); 234363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 235363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkString outputPath(outputDir); 236363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger outputPath.append("index.html"); 237363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger //SkFILEWStream outputStream ("index.html"); 238363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkFILEWStream outputStream(outputPath.c_str()); 239363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 240363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // Need to convert paths from relative-to-cwd to relative-to-outputDir 241363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // FIXME this doesn't work if there are '..' inside the outputDir 242363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 243363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool isPathAbsolute = false; 244363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // On Windows or Linux, a path starting with PATH_DIV_CHAR is absolute. 245363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (outputDir.size() > 0 && PATH_DIV_CHAR == outputDir[0]) { 246363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger isPathAbsolute = true; 247363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 248363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#ifdef SK_BUILD_FOR_WIN32 249363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // On Windows, absolute paths can also start with "x:", where x is any 250363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // drive letter. 251363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (outputDir.size() > 1 && ':' == outputDir[1]) { 252363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger isPathAbsolute = true; 253363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 254363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#endif 255363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 256363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkString relativePath; 257363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (!isPathAbsolute) { 258363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger unsigned int ui; 259363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (ui = 0; ui < outputDir.size(); ui++) { 260363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (outputDir[ui] == PATH_DIV_CHAR) { 261363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger relativePath.append(".." PATH_DIV_STR); 262363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 263363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 264363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 265363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 266363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger outputStream.writeText( 267363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "<html>\n<head>\n" 268363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "<script src=\"https://ajax.googleapis.com/ajax/" 269363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "libs/jquery/1.7.2/jquery.min.js\"></script>\n" 270363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "<script type=\"text/javascript\">\n" 271363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "function generateCheckedList() {\n" 272363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "var boxes = $(\":checkbox:checked\");\n" 273363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "var fileCmdLineString = '';\n" 274363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "var fileMultiLineString = '';\n" 275363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "for (var i = 0; i < boxes.length; i++) {\n" 276363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "fileMultiLineString += boxes[i].name + '<br>';\n" 277363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "fileCmdLineString += boxes[i].name + ' ';\n" 278363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "}\n" 279363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "$(\"#checkedList\").html(fileCmdLineString + " 280363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "'<br><br>' + fileMultiLineString);\n" 281363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "}\n" 282363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "</script>\n</head>\n<body>\n"); 283363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger print_table_header(&outputStream, matchCount, colorThreshold, differences, 284363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger baseDir, comparisonDir); 285363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int i; 286363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (i = 0; i < differences.count(); i++) { 287363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger DiffRecord* diff = differences[i]; 288363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 289363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger switch (diff->fResult) { 290363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // Cases in which there is no diff to report. 291363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kEqualBits_Result: 292363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kEqualPixels_Result: 293363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger continue; 294363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // Cases in which we want a detailed pixel diff. 295363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kDifferentPixels_Result: 296363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kDifferentSizes_Result: 297363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kCouldNotCompare_Result: 298363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger print_diff_row(&outputStream, *diff, relativePath); 299363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger continue; 300363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger default: 301363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDEBUGFAIL("encountered DiffRecord with unknown result type"); 302363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger continue; 303363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 304363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 305363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger outputStream.writeText( 306363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "</table>\n" 307363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "<input type=\"button\" " 308363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "onclick=\"generateCheckedList()\" " 309363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "value=\"Create Rebaseline List\">\n" 310363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "<div id=\"checkedList\"></div>\n" 311363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "</body>\n</html>\n"); 312363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger outputStream.flush(); 313363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 314