1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cc/test/pixel_comparator.h"
6
7 #include <stdint.h>
8
9 #include <algorithm>
10
11 #include "base/check_op.h"
12 #include "base/logging.h"
13 #include "ui/gfx/geometry/rect.h"
14
15 namespace cc {
16
ExactPixelComparator(const bool discard_alpha)17 ExactPixelComparator::ExactPixelComparator(const bool discard_alpha)
18 : discard_alpha_(discard_alpha) {
19 }
20
Compare(const SkBitmap & actual_bmp,const SkBitmap & expected_bmp) const21 bool ExactPixelComparator::Compare(const SkBitmap& actual_bmp,
22 const SkBitmap& expected_bmp) const {
23 // Number of pixels with an error
24 int error_pixels_count = 0;
25
26 gfx::Rect error_bounding_rect = gfx::Rect();
27
28 // Check that bitmaps have identical dimensions.
29 DCHECK_EQ(actual_bmp.width(), expected_bmp.width());
30 DCHECK_EQ(actual_bmp.height(), expected_bmp.height());
31
32 for (int x = 0; x < actual_bmp.width(); ++x) {
33 for (int y = 0; y < actual_bmp.height(); ++y) {
34 SkColor actual_color = actual_bmp.getColor(x, y);
35 SkColor expected_color = expected_bmp.getColor(x, y);
36 if (discard_alpha_) {
37 actual_color = SkColorSetA(actual_color, 0);
38 expected_color = SkColorSetA(expected_color, 0);
39 }
40 if (actual_color != expected_color) {
41 ++error_pixels_count;
42 error_bounding_rect.Union(gfx::Rect(x, y, 1, 1));
43 }
44 }
45 }
46
47 if (error_pixels_count != 0) {
48 LOG(ERROR) << "Number of pixel with an error: " << error_pixels_count;
49 LOG(ERROR) << "Error Bounding Box : " << error_bounding_rect.ToString();
50 return false;
51 }
52
53 return true;
54 }
55
ManhattanDistancePixelComparator(int tolerance)56 ManhattanDistancePixelComparator::ManhattanDistancePixelComparator(
57 int tolerance)
58 : tolerance_(tolerance) {}
59
Compare(const SkBitmap & actual_bmp,const SkBitmap & expected_bmp) const60 bool ManhattanDistancePixelComparator::Compare(
61 const SkBitmap& actual_bmp,
62 const SkBitmap& expected_bmp) const {
63 // Check that bitmaps have identical dimensions.
64 DCHECK_EQ(actual_bmp.width(), expected_bmp.width());
65 DCHECK_EQ(actual_bmp.height(), expected_bmp.height());
66
67 for (int y = 0; y < actual_bmp.height(); ++y) {
68 for (int x = 0; x < actual_bmp.width(); ++x) {
69 SkColor actual_color = actual_bmp.getColor(x, y);
70 SkColor expected_color = expected_bmp.getColor(x, y);
71
72 int pixel_b = SkColorGetB(actual_color);
73 int pixel_g = SkColorGetG(actual_color);
74 int pixel_r = SkColorGetR(actual_color);
75
76 int ref_pixel_b = SkColorGetB(expected_color);
77 int ref_pixel_g = SkColorGetG(expected_color);
78 int ref_pixel_r = SkColorGetR(expected_color);
79
80 int manhattan_distance = std::abs(pixel_b - ref_pixel_b) +
81 std::abs(pixel_g - ref_pixel_g) +
82 std::abs(pixel_r - ref_pixel_r);
83
84 if (manhattan_distance > tolerance_) {
85 LOG(ERROR) << "Pixel test failed on (" << x << ", " << y << "). "
86 << "Manhattan distance: " << manhattan_distance << ".";
87 return false;
88 }
89 }
90 }
91
92 return true;
93 }
94
FuzzyPixelComparator(bool discard_alpha,float error_pixels_percentage_limit,float small_error_pixels_percentage_limit,float avg_abs_error_limit,int max_abs_error_limit,int small_error_threshold,bool check_critical_error)95 FuzzyPixelComparator::FuzzyPixelComparator(
96 bool discard_alpha,
97 float error_pixels_percentage_limit,
98 float small_error_pixels_percentage_limit,
99 float avg_abs_error_limit,
100 int max_abs_error_limit,
101 int small_error_threshold,
102 bool check_critical_error)
103 : discard_alpha_(discard_alpha),
104 error_pixels_percentage_limit_(error_pixels_percentage_limit),
105 small_error_pixels_percentage_limit_(small_error_pixels_percentage_limit),
106 avg_abs_error_limit_(avg_abs_error_limit),
107 max_abs_error_limit_(max_abs_error_limit),
108 small_error_threshold_(small_error_threshold),
109 check_critical_error_(check_critical_error) {}
110
Compare(const SkBitmap & actual_bmp,const SkBitmap & expected_bmp) const111 bool FuzzyPixelComparator::Compare(const SkBitmap& actual_bmp,
112 const SkBitmap& expected_bmp) const {
113 // Number of pixels with an error
114 int error_pixels_count = 0;
115 // Number of pixels with a small error
116 int small_error_pixels_count = 0;
117 // Number of pixels with a critical error.
118 int critial_error_pixels_count = 0;
119 // The per channel sums of absolute errors over all pixels.
120 int64_t sum_abs_error_r = 0;
121 int64_t sum_abs_error_g = 0;
122 int64_t sum_abs_error_b = 0;
123 int64_t sum_abs_error_a = 0;
124 // The per channel maximum absolute errors over all pixels.
125 int max_abs_error_r = 0;
126 int max_abs_error_g = 0;
127 int max_abs_error_b = 0;
128 int max_abs_error_a = 0;
129
130 gfx::Rect error_bounding_rect = gfx::Rect();
131
132 // Check that bitmaps have identical dimensions.
133 DCHECK_EQ(actual_bmp.width(), expected_bmp.width());
134 DCHECK_EQ(actual_bmp.height(), expected_bmp.height());
135
136 // Check that bitmaps are not empty.
137 DCHECK_GT(actual_bmp.width(), 0);
138 DCHECK_GT(actual_bmp.height(), 0);
139
140 for (int x = 0; x < actual_bmp.width(); ++x) {
141 for (int y = 0; y < actual_bmp.height(); ++y) {
142 SkColor actual_color = actual_bmp.getColor(x, y);
143 SkColor expected_color = expected_bmp.getColor(x, y);
144 if (discard_alpha_) {
145 actual_color = SkColorSetA(actual_color, 0);
146 expected_color = SkColorSetA(expected_color, 0);
147 }
148
149 if (actual_color != expected_color) {
150 ++error_pixels_count;
151
152 // Compute per channel errors
153 uint32_t expected_alpha = SkColorGetA(expected_color);
154 int error_r = SkColorGetR(actual_color) - SkColorGetR(expected_color);
155 int error_g = SkColorGetG(actual_color) - SkColorGetG(expected_color);
156 int error_b = SkColorGetB(actual_color) - SkColorGetB(expected_color);
157 int error_a = SkColorGetA(actual_color) - expected_alpha;
158 int abs_error_r = std::abs(error_r);
159 int abs_error_g = std::abs(error_g);
160 int abs_error_b = std::abs(error_b);
161 int abs_error_a = std::abs(error_a);
162
163 // Increment small error counter if error is below threshold
164 if (abs_error_r <= small_error_threshold_ &&
165 abs_error_g <= small_error_threshold_ &&
166 abs_error_b <= small_error_threshold_ &&
167 abs_error_a <= small_error_threshold_)
168 ++small_error_pixels_count;
169
170 if (check_critical_error_ && abs_error_a != 0 &&
171 (expected_alpha == 0 || expected_alpha == 0xff))
172 ++critial_error_pixels_count;
173
174 // Update per channel maximum absolute errors
175 max_abs_error_r = std::max(max_abs_error_r, abs_error_r);
176 max_abs_error_g = std::max(max_abs_error_g, abs_error_g);
177 max_abs_error_b = std::max(max_abs_error_b, abs_error_b);
178 max_abs_error_a = std::max(max_abs_error_a, abs_error_a);
179
180 // Update per channel absolute error sums
181 sum_abs_error_r += abs_error_r;
182 sum_abs_error_g += abs_error_g;
183 sum_abs_error_b += abs_error_b;
184 sum_abs_error_a += abs_error_a;
185 }
186 }
187 }
188
189 // Compute error metrics from collected data
190 int pixels_count = actual_bmp.width() * actual_bmp.height();
191 float error_pixels_percentage = 0.0f;
192 float small_error_pixels_percentage = 0.0f;
193 if (pixels_count > 0) {
194 error_pixels_percentage = static_cast<float>(error_pixels_count) /
195 pixels_count * 100.0f;
196 small_error_pixels_percentage =
197 static_cast<float>(small_error_pixels_count) / pixels_count * 100.0f;
198 }
199 float avg_abs_error_r = 0.0f;
200 float avg_abs_error_g = 0.0f;
201 float avg_abs_error_b = 0.0f;
202 float avg_abs_error_a = 0.0f;
203 if (error_pixels_count > 0) {
204 avg_abs_error_r = static_cast<float>(sum_abs_error_r) / error_pixels_count;
205 avg_abs_error_g = static_cast<float>(sum_abs_error_g) / error_pixels_count;
206 avg_abs_error_b = static_cast<float>(sum_abs_error_b) / error_pixels_count;
207 avg_abs_error_a = static_cast<float>(sum_abs_error_a) / error_pixels_count;
208 }
209
210 if (error_pixels_percentage > error_pixels_percentage_limit_ ||
211 small_error_pixels_percentage > small_error_pixels_percentage_limit_ ||
212 avg_abs_error_r > avg_abs_error_limit_ ||
213 avg_abs_error_g > avg_abs_error_limit_ ||
214 avg_abs_error_b > avg_abs_error_limit_ ||
215 avg_abs_error_a > avg_abs_error_limit_ ||
216 max_abs_error_r > max_abs_error_limit_ ||
217 max_abs_error_g > max_abs_error_limit_ ||
218 max_abs_error_b > max_abs_error_limit_ ||
219 max_abs_error_a > max_abs_error_limit_ || critial_error_pixels_count) {
220 LOG(ERROR) << "Percentage of pixels with an error: "
221 << error_pixels_percentage;
222 LOG(ERROR) << "Percentage of pixels with errors not greater than "
223 << small_error_threshold_ << ": "
224 << small_error_pixels_percentage;
225 LOG(ERROR) << "Average absolute error (excluding identical pixels): "
226 << "R=" << avg_abs_error_r << " "
227 << "G=" << avg_abs_error_g << " "
228 << "B=" << avg_abs_error_b << " "
229 << "A=" << avg_abs_error_a;
230 LOG(ERROR) << "Largest absolute error: "
231 << "R=" << max_abs_error_r << " "
232 << "G=" << max_abs_error_g << " "
233 << "B=" << max_abs_error_b << " "
234 << "A=" << max_abs_error_a;
235 LOG(ERROR) << "Critical error: " << critial_error_pixels_count;
236
237 for (int x = 0; x < actual_bmp.width(); ++x) {
238 for (int y = 0; y < actual_bmp.height(); ++y) {
239 SkColor actual_color = actual_bmp.getColor(x, y);
240 SkColor expected_color = expected_bmp.getColor(x, y);
241 if (discard_alpha_) {
242 actual_color = SkColorSetA(actual_color, 0);
243 expected_color = SkColorSetA(expected_color, 0);
244 }
245 if (actual_color != expected_color)
246 error_bounding_rect.Union(gfx::Rect(x, y, 1, 1));
247 }
248 }
249 LOG(ERROR) << "Error Bounding Box : " << error_bounding_rect.ToString();
250 return false;
251 } else {
252 return true;
253 }
254 }
255
256 } // namespace cc
257