summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/skia/tools/skdiff.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/skia/tools/skdiff.cpp')
-rw-r--r--chromium/third_party/skia/tools/skdiff.cpp228
1 files changed, 228 insertions, 0 deletions
diff --git a/chromium/third_party/skia/tools/skdiff.cpp b/chromium/third_party/skia/tools/skdiff.cpp
new file mode 100644
index 00000000000..ae6d72cd7a0
--- /dev/null
+++ b/chromium/third_party/skia/tools/skdiff.cpp
@@ -0,0 +1,228 @@
+/*
+ * 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 "SkBitmap.h"
+#include "SkColor.h"
+#include "SkColorPriv.h"
+#include "SkTypes.h"
+
+/*static*/ char const * const DiffRecord::ResultNames[DiffRecord::kResultCount] = {
+ "EqualBits",
+ "EqualPixels",
+ "DifferentPixels",
+ "DifferentSizes",
+ "CouldNotCompare",
+ "Unknown",
+};
+
+DiffRecord::Result DiffRecord::getResultByName(const char *name) {
+ for (int result = 0; result < DiffRecord::kResultCount; ++result) {
+ if (0 == strcmp(DiffRecord::ResultNames[result], name)) {
+ return static_cast<DiffRecord::Result>(result);
+ }
+ }
+ return DiffRecord::kResultCount;
+}
+
+static char const * const ResultDescriptions[DiffRecord::kResultCount] = {
+ "contain exactly the same bits",
+ "contain the same pixel values, but not the same bits",
+ "have identical dimensions but some differing pixels",
+ "have differing dimensions",
+ "could not be compared",
+ "not compared yet",
+};
+
+const char* DiffRecord::getResultDescription(DiffRecord::Result result) {
+ return ResultDescriptions[result];
+}
+
+/*static*/ char const * const DiffResource::StatusNames[DiffResource::kStatusCount] = {
+ "Decoded",
+ "CouldNotDecode",
+
+ "Read",
+ "CouldNotRead",
+
+ "Exists",
+ "DoesNotExist",
+
+ "Specified",
+ "Unspecified",
+
+ "Unknown",
+};
+
+DiffResource::Status DiffResource::getStatusByName(const char *name) {
+ for (int status = 0; status < DiffResource::kStatusCount; ++status) {
+ if (0 == strcmp(DiffResource::StatusNames[status], name)) {
+ return static_cast<DiffResource::Status>(status);
+ }
+ }
+ return DiffResource::kStatusCount;
+}
+
+static char const * const StatusDescriptions[DiffResource::kStatusCount] = {
+ "decoded",
+ "could not be decoded",
+
+ "read",
+ "could not be read",
+
+ "found",
+ "not found",
+
+ "specified",
+ "unspecified",
+
+ "unknown",
+};
+
+const char* DiffResource::getStatusDescription(DiffResource::Status status) {
+ return StatusDescriptions[status];
+}
+
+bool DiffResource::isStatusFailed(DiffResource::Status status) {
+ return DiffResource::kCouldNotDecode_Status == status ||
+ DiffResource::kCouldNotRead_Status == status ||
+ DiffResource::kDoesNotExist_Status == status ||
+ DiffResource::kUnspecified_Status == status ||
+ DiffResource::kUnknown_Status == status;
+}
+
+bool DiffResource::getMatchingStatuses(char* selector, bool statuses[kStatusCount]) {
+ if (!strcmp(selector, "any")) {
+ for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) {
+ statuses[statusIndex] = true;
+ }
+ return true;
+ }
+
+ for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) {
+ statuses[statusIndex] = false;
+ }
+
+ static const char kDelimiterChar = ',';
+ bool understood = true;
+ while (true) {
+ char* delimiterPtr = strchr(selector, kDelimiterChar);
+
+ if (delimiterPtr) {
+ *delimiterPtr = '\0';
+ }
+
+ if (!strcmp(selector, "failed")) {
+ for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) {
+ Status status = static_cast<Status>(statusIndex);
+ statuses[statusIndex] |= isStatusFailed(status);
+ }
+ } else {
+ Status status = getStatusByName(selector);
+ if (status == kStatusCount) {
+ understood = false;
+ } else {
+ statuses[status] = true;
+ }
+ }
+
+ if (!delimiterPtr) {
+ break;
+ }
+
+ *delimiterPtr = kDelimiterChar;
+ selector = delimiterPtr + 1;
+ }
+ return understood;
+}
+
+static inline bool colors_match_thresholded(SkPMColor c0, SkPMColor c1, const int threshold) {
+ int da = SkGetPackedA32(c0) - SkGetPackedA32(c1);
+ int dr = SkGetPackedR32(c0) - SkGetPackedR32(c1);
+ int dg = SkGetPackedG32(c0) - SkGetPackedG32(c1);
+ int db = SkGetPackedB32(c0) - SkGetPackedB32(c1);
+
+ return ((SkAbs32(da) <= threshold) &&
+ (SkAbs32(dr) <= threshold) &&
+ (SkAbs32(dg) <= threshold) &&
+ (SkAbs32(db) <= threshold));
+}
+
+const SkPMColor PMCOLOR_WHITE = SkPreMultiplyColor(SK_ColorWHITE);
+const SkPMColor PMCOLOR_BLACK = SkPreMultiplyColor(SK_ColorBLACK);
+
+void compute_diff(DiffRecord* dr, DiffMetricProc diffFunction, const int colorThreshold) {
+ const int w = dr->fComparison.fBitmap.width();
+ const int h = dr->fComparison.fBitmap.height();
+ if (w != dr->fBase.fBitmap.width() || h != dr->fBase.fBitmap.height()) {
+ dr->fResult = DiffRecord::kDifferentSizes_Result;
+ return;
+ }
+
+ SkAutoLockPixels alpDiff(dr->fDifference.fBitmap);
+ SkAutoLockPixels alpWhite(dr->fWhite.fBitmap);
+ int mismatchedPixels = 0;
+ int totalMismatchA = 0;
+ int totalMismatchR = 0;
+ int totalMismatchG = 0;
+ int totalMismatchB = 0;
+
+ // Accumulate fractionally different pixels, then divide out
+ // # of pixels at the end.
+ dr->fWeightedFraction = 0;
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ SkPMColor c0 = *dr->fBase.fBitmap.getAddr32(x, y);
+ SkPMColor c1 = *dr->fComparison.fBitmap.getAddr32(x, y);
+ SkPMColor outputDifference = diffFunction(c0, c1);
+ uint32_t thisA = SkAbs32(SkGetPackedA32(c0) - SkGetPackedA32(c1));
+ uint32_t thisR = SkAbs32(SkGetPackedR32(c0) - SkGetPackedR32(c1));
+ uint32_t thisG = SkAbs32(SkGetPackedG32(c0) - SkGetPackedG32(c1));
+ uint32_t thisB = SkAbs32(SkGetPackedB32(c0) - SkGetPackedB32(c1));
+ totalMismatchA += thisA;
+ totalMismatchR += thisR;
+ totalMismatchG += thisG;
+ totalMismatchB += thisB;
+ // In HSV, value is defined as max RGB component.
+ int value = MAX3(thisR, thisG, thisB);
+ dr->fWeightedFraction += ((float) value) / 255;
+ if (thisA > dr->fMaxMismatchA) {
+ dr->fMaxMismatchA = thisA;
+ }
+ if (thisR > dr->fMaxMismatchR) {
+ dr->fMaxMismatchR = thisR;
+ }
+ if (thisG > dr->fMaxMismatchG) {
+ dr->fMaxMismatchG = thisG;
+ }
+ if (thisB > dr->fMaxMismatchB) {
+ dr->fMaxMismatchB = thisB;
+ }
+ if (!colors_match_thresholded(c0, c1, colorThreshold)) {
+ mismatchedPixels++;
+ *dr->fDifference.fBitmap.getAddr32(x, y) = outputDifference;
+ *dr->fWhite.fBitmap.getAddr32(x, y) = PMCOLOR_WHITE;
+ } else {
+ *dr->fDifference.fBitmap.getAddr32(x, y) = 0;
+ *dr->fWhite.fBitmap.getAddr32(x, y) = PMCOLOR_BLACK;
+ }
+ }
+ }
+ if (0 == mismatchedPixels) {
+ dr->fResult = DiffRecord::kEqualPixels_Result;
+ return;
+ }
+ dr->fResult = DiffRecord::kDifferentPixels_Result;
+ int pixelCount = w * h;
+ dr->fFractionDifference = ((float) mismatchedPixels) / pixelCount;
+ dr->fWeightedFraction /= pixelCount;
+ dr->fTotalMismatchA = totalMismatchA;
+ dr->fAverageMismatchA = ((float) totalMismatchA) / pixelCount;
+ dr->fAverageMismatchR = ((float) totalMismatchR) / pixelCount;
+ dr->fAverageMismatchG = ((float) totalMismatchG) / pixelCount;
+ dr->fAverageMismatchB = ((float) totalMismatchB) / pixelCount;
+}