1e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com/*
2e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com * Copyright 2012 Google Inc.
3e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com *
4e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com * Use of this source code is governed by a BSD-style license that can be
5e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com * found in the LICENSE file.
6e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com */
7e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
8e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "skdiff.h"
9e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "SkBitmap.h"
10e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "SkColor.h"
11e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "SkColorPriv.h"
12e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com#include "SkTypes.h"
13e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
14e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com/*static*/ char const * const DiffRecord::ResultNames[DiffRecord::kResultCount] = {
15e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "EqualBits",
16e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "EqualPixels",
17e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "DifferentPixels",
18e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "DifferentSizes",
19e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "CouldNotCompare",
20e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "Unknown",
21e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com};
22e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
23e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comDiffRecord::Result DiffRecord::getResultByName(const char *name) {
24e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    for (int result = 0; result < DiffRecord::kResultCount; ++result) {
25e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        if (0 == strcmp(DiffRecord::ResultNames[result], name)) {
26e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            return static_cast<DiffRecord::Result>(result);
27e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        }
28e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    }
29e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    return DiffRecord::kResultCount;
30e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com}
31e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
32e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comstatic char const * const ResultDescriptions[DiffRecord::kResultCount] = {
33e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "contain exactly the same bits",
34e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "contain the same pixel values, but not the same bits",
35e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "have identical dimensions but some differing pixels",
36e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "have differing dimensions",
37e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "could not be compared",
38e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "not compared yet",
39e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com};
40e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
41e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comconst char* DiffRecord::getResultDescription(DiffRecord::Result result) {
42e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    return ResultDescriptions[result];
43e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com}
44e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
45e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com/*static*/ char const * const DiffResource::StatusNames[DiffResource::kStatusCount] = {
46e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "Decoded",
47e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "CouldNotDecode",
48e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
49e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "Read",
50e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "CouldNotRead",
51e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
52e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "Exists",
53e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "DoesNotExist",
54e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
55e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "Specified",
56e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "Unspecified",
57e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
58e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "Unknown",
59e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com};
60e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
61e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comDiffResource::Status DiffResource::getStatusByName(const char *name) {
62e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    for (int status = 0; status < DiffResource::kStatusCount; ++status) {
63e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        if (0 == strcmp(DiffResource::StatusNames[status], name)) {
64e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            return static_cast<DiffResource::Status>(status);
65e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        }
66e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    }
67e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    return DiffResource::kStatusCount;
68e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com}
69e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
70e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comstatic char const * const StatusDescriptions[DiffResource::kStatusCount] = {
71e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "decoded",
72e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "could not be decoded",
73e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
74e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "read",
75e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "could not be read",
76e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
77e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "found",
78e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "not found",
79e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
80e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "specified",
81e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "unspecified",
82e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
83e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    "unknown",
84e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com};
85e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
86e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comconst char* DiffResource::getStatusDescription(DiffResource::Status status) {
87e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    return StatusDescriptions[status];
88e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com}
89e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
90e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.combool DiffResource::isStatusFailed(DiffResource::Status status) {
91e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    return DiffResource::kCouldNotDecode_Status == status ||
92e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com           DiffResource::kCouldNotRead_Status == status ||
93e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com           DiffResource::kDoesNotExist_Status == status ||
94e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com           DiffResource::kUnspecified_Status == status ||
95e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com           DiffResource::kUnknown_Status == status;
96e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com}
97e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
98e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.combool DiffResource::getMatchingStatuses(char* selector, bool statuses[kStatusCount]) {
99e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    if (!strcmp(selector, "any")) {
100e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) {
101e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            statuses[statusIndex] = true;
102e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        }
103e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        return true;
104e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    }
105e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
106e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) {
107e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        statuses[statusIndex] = false;
108e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    }
109e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
110e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    static const char kDelimiterChar = ',';
111e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    bool understood = true;
112e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    while (true) {
113e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        char* delimiterPtr = strchr(selector, kDelimiterChar);
114e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
115e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        if (delimiterPtr) {
116e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            *delimiterPtr = '\0';
117e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        }
118e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
119e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        if (!strcmp(selector, "failed")) {
120e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) {
121e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com                Status status = static_cast<Status>(statusIndex);
122e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com                statuses[statusIndex] |= isStatusFailed(status);
123e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            }
124e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        } else {
125e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            Status status = getStatusByName(selector);
126e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            if (status == kStatusCount) {
127e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com                understood = false;
128e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            } else {
129e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com                statuses[status] = true;
130e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            }
131e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        }
132e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
133e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        if (!delimiterPtr) {
134e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            break;
135e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        }
136e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
137e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        *delimiterPtr = kDelimiterChar;
138e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        selector = delimiterPtr + 1;
139e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    }
140e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    return understood;
141e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com}
142e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
143e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comstatic inline bool colors_match_thresholded(SkPMColor c0, SkPMColor c1, const int threshold) {
144e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    int da = SkGetPackedA32(c0) - SkGetPackedA32(c1);
145e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    int dr = SkGetPackedR32(c0) - SkGetPackedR32(c1);
146e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    int dg = SkGetPackedG32(c0) - SkGetPackedG32(c1);
147e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    int db = SkGetPackedB32(c0) - SkGetPackedB32(c1);
148e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
149e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    return ((SkAbs32(da) <= threshold) &&
150e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            (SkAbs32(dr) <= threshold) &&
151e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            (SkAbs32(dg) <= threshold) &&
152e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            (SkAbs32(db) <= threshold));
153e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com}
154e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
155e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comconst SkPMColor PMCOLOR_WHITE = SkPreMultiplyColor(SK_ColorWHITE);
156e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comconst SkPMColor PMCOLOR_BLACK = SkPreMultiplyColor(SK_ColorBLACK);
157e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
158e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.comvoid compute_diff(DiffRecord* dr, DiffMetricProc diffFunction, const int colorThreshold) {
159e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    const int w = dr->fComparison.fBitmap.width();
160e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    const int h = dr->fComparison.fBitmap.height();
161e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    if (w != dr->fBase.fBitmap.width() || h != dr->fBase.fBitmap.height()) {
162e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        dr->fResult = DiffRecord::kDifferentSizes_Result;
163e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        return;
164e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    }
165e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
166e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    SkAutoLockPixels alpDiff(dr->fDifference.fBitmap);
167e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    SkAutoLockPixels alpWhite(dr->fWhite.fBitmap);
168e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    int mismatchedPixels = 0;
169ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com    int totalMismatchA = 0;
170e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    int totalMismatchR = 0;
171e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    int totalMismatchG = 0;
172e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    int totalMismatchB = 0;
173e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com
174e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    // Accumulate fractionally different pixels, then divide out
175e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    // # of pixels at the end.
176e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    dr->fWeightedFraction = 0;
177e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    for (int y = 0; y < h; y++) {
178e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        for (int x = 0; x < w; x++) {
179e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            SkPMColor c0 = *dr->fBase.fBitmap.getAddr32(x, y);
180e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            SkPMColor c1 = *dr->fComparison.fBitmap.getAddr32(x, y);
181e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            SkPMColor outputDifference = diffFunction(c0, c1);
182ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com            uint32_t thisA = SkAbs32(SkGetPackedA32(c0) - SkGetPackedA32(c1));
183ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com            uint32_t thisR = SkAbs32(SkGetPackedR32(c0) - SkGetPackedR32(c1));
184ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com            uint32_t thisG = SkAbs32(SkGetPackedG32(c0) - SkGetPackedG32(c1));
185ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com            uint32_t thisB = SkAbs32(SkGetPackedB32(c0) - SkGetPackedB32(c1));
186ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com            totalMismatchA += thisA;
187e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            totalMismatchR += thisR;
188e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            totalMismatchG += thisG;
189e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            totalMismatchB += thisB;
190e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            // In HSV, value is defined as max RGB component.
191e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            int value = MAX3(thisR, thisG, thisB);
192e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            dr->fWeightedFraction += ((float) value) / 255;
193ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com            if (thisA > dr->fMaxMismatchA) {
194ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com                dr->fMaxMismatchA = thisA;
195ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com            }
196e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            if (thisR > dr->fMaxMismatchR) {
197e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com                dr->fMaxMismatchR = thisR;
198e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            }
199e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            if (thisG > dr->fMaxMismatchG) {
200e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com                dr->fMaxMismatchG = thisG;
201e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            }
202e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            if (thisB > dr->fMaxMismatchB) {
203e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com                dr->fMaxMismatchB = thisB;
204e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            }
205e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            if (!colors_match_thresholded(c0, c1, colorThreshold)) {
206e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com                mismatchedPixels++;
207e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com                *dr->fDifference.fBitmap.getAddr32(x, y) = outputDifference;
208e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com                *dr->fWhite.fBitmap.getAddr32(x, y) = PMCOLOR_WHITE;
209e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            } else {
210e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com                *dr->fDifference.fBitmap.getAddr32(x, y) = 0;
211e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com                *dr->fWhite.fBitmap.getAddr32(x, y) = PMCOLOR_BLACK;
212e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com            }
213e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        }
214e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    }
215e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    if (0 == mismatchedPixels) {
216e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        dr->fResult = DiffRecord::kEqualPixels_Result;
217e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com        return;
218e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    }
219e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    dr->fResult = DiffRecord::kDifferentPixels_Result;
220e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    int pixelCount = w * h;
221e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    dr->fFractionDifference = ((float) mismatchedPixels) / pixelCount;
222e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    dr->fWeightedFraction /= pixelCount;
223ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com    dr->fTotalMismatchA = totalMismatchA;
224ee5a5eee12b3befac33ed6c379f81bf749f57161rmistry@google.com    dr->fAverageMismatchA = ((float) totalMismatchA) / pixelCount;
225e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    dr->fAverageMismatchR = ((float) totalMismatchR) / pixelCount;
226e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    dr->fAverageMismatchG = ((float) totalMismatchG) / pixelCount;
227e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com    dr->fAverageMismatchB = ((float) totalMismatchB) / pixelCount;
228e3c8ddfd03fdf587b4d8400718ae4bb6e9aa8b6dbungeman@google.com}
229