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. 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 26 inline bool MultipliedColorsClose(uint32_t a, uint32_t b) { 27 return ColorsClose(SkUnPreMultiply::PMColorToColor(a), 28 SkUnPreMultiply::PMColorToColor(b)); 29 } 30 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 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()|. 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. 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. 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. 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). 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. 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. 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. 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. 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 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. 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. 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 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 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 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