diff options
Diffstat (limited to 'chromium/third_party/skia/tools/skdiff.cpp')
-rw-r--r-- | chromium/third_party/skia/tools/skdiff.cpp | 228 |
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; +} |