diff options
Diffstat (limited to 'tools/skdiff/skdiff_html.cpp')
-rw-r--r-- | tools/skdiff/skdiff_html.cpp | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/tools/skdiff/skdiff_html.cpp b/tools/skdiff/skdiff_html.cpp new file mode 100644 index 0000000000..6f3c3b09e1 --- /dev/null +++ b/tools/skdiff/skdiff_html.cpp @@ -0,0 +1,313 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "skdiff.h" +#include "skdiff_html.h" +#include "SkStream.h" +#include "SkTime.h" + +/// Make layout more consistent by scaling image to 240 height, 360 width, +/// or natural size, whichever is smallest. +static int compute_image_height(int height, int width) { + int retval = 240; + if (height < retval) { + retval = height; + } + float scale = (float) retval / height; + if (width * scale > 360) { + scale = (float) 360 / width; + retval = static_cast<int>(height * scale); + } + return retval; +} + +static void print_table_header(SkFILEWStream* stream, + const int matchCount, + const int colorThreshold, + const RecordArray& differences, + const SkString &baseDir, + const SkString &comparisonDir, + bool doOutputDate = false) { + stream->writeText("<table>\n"); + stream->writeText("<tr><th>"); + stream->writeText("select image</th>\n<th>"); + if (doOutputDate) { + SkTime::DateTime dt; + SkTime::GetDateTime(&dt); + stream->writeText("SkDiff run at "); + stream->writeDecAsText(dt.fHour); + stream->writeText(":"); + if (dt.fMinute < 10) { + stream->writeText("0"); + } + stream->writeDecAsText(dt.fMinute); + stream->writeText(":"); + if (dt.fSecond < 10) { + stream->writeText("0"); + } + stream->writeDecAsText(dt.fSecond); + stream->writeText("<br>"); + } + stream->writeDecAsText(matchCount); + stream->writeText(" of "); + stream->writeDecAsText(differences.count()); + stream->writeText(" diffs matched "); + if (colorThreshold == 0) { + stream->writeText("exactly"); + } else { + stream->writeText("within "); + stream->writeDecAsText(colorThreshold); + stream->writeText(" color units per component"); + } + stream->writeText(".<br>"); + stream->writeText("</th>\n<th>"); + stream->writeText("every different pixel shown in white"); + stream->writeText("</th>\n<th>"); + stream->writeText("color difference at each pixel"); + stream->writeText("</th>\n<th>baseDir: "); + stream->writeText(baseDir.c_str()); + stream->writeText("</th>\n<th>comparisonDir: "); + stream->writeText(comparisonDir.c_str()); + stream->writeText("</th>\n"); + stream->writeText("</tr>\n"); +} + +static void print_pixel_count(SkFILEWStream* stream, const DiffRecord& diff) { + stream->writeText("<br>("); + stream->writeDecAsText(static_cast<int>(diff.fFractionDifference * + diff.fBase.fBitmap.width() * + diff.fBase.fBitmap.height())); + stream->writeText(" pixels)"); +/* + stream->writeDecAsText(diff.fWeightedFraction * + diff.fBaseWidth * + diff.fBaseHeight); + stream->writeText(" weighted pixels)"); +*/ +} + +static void print_checkbox_cell(SkFILEWStream* stream, const DiffRecord& diff) { + stream->writeText("<td><input type=\"checkbox\" name=\""); + stream->writeText(diff.fBase.fFilename.c_str()); + stream->writeText("\" checked=\"yes\"></td>"); +} + +static void print_label_cell(SkFILEWStream* stream, const DiffRecord& diff) { + char metricBuf [20]; + + stream->writeText("<td><b>"); + stream->writeText(diff.fBase.fFilename.c_str()); + stream->writeText("</b><br>"); + switch (diff.fResult) { + case DiffRecord::kEqualBits_Result: + SkDEBUGFAIL("should not encounter DiffRecord with kEqualBits here"); + return; + case DiffRecord::kEqualPixels_Result: + SkDEBUGFAIL("should not encounter DiffRecord with kEqualPixels here"); + return; + case DiffRecord::kDifferentSizes_Result: + stream->writeText("Image sizes differ</td>"); + return; + case DiffRecord::kDifferentPixels_Result: + sprintf(metricBuf, "%.4f%%", 100 * diff.fFractionDifference); + stream->writeText(metricBuf); + stream->writeText(" of pixels differ"); + stream->writeText("\n ("); + sprintf(metricBuf, "%.4f%%", 100 * diff.fWeightedFraction); + stream->writeText(metricBuf); + stream->writeText(" weighted)"); + // Write the actual number of pixels that differ if it's < 1% + if (diff.fFractionDifference < 0.01) { + print_pixel_count(stream, diff); + } + stream->writeText("<br>"); + if (SkScalarRoundToInt(diff.fAverageMismatchA) > 0) { + stream->writeText("<br>Average alpha channel mismatch "); + stream->writeDecAsText(SkScalarRoundToInt(diff.fAverageMismatchA)); + } + + stream->writeText("<br>Max alpha channel mismatch "); + stream->writeDecAsText(SkScalarRoundToInt(diff.fMaxMismatchA)); + + stream->writeText("<br>Total alpha channel mismatch "); + stream->writeDecAsText(static_cast<int>(diff.fTotalMismatchA)); + + stream->writeText("<br>"); + stream->writeText("<br>Average color mismatch "); + stream->writeDecAsText(SkScalarRoundToInt(MAX3(diff.fAverageMismatchR, + diff.fAverageMismatchG, + diff.fAverageMismatchB))); + stream->writeText("<br>Max color mismatch "); + stream->writeDecAsText(MAX3(diff.fMaxMismatchR, + diff.fMaxMismatchG, + diff.fMaxMismatchB)); + stream->writeText("</td>"); + break; + case DiffRecord::kCouldNotCompare_Result: + stream->writeText("Could not compare.<br>base: "); + stream->writeText(DiffResource::getStatusDescription(diff.fBase.fStatus)); + stream->writeText("<br>comparison: "); + stream->writeText(DiffResource::getStatusDescription(diff.fComparison.fStatus)); + stream->writeText("</td>"); + return; + default: + SkDEBUGFAIL("encountered DiffRecord with unknown result type"); + return; + } +} + +static void print_image_cell(SkFILEWStream* stream, const SkString& path, int height) { + stream->writeText("<td><a href=\""); + stream->writeText(path.c_str()); + stream->writeText("\"><img src=\""); + stream->writeText(path.c_str()); + stream->writeText("\" height=\""); + stream->writeDecAsText(height); + stream->writeText("px\"></a></td>"); +} + +static void print_link_cell(SkFILEWStream* stream, const SkString& path, const char* text) { + stream->writeText("<td><a href=\""); + stream->writeText(path.c_str()); + stream->writeText("\">"); + stream->writeText(text); + stream->writeText("</a></td>"); +} + +static void print_diff_resource_cell(SkFILEWStream* stream, DiffResource& resource, + const SkString& relativePath, bool local) { + if (resource.fBitmap.empty()) { + if (DiffResource::kCouldNotDecode_Status == resource.fStatus) { + if (local && !resource.fFilename.isEmpty()) { + print_link_cell(stream, resource.fFilename, "N/A"); + return; + } + if (!resource.fFullPath.isEmpty()) { + if (!resource.fFullPath.startsWith(PATH_DIV_STR)) { + resource.fFullPath.prepend(relativePath); + } + print_link_cell(stream, resource.fFullPath, "N/A"); + return; + } + } + stream->writeText("<td>N/A</td>"); + return; + } + + int height = compute_image_height(resource.fBitmap.height(), resource.fBitmap.width()); + if (local) { + print_image_cell(stream, resource.fFilename, height); + return; + } + if (!resource.fFullPath.startsWith(PATH_DIV_STR)) { + resource.fFullPath.prepend(relativePath); + } + print_image_cell(stream, resource.fFullPath, height); +} + +static void print_diff_row(SkFILEWStream* stream, DiffRecord& diff, const SkString& relativePath) { + stream->writeText("<tr>\n"); + print_checkbox_cell(stream, diff); + print_label_cell(stream, diff); + print_diff_resource_cell(stream, diff.fWhite, relativePath, true); + print_diff_resource_cell(stream, diff.fDifference, relativePath, true); + print_diff_resource_cell(stream, diff.fBase, relativePath, false); + print_diff_resource_cell(stream, diff.fComparison, relativePath, false); + stream->writeText("</tr>\n"); + stream->flush(); +} + +void print_diff_page(const int matchCount, + const int colorThreshold, + const RecordArray& differences, + const SkString& baseDir, + const SkString& comparisonDir, + const SkString& outputDir) { + + SkASSERT(!baseDir.isEmpty()); + SkASSERT(!comparisonDir.isEmpty()); + SkASSERT(!outputDir.isEmpty()); + + SkString outputPath(outputDir); + outputPath.append("index.html"); + //SkFILEWStream outputStream ("index.html"); + SkFILEWStream outputStream(outputPath.c_str()); + + // Need to convert paths from relative-to-cwd to relative-to-outputDir + // FIXME this doesn't work if there are '..' inside the outputDir + + bool isPathAbsolute = false; + // On Windows or Linux, a path starting with PATH_DIV_CHAR is absolute. + if (outputDir.size() > 0 && PATH_DIV_CHAR == outputDir[0]) { + isPathAbsolute = true; + } +#ifdef SK_BUILD_FOR_WIN32 + // On Windows, absolute paths can also start with "x:", where x is any + // drive letter. + if (outputDir.size() > 1 && ':' == outputDir[1]) { + isPathAbsolute = true; + } +#endif + + SkString relativePath; + if (!isPathAbsolute) { + unsigned int ui; + for (ui = 0; ui < outputDir.size(); ui++) { + if (outputDir[ui] == PATH_DIV_CHAR) { + relativePath.append(".." PATH_DIV_STR); + } + } + } + + outputStream.writeText( + "<html>\n<head>\n" + "<script src=\"https://ajax.googleapis.com/ajax/" + "libs/jquery/1.7.2/jquery.min.js\"></script>\n" + "<script type=\"text/javascript\">\n" + "function generateCheckedList() {\n" + "var boxes = $(\":checkbox:checked\");\n" + "var fileCmdLineString = '';\n" + "var fileMultiLineString = '';\n" + "for (var i = 0; i < boxes.length; i++) {\n" + "fileMultiLineString += boxes[i].name + '<br>';\n" + "fileCmdLineString += boxes[i].name + ' ';\n" + "}\n" + "$(\"#checkedList\").html(fileCmdLineString + " + "'<br><br>' + fileMultiLineString);\n" + "}\n" + "</script>\n</head>\n<body>\n"); + print_table_header(&outputStream, matchCount, colorThreshold, differences, + baseDir, comparisonDir); + int i; + for (i = 0; i < differences.count(); i++) { + DiffRecord* diff = differences[i]; + + switch (diff->fResult) { + // Cases in which there is no diff to report. + case DiffRecord::kEqualBits_Result: + case DiffRecord::kEqualPixels_Result: + continue; + // Cases in which we want a detailed pixel diff. + case DiffRecord::kDifferentPixels_Result: + case DiffRecord::kDifferentSizes_Result: + case DiffRecord::kCouldNotCompare_Result: + print_diff_row(&outputStream, *diff, relativePath); + continue; + default: + SkDEBUGFAIL("encountered DiffRecord with unknown result type"); + continue; + } + } + outputStream.writeText( + "</table>\n" + "<input type=\"button\" " + "onclick=\"generateCheckedList()\" " + "value=\"Create Rebaseline List\">\n" + "<div id=\"checkedList\"></div>\n" + "</body>\n</html>\n"); + outputStream.flush(); +} |