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