1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkBitmap.h" 9 #include "SkRect.h" 10 #include "Test.h" 11 12 static const char* boolStr(bool value) { 13 return value ? "true" : "false"; 14 } 15 16 // these are in the same order as the SkColorType enum 17 static const char* gColorTypeName[] = { 18 "None", "A8", "565", "4444", "RGBA", "BGRA", "Index8" 19 }; 20 21 static void report_opaqueness(skiatest::Reporter* reporter, const SkBitmap& src, 22 const SkBitmap& dst) { 23 ERRORF(reporter, "src %s opaque:%d, dst %s opaque:%d", 24 gColorTypeName[src.colorType()], src.isOpaque(), 25 gColorTypeName[dst.colorType()], dst.isOpaque()); 26 } 27 28 static bool canHaveAlpha(SkColorType ct) { 29 return kRGB_565_SkColorType != ct; 30 } 31 32 // copyTo() should preserve isOpaque when it makes sense 33 static void test_isOpaque(skiatest::Reporter* reporter, 34 const SkBitmap& srcOpaque, const SkBitmap& srcPremul, 35 SkColorType dstColorType) { 36 SkBitmap dst; 37 38 if (canHaveAlpha(srcPremul.colorType()) && canHaveAlpha(dstColorType)) { 39 REPORTER_ASSERT(reporter, srcPremul.copyTo(&dst, dstColorType)); 40 REPORTER_ASSERT(reporter, dst.colorType() == dstColorType); 41 if (srcPremul.isOpaque() != dst.isOpaque()) { 42 report_opaqueness(reporter, srcPremul, dst); 43 } 44 } 45 46 REPORTER_ASSERT(reporter, srcOpaque.copyTo(&dst, dstColorType)); 47 REPORTER_ASSERT(reporter, dst.colorType() == dstColorType); 48 if (srcOpaque.isOpaque() != dst.isOpaque()) { 49 report_opaqueness(reporter, srcOpaque, dst); 50 } 51 } 52 53 static void init_src(const SkBitmap& bitmap) { 54 SkAutoLockPixels lock(bitmap); 55 if (bitmap.getPixels()) { 56 if (bitmap.getColorTable()) { 57 sk_bzero(bitmap.getPixels(), bitmap.getSize()); 58 } else { 59 bitmap.eraseColor(SK_ColorWHITE); 60 } 61 } 62 } 63 64 static SkColorTable* init_ctable(SkAlphaType alphaType) { 65 static const SkColor colors[] = { 66 SK_ColorBLACK, SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE 67 }; 68 return new SkColorTable(colors, SK_ARRAY_COUNT(colors), alphaType); 69 } 70 71 struct Pair { 72 SkColorType fColorType; 73 const char* fValid; 74 }; 75 76 // Utility functions for copyPixelsTo()/copyPixelsFrom() tests. 77 // getPixel() 78 // setPixel() 79 // getSkConfigName() 80 // struct Coordinates 81 // reportCopyVerification() 82 // writeCoordPixels() 83 84 // Utility function to read the value of a given pixel in bm. All 85 // values converted to uint32_t for simplification of comparisons. 86 static uint32_t getPixel(int x, int y, const SkBitmap& bm) { 87 uint32_t val = 0; 88 uint16_t val16; 89 uint8_t val8; 90 SkAutoLockPixels lock(bm); 91 const void* rawAddr = bm.getAddr(x,y); 92 93 switch (bm.bytesPerPixel()) { 94 case 4: 95 memcpy(&val, rawAddr, sizeof(uint32_t)); 96 break; 97 case 2: 98 memcpy(&val16, rawAddr, sizeof(uint16_t)); 99 val = val16; 100 break; 101 case 1: 102 memcpy(&val8, rawAddr, sizeof(uint8_t)); 103 val = val8; 104 break; 105 default: 106 break; 107 } 108 return val; 109 } 110 111 // Utility function to set value of any pixel in bm. 112 // bm.getConfig() specifies what format 'val' must be 113 // converted to, but at present uint32_t can handle all formats. 114 static void setPixel(int x, int y, uint32_t val, SkBitmap& bm) { 115 uint16_t val16; 116 uint8_t val8; 117 SkAutoLockPixels lock(bm); 118 void* rawAddr = bm.getAddr(x,y); 119 120 switch (bm.bytesPerPixel()) { 121 case 4: 122 memcpy(rawAddr, &val, sizeof(uint32_t)); 123 break; 124 case 2: 125 val16 = val & 0xFFFF; 126 memcpy(rawAddr, &val16, sizeof(uint16_t)); 127 break; 128 case 1: 129 val8 = val & 0xFF; 130 memcpy(rawAddr, &val8, sizeof(uint8_t)); 131 break; 132 default: 133 // Ignore. 134 break; 135 } 136 } 137 138 // Helper struct to contain pixel locations, while avoiding need for STL. 139 struct Coordinates { 140 141 const int length; 142 SkIPoint* const data; 143 144 explicit Coordinates(int _length): length(_length) 145 , data(new SkIPoint[length]) { } 146 147 ~Coordinates(){ 148 delete [] data; 149 } 150 151 SkIPoint* operator[](int i) const { 152 // Use with care, no bounds checking. 153 return data + i; 154 } 155 }; 156 157 // A function to verify that two bitmaps contain the same pixel values 158 // at all coordinates indicated by coords. Simplifies verification of 159 // copied bitmaps. 160 static void reportCopyVerification(const SkBitmap& bm1, const SkBitmap& bm2, 161 Coordinates& coords, 162 const char* msg, 163 skiatest::Reporter* reporter){ 164 bool success = true; 165 166 // Confirm all pixels in the list match. 167 for (int i = 0; i < coords.length; ++i) { 168 success = success && 169 (getPixel(coords[i]->fX, coords[i]->fY, bm1) == 170 getPixel(coords[i]->fX, coords[i]->fY, bm2)); 171 } 172 173 if (!success) { 174 ERRORF(reporter, "%s [colortype = %s]", msg, 175 gColorTypeName[bm1.colorType()]); 176 } 177 } 178 179 // Writes unique pixel values at locations specified by coords. 180 static void writeCoordPixels(SkBitmap& bm, const Coordinates& coords) { 181 for (int i = 0; i < coords.length; ++i) 182 setPixel(coords[i]->fX, coords[i]->fY, i, bm); 183 } 184 185 static const Pair gPairs[] = { 186 { kUnknown_SkColorType, "000000" }, 187 { kAlpha_8_SkColorType, "010101" }, 188 { kIndex_8_SkColorType, "011111" }, 189 { kRGB_565_SkColorType, "010101" }, 190 { kARGB_4444_SkColorType, "010111" }, 191 { kN32_SkColorType, "010111" }, 192 }; 193 194 static const int W = 20; 195 static const int H = 33; 196 197 static void setup_src_bitmaps(SkBitmap* srcOpaque, SkBitmap* srcPremul, 198 SkColorType ct) { 199 SkColorTable* ctOpaque = NULL; 200 SkColorTable* ctPremul = NULL; 201 if (kIndex_8_SkColorType == ct) { 202 ctOpaque = init_ctable(kOpaque_SkAlphaType); 203 ctPremul = init_ctable(kPremul_SkAlphaType); 204 } 205 206 srcOpaque->allocPixels(SkImageInfo::Make(W, H, ct, kOpaque_SkAlphaType), 207 NULL, ctOpaque); 208 srcPremul->allocPixels(SkImageInfo::Make(W, H, ct, kPremul_SkAlphaType), 209 NULL, ctPremul); 210 SkSafeUnref(ctOpaque); 211 SkSafeUnref(ctPremul); 212 init_src(*srcOpaque); 213 init_src(*srcPremul); 214 } 215 216 DEF_TEST(BitmapCopy_extractSubset, reporter) { 217 for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) { 218 SkBitmap srcOpaque, srcPremul; 219 setup_src_bitmaps(&srcOpaque, &srcPremul, gPairs[i].fColorType); 220 221 SkBitmap bitmap(srcOpaque); 222 SkBitmap subset; 223 SkIRect r; 224 // Extract a subset which has the same width as the original. This 225 // catches a bug where we cloned the genID incorrectly. 226 r.set(0, 1, W, 3); 227 bitmap.setIsVolatile(true); 228 // Relies on old behavior of extractSubset failing if colortype is unknown 229 if (kUnknown_SkColorType != bitmap.colorType() && bitmap.extractSubset(&subset, r)) { 230 REPORTER_ASSERT(reporter, subset.width() == W); 231 REPORTER_ASSERT(reporter, subset.height() == 2); 232 REPORTER_ASSERT(reporter, subset.alphaType() == bitmap.alphaType()); 233 REPORTER_ASSERT(reporter, subset.isVolatile() == true); 234 235 // Test copying an extracted subset. 236 for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) { 237 SkBitmap copy; 238 bool success = subset.copyTo(©, gPairs[j].fColorType); 239 if (!success) { 240 // Skip checking that success matches fValid, which is redundant 241 // with the code below. 242 REPORTER_ASSERT(reporter, gPairs[i].fColorType != gPairs[j].fColorType); 243 continue; 244 } 245 246 // When performing a copy of an extracted subset, the gen id should 247 // change. 248 REPORTER_ASSERT(reporter, copy.getGenerationID() != subset.getGenerationID()); 249 250 REPORTER_ASSERT(reporter, copy.width() == W); 251 REPORTER_ASSERT(reporter, copy.height() == 2); 252 253 if (gPairs[i].fColorType == gPairs[j].fColorType) { 254 SkAutoLockPixels alp0(subset); 255 SkAutoLockPixels alp1(copy); 256 // they should both have, or both not-have, a colortable 257 bool hasCT = subset.getColorTable() != NULL; 258 REPORTER_ASSERT(reporter, (copy.getColorTable() != NULL) == hasCT); 259 } 260 } 261 } 262 263 bitmap = srcPremul; 264 bitmap.setIsVolatile(false); 265 if (bitmap.extractSubset(&subset, r)) { 266 REPORTER_ASSERT(reporter, subset.alphaType() == bitmap.alphaType()); 267 REPORTER_ASSERT(reporter, subset.isVolatile() == false); 268 } 269 } 270 } 271 272 DEF_TEST(BitmapCopy, reporter) { 273 static const bool isExtracted[] = { 274 false, true 275 }; 276 277 for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) { 278 SkBitmap srcOpaque, srcPremul; 279 setup_src_bitmaps(&srcOpaque, &srcPremul, gPairs[i].fColorType); 280 281 for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) { 282 SkBitmap dst; 283 284 bool success = srcPremul.copyTo(&dst, gPairs[j].fColorType); 285 bool expected = gPairs[i].fValid[j] != '0'; 286 if (success != expected) { 287 ERRORF(reporter, "SkBitmap::copyTo from %s to %s. expected %s " 288 "returned %s", gColorTypeName[i], gColorTypeName[j], 289 boolStr(expected), boolStr(success)); 290 } 291 292 bool canSucceed = srcPremul.canCopyTo(gPairs[j].fColorType); 293 if (success != canSucceed) { 294 ERRORF(reporter, "SkBitmap::copyTo from %s to %s. returned %s " 295 "canCopyTo %s", gColorTypeName[i], gColorTypeName[j], 296 boolStr(success), boolStr(canSucceed)); 297 } 298 299 if (success) { 300 REPORTER_ASSERT(reporter, srcPremul.width() == dst.width()); 301 REPORTER_ASSERT(reporter, srcPremul.height() == dst.height()); 302 REPORTER_ASSERT(reporter, dst.colorType() == gPairs[j].fColorType); 303 test_isOpaque(reporter, srcOpaque, srcPremul, dst.colorType()); 304 if (srcPremul.colorType() == dst.colorType()) { 305 SkAutoLockPixels srcLock(srcPremul); 306 SkAutoLockPixels dstLock(dst); 307 REPORTER_ASSERT(reporter, srcPremul.readyToDraw()); 308 REPORTER_ASSERT(reporter, dst.readyToDraw()); 309 const char* srcP = (const char*)srcPremul.getAddr(0, 0); 310 const char* dstP = (const char*)dst.getAddr(0, 0); 311 REPORTER_ASSERT(reporter, srcP != dstP); 312 REPORTER_ASSERT(reporter, !memcmp(srcP, dstP, 313 srcPremul.getSize())); 314 REPORTER_ASSERT(reporter, srcPremul.getGenerationID() == dst.getGenerationID()); 315 } else { 316 REPORTER_ASSERT(reporter, srcPremul.getGenerationID() != dst.getGenerationID()); 317 } 318 } else { 319 // dst should be unchanged from its initial state 320 REPORTER_ASSERT(reporter, dst.colorType() == kUnknown_SkColorType); 321 REPORTER_ASSERT(reporter, dst.width() == 0); 322 REPORTER_ASSERT(reporter, dst.height() == 0); 323 } 324 } // for (size_t j = ... 325 326 // Tests for getSafeSize(), getSafeSize64(), copyPixelsTo(), 327 // copyPixelsFrom(). 328 // 329 for (size_t copyCase = 0; copyCase < SK_ARRAY_COUNT(isExtracted); 330 ++copyCase) { 331 // Test copying to/from external buffer. 332 // Note: the tests below have hard-coded values --- 333 // Please take care if modifying. 334 335 // Tests for getSafeSize64(). 336 // Test with a very large configuration without pixel buffer 337 // attached. 338 SkBitmap tstSafeSize; 339 tstSafeSize.setInfo(SkImageInfo::Make(100000000U, 100000000U, 340 gPairs[i].fColorType, kPremul_SkAlphaType)); 341 int64_t safeSize = tstSafeSize.computeSafeSize64(); 342 if (safeSize < 0) { 343 ERRORF(reporter, "getSafeSize64() negative: %s", 344 gColorTypeName[tstSafeSize.colorType()]); 345 } 346 bool sizeFail = false; 347 // Compare against hand-computed values. 348 switch (gPairs[i].fColorType) { 349 case kUnknown_SkColorType: 350 break; 351 352 case kAlpha_8_SkColorType: 353 case kIndex_8_SkColorType: 354 if (safeSize != 0x2386F26FC10000LL) { 355 sizeFail = true; 356 } 357 break; 358 359 case kRGB_565_SkColorType: 360 case kARGB_4444_SkColorType: 361 if (safeSize != 0x470DE4DF820000LL) { 362 sizeFail = true; 363 } 364 break; 365 366 case kN32_SkColorType: 367 if (safeSize != 0x8E1BC9BF040000LL) { 368 sizeFail = true; 369 } 370 break; 371 372 default: 373 break; 374 } 375 if (sizeFail) { 376 ERRORF(reporter, "computeSafeSize64() wrong size: %s", 377 gColorTypeName[tstSafeSize.colorType()]); 378 } 379 380 int subW = 2; 381 int subH = 2; 382 383 // Create bitmap to act as source for copies and subsets. 384 SkBitmap src, subset; 385 SkColorTable* ct = NULL; 386 if (kIndex_8_SkColorType == src.colorType()) { 387 ct = init_ctable(kPremul_SkAlphaType); 388 } 389 390 int localSubW; 391 if (isExtracted[copyCase]) { // A larger image to extract from. 392 localSubW = 2 * subW + 1; 393 } else { // Tests expect a 2x2 bitmap, so make smaller. 394 localSubW = subW; 395 } 396 // could fail if we pass kIndex_8 for the colortype 397 if (src.tryAllocPixels(SkImageInfo::Make(localSubW, subH, gPairs[i].fColorType, 398 kPremul_SkAlphaType))) { 399 // failure is fine, as we will notice later on 400 } 401 SkSafeUnref(ct); 402 403 // Either copy src or extract into 'subset', which is used 404 // for subsequent calls to copyPixelsTo/From. 405 bool srcReady = false; 406 // Test relies on older behavior that extractSubset will fail on 407 // kUnknown_SkColorType 408 if (kUnknown_SkColorType != src.colorType() && 409 isExtracted[copyCase]) { 410 // The extractedSubset() test case allows us to test copy- 411 // ing when src and dst mave possibly different strides. 412 SkIRect r; 413 r.set(1, 0, 1 + subW, subH); // 2x2 extracted bitmap 414 415 srcReady = src.extractSubset(&subset, r); 416 } else { 417 srcReady = src.copyTo(&subset); 418 } 419 420 // Not all configurations will generate a valid 'subset'. 421 if (srcReady) { 422 423 // Allocate our target buffer 'buf' for all copies. 424 // To simplify verifying correctness of copies attach 425 // buf to a SkBitmap, but copies are done using the 426 // raw buffer pointer. 427 const size_t bufSize = subH * 428 SkColorTypeMinRowBytes(src.colorType(), subW) * 2; 429 SkAutoMalloc autoBuf (bufSize); 430 uint8_t* buf = static_cast<uint8_t*>(autoBuf.get()); 431 432 SkBitmap bufBm; // Attach buf to this bitmap. 433 bool successExpected; 434 435 // Set up values for each pixel being copied. 436 Coordinates coords(subW * subH); 437 for (int x = 0; x < subW; ++x) 438 for (int y = 0; y < subH; ++y) 439 { 440 int index = y * subW + x; 441 SkASSERT(index < coords.length); 442 coords[index]->fX = x; 443 coords[index]->fY = y; 444 } 445 446 writeCoordPixels(subset, coords); 447 448 // Test #1 //////////////////////////////////////////// 449 450 const SkImageInfo info = SkImageInfo::Make(subW, subH, 451 gPairs[i].fColorType, 452 kPremul_SkAlphaType); 453 // Before/after comparisons easier if we attach buf 454 // to an appropriately configured SkBitmap. 455 memset(buf, 0xFF, bufSize); 456 // Config with stride greater than src but that fits in buf. 457 bufBm.installPixels(info, buf, info.minRowBytes() * 2); 458 successExpected = false; 459 // Then attempt to copy with a stride that is too large 460 // to fit in the buffer. 461 REPORTER_ASSERT(reporter, 462 subset.copyPixelsTo(buf, bufSize, bufBm.rowBytes() * 3) 463 == successExpected); 464 465 if (successExpected) 466 reportCopyVerification(subset, bufBm, coords, 467 "copyPixelsTo(buf, bufSize, 1.5*maxRowBytes)", 468 reporter); 469 470 // Test #2 //////////////////////////////////////////// 471 // This test should always succeed, but in the case 472 // of extracted bitmaps only because we handle the 473 // issue of getSafeSize(). Without getSafeSize() 474 // buffer overrun/read would occur. 475 memset(buf, 0xFF, bufSize); 476 bufBm.installPixels(info, buf, subset.rowBytes()); 477 successExpected = subset.getSafeSize() <= bufSize; 478 REPORTER_ASSERT(reporter, 479 subset.copyPixelsTo(buf, bufSize) == 480 successExpected); 481 if (successExpected) 482 reportCopyVerification(subset, bufBm, coords, 483 "copyPixelsTo(buf, bufSize)", reporter); 484 485 // Test #3 //////////////////////////////////////////// 486 // Copy with different stride between src and dst. 487 memset(buf, 0xFF, bufSize); 488 bufBm.installPixels(info, buf, subset.rowBytes()+1); 489 successExpected = true; // Should always work. 490 REPORTER_ASSERT(reporter, 491 subset.copyPixelsTo(buf, bufSize, 492 subset.rowBytes()+1) == successExpected); 493 if (successExpected) 494 reportCopyVerification(subset, bufBm, coords, 495 "copyPixelsTo(buf, bufSize, rowBytes+1)", reporter); 496 497 // Test #4 //////////////////////////////////////////// 498 // Test copy with stride too small. 499 memset(buf, 0xFF, bufSize); 500 bufBm.installPixels(info, buf, info.minRowBytes()); 501 successExpected = false; 502 // Request copy with stride too small. 503 REPORTER_ASSERT(reporter, 504 subset.copyPixelsTo(buf, bufSize, bufBm.rowBytes()-1) 505 == successExpected); 506 if (successExpected) 507 reportCopyVerification(subset, bufBm, coords, 508 "copyPixelsTo(buf, bufSize, rowBytes()-1)", reporter); 509 510 #if 0 // copyPixelsFrom is gone 511 // Test #5 //////////////////////////////////////////// 512 // Tests the case where the source stride is too small 513 // for the source configuration. 514 memset(buf, 0xFF, bufSize); 515 bufBm.installPixels(info, buf, info.minRowBytes()); 516 writeCoordPixels(bufBm, coords); 517 REPORTER_ASSERT(reporter, 518 subset.copyPixelsFrom(buf, bufSize, 1) == false); 519 520 // Test #6 /////////////////////////////////////////// 521 // Tests basic copy from an external buffer to the bitmap. 522 // If the bitmap is "extracted", this also tests the case 523 // where the source stride is different from the dest. 524 // stride. 525 // We've made the buffer large enough to always succeed. 526 bufBm.installPixels(info, buf, info.minRowBytes()); 527 writeCoordPixels(bufBm, coords); 528 REPORTER_ASSERT(reporter, 529 subset.copyPixelsFrom(buf, bufSize, bufBm.rowBytes()) == 530 true); 531 reportCopyVerification(bufBm, subset, coords, 532 "copyPixelsFrom(buf, bufSize)", 533 reporter); 534 535 // Test #7 //////////////////////////////////////////// 536 // Tests the case where the source buffer is too small 537 // for the transfer. 538 REPORTER_ASSERT(reporter, 539 subset.copyPixelsFrom(buf, 1, subset.rowBytes()) == 540 false); 541 542 #endif 543 } 544 } // for (size_t copyCase ... 545 } 546 } 547 548 #include "SkColorPriv.h" 549 #include "SkUtils.h" 550 551 /** 552 * Construct 4x4 pixels where we can look at a color and determine where it should be in the grid. 553 * alpha = 0xFF, blue = 0x80, red = x, green = y 554 */ 555 static void fill_4x4_pixels(SkPMColor colors[16]) { 556 for (int y = 0; y < 4; ++y) { 557 for (int x = 0; x < 4; ++x) { 558 colors[y*4+x] = SkPackARGB32(0xFF, x, y, 0x80); 559 } 560 } 561 } 562 563 static bool check_4x4_pixel(SkPMColor color, unsigned x, unsigned y) { 564 SkASSERT(x < 4 && y < 4); 565 return 0xFF == SkGetPackedA32(color) && 566 x == SkGetPackedR32(color) && 567 y == SkGetPackedG32(color) && 568 0x80 == SkGetPackedB32(color); 569 } 570 571 /** 572 * Fill with all zeros, which will never match any value from fill_4x4_pixels 573 */ 574 static void clear_4x4_pixels(SkPMColor colors[16]) { 575 sk_memset32(colors, 0, 16); 576 } 577 578 // Much of readPixels is exercised by copyTo testing, since readPixels is the backend for that 579 // method. Here we explicitly test subset copies. 580 // 581 DEF_TEST(BitmapReadPixels, reporter) { 582 const int W = 4; 583 const int H = 4; 584 const size_t rowBytes = W * sizeof(SkPMColor); 585 const SkImageInfo srcInfo = SkImageInfo::MakeN32Premul(W, H); 586 SkPMColor srcPixels[16]; 587 fill_4x4_pixels(srcPixels); 588 SkBitmap srcBM; 589 srcBM.installPixels(srcInfo, srcPixels, rowBytes); 590 591 SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(W, H); 592 SkPMColor dstPixels[16]; 593 594 const struct { 595 bool fExpectedSuccess; 596 SkIPoint fRequestedSrcLoc; 597 SkISize fRequestedDstSize; 598 // If fExpectedSuccess, check these, otherwise ignore 599 SkIPoint fExpectedDstLoc; 600 SkIRect fExpectedSrcR; 601 } gRec[] = { 602 { true, { 0, 0 }, { 4, 4 }, { 0, 0 }, { 0, 0, 4, 4 } }, 603 { true, { 1, 1 }, { 2, 2 }, { 0, 0 }, { 1, 1, 3, 3 } }, 604 { true, { 2, 2 }, { 4, 4 }, { 0, 0 }, { 2, 2, 4, 4 } }, 605 { true, {-1,-1 }, { 2, 2 }, { 1, 1 }, { 0, 0, 1, 1 } }, 606 { false, {-1,-1 }, { 1, 1 }, { 0, 0 }, { 0, 0, 0, 0 } }, 607 }; 608 609 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { 610 clear_4x4_pixels(dstPixels); 611 612 dstInfo = dstInfo.makeWH(gRec[i].fRequestedDstSize.width(), 613 gRec[i].fRequestedDstSize.height()); 614 bool success = srcBM.readPixels(dstInfo, dstPixels, rowBytes, 615 gRec[i].fRequestedSrcLoc.x(), gRec[i].fRequestedSrcLoc.y()); 616 617 REPORTER_ASSERT(reporter, gRec[i].fExpectedSuccess == success); 618 if (success) { 619 const SkIRect srcR = gRec[i].fExpectedSrcR; 620 const int dstX = gRec[i].fExpectedDstLoc.x(); 621 const int dstY = gRec[i].fExpectedDstLoc.y(); 622 // Walk the dst pixels, and check if we got what we expected 623 for (int y = 0; y < H; ++y) { 624 for (int x = 0; x < W; ++x) { 625 SkPMColor dstC = dstPixels[y*4+x]; 626 // get into src coordinates 627 int sx = x - dstX + srcR.x(); 628 int sy = y - dstY + srcR.y(); 629 if (srcR.contains(sx, sy)) { 630 REPORTER_ASSERT(reporter, check_4x4_pixel(dstC, sx, sy)); 631 } else { 632 REPORTER_ASSERT(reporter, 0 == dstC); 633 } 634 } 635 } 636 } 637 } 638 } 639 640