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