Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(822)

Side by Side Diff: gfx/skbitmap_operations_unittest.cc

Issue 6246027: Move src/gfx/ to src/ui/gfx... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « gfx/skbitmap_operations.cc ('k') | gfx/skia_util.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2009 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 "gfx/skbitmap_operations.h"
6
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "third_party/skia/include/core/SkBitmap.h"
9 #include "third_party/skia/include/core/SkColorPriv.h"
10 #include "third_party/skia/include/core/SkUnPreMultiply.h"
11
12 namespace {
13
14 // Returns true if each channel of the given two colors are "close." This is
15 // used for comparing colors where rounding errors may cause off-by-one.
16 inline bool ColorsClose(uint32_t a, uint32_t b) {
17 return abs(static_cast<int>(SkColorGetB(a) - SkColorGetB(b))) <= 2 &&
18 abs(static_cast<int>(SkColorGetG(a) - SkColorGetG(b))) <= 2 &&
19 abs(static_cast<int>(SkColorGetR(a) - SkColorGetR(b))) <= 2 &&
20 abs(static_cast<int>(SkColorGetA(a) - SkColorGetA(b))) <= 2;
21 }
22
23 inline bool MultipliedColorsClose(uint32_t a, uint32_t b) {
24 return ColorsClose(SkUnPreMultiply::PMColorToColor(a),
25 SkUnPreMultiply::PMColorToColor(b));
26 }
27
28 bool BitmapsClose(const SkBitmap& a, const SkBitmap& b) {
29 SkAutoLockPixels a_lock(a);
30 SkAutoLockPixels b_lock(b);
31
32 for (int y = 0; y < a.height(); y++) {
33 for (int x = 0; x < a.width(); x++) {
34 SkColor a_pixel = *a.getAddr32(x, y);
35 SkColor b_pixel = *b.getAddr32(x, y);
36 if (!ColorsClose(a_pixel, b_pixel))
37 return false;
38 }
39 }
40 return true;
41 }
42
43 void FillDataToBitmap(int w, int h, SkBitmap* bmp) {
44 bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h);
45 bmp->allocPixels();
46
47 unsigned char* src_data =
48 reinterpret_cast<unsigned char*>(bmp->getAddr32(0, 0));
49 for (int i = 0; i < w * h; i++) {
50 src_data[i * 4 + 0] = static_cast<unsigned char>(i % 255);
51 src_data[i * 4 + 1] = static_cast<unsigned char>(i % 255);
52 src_data[i * 4 + 2] = static_cast<unsigned char>(i % 255);
53 src_data[i * 4 + 3] = static_cast<unsigned char>(i % 255);
54 }
55 }
56
57 // The reference (i.e., old) implementation of |CreateHSLShiftedBitmap()|.
58 SkBitmap ReferenceCreateHSLShiftedBitmap(
59 const SkBitmap& bitmap,
60 color_utils::HSL hsl_shift) {
61 SkBitmap shifted;
62 shifted.setConfig(SkBitmap::kARGB_8888_Config, bitmap.width(),
63 bitmap.height(), 0);
64 shifted.allocPixels();
65 shifted.eraseARGB(0, 0, 0, 0);
66 shifted.setIsOpaque(false);
67
68 SkAutoLockPixels lock_bitmap(bitmap);
69 SkAutoLockPixels lock_shifted(shifted);
70
71 // Loop through the pixels of the original bitmap.
72 for (int y = 0; y < bitmap.height(); ++y) {
73 SkPMColor* pixels = bitmap.getAddr32(0, y);
74 SkPMColor* tinted_pixels = shifted.getAddr32(0, y);
75
76 for (int x = 0; x < bitmap.width(); ++x) {
77 tinted_pixels[x] = SkPreMultiplyColor(color_utils::HSLShift(
78 SkUnPreMultiply::PMColorToColor(pixels[x]), hsl_shift));
79 }
80 }
81
82 return shifted;
83 }
84
85 } // namespace
86
87 // Invert bitmap and verify the each pixel is inverted and the alpha value is
88 // not changed.
89 TEST(SkBitmapOperationsTest, CreateInvertedBitmap) {
90 int src_w = 16, src_h = 16;
91 SkBitmap src;
92 src.setConfig(SkBitmap::kARGB_8888_Config, src_w, src_h);
93 src.allocPixels();
94
95 for (int y = 0; y < src_h; y++) {
96 for (int x = 0; x < src_w; x++) {
97 int i = y * src_w + x;
98 *src.getAddr32(x, y) =
99 SkColorSetARGB((255 - i) % 255, i % 255, i * 4 % 255, 0);
100 }
101 }
102
103 SkBitmap inverted = SkBitmapOperations::CreateInvertedBitmap(src);
104 SkAutoLockPixels src_lock(src);
105 SkAutoLockPixels inverted_lock(inverted);
106
107 for (int y = 0; y < src_h; y++) {
108 for (int x = 0; x < src_w; x++) {
109 int i = y * src_w + x;
110 EXPECT_EQ(static_cast<unsigned int>((255 - i) % 255),
111 SkColorGetA(*inverted.getAddr32(x, y)));
112 EXPECT_EQ(static_cast<unsigned int>(255 - (i % 255)),
113 SkColorGetR(*inverted.getAddr32(x, y)));
114 EXPECT_EQ(static_cast<unsigned int>(255 - (i * 4 % 255)),
115 SkColorGetG(*inverted.getAddr32(x, y)));
116 EXPECT_EQ(static_cast<unsigned int>(255),
117 SkColorGetB(*inverted.getAddr32(x, y)));
118 }
119 }
120 }
121
122 // Blend two bitmaps together at 50% alpha and verify that the result
123 // is the middle-blend of the two.
124 TEST(SkBitmapOperationsTest, CreateBlendedBitmap) {
125 int src_w = 16, src_h = 16;
126 SkBitmap src_a;
127 src_a.setConfig(SkBitmap::kARGB_8888_Config, src_w, src_h);
128 src_a.allocPixels();
129
130 SkBitmap src_b;
131 src_b.setConfig(SkBitmap::kARGB_8888_Config, src_w, src_h);
132 src_b.allocPixels();
133
134 for (int y = 0, i = 0; y < src_h; y++) {
135 for (int x = 0; x < src_w; x++) {
136 *src_a.getAddr32(x, y) = SkColorSetARGB(255, 0, i * 2 % 255, i % 255);
137 *src_b.getAddr32(x, y) =
138 SkColorSetARGB((255 - i) % 255, i % 255, i * 4 % 255, 0);
139 i++;
140 }
141 }
142
143 // Shift to red.
144 SkBitmap blended = SkBitmapOperations::CreateBlendedBitmap(
145 src_a, src_b, 0.5);
146 SkAutoLockPixels srca_lock(src_a);
147 SkAutoLockPixels srcb_lock(src_b);
148 SkAutoLockPixels blended_lock(blended);
149
150 for (int y = 0; y < src_h; y++) {
151 for (int x = 0; x < src_w; x++) {
152 int i = y * src_w + x;
153 EXPECT_EQ(static_cast<unsigned int>((255 + ((255 - i) % 255)) / 2),
154 SkColorGetA(*blended.getAddr32(x, y)));
155 EXPECT_EQ(static_cast<unsigned int>(i % 255 / 2),
156 SkColorGetR(*blended.getAddr32(x, y)));
157 EXPECT_EQ((static_cast<unsigned int>((i * 2) % 255 + (i * 4) % 255) / 2),
158 SkColorGetG(*blended.getAddr32(x, y)));
159 EXPECT_EQ(static_cast<unsigned int>(i % 255 / 2),
160 SkColorGetB(*blended.getAddr32(x, y)));
161 }
162 }
163 }
164
165 // Test our masking functions.
166 TEST(SkBitmapOperationsTest, CreateMaskedBitmap) {
167 int src_w = 16, src_h = 16;
168
169 SkBitmap src;
170 FillDataToBitmap(src_w, src_h, &src);
171
172 // Generate alpha mask
173 SkBitmap alpha;
174 alpha.setConfig(SkBitmap::kARGB_8888_Config, src_w, src_h);
175 alpha.allocPixels();
176 for (int y = 0, i = 0; y < src_h; y++) {
177 for (int x = 0; x < src_w; x++) {
178 *alpha.getAddr32(x, y) = SkColorSetARGB((i + 128) % 255,
179 (i + 128) % 255,
180 (i + 64) % 255,
181 (i + 0) % 255);
182 i++;
183 }
184 }
185
186 SkBitmap masked = SkBitmapOperations::CreateMaskedBitmap(src, alpha);
187
188 SkAutoLockPixels src_lock(src);
189 SkAutoLockPixels alpha_lock(alpha);
190 SkAutoLockPixels masked_lock(masked);
191 for (int y = 0; y < src_h; y++) {
192 for (int x = 0; x < src_w; x++) {
193 // Test that the alpha is equal.
194 SkColor src_pixel = SkUnPreMultiply::PMColorToColor(*src.getAddr32(x, y));
195 SkColor alpha_pixel =
196 SkUnPreMultiply::PMColorToColor(*alpha.getAddr32(x, y));
197 SkColor masked_pixel = *masked.getAddr32(x, y);
198
199 int alpha_value = SkAlphaMul(SkColorGetA(src_pixel),
200 SkColorGetA(alpha_pixel));
201 SkColor expected_pixel = SkColorSetARGB(
202 alpha_value,
203 SkAlphaMul(SkColorGetR(src_pixel), alpha_value),
204 SkAlphaMul(SkColorGetG(src_pixel), alpha_value),
205 SkAlphaMul(SkColorGetB(src_pixel), alpha_value));
206
207 EXPECT_TRUE(ColorsClose(expected_pixel, masked_pixel));
208 }
209 }
210 }
211
212 // Make sure that when shifting a bitmap without any shift parameters,
213 // the end result is close enough to the original (rounding errors
214 // notwithstanding).
215 TEST(SkBitmapOperationsTest, CreateHSLShiftedBitmapToSame) {
216 int src_w = 16, src_h = 16;
217 SkBitmap src;
218 src.setConfig(SkBitmap::kARGB_8888_Config, src_w, src_h);
219 src.allocPixels();
220
221 for (int y = 0, i = 0; y < src_h; y++) {
222 for (int x = 0; x < src_w; x++) {
223 *src.getAddr32(x, y) = SkPreMultiplyColor(SkColorSetARGB((i + 128) % 255,
224 (i + 128) % 255, (i + 64) % 255, (i + 0) % 255));
225 i++;
226 }
227 }
228
229 color_utils::HSL hsl = { -1, -1, -1 };
230 SkBitmap shifted = ReferenceCreateHSLShiftedBitmap(src, hsl);
231
232 SkAutoLockPixels src_lock(src);
233 SkAutoLockPixels shifted_lock(shifted);
234
235 for (int y = 0; y < src_h; y++) {
236 for (int x = 0; x < src_w; x++) {
237 SkColor src_pixel = *src.getAddr32(x, y);
238 SkColor shifted_pixel = *shifted.getAddr32(x, y);
239 EXPECT_TRUE(MultipliedColorsClose(src_pixel, shifted_pixel)) <<
240 "source: (a,r,g,b) = (" << SkColorGetA(src_pixel) << "," <<
241 SkColorGetR(src_pixel) << "," <<
242 SkColorGetG(src_pixel) << "," <<
243 SkColorGetB(src_pixel) << "); " <<
244 "shifted: (a,r,g,b) = (" << SkColorGetA(shifted_pixel) << "," <<
245 SkColorGetR(shifted_pixel) << "," <<
246 SkColorGetG(shifted_pixel) << "," <<
247 SkColorGetB(shifted_pixel) << ")";
248 }
249 }
250 }
251
252 // Shift a blue bitmap to red.
253 TEST(SkBitmapOperationsTest, CreateHSLShiftedBitmapHueOnly) {
254 int src_w = 16, src_h = 16;
255 SkBitmap src;
256 src.setConfig(SkBitmap::kARGB_8888_Config, src_w, src_h);
257 src.allocPixels();
258
259 for (int y = 0, i = 0; y < src_h; y++) {
260 for (int x = 0; x < src_w; x++) {
261 *src.getAddr32(x, y) = SkColorSetARGB(255, 0, 0, i % 255);
262 i++;
263 }
264 }
265
266 // Shift to red.
267 color_utils::HSL hsl = { 0, -1, -1 };
268
269 SkBitmap shifted = SkBitmapOperations::CreateHSLShiftedBitmap(src, hsl);
270
271 SkAutoLockPixels src_lock(src);
272 SkAutoLockPixels shifted_lock(shifted);
273
274 for (int y = 0, i = 0; y < src_h; y++) {
275 for (int x = 0; x < src_w; x++) {
276 EXPECT_TRUE(ColorsClose(*shifted.getAddr32(x, y),
277 SkColorSetARGB(255, i % 255, 0, 0)));
278 i++;
279 }
280 }
281 }
282
283 // Validate HSL shift.
284 TEST(SkBitmapOperationsTest, ValidateHSLShift) {
285 // Note: 255/51 = 5 (exactly) => 6 including 0!
286 const int inc = 51;
287 const int dim = 255 / inc + 1;
288 SkBitmap src;
289 src.setConfig(SkBitmap::kARGB_8888_Config, dim*dim, dim*dim);
290 src.allocPixels();
291
292 for (int a = 0, y = 0; a <= 255; a += inc) {
293 for (int r = 0; r <= 255; r += inc, y++) {
294 for (int g = 0, x = 0; g <= 255; g += inc) {
295 for (int b = 0; b <= 255; b+= inc, x++) {
296 *src.getAddr32(x, y) =
297 SkPreMultiplyColor(SkColorSetARGB(a, r, g, b));
298 }
299 }
300 }
301 }
302
303 // Shhhh. The spec says I should set things to -1 for "no change", but
304 // actually -0.1 will do. Don't tell anyone I did this.
305 for (double h = -0.1; h <= 1.0001; h += 0.1) {
306 for (double s = -0.1; s <= 1.0001; s += 0.1) {
307 for (double l = -0.1; l <= 1.0001; l += 0.1) {
308 color_utils::HSL hsl = { h, s, l };
309 SkBitmap ref_shifted = ReferenceCreateHSLShiftedBitmap(src, hsl);
310 SkBitmap shifted = SkBitmapOperations::CreateHSLShiftedBitmap(src, hsl);
311 EXPECT_TRUE(BitmapsClose(ref_shifted, shifted))
312 << "h = " << h << ", s = " << s << ", l = " << l;
313 }
314 }
315 }
316 }
317
318 // Test our cropping.
319 TEST(SkBitmapOperationsTest, CreateCroppedBitmap) {
320 int src_w = 16, src_h = 16;
321 SkBitmap src;
322 FillDataToBitmap(src_w, src_h, &src);
323
324 SkBitmap cropped = SkBitmapOperations::CreateTiledBitmap(src, 4, 4,
325 8, 8);
326 ASSERT_EQ(8, cropped.width());
327 ASSERT_EQ(8, cropped.height());
328
329 SkAutoLockPixels src_lock(src);
330 SkAutoLockPixels cropped_lock(cropped);
331 for (int y = 4; y < 12; y++) {
332 for (int x = 4; x < 12; x++) {
333 EXPECT_EQ(*src.getAddr32(x, y),
334 *cropped.getAddr32(x - 4, y - 4));
335 }
336 }
337 }
338
339 // Test whether our cropping correctly wraps across image boundaries.
340 TEST(SkBitmapOperationsTest, CreateCroppedBitmapWrapping) {
341 int src_w = 16, src_h = 16;
342 SkBitmap src;
343 FillDataToBitmap(src_w, src_h, &src);
344
345 SkBitmap cropped = SkBitmapOperations::CreateTiledBitmap(
346 src, src_w / 2, src_h / 2, src_w, src_h);
347 ASSERT_EQ(src_w, cropped.width());
348 ASSERT_EQ(src_h, cropped.height());
349
350 SkAutoLockPixels src_lock(src);
351 SkAutoLockPixels cropped_lock(cropped);
352 for (int y = 0; y < src_h; y++) {
353 for (int x = 0; x < src_w; x++) {
354 EXPECT_EQ(*src.getAddr32(x, y),
355 *cropped.getAddr32((x + src_w / 2) % src_w,
356 (y + src_h / 2) % src_h));
357 }
358 }
359 }
360
361 TEST(SkBitmapOperationsTest, DownsampleByTwo) {
362 // Use an odd-sized bitmap to make sure the edge cases where there isn't a
363 // 2x2 block of pixels is handled correctly.
364 // Here's the ARGB example
365 //
366 // 50% transparent green opaque 50% blue white
367 // 80008000 FF000080 FFFFFFFF
368 //
369 // 50% transparent red opaque 50% gray black
370 // 80800000 80808080 FF000000
371 //
372 // black white 50% gray
373 // FF000000 FFFFFFFF FF808080
374 //
375 // The result of this computation should be:
376 // A0404040 FF808080
377 // FF808080 FF808080
378 SkBitmap input;
379 input.setConfig(SkBitmap::kARGB_8888_Config, 3, 3);
380 input.allocPixels();
381
382 // The color order may be different, but we don't care (the channels are
383 // trated the same).
384 *input.getAddr32(0, 0) = 0x80008000;
385 *input.getAddr32(1, 0) = 0xFF000080;
386 *input.getAddr32(2, 0) = 0xFFFFFFFF;
387 *input.getAddr32(0, 1) = 0x80800000;
388 *input.getAddr32(1, 1) = 0x80808080;
389 *input.getAddr32(2, 1) = 0xFF000000;
390 *input.getAddr32(0, 2) = 0xFF000000;
391 *input.getAddr32(1, 2) = 0xFFFFFFFF;
392 *input.getAddr32(2, 2) = 0xFF808080;
393
394 SkBitmap result = SkBitmapOperations::DownsampleByTwo(input);
395 EXPECT_EQ(2, result.width());
396 EXPECT_EQ(2, result.height());
397
398 // Some of the values are off-by-one due to rounding.
399 SkAutoLockPixels lock(result);
400 EXPECT_EQ(0x9f404040, *result.getAddr32(0, 0));
401 EXPECT_EQ(0xFF7f7f7f, *result.getAddr32(1, 0));
402 EXPECT_EQ(0xFF7f7f7f, *result.getAddr32(0, 1));
403 EXPECT_EQ(0xFF808080, *result.getAddr32(1, 1));
404 }
405
406 // Test edge cases for DownsampleByTwo.
407 TEST(SkBitmapOperationsTest, DownsampleByTwoSmall) {
408 SkPMColor reference = 0xFF4080FF;
409
410 // Test a 1x1 bitmap.
411 SkBitmap one_by_one;
412 one_by_one.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
413 one_by_one.allocPixels();
414 *one_by_one.getAddr32(0, 0) = reference;
415 SkBitmap result = SkBitmapOperations::DownsampleByTwo(one_by_one);
416 SkAutoLockPixels lock1(result);
417 EXPECT_EQ(1, result.width());
418 EXPECT_EQ(1, result.height());
419 EXPECT_EQ(reference, *result.getAddr32(0, 0));
420
421 // Test an n by 1 bitmap.
422 SkBitmap one_by_n;
423 one_by_n.setConfig(SkBitmap::kARGB_8888_Config, 300, 1);
424 one_by_n.allocPixels();
425 result = SkBitmapOperations::DownsampleByTwo(one_by_n);
426 SkAutoLockPixels lock2(result);
427 EXPECT_EQ(300, result.width());
428 EXPECT_EQ(1, result.height());
429
430 // Test a 1 by n bitmap.
431 SkBitmap n_by_one;
432 n_by_one.setConfig(SkBitmap::kARGB_8888_Config, 1, 300);
433 n_by_one.allocPixels();
434 result = SkBitmapOperations::DownsampleByTwo(n_by_one);
435 SkAutoLockPixels lock3(result);
436 EXPECT_EQ(1, result.width());
437 EXPECT_EQ(300, result.height());
438
439 // Test an empty bitmap
440 SkBitmap empty;
441 result = SkBitmapOperations::DownsampleByTwo(empty);
442 EXPECT_TRUE(result.isNull());
443 EXPECT_EQ(0, result.width());
444 EXPECT_EQ(0, result.height());
445 }
446
447 // Here we assume DownsampleByTwo works correctly (it's tested above) and
448 // just make sure that the wrapper function does the right thing.
449 TEST(SkBitmapOperationsTest, DownsampleByTwoUntilSize) {
450 // First make sure a "too small" bitmap doesn't get modified at all.
451 SkBitmap too_small;
452 too_small.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
453 too_small.allocPixels();
454 SkBitmap result = SkBitmapOperations::DownsampleByTwoUntilSize(
455 too_small, 16, 16);
456 EXPECT_EQ(10, result.width());
457 EXPECT_EQ(10, result.height());
458
459 // Now make sure giving it a 0x0 target returns something reasonable.
460 result = SkBitmapOperations::DownsampleByTwoUntilSize(too_small, 0, 0);
461 EXPECT_EQ(1, result.width());
462 EXPECT_EQ(1, result.height());
463
464 // Test multiple steps of downsampling.
465 SkBitmap large;
466 large.setConfig(SkBitmap::kARGB_8888_Config, 100, 43);
467 large.allocPixels();
468 result = SkBitmapOperations::DownsampleByTwoUntilSize(large, 6, 6);
469
470 // The result should be divided in half 100x43 -> 50x22 -> 25x11
471 EXPECT_EQ(25, result.width());
472 EXPECT_EQ(11, result.height());
473 }
474
475 TEST(SkBitmapOperationsTest, UnPreMultiply) {
476 SkBitmap input;
477 input.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
478 input.allocPixels();
479
480 *input.getAddr32(0, 0) = 0x80000000;
481 *input.getAddr32(1, 0) = 0x80808080;
482 *input.getAddr32(0, 1) = 0xFF00CC88;
483 *input.getAddr32(1, 1) = 0x0000CC88;
484
485 SkBitmap result = SkBitmapOperations::UnPreMultiply(input);
486 EXPECT_EQ(2, result.width());
487 EXPECT_EQ(2, result.height());
488
489 SkAutoLockPixels lock(result);
490 EXPECT_EQ(0x80000000, *result.getAddr32(0, 0));
491 EXPECT_EQ(0x80FFFFFF, *result.getAddr32(1, 0));
492 EXPECT_EQ(0xFF00CC88, *result.getAddr32(0, 1));
493 EXPECT_EQ(0x00000000u, *result.getAddr32(1, 1)); // "Division by zero".
494 }
495
496 TEST(SkBitmapOperationsTest, CreateTransposedBtmap) {
497 SkBitmap input;
498 input.setConfig(SkBitmap::kARGB_8888_Config, 2, 3);
499 input.allocPixels();
500
501 for (int x = 0; x < input.width(); ++x) {
502 for (int y = 0; y < input.height(); ++y) {
503 *input.getAddr32(x, y) = x * input.width() + y;
504 }
505 }
506
507 SkBitmap result = SkBitmapOperations::CreateTransposedBtmap(input);
508 EXPECT_EQ(3, result.width());
509 EXPECT_EQ(2, result.height());
510
511 SkAutoLockPixels lock(result);
512 for (int x = 0; x < input.width(); ++x) {
513 for (int y = 0; y < input.height(); ++y) {
514 EXPECT_EQ(*input.getAddr32(x, y), *result.getAddr32(y, x));
515 }
516 }
517 }
OLDNEW
« no previous file with comments | « gfx/skbitmap_operations.cc ('k') | gfx/skia_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698