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