1e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com/* 2e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com * Copyright 2012 Google Inc. 3e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com * 4e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com * Use of this source code is governed by a BSD-style license that can be 5e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com * found in the LICENSE file. 6e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com */ 7e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 8e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "skdiff.h" 9e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "skdiff_html.h" 10e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "SkStream.h" 11e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "SkTime.h" 12e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 13e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com/// Make layout more consistent by scaling image to 240 height, 360 width, 14e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com/// or natural size, whichever is smallest. 15e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comstatic int compute_image_height(int height, int width) { 16e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com int retval = 240; 17e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (height < retval) { 18e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com retval = height; 19e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 20e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com float scale = (float) retval / height; 21e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (width * scale > 360) { 22e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com scale = (float) 360 / width; 23e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com retval = static_cast<int>(height * scale); 24e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 25e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return retval; 26e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com} 27e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 28e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comstatic void print_table_header(SkFILEWStream* stream, 29e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const int matchCount, 30e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const int colorThreshold, 31e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const RecordArray& differences, 32e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const SkString &baseDir, 33e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const SkString &comparisonDir, 34e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com bool doOutputDate = false) { 35e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("<table>\n"); 36e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("<tr><th>"); 37e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("select image</th>\n<th>"); 38e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (doOutputDate) { 39e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkTime::DateTime dt; 40e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkTime::GetDateTime(&dt); 41e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("SkDiff run at "); 42e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeDecAsText(dt.fHour); 43e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(":"); 44e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (dt.fMinute < 10) { 45e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("0"); 46e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 47e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeDecAsText(dt.fMinute); 48e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(":"); 49e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (dt.fSecond < 10) { 50e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("0"); 51e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 52e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeDecAsText(dt.fSecond); 53e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("<br>"); 54e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 55e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeDecAsText(matchCount); 56e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(" of "); 57e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeDecAsText(differences.count()); 58e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(" diffs matched "); 59e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (colorThreshold == 0) { 60e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("exactly"); 61e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } else { 62e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("within "); 63e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeDecAsText(colorThreshold); 64e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(" color units per component"); 65e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 66e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(".<br>"); 67e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("</th>\n<th>"); 68e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("every different pixel shown in white"); 69e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("</th>\n<th>"); 70e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("color difference at each pixel"); 71e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("</th>\n<th>baseDir: "); 72e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(baseDir.c_str()); 73e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("</th>\n<th>comparisonDir: "); 74e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(comparisonDir.c_str()); 75e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("</th>\n"); 76e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("</tr>\n"); 77e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com} 78e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 79e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comstatic void print_pixel_count(SkFILEWStream* stream, const DiffRecord& diff) { 80e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("<br>("); 81e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeDecAsText(static_cast<int>(diff.fFractionDifference * 82e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com diff.fBase.fBitmap.width() * 83e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com diff.fBase.fBitmap.height())); 84e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(" pixels)"); 85e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com/* 86e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeDecAsText(diff.fWeightedFraction * 87e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com diff.fBaseWidth * 88e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com diff.fBaseHeight); 89e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(" weighted pixels)"); 90e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com*/ 91e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com} 92e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 93e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comstatic void print_checkbox_cell(SkFILEWStream* stream, const DiffRecord& diff) { 94e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("<td><input type=\"checkbox\" name=\""); 95e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(diff.fBase.fFilename.c_str()); 96e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("\" checked=\"yes\"></td>"); 97e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com} 98e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 99e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comstatic void print_label_cell(SkFILEWStream* stream, const DiffRecord& diff) { 100e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com char metricBuf [20]; 101e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 102e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("<td><b>"); 103e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(diff.fBase.fFilename.c_str()); 104e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("</b><br>"); 105e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com switch (diff.fResult) { 106e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com case DiffRecord::kEqualBits_Result: 107e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDEBUGFAIL("should not encounter DiffRecord with kEqualBits here"); 108e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return; 109e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com case DiffRecord::kEqualPixels_Result: 110e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDEBUGFAIL("should not encounter DiffRecord with kEqualPixels here"); 111e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return; 112e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com case DiffRecord::kDifferentSizes_Result: 113e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("Image sizes differ</td>"); 114e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return; 115e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com case DiffRecord::kDifferentPixels_Result: 116e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com sprintf(metricBuf, "%.4f%%", 100 * diff.fFractionDifference); 117e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(metricBuf); 118e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(" of pixels differ"); 119e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("\n ("); 120e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com sprintf(metricBuf, "%.4f%%", 100 * diff.fWeightedFraction); 121e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(metricBuf); 122e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(" weighted)"); 123e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Write the actual number of pixels that differ if it's < 1% 124e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (diff.fFractionDifference < 0.01) { 125e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com print_pixel_count(stream, diff); 126e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 127ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com stream->writeText("<br>"); 12889d15a28b52faed37b1bda1fbcdd1afae4bae457reed@google.com if (SkScalarRoundToInt(diff.fAverageMismatchA) > 0) { 129ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com stream->writeText("<br>Average alpha channel mismatch "); 13089d15a28b52faed37b1bda1fbcdd1afae4bae457reed@google.com stream->writeDecAsText(SkScalarRoundToInt(diff.fAverageMismatchA)); 131ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com } 132ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com 133ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com stream->writeText("<br>Max alpha channel mismatch "); 13489d15a28b52faed37b1bda1fbcdd1afae4bae457reed@google.com stream->writeDecAsText(SkScalarRoundToInt(diff.fMaxMismatchA)); 135ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com 136ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com stream->writeText("<br>Total alpha channel mismatch "); 137ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com stream->writeDecAsText(static_cast<int>(diff.fTotalMismatchA)); 138ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com 139ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com stream->writeText("<br>"); 140e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("<br>Average color mismatch "); 14189d15a28b52faed37b1bda1fbcdd1afae4bae457reed@google.com stream->writeDecAsText(SkScalarRoundToInt(MAX3(diff.fAverageMismatchR, 14289d15a28b52faed37b1bda1fbcdd1afae4bae457reed@google.com diff.fAverageMismatchG, 14389d15a28b52faed37b1bda1fbcdd1afae4bae457reed@google.com diff.fAverageMismatchB))); 144e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("<br>Max color mismatch "); 145e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeDecAsText(MAX3(diff.fMaxMismatchR, 146e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com diff.fMaxMismatchG, 147e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com diff.fMaxMismatchB)); 148e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("</td>"); 149e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com break; 150e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com case DiffRecord::kCouldNotCompare_Result: 151e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("Could not compare.<br>base: "); 152e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(DiffResource::getStatusDescription(diff.fBase.fStatus)); 153e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("<br>comparison: "); 154e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(DiffResource::getStatusDescription(diff.fComparison.fStatus)); 155e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("</td>"); 156e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return; 157e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com default: 158e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDEBUGFAIL("encountered DiffRecord with unknown result type"); 159e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return; 160e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 161e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com} 162e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 163e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comstatic void print_image_cell(SkFILEWStream* stream, const SkString& path, int height) { 164e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("<td><a href=\""); 165e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(path.c_str()); 166e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("\"><img src=\""); 167e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(path.c_str()); 168e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("\" height=\""); 169e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeDecAsText(height); 170e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("px\"></a></td>"); 171e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com} 172e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 173e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comstatic void print_link_cell(SkFILEWStream* stream, const SkString& path, const char* text) { 174e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("<td><a href=\""); 175e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(path.c_str()); 176e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("\">"); 177e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText(text); 178e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("</a></td>"); 179e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com} 180e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 181e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comstatic void print_diff_resource_cell(SkFILEWStream* stream, DiffResource& resource, 182e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const SkString& relativePath, bool local) { 183e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (resource.fBitmap.empty()) { 184e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (DiffResource::kCouldNotDecode_Status == resource.fStatus) { 185e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (local && !resource.fFilename.isEmpty()) { 186e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com print_link_cell(stream, resource.fFilename, "N/A"); 187e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return; 188e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 189e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!resource.fFullPath.isEmpty()) { 190e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!resource.fFullPath.startsWith(PATH_DIV_STR)) { 191e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com resource.fFullPath.prepend(relativePath); 192e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 193e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com print_link_cell(stream, resource.fFullPath, "N/A"); 194e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return; 195e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 196e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 197e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("<td>N/A</td>"); 198e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return; 199e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 200e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 201e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com int height = compute_image_height(resource.fBitmap.height(), resource.fBitmap.width()); 202e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (local) { 203e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com print_image_cell(stream, resource.fFilename, height); 204e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com return; 205e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 206e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!resource.fFullPath.startsWith(PATH_DIV_STR)) { 207e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com resource.fFullPath.prepend(relativePath); 208e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 209e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com print_image_cell(stream, resource.fFullPath, height); 210e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com} 211e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 212e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comstatic void print_diff_row(SkFILEWStream* stream, DiffRecord& diff, const SkString& relativePath) { 213e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("<tr>\n"); 214e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com print_checkbox_cell(stream, diff); 215e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com print_label_cell(stream, diff); 216e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com print_diff_resource_cell(stream, diff.fWhite, relativePath, true); 217e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com print_diff_resource_cell(stream, diff.fDifference, relativePath, true); 218e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com print_diff_resource_cell(stream, diff.fBase, relativePath, false); 219e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com print_diff_resource_cell(stream, diff.fComparison, relativePath, false); 220e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->writeText("</tr>\n"); 221e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com stream->flush(); 222e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com} 223e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 224e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comvoid print_diff_page(const int matchCount, 225e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const int colorThreshold, 226e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const RecordArray& differences, 227e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const SkString& baseDir, 228e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const SkString& comparisonDir, 229e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com const SkString& outputDir) { 230e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 231e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkASSERT(!baseDir.isEmpty()); 232e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkASSERT(!comparisonDir.isEmpty()); 233e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkASSERT(!outputDir.isEmpty()); 234e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 235e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkString outputPath(outputDir); 236e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com outputPath.append("index.html"); 237e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com //SkFILEWStream outputStream ("index.html"); 238e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkFILEWStream outputStream(outputPath.c_str()); 239e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 240e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Need to convert paths from relative-to-cwd to relative-to-outputDir 241e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // FIXME this doesn't work if there are '..' inside the outputDir 242e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 243e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com bool isPathAbsolute = false; 244e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // On Windows or Linux, a path starting with PATH_DIV_CHAR is absolute. 245e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (outputDir.size() > 0 && PATH_DIV_CHAR == outputDir[0]) { 246e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com isPathAbsolute = true; 247e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 248e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#ifdef SK_BUILD_FOR_WIN32 249e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // On Windows, absolute paths can also start with "x:", where x is any 250e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // drive letter. 251e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (outputDir.size() > 1 && ':' == outputDir[1]) { 252e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com isPathAbsolute = true; 253e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 254e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#endif 255e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 256e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkString relativePath; 257e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (!isPathAbsolute) { 258e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com unsigned int ui; 259e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com for (ui = 0; ui < outputDir.size(); ui++) { 260e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com if (outputDir[ui] == PATH_DIV_CHAR) { 261e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com relativePath.append(".." PATH_DIV_STR); 262e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 263e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 264e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 265e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 266e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com outputStream.writeText( 267e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "<html>\n<head>\n" 268e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "<script src=\"https://ajax.googleapis.com/ajax/" 269e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "libs/jquery/1.7.2/jquery.min.js\"></script>\n" 270e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "<script type=\"text/javascript\">\n" 271e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "function generateCheckedList() {\n" 272e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "var boxes = $(\":checkbox:checked\");\n" 273e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "var fileCmdLineString = '';\n" 274e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "var fileMultiLineString = '';\n" 275e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "for (var i = 0; i < boxes.length; i++) {\n" 276e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "fileMultiLineString += boxes[i].name + '<br>';\n" 277e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "fileCmdLineString += boxes[i].name + ' ';\n" 278e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "}\n" 279e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "$(\"#checkedList\").html(fileCmdLineString + " 280e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "'<br><br>' + fileMultiLineString);\n" 281e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "}\n" 282e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "</script>\n</head>\n<body>\n"); 283e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com print_table_header(&outputStream, matchCount, colorThreshold, differences, 284e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com baseDir, comparisonDir); 285e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com int i; 286e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com for (i = 0; i < differences.count(); i++) { 287e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com DiffRecord* diff = differences[i]; 288e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com 289e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com switch (diff->fResult) { 290e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Cases in which there is no diff to report. 291e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com case DiffRecord::kEqualBits_Result: 292e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com case DiffRecord::kEqualPixels_Result: 293e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 294e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com // Cases in which we want a detailed pixel diff. 295e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com case DiffRecord::kDifferentPixels_Result: 296e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com case DiffRecord::kDifferentSizes_Result: 297e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com case DiffRecord::kCouldNotCompare_Result: 298e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com print_diff_row(&outputStream, *diff, relativePath); 299e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 300e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com default: 301e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com SkDEBUGFAIL("encountered DiffRecord with unknown result type"); 302e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com continue; 303e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 304e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com } 305e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com outputStream.writeText( 306e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "</table>\n" 307e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "<input type=\"button\" " 308e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "onclick=\"generateCheckedList()\" " 309e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "value=\"Create Rebaseline List\">\n" 310e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "<div id=\"checkedList\"></div>\n" 311e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com "</body>\n</html>\n"); 312e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com outputStream.flush(); 313e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com} 314