1363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/*
2363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * Copyright 2012 Google Inc.
3363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger *
4363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * Use of this source code is governed by a BSD-style license that can be
5363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * found in the LICENSE file.
6363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger */
7363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
8363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "skdiff.h"
9363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkBitmap.h"
10363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkColor.h"
11363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkColorPriv.h"
12363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkTypes.h"
13363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
14363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/*static*/ char const * const DiffRecord::ResultNames[DiffRecord::kResultCount] = {
15363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "EqualBits",
16363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "EqualPixels",
17363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "DifferentPixels",
18363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "DifferentSizes",
19363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "CouldNotCompare",
20363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "Unknown",
21363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger};
22363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
23363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek SollenbergerDiffRecord::Result DiffRecord::getResultByName(const char *name) {
24363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    for (int result = 0; result < DiffRecord::kResultCount; ++result) {
25363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        if (0 == strcmp(DiffRecord::ResultNames[result], name)) {
26363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            return static_cast<DiffRecord::Result>(result);
27363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        }
28363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
29363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    return DiffRecord::kResultCount;
30363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}
31363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
32363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic char const * const ResultDescriptions[DiffRecord::kResultCount] = {
33363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "contain exactly the same bits",
34363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "contain the same pixel values, but not the same bits",
35363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "have identical dimensions but some differing pixels",
36363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "have differing dimensions",
37363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "could not be compared",
38363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "not compared yet",
39363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger};
40363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
41363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerconst char* DiffRecord::getResultDescription(DiffRecord::Result result) {
42363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    return ResultDescriptions[result];
43363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}
44363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
45363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/*static*/ char const * const DiffResource::StatusNames[DiffResource::kStatusCount] = {
46363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "Decoded",
47363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "CouldNotDecode",
48363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
49363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "Read",
50363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "CouldNotRead",
51363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
52363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "Exists",
53363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "DoesNotExist",
54363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
55363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "Specified",
56363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "Unspecified",
57363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
58363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "Unknown",
59363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger};
60363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
61363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek SollenbergerDiffResource::Status DiffResource::getStatusByName(const char *name) {
62363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    for (int status = 0; status < DiffResource::kStatusCount; ++status) {
63363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        if (0 == strcmp(DiffResource::StatusNames[status], name)) {
64363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            return static_cast<DiffResource::Status>(status);
65363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        }
66363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
67363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    return DiffResource::kStatusCount;
68363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}
69363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
70363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic char const * const StatusDescriptions[DiffResource::kStatusCount] = {
71363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "decoded",
72363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "could not be decoded",
73363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
74363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "read",
75363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "could not be read",
76363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
77363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "found",
78363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "not found",
79363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
80363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "specified",
81363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "unspecified",
82363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
83363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    "unknown",
84363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger};
85363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
86363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerconst char* DiffResource::getStatusDescription(DiffResource::Status status) {
87363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    return StatusDescriptions[status];
88363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}
89363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
90363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerbool DiffResource::isStatusFailed(DiffResource::Status status) {
91363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    return DiffResource::kCouldNotDecode_Status == status ||
92363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger           DiffResource::kCouldNotRead_Status == status ||
93363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger           DiffResource::kDoesNotExist_Status == status ||
94363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger           DiffResource::kUnspecified_Status == status ||
95363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger           DiffResource::kUnknown_Status == status;
96363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}
97363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
98363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerbool DiffResource::getMatchingStatuses(char* selector, bool statuses[kStatusCount]) {
99363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    if (!strcmp(selector, "any")) {
100363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) {
101363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            statuses[statusIndex] = true;
102363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        }
103363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        return true;
104363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
105363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
106363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) {
107363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        statuses[statusIndex] = false;
108363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
109363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
110363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    static const char kDelimiterChar = ',';
111363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    bool understood = true;
112363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    while (true) {
113363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        char* delimiterPtr = strchr(selector, kDelimiterChar);
114363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
115363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        if (delimiterPtr) {
116363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            *delimiterPtr = '\0';
117363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        }
118363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
119363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        if (!strcmp(selector, "failed")) {
120363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) {
121363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                Status status = static_cast<Status>(statusIndex);
122363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                statuses[statusIndex] |= isStatusFailed(status);
123363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            }
124363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        } else {
125363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            Status status = getStatusByName(selector);
126363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            if (status == kStatusCount) {
127363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                understood = false;
128363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            } else {
129363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                statuses[status] = true;
130363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            }
131363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        }
132363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
133363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        if (!delimiterPtr) {
134363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            break;
135363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        }
136363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
137363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        *delimiterPtr = kDelimiterChar;
138363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        selector = delimiterPtr + 1;
139363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
140363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    return understood;
141363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}
142363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
143363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic inline bool colors_match_thresholded(SkPMColor c0, SkPMColor c1, const int threshold) {
144363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    int da = SkGetPackedA32(c0) - SkGetPackedA32(c1);
145363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    int dr = SkGetPackedR32(c0) - SkGetPackedR32(c1);
146363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    int dg = SkGetPackedG32(c0) - SkGetPackedG32(c1);
147363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    int db = SkGetPackedB32(c0) - SkGetPackedB32(c1);
148363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
149363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    return ((SkAbs32(da) <= threshold) &&
150363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            (SkAbs32(dr) <= threshold) &&
151363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            (SkAbs32(dg) <= threshold) &&
152363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            (SkAbs32(db) <= threshold));
153363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}
154363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
155363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerconst SkPMColor PMCOLOR_WHITE = SkPreMultiplyColor(SK_ColorWHITE);
156363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerconst SkPMColor PMCOLOR_BLACK = SkPreMultiplyColor(SK_ColorBLACK);
157363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
158363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid compute_diff(DiffRecord* dr, DiffMetricProc diffFunction, const int colorThreshold) {
159363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    const int w = dr->fComparison.fBitmap.width();
160363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    const int h = dr->fComparison.fBitmap.height();
161363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    if (w != dr->fBase.fBitmap.width() || h != dr->fBase.fBitmap.height()) {
162363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        dr->fResult = DiffRecord::kDifferentSizes_Result;
163363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        return;
164363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
165363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
166363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkAutoLockPixels alpDiff(dr->fDifference.fBitmap);
167363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkAutoLockPixels alpWhite(dr->fWhite.fBitmap);
168363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    int mismatchedPixels = 0;
169d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    int totalMismatchA = 0;
170363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    int totalMismatchR = 0;
171363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    int totalMismatchG = 0;
172363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    int totalMismatchB = 0;
173363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
174363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    // Accumulate fractionally different pixels, then divide out
175363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    // # of pixels at the end.
176363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    dr->fWeightedFraction = 0;
177363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    for (int y = 0; y < h; y++) {
178363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        for (int x = 0; x < w; x++) {
179363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            SkPMColor c0 = *dr->fBase.fBitmap.getAddr32(x, y);
180363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            SkPMColor c1 = *dr->fComparison.fBitmap.getAddr32(x, y);
181363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            SkPMColor outputDifference = diffFunction(c0, c1);
182d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger            uint32_t thisA = SkAbs32(SkGetPackedA32(c0) - SkGetPackedA32(c1));
183d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger            uint32_t thisR = SkAbs32(SkGetPackedR32(c0) - SkGetPackedR32(c1));
184d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger            uint32_t thisG = SkAbs32(SkGetPackedG32(c0) - SkGetPackedG32(c1));
185d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger            uint32_t thisB = SkAbs32(SkGetPackedB32(c0) - SkGetPackedB32(c1));
186d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger            totalMismatchA += thisA;
187363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            totalMismatchR += thisR;
188363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            totalMismatchG += thisG;
189363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            totalMismatchB += thisB;
190363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            // In HSV, value is defined as max RGB component.
191363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            int value = MAX3(thisR, thisG, thisB);
192363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            dr->fWeightedFraction += ((float) value) / 255;
193d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger            if (thisA > dr->fMaxMismatchA) {
194d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                dr->fMaxMismatchA = thisA;
195d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger            }
196363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            if (thisR > dr->fMaxMismatchR) {
197363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                dr->fMaxMismatchR = thisR;
198363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            }
199363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            if (thisG > dr->fMaxMismatchG) {
200363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                dr->fMaxMismatchG = thisG;
201363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            }
202363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            if (thisB > dr->fMaxMismatchB) {
203363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                dr->fMaxMismatchB = thisB;
204363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            }
205363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            if (!colors_match_thresholded(c0, c1, colorThreshold)) {
206363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                mismatchedPixels++;
207363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                *dr->fDifference.fBitmap.getAddr32(x, y) = outputDifference;
208363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                *dr->fWhite.fBitmap.getAddr32(x, y) = PMCOLOR_WHITE;
209363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            } else {
210363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                *dr->fDifference.fBitmap.getAddr32(x, y) = 0;
211363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                *dr->fWhite.fBitmap.getAddr32(x, y) = PMCOLOR_BLACK;
212363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            }
213363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        }
214363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
215363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    if (0 == mismatchedPixels) {
216363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        dr->fResult = DiffRecord::kEqualPixels_Result;
217363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        return;
218363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
219363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    dr->fResult = DiffRecord::kDifferentPixels_Result;
220363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    int pixelCount = w * h;
221363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    dr->fFractionDifference = ((float) mismatchedPixels) / pixelCount;
222363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    dr->fWeightedFraction /= pixelCount;
223d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    dr->fTotalMismatchA = totalMismatchA;
224d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    dr->fAverageMismatchA = ((float) totalMismatchA) / pixelCount;
225363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    dr->fAverageMismatchR = ((float) totalMismatchR) / pixelCount;
226363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    dr->fAverageMismatchG = ((float) totalMismatchG) / pixelCount;
227363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    dr->fAverageMismatchB = ((float) totalMismatchB) / pixelCount;
228363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}
229