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 "include/core/SkBitmap.h"
9 #include "include/core/SkColor.h"
10 #include "include/core/SkColorSpace.h"
11 #include "include/core/SkImageInfo.h"
12 #include "include/core/SkPoint.h"
13 #include "include/core/SkRect.h"
14 #include "include/core/SkRefCnt.h"
15 #include "include/core/SkSize.h"
16 #include "include/core/SkTypes.h"
17 #include "tests/Test.h"
18 #include "tools/ToolUtils.h"
19 
init_src(const SkBitmap & bitmap)20 static void init_src(const SkBitmap& bitmap) {
21     if (bitmap.getPixels()) {
22         bitmap.eraseColor(SK_ColorWHITE);
23     }
24 }
25 
26 struct Pair {
27     SkColorType fColorType;
28     const char* fValid;
29 };
30 
31 // Utility functions for copyPixelsTo()/copyPixelsFrom() tests.
32 // getPixel()
33 // setPixel()
34 // getSkConfigName()
35 // struct Coordinates
36 // reportCopyVerification()
37 // writeCoordPixels()
38 
39 // Helper struct to contain pixel locations, while avoiding need for STL.
40 struct Coordinates {
41 
42     const int length;
43     SkIPoint* const data;
44 
CoordinatesCoordinates45     explicit Coordinates(int _length): length(_length)
46                                      , data(new SkIPoint[length]) { }
47 
~CoordinatesCoordinates48     ~Coordinates(){
49         delete [] data;
50     }
51 
operator []Coordinates52     SkIPoint* operator[](int i) const {
53         // Use with care, no bounds checking.
54         return data + i;
55     }
56 };
57 
58 static const Pair gPairs[] = {
59     { kUnknown_SkColorType,     "0000000"  },
60     { kAlpha_8_SkColorType,     "0100000"  },
61     { kRGB_565_SkColorType,     "0101011"  },
62     { kARGB_4444_SkColorType,   "0101111"  },
63     { kN32_SkColorType,         "0101111"  },
64     { kRGBA_F16_SkColorType,    "0101011"  },
65 };
66 
67 static const int W = 20;
68 static const int H = 33;
69 
setup_src_bitmaps(SkBitmap * srcOpaque,SkBitmap * srcPremul,SkColorType ct)70 static void setup_src_bitmaps(SkBitmap* srcOpaque, SkBitmap* srcPremul,
71                               SkColorType ct) {
72     sk_sp<SkColorSpace> colorSpace = nullptr;
73     if (kRGBA_F16_SkColorType == ct) {
74         colorSpace = SkColorSpace::MakeSRGB();
75     }
76 
77     srcOpaque->allocPixels(SkImageInfo::Make(W, H, ct, kOpaque_SkAlphaType, colorSpace));
78     srcPremul->allocPixels(SkImageInfo::Make(W, H, ct, kPremul_SkAlphaType, colorSpace));
79     init_src(*srcOpaque);
80     init_src(*srcPremul);
81 }
82 
DEF_TEST(BitmapCopy_extractSubset,reporter)83 DEF_TEST(BitmapCopy_extractSubset, reporter) {
84     for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
85         SkBitmap srcOpaque, srcPremul;
86         setup_src_bitmaps(&srcOpaque, &srcPremul, gPairs[i].fColorType);
87 
88         SkBitmap bitmap(srcOpaque);
89         SkBitmap subset;
90         SkIRect r;
91         // Extract a subset which has the same width as the original. This
92         // catches a bug where we cloned the genID incorrectly.
93         r.setLTRB(0, 1, W, 3);
94         // Relies on old behavior of extractSubset failing if colortype is unknown
95         if (kUnknown_SkColorType != bitmap.colorType() && bitmap.extractSubset(&subset, r)) {
96             REPORTER_ASSERT(reporter, subset.width() == W);
97             REPORTER_ASSERT(reporter, subset.height() == 2);
98             REPORTER_ASSERT(reporter, subset.alphaType() == bitmap.alphaType());
99 
100             // Test copying an extracted subset.
101             for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) {
102                 SkBitmap copy;
103                 bool     success = ToolUtils::copy_to(&copy, gPairs[j].fColorType, subset);
104                 if (!success) {
105                     // Skip checking that success matches fValid, which is redundant
106                     // with the code below.
107                     REPORTER_ASSERT(reporter, gPairs[i].fColorType != gPairs[j].fColorType);
108                     continue;
109                 }
110 
111                 // When performing a copy of an extracted subset, the gen id should
112                 // change.
113                 REPORTER_ASSERT(reporter, copy.getGenerationID() != subset.getGenerationID());
114 
115                 REPORTER_ASSERT(reporter, copy.width() == W);
116                 REPORTER_ASSERT(reporter, copy.height() == 2);
117             }
118         }
119 
120         bitmap = srcPremul;
121         if (bitmap.extractSubset(&subset, r)) {
122             REPORTER_ASSERT(reporter, subset.alphaType() == bitmap.alphaType());
123         }
124     }
125 }
126 
127 #include "include/core/SkColorPriv.h"
128 #include "src/core/SkUtils.h"
129 
130 /**
131  *  Construct 4x4 pixels where we can look at a color and determine where it should be in the grid.
132  *  alpha = 0xFF, blue = 0x80, red = x, green = y
133  */
fill_4x4_pixels(SkPMColor colors[16])134 static void fill_4x4_pixels(SkPMColor colors[16]) {
135     for (int y = 0; y < 4; ++y) {
136         for (int x = 0; x < 4; ++x) {
137             colors[y*4+x] = SkPackARGB32(0xFF, x, y, 0x80);
138         }
139     }
140 }
141 
check_4x4_pixel(SkPMColor color,unsigned x,unsigned y)142 static bool check_4x4_pixel(SkPMColor color, unsigned x, unsigned y) {
143     SkASSERT(x < 4 && y < 4);
144     return  0xFF == SkGetPackedA32(color) &&
145             x    == SkGetPackedR32(color) &&
146             y    == SkGetPackedG32(color) &&
147             0x80 == SkGetPackedB32(color);
148 }
149 
150 /**
151  *  Fill with all zeros, which will never match any value from fill_4x4_pixels
152  */
clear_4x4_pixels(SkPMColor colors[16])153 static void clear_4x4_pixels(SkPMColor colors[16]) {
154     sk_memset32(colors, 0, 16);
155 }
156 
157 // Much of readPixels is exercised by copyTo testing, since readPixels is the backend for that
158 // method. Here we explicitly test subset copies.
159 //
DEF_TEST(BitmapReadPixels,reporter)160 DEF_TEST(BitmapReadPixels, reporter) {
161     const int W = 4;
162     const int H = 4;
163     const size_t rowBytes = W * sizeof(SkPMColor);
164     const SkImageInfo srcInfo = SkImageInfo::MakeN32Premul(W, H);
165     SkPMColor srcPixels[16];
166     fill_4x4_pixels(srcPixels);
167     SkBitmap srcBM;
168     srcBM.installPixels(srcInfo, srcPixels, rowBytes);
169 
170     SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(W, H);
171     SkPMColor dstPixels[16];
172 
173     const struct {
174         bool     fExpectedSuccess;
175         SkIPoint fRequestedSrcLoc;
176         SkISize  fRequestedDstSize;
177         // If fExpectedSuccess, check these, otherwise ignore
178         SkIPoint fExpectedDstLoc;
179         SkIRect  fExpectedSrcR;
180     } gRec[] = {
181         { true,  { 0, 0 }, { 4, 4 }, { 0, 0 }, { 0, 0, 4, 4 } },
182         { true,  { 1, 1 }, { 2, 2 }, { 0, 0 }, { 1, 1, 3, 3 } },
183         { true,  { 2, 2 }, { 4, 4 }, { 0, 0 }, { 2, 2, 4, 4 } },
184         { true,  {-1,-1 }, { 2, 2 }, { 1, 1 }, { 0, 0, 1, 1 } },
185         { false, {-1,-1 }, { 1, 1 }, { 0, 0 }, { 0, 0, 0, 0 } },
186     };
187 
188     for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
189         clear_4x4_pixels(dstPixels);
190 
191         dstInfo = dstInfo.makeDimensions(gRec[i].fRequestedDstSize);
192         bool success = srcBM.readPixels(dstInfo, dstPixels, rowBytes,
193                                         gRec[i].fRequestedSrcLoc.x(), gRec[i].fRequestedSrcLoc.y());
194 
195         REPORTER_ASSERT(reporter, gRec[i].fExpectedSuccess == success);
196         if (success) {
197             const SkIRect srcR = gRec[i].fExpectedSrcR;
198             const int dstX = gRec[i].fExpectedDstLoc.x();
199             const int dstY = gRec[i].fExpectedDstLoc.y();
200             // Walk the dst pixels, and check if we got what we expected
201             for (int y = 0; y < H; ++y) {
202                 for (int x = 0; x < W; ++x) {
203                     SkPMColor dstC = dstPixels[y*4+x];
204                     // get into src coordinates
205                     int sx = x - dstX + srcR.x();
206                     int sy = y - dstY + srcR.y();
207                     if (srcR.contains(sx, sy)) {
208                         REPORTER_ASSERT(reporter, check_4x4_pixel(dstC, sx, sy));
209                     } else {
210                         REPORTER_ASSERT(reporter, 0 == dstC);
211                     }
212                 }
213             }
214         }
215     }
216 }
217