| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 |
| 7 #include "SkBitmap.h" | 8 #include "SkBitmap.h" |
| 8 #include "SkRect.h" | 9 #include "SkRect.h" |
| 9 #include "Test.h" | 10 #include "Test.h" |
| 10 | 11 |
| 11 static const char* boolStr(bool value) { | 12 static const char* boolStr(bool value) { |
| 12 return value ? "true" : "false"; | 13 return value ? "true" : "false"; |
| 13 } | 14 } |
| 14 | 15 |
| 15 // these are in the same order as the SkBitmap::Config enum | 16 // these are in the same order as the SkColorType enum |
| 16 static const char* gColorTypeName[] = { | 17 static const char* gColorTypeName[] = { |
| 17 "None", "A8", "565", "4444", "RGBA", "BGRA", "Index8" | 18 "None", "A8", "565", "4444", "RGBA", "BGRA", "Index8" |
| 18 }; | 19 }; |
| 19 | 20 |
| 20 static void report_opaqueness(skiatest::Reporter* reporter, const SkBitmap& src, | 21 static void report_opaqueness(skiatest::Reporter* reporter, const SkBitmap& src, |
| 21 const SkBitmap& dst) { | 22 const SkBitmap& dst) { |
| 22 ERRORF(reporter, "src %s opaque:%d, dst %s opaque:%d", | 23 ERRORF(reporter, "src %s opaque:%d, dst %s opaque:%d", |
| 23 gColorTypeName[src.colorType()], src.isOpaque(), | 24 gColorTypeName[src.colorType()], src.isOpaque(), |
| 24 gColorTypeName[dst.colorType()], dst.isOpaque()); | 25 gColorTypeName[dst.colorType()], dst.isOpaque()); |
| 25 } | 26 } |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 | 83 |
| 83 // Utility function to read the value of a given pixel in bm. All | 84 // Utility function to read the value of a given pixel in bm. All |
| 84 // values converted to uint32_t for simplification of comparisons. | 85 // values converted to uint32_t for simplification of comparisons. |
| 85 static uint32_t getPixel(int x, int y, const SkBitmap& bm) { | 86 static uint32_t getPixel(int x, int y, const SkBitmap& bm) { |
| 86 uint32_t val = 0; | 87 uint32_t val = 0; |
| 87 uint16_t val16; | 88 uint16_t val16; |
| 88 uint8_t val8; | 89 uint8_t val8; |
| 89 SkAutoLockPixels lock(bm); | 90 SkAutoLockPixels lock(bm); |
| 90 const void* rawAddr = bm.getAddr(x,y); | 91 const void* rawAddr = bm.getAddr(x,y); |
| 91 | 92 |
| 92 switch (bm.config()) { | 93 switch (bm.bytesPerPixel()) { |
| 93 case SkBitmap::kARGB_8888_Config: | 94 case 4: |
| 94 memcpy(&val, rawAddr, sizeof(uint32_t)); | 95 memcpy(&val, rawAddr, sizeof(uint32_t)); |
| 95 break; | 96 break; |
| 96 case SkBitmap::kARGB_4444_Config: | 97 case 2: |
| 97 case SkBitmap::kRGB_565_Config: | |
| 98 memcpy(&val16, rawAddr, sizeof(uint16_t)); | 98 memcpy(&val16, rawAddr, sizeof(uint16_t)); |
| 99 val = val16; | 99 val = val16; |
| 100 break; | 100 break; |
| 101 case SkBitmap::kA8_Config: | 101 case 1: |
| 102 case SkBitmap::kIndex8_Config: | |
| 103 memcpy(&val8, rawAddr, sizeof(uint8_t)); | 102 memcpy(&val8, rawAddr, sizeof(uint8_t)); |
| 104 val = val8; | 103 val = val8; |
| 105 break; | 104 break; |
| 106 default: | 105 default: |
| 107 break; | 106 break; |
| 108 } | 107 } |
| 109 return val; | 108 return val; |
| 110 } | 109 } |
| 111 | 110 |
| 112 // Utility function to set value of any pixel in bm. | 111 // Utility function to set value of any pixel in bm. |
| 113 // bm.getConfig() specifies what format 'val' must be | 112 // bm.getConfig() specifies what format 'val' must be |
| 114 // converted to, but at present uint32_t can handle all formats. | 113 // converted to, but at present uint32_t can handle all formats. |
| 115 static void setPixel(int x, int y, uint32_t val, SkBitmap& bm) { | 114 static void setPixel(int x, int y, uint32_t val, SkBitmap& bm) { |
| 116 uint16_t val16; | 115 uint16_t val16; |
| 117 uint8_t val8; | 116 uint8_t val8; |
| 118 SkAutoLockPixels lock(bm); | 117 SkAutoLockPixels lock(bm); |
| 119 void* rawAddr = bm.getAddr(x,y); | 118 void* rawAddr = bm.getAddr(x,y); |
| 120 | 119 |
| 121 switch (bm.config()) { | 120 switch (bm.bytesPerPixel()) { |
| 122 case SkBitmap::kARGB_8888_Config: | 121 case 4: |
| 123 memcpy(rawAddr, &val, sizeof(uint32_t)); | 122 memcpy(rawAddr, &val, sizeof(uint32_t)); |
| 124 break; | 123 break; |
| 125 case SkBitmap::kARGB_4444_Config: | 124 case 2: |
| 126 case SkBitmap::kRGB_565_Config: | |
| 127 val16 = val & 0xFFFF; | 125 val16 = val & 0xFFFF; |
| 128 memcpy(rawAddr, &val16, sizeof(uint16_t)); | 126 memcpy(rawAddr, &val16, sizeof(uint16_t)); |
| 129 break; | 127 break; |
| 130 case SkBitmap::kA8_Config: | 128 case 1: |
| 131 case SkBitmap::kIndex8_Config: | |
| 132 val8 = val & 0xFF; | 129 val8 = val & 0xFF; |
| 133 memcpy(rawAddr, &val8, sizeof(uint8_t)); | 130 memcpy(rawAddr, &val8, sizeof(uint8_t)); |
| 134 break; | 131 break; |
| 135 default: | 132 default: |
| 136 // Ignore. | 133 // Ignore. |
| 137 break; | 134 break; |
| 138 } | 135 } |
| 139 } | 136 } |
| 140 | 137 |
| 141 // Utility to return string containing name of each format, to | |
| 142 // simplify diagnostic output. | |
| 143 static const char* getSkConfigName(const SkBitmap& bm) { | |
| 144 switch (bm.config()) { | |
| 145 case SkBitmap::kNo_Config: return "SkBitmap::kNo_Config"; | |
| 146 case SkBitmap::kA8_Config: return "SkBitmap::kA8_Config"; | |
| 147 case SkBitmap::kIndex8_Config: return "SkBitmap::kIndex8_Config"; | |
| 148 case SkBitmap::kRGB_565_Config: return "SkBitmap::kRGB_565_Config"; | |
| 149 case SkBitmap::kARGB_4444_Config: return "SkBitmap::kARGB_4444_Config"; | |
| 150 case SkBitmap::kARGB_8888_Config: return "SkBitmap::kARGB_8888_Config"; | |
| 151 default: return "Unknown SkBitmap configuration."; | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 // Helper struct to contain pixel locations, while avoiding need for STL. | 138 // Helper struct to contain pixel locations, while avoiding need for STL. |
| 156 struct Coordinates { | 139 struct Coordinates { |
| 157 | 140 |
| 158 const int length; | 141 const int length; |
| 159 SkIPoint* const data; | 142 SkIPoint* const data; |
| 160 | 143 |
| 161 explicit Coordinates(int _length): length(_length) | 144 explicit Coordinates(int _length): length(_length) |
| 162 , data(new SkIPoint[length]) { } | 145 , data(new SkIPoint[length]) { } |
| 163 | 146 |
| 164 ~Coordinates(){ | 147 ~Coordinates(){ |
| (...skipping 16 matching lines...) Expand all Loading... |
| 181 bool success = true; | 164 bool success = true; |
| 182 | 165 |
| 183 // Confirm all pixels in the list match. | 166 // Confirm all pixels in the list match. |
| 184 for (int i = 0; i < coords.length; ++i) { | 167 for (int i = 0; i < coords.length; ++i) { |
| 185 success = success && | 168 success = success && |
| 186 (getPixel(coords[i]->fX, coords[i]->fY, bm1) == | 169 (getPixel(coords[i]->fX, coords[i]->fY, bm1) == |
| 187 getPixel(coords[i]->fX, coords[i]->fY, bm2)); | 170 getPixel(coords[i]->fX, coords[i]->fY, bm2)); |
| 188 } | 171 } |
| 189 | 172 |
| 190 if (!success) { | 173 if (!success) { |
| 191 ERRORF(reporter, "%s [config = %s]", msg, getSkConfigName(bm1)); | 174 ERRORF(reporter, "%s [colortype = %s]", msg, |
| 175 gColorTypeName[bm1.colorType()]); |
| 192 } | 176 } |
| 193 } | 177 } |
| 194 | 178 |
| 195 // Writes unique pixel values at locations specified by coords. | 179 // Writes unique pixel values at locations specified by coords. |
| 196 static void writeCoordPixels(SkBitmap& bm, const Coordinates& coords) { | 180 static void writeCoordPixels(SkBitmap& bm, const Coordinates& coords) { |
| 197 for (int i = 0; i < coords.length; ++i) | 181 for (int i = 0; i < coords.length; ++i) |
| 198 setPixel(coords[i]->fX, coords[i]->fY, i, bm); | 182 setPixel(coords[i]->fX, coords[i]->fY, i, bm); |
| 199 } | 183 } |
| 200 | 184 |
| 201 static const Pair gPairs[] = { | 185 static const Pair gPairs[] = { |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 ERRORF(reporter, "SkBitmap::copyTo from %s to %s. returned %s " | 294 ERRORF(reporter, "SkBitmap::copyTo from %s to %s. returned %s " |
| 311 "canCopyTo %s", gColorTypeName[i], gColorTypeName[j], | 295 "canCopyTo %s", gColorTypeName[i], gColorTypeName[j], |
| 312 boolStr(success), boolStr(canSucceed)); | 296 boolStr(success), boolStr(canSucceed)); |
| 313 } | 297 } |
| 314 | 298 |
| 315 if (success) { | 299 if (success) { |
| 316 REPORTER_ASSERT(reporter, srcPremul.width() == dst.width()); | 300 REPORTER_ASSERT(reporter, srcPremul.width() == dst.width()); |
| 317 REPORTER_ASSERT(reporter, srcPremul.height() == dst.height()); | 301 REPORTER_ASSERT(reporter, srcPremul.height() == dst.height()); |
| 318 REPORTER_ASSERT(reporter, dst.colorType() == gPairs[j].fColorTyp
e); | 302 REPORTER_ASSERT(reporter, dst.colorType() == gPairs[j].fColorTyp
e); |
| 319 test_isOpaque(reporter, srcOpaque, srcPremul, dst.colorType()); | 303 test_isOpaque(reporter, srcOpaque, srcPremul, dst.colorType()); |
| 320 if (srcPremul.config() == dst.config()) { | 304 if (srcPremul.colorType() == dst.colorType()) { |
| 321 SkAutoLockPixels srcLock(srcPremul); | 305 SkAutoLockPixels srcLock(srcPremul); |
| 322 SkAutoLockPixels dstLock(dst); | 306 SkAutoLockPixels dstLock(dst); |
| 323 REPORTER_ASSERT(reporter, srcPremul.readyToDraw()); | 307 REPORTER_ASSERT(reporter, srcPremul.readyToDraw()); |
| 324 REPORTER_ASSERT(reporter, dst.readyToDraw()); | 308 REPORTER_ASSERT(reporter, dst.readyToDraw()); |
| 325 const char* srcP = (const char*)srcPremul.getAddr(0, 0); | 309 const char* srcP = (const char*)srcPremul.getAddr(0, 0); |
| 326 const char* dstP = (const char*)dst.getAddr(0, 0); | 310 const char* dstP = (const char*)dst.getAddr(0, 0); |
| 327 REPORTER_ASSERT(reporter, srcP != dstP); | 311 REPORTER_ASSERT(reporter, srcP != dstP); |
| 328 REPORTER_ASSERT(reporter, !memcmp(srcP, dstP, | 312 REPORTER_ASSERT(reporter, !memcmp(srcP, dstP, |
| 329 srcPremul.getSize())); | 313 srcPremul.getSize())); |
| 330 REPORTER_ASSERT(reporter, srcPremul.getGenerationID() == dst
.getGenerationID()); | 314 REPORTER_ASSERT(reporter, srcPremul.getGenerationID() == dst
.getGenerationID()); |
| 331 } else { | 315 } else { |
| 332 REPORTER_ASSERT(reporter, srcPremul.getGenerationID() != dst
.getGenerationID()); | 316 REPORTER_ASSERT(reporter, srcPremul.getGenerationID() != dst
.getGenerationID()); |
| 333 } | 317 } |
| 334 } else { | 318 } else { |
| 335 // dst should be unchanged from its initial state | 319 // dst should be unchanged from its initial state |
| 336 REPORTER_ASSERT(reporter, dst.config() == SkBitmap::kNo_Config); | 320 REPORTER_ASSERT(reporter, dst.colorType() == kUnknown_SkColorTyp
e); |
| 337 REPORTER_ASSERT(reporter, dst.width() == 0); | 321 REPORTER_ASSERT(reporter, dst.width() == 0); |
| 338 REPORTER_ASSERT(reporter, dst.height() == 0); | 322 REPORTER_ASSERT(reporter, dst.height() == 0); |
| 339 } | 323 } |
| 340 } // for (size_t j = ... | 324 } // for (size_t j = ... |
| 341 | 325 |
| 342 // Tests for getSafeSize(), getSafeSize64(), copyPixelsTo(), | 326 // Tests for getSafeSize(), getSafeSize64(), copyPixelsTo(), |
| 343 // copyPixelsFrom(). | 327 // copyPixelsFrom(). |
| 344 // | 328 // |
| 345 for (size_t copyCase = 0; copyCase < SK_ARRAY_COUNT(isExtracted); | 329 for (size_t copyCase = 0; copyCase < SK_ARRAY_COUNT(isExtracted); |
| 346 ++copyCase) { | 330 ++copyCase) { |
| 347 // Test copying to/from external buffer. | 331 // Test copying to/from external buffer. |
| 348 // Note: the tests below have hard-coded values --- | 332 // Note: the tests below have hard-coded values --- |
| 349 // Please take care if modifying. | 333 // Please take care if modifying. |
| 350 | 334 |
| 351 // Tests for getSafeSize64(). | 335 // Tests for getSafeSize64(). |
| 352 // Test with a very large configuration without pixel buffer | 336 // Test with a very large configuration without pixel buffer |
| 353 // attached. | 337 // attached. |
| 354 SkBitmap tstSafeSize; | 338 SkBitmap tstSafeSize; |
| 355 tstSafeSize.setConfig(SkImageInfo::Make(100000000U, 100000000U, | 339 tstSafeSize.setConfig(SkImageInfo::Make(100000000U, 100000000U, |
| 356 gPairs[i].fColorType, | 340 gPairs[i].fColorType, |
| 357 kPremul_SkAlphaType)); | 341 kPremul_SkAlphaType)); |
| 358 int64_t safeSize = tstSafeSize.computeSafeSize64(); | 342 int64_t safeSize = tstSafeSize.computeSafeSize64(); |
| 359 if (safeSize < 0) { | 343 if (safeSize < 0) { |
| 360 ERRORF(reporter, "getSafeSize64() negative: %s", | 344 ERRORF(reporter, "getSafeSize64() negative: %s", |
| 361 getSkConfigName(tstSafeSize)); | 345 gColorTypeName[tstSafeSize.colorType()]); |
| 362 } | 346 } |
| 363 bool sizeFail = false; | 347 bool sizeFail = false; |
| 364 // Compare against hand-computed values. | 348 // Compare against hand-computed values. |
| 365 switch (gPairs[i].fColorType) { | 349 switch (gPairs[i].fColorType) { |
| 366 case kUnknown_SkColorType: | 350 case kUnknown_SkColorType: |
| 367 break; | 351 break; |
| 368 | 352 |
| 369 case kAlpha_8_SkColorType: | 353 case kAlpha_8_SkColorType: |
| 370 case kIndex_8_SkColorType: | 354 case kIndex_8_SkColorType: |
| 371 if (safeSize != 0x2386F26FC10000LL) { | 355 if (safeSize != 0x2386F26FC10000LL) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 384 if (safeSize != 0x8E1BC9BF040000LL) { | 368 if (safeSize != 0x8E1BC9BF040000LL) { |
| 385 sizeFail = true; | 369 sizeFail = true; |
| 386 } | 370 } |
| 387 break; | 371 break; |
| 388 | 372 |
| 389 default: | 373 default: |
| 390 break; | 374 break; |
| 391 } | 375 } |
| 392 if (sizeFail) { | 376 if (sizeFail) { |
| 393 ERRORF(reporter, "computeSafeSize64() wrong size: %s", | 377 ERRORF(reporter, "computeSafeSize64() wrong size: %s", |
| 394 getSkConfigName(tstSafeSize)); | 378 gColorTypeName[tstSafeSize.colorType()]); |
| 395 } | 379 } |
| 396 | 380 |
| 397 int subW = 2; | 381 int subW = 2; |
| 398 int subH = 2; | 382 int subH = 2; |
| 399 | 383 |
| 400 // Create bitmap to act as source for copies and subsets. | 384 // Create bitmap to act as source for copies and subsets. |
| 401 SkBitmap src, subset; | 385 SkBitmap src, subset; |
| 402 SkColorTable* ct = NULL; | 386 SkColorTable* ct = NULL; |
| 403 if (SkBitmap::kIndex8_Config == src.config()) { | 387 if (kIndex_8_SkColorType == src.colorType()) { |
| 404 ct = init_ctable(kPremul_SkAlphaType); | 388 ct = init_ctable(kPremul_SkAlphaType); |
| 405 } | 389 } |
| 406 | 390 |
| 407 if (isExtracted[copyCase]) { // A larger image to extract from. | 391 if (isExtracted[copyCase]) { // A larger image to extract from. |
| 408 src.allocPixels(SkImageInfo::Make(2 * subW + 1, subH, | 392 src.allocPixels(SkImageInfo::Make(2 * subW + 1, subH, |
| 409 gPairs[i].fColorType, | 393 gPairs[i].fColorType, |
| 410 kPremul_SkAlphaType)); | 394 kPremul_SkAlphaType)); |
| 411 } else { // Tests expect a 2x2 bitmap, so make smaller. | 395 } else { // Tests expect a 2x2 bitmap, so make smaller. |
| 412 src.allocPixels(SkImageInfo::Make(subW, subH, | 396 src.allocPixels(SkImageInfo::Make(subW, subH, |
| 413 gPairs[i].fColorType, | 397 gPairs[i].fColorType, |
| 414 kPremul_SkAlphaType)); | 398 kPremul_SkAlphaType)); |
| 415 } | 399 } |
| 416 SkSafeUnref(ct); | 400 SkSafeUnref(ct); |
| 417 | 401 |
| 418 // Either copy src or extract into 'subset', which is used | 402 // Either copy src or extract into 'subset', which is used |
| 419 // for subsequent calls to copyPixelsTo/From. | 403 // for subsequent calls to copyPixelsTo/From. |
| 420 bool srcReady = false; | 404 bool srcReady = false; |
| 421 // Test relies on older behavior that extractSubset will fail on | 405 // Test relies on older behavior that extractSubset will fail on |
| 422 // no_config | 406 // kUnknown_SkColorType |
| 423 if (kUnknown_SkColorType != src.colorType() && | 407 if (kUnknown_SkColorType != src.colorType() && |
| 424 isExtracted[copyCase]) { | 408 isExtracted[copyCase]) { |
| 425 // The extractedSubset() test case allows us to test copy- | 409 // The extractedSubset() test case allows us to test copy- |
| 426 // ing when src and dst mave possibly different strides. | 410 // ing when src and dst mave possibly different strides. |
| 427 SkIRect r; | 411 SkIRect r; |
| 428 r.set(1, 0, 1 + subW, subH); // 2x2 extracted bitmap | 412 r.set(1, 0, 1 + subW, subH); // 2x2 extracted bitmap |
| 429 | 413 |
| 430 srcReady = src.extractSubset(&subset, r); | 414 srcReady = src.extractSubset(&subset, r); |
| 431 } else { | 415 } else { |
| 432 srcReady = src.copyTo(&subset); | 416 srcReady = src.copyTo(&subset); |
| 433 } | 417 } |
| 434 | 418 |
| 435 // Not all configurations will generate a valid 'subset'. | 419 // Not all configurations will generate a valid 'subset'. |
| 436 if (srcReady) { | 420 if (srcReady) { |
| 437 | 421 |
| 438 // Allocate our target buffer 'buf' for all copies. | 422 // Allocate our target buffer 'buf' for all copies. |
| 439 // To simplify verifying correctness of copies attach | 423 // To simplify verifying correctness of copies attach |
| 440 // buf to a SkBitmap, but copies are done using the | 424 // buf to a SkBitmap, but copies are done using the |
| 441 // raw buffer pointer. | 425 // raw buffer pointer. |
| 442 const size_t bufSize = subH * | 426 const size_t bufSize = subH * |
| 443 SkBitmap::ComputeRowBytes(src.config(), subW) * 2; | 427 SkColorTypeMinRowBytes(src.colorType(), subW) * 2; |
| 444 SkAutoMalloc autoBuf (bufSize); | 428 SkAutoMalloc autoBuf (bufSize); |
| 445 uint8_t* buf = static_cast<uint8_t*>(autoBuf.get()); | 429 uint8_t* buf = static_cast<uint8_t*>(autoBuf.get()); |
| 446 | 430 |
| 447 SkBitmap bufBm; // Attach buf to this bitmap. | 431 SkBitmap bufBm; // Attach buf to this bitmap. |
| 448 bool successExpected; | 432 bool successExpected; |
| 449 | 433 |
| 450 // Set up values for each pixel being copied. | 434 // Set up values for each pixel being copied. |
| 451 Coordinates coords(subW * subH); | 435 Coordinates coords(subW * subH); |
| 452 for (int x = 0; x < subW; ++x) | 436 for (int x = 0; x < subW; ++x) |
| 453 for (int y = 0; y < subH; ++y) | 437 for (int y = 0; y < subH; ++y) |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 // for the transfer. | 536 // for the transfer. |
| 553 REPORTER_ASSERT(reporter, | 537 REPORTER_ASSERT(reporter, |
| 554 subset.copyPixelsFrom(buf, 1, subset.rowBytes()) == | 538 subset.copyPixelsFrom(buf, 1, subset.rowBytes()) == |
| 555 false); | 539 false); |
| 556 | 540 |
| 557 #endif | 541 #endif |
| 558 } | 542 } |
| 559 } // for (size_t copyCase ... | 543 } // for (size_t copyCase ... |
| 560 } | 544 } |
| 561 } | 545 } |
| OLD | NEW |