aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/skdiff/skdiff_html.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/skdiff/skdiff_html.cpp')
-rw-r--r--tools/skdiff/skdiff_html.cpp313
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 + '&nbsp;';\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();
+}