2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
13 #include "SkColorPriv.h"
15 #include "SkTDArray.h"
17 #if defined(SK_BUILD_FOR_WIN32)
18 #define PATH_DIV_STR "\\"
19 #define PATH_DIV_CHAR '\\'
21 #define PATH_DIV_STR "/"
22 #define PATH_DIV_CHAR '/'
25 #define MAX2(a,b) (((b) < (a)) ? (a) : (b))
26 #define MAX3(a,b,c) (((b) < (a)) ? MAX2((a), (c)) : MAX2((b), (c)))
31 /** The resource was specified, exists, read, and decoded. */
33 /** The resource was specified, exists, read, but could not be decoded. */
34 kCouldNotDecode_Status,
36 /** The resource was specified, exists, and read. */
38 /** The resource was specified, exists, but could not be read. */
41 /** The resource was specified and exists. */
43 /** The resource was specified, but does not exist. */
46 /** The resource was specified. */
48 /** The resource was not specified. */
51 /** Nothing is yet known about the resource. */
54 /** NOT A VALID VALUE -- used to set up arrays and to represent an unknown value. */
57 static char const * const StatusNames[DiffResource::kStatusCount];
59 /** Returns the Status with this name.
60 * If there is no Status with this name, returns kStatusCount.
62 static Status getStatusByName(const char *name);
64 /** Returns a text description of the given Status type. */
65 static const char *getStatusDescription(Status status);
67 /** Returns true if the Status indicates some kind of failure. */
68 static bool isStatusFailed(Status status);
70 /** Sets statuses[i] if it is implied by selector, unsets it if not.
71 * Selector may be a comma delimited list of status names, "any", or "failed".
72 * Returns true if the selector was entirely understood, false otherwise.
74 static bool getMatchingStatuses(char* selector, bool statuses[kStatusCount]);
76 DiffResource() : fFilename(), fFullPath(), fBitmap(), fStatus(kUnknown_Status) { };
78 /** If isEmpty() indicates no filename available. */
80 /** If isEmpty() indicates no path available. */
82 /** If empty() indicates the bitmap could not be created. */
89 // Result of comparison for each pair of files.
90 // Listed from "better" to "worse", for sorting of results.
94 kDifferentPixels_Result,
95 kDifferentSizes_Result,
96 kCouldNotCompare_Result,
99 kResultCount // NOT A VALID VALUE--used to set up arrays. Must be last.
101 static char const * const ResultNames[DiffRecord::kResultCount];
103 /** Returns the Result with this name.
104 * If there is no Result with this name, returns kResultCount.
106 static Result getResultByName(const char *name);
108 /** Returns a text description of the given Result type. */
109 static const char *getResultDescription(Result result);
116 , fFractionDifference(0)
117 , fWeightedFraction(0)
118 , fAverageMismatchA(0)
119 , fAverageMismatchR(0)
120 , fAverageMismatchG(0)
121 , fAverageMismatchB(0)
127 , fResult(kUnknown_Result) {
131 DiffResource fComparison;
132 DiffResource fDifference;
135 /// Arbitrary floating-point metric to be used to sort images from most
136 /// to least different from baseline; values of 0 will be omitted from the
138 float fFractionDifference;
139 float fWeightedFraction;
141 float fAverageMismatchA;
142 float fAverageMismatchR;
143 float fAverageMismatchG;
144 float fAverageMismatchB;
146 uint32_t fTotalMismatchA;
148 uint32_t fMaxMismatchA;
149 uint32_t fMaxMismatchR;
150 uint32_t fMaxMismatchG;
151 uint32_t fMaxMismatchB;
153 /// Which category of diff result.
157 typedef SkTDArray<DiffRecord*> RecordArray;
159 /// A wrapper for any sortProc (comparison routine) which applies a first-order
160 /// sort beforehand, and a tiebreaker if the sortProc returns 0.
161 template<typename T> static int compare(const void* untyped_lhs, const void* untyped_rhs) {
162 const DiffRecord* lhs = *reinterpret_cast<DiffRecord* const *>(untyped_lhs);
163 const DiffRecord* rhs = *reinterpret_cast<DiffRecord* const *>(untyped_rhs);
165 // First-order sort... these comparisons should be applied before comparing
166 // pixel values, no matter what.
167 if (lhs->fResult != rhs->fResult) {
168 return (lhs->fResult < rhs->fResult) ? 1 : -1;
171 // Passed first-order sort, so call the pixel comparison routine.
172 int result = T::comparePixels(lhs, rhs);
177 // Tiebreaker... if we got to this point, we don't really care
178 // which order they are sorted in, but let's at least be consistent.
179 return strcmp(lhs->fBase.fFilename.c_str(), rhs->fBase.fFilename.c_str());
182 /// Comparison routine for qsort; sorts by fFractionDifference
183 /// from largest to smallest.
184 class CompareDiffMetrics {
186 static int comparePixels(const DiffRecord* lhs, const DiffRecord* rhs) {
187 if (lhs->fFractionDifference < rhs->fFractionDifference) {
190 if (rhs->fFractionDifference < lhs->fFractionDifference) {
197 class CompareDiffWeighted {
199 static int comparePixels(const DiffRecord* lhs, const DiffRecord* rhs) {
200 if (lhs->fWeightedFraction < rhs->fWeightedFraction) {
203 if (lhs->fWeightedFraction > rhs->fWeightedFraction) {
210 /// Comparison routine for qsort; sorts by max(fAverageMismatch{RGB})
211 /// from largest to smallest.
212 class CompareDiffMeanMismatches {
214 static int comparePixels(const DiffRecord* lhs, const DiffRecord* rhs) {
215 float leftValue = MAX3(lhs->fAverageMismatchR,
216 lhs->fAverageMismatchG,
217 lhs->fAverageMismatchB);
218 float rightValue = MAX3(rhs->fAverageMismatchR,
219 rhs->fAverageMismatchG,
220 rhs->fAverageMismatchB);
221 if (leftValue < rightValue) {
224 if (rightValue < leftValue) {
231 /// Comparison routine for qsort; sorts by max(fMaxMismatch{RGB})
232 /// from largest to smallest.
233 class CompareDiffMaxMismatches {
235 static int comparePixels(const DiffRecord* lhs, const DiffRecord* rhs) {
236 uint32_t leftValue = MAX3(lhs->fMaxMismatchR,
239 uint32_t rightValue = MAX3(rhs->fMaxMismatchR,
242 if (leftValue < rightValue) {
245 if (rightValue < leftValue) {
249 return CompareDiffMeanMismatches::comparePixels(lhs, rhs);
254 /// Parameterized routine to compute the color of a pixel in a difference image.
255 typedef SkPMColor (*DiffMetricProc)(SkPMColor, SkPMColor);
258 static inline SkPMColor compute_diff_pmcolor(SkPMColor c0, SkPMColor c1) {
259 int dr = SkGetPackedR32(c0) - SkGetPackedR32(c1);
260 int dg = SkGetPackedG32(c0) - SkGetPackedG32(c1);
261 int db = SkGetPackedB32(c0) - SkGetPackedB32(c1);
263 return SkPackARGB32(0xFF, SkAbs32(dr), SkAbs32(dg), SkAbs32(db));
266 /** When finished, dr->fResult should have some value other than kUnknown_Result.
267 * Expects dr->fWhite.fBitmap and dr->fDifference.fBitmap to have the same bounds as
268 * dr->fBase.fBitmap and have a valid pixelref.
270 void compute_diff(DiffRecord* dr, DiffMetricProc diffFunction, const int colorThreshold);