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