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 |