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 "SkColor.h"
10 #include "SkColorSpace.h"
11 #include "SkImageInfo.h"
12 #include "SkPoint.h"
13 #include "SkRect.h"
14 #include "SkRefCnt.h"
15 #include "SkSize.h"
16 #include "SkTypes.h"
17 #include "Test.h"
18 #include "sk_tool_utils.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.set(0, 1, W, 3);
94 bitmap.setIsVolatile(true);
95 // Relies on old behavior of extractSubset failing if colortype is unknown
96 if (kUnknown_SkColorType != bitmap.colorType() && bitmap.extractSubset(&subset, r)) {
97 REPORTER_ASSERT(reporter, subset.width() == W);
98 REPORTER_ASSERT(reporter, subset.height() == 2);
99 REPORTER_ASSERT(reporter, subset.alphaType() == bitmap.alphaType());
100 REPORTER_ASSERT(reporter, subset.isVolatile() == true);
101
102 // Test copying an extracted subset.
103 for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) {
104 SkBitmap copy;
105 bool success = sk_tool_utils::copy_to(©, gPairs[j].fColorType, subset);
106 if (!success) {
107 // Skip checking that success matches fValid, which is redundant
108 // with the code below.
109 REPORTER_ASSERT(reporter, gPairs[i].fColorType != gPairs[j].fColorType);
110 continue;
111 }
112
113 // When performing a copy of an extracted subset, the gen id should
114 // change.
115 REPORTER_ASSERT(reporter, copy.getGenerationID() != subset.getGenerationID());
116
117 REPORTER_ASSERT(reporter, copy.width() == W);
118 REPORTER_ASSERT(reporter, copy.height() == 2);
119 }
120 }
121
122 bitmap = srcPremul;
123 bitmap.setIsVolatile(false);
124 if (bitmap.extractSubset(&subset, r)) {
125 REPORTER_ASSERT(reporter, subset.alphaType() == bitmap.alphaType());
126 REPORTER_ASSERT(reporter, subset.isVolatile() == false);
127 }
128 }
129 }
130
131 #include "SkColorPriv.h"
132 #include "SkUtils.h"
133
134 /**
135 * Construct 4x4 pixels where we can look at a color and determine where it should be in the grid.
136 * alpha = 0xFF, blue = 0x80, red = x, green = y
137 */
fill_4x4_pixels(SkPMColor colors[16])138 static void fill_4x4_pixels(SkPMColor colors[16]) {
139 for (int y = 0; y < 4; ++y) {
140 for (int x = 0; x < 4; ++x) {
141 colors[y*4+x] = SkPackARGB32(0xFF, x, y, 0x80);
142 }
143 }
144 }
145
check_4x4_pixel(SkPMColor color,unsigned x,unsigned y)146 static bool check_4x4_pixel(SkPMColor color, unsigned x, unsigned y) {
147 SkASSERT(x < 4 && y < 4);
148 return 0xFF == SkGetPackedA32(color) &&
149 x == SkGetPackedR32(color) &&
150 y == SkGetPackedG32(color) &&
151 0x80 == SkGetPackedB32(color);
152 }
153
154 /**
155 * Fill with all zeros, which will never match any value from fill_4x4_pixels
156 */
clear_4x4_pixels(SkPMColor colors[16])157 static void clear_4x4_pixels(SkPMColor colors[16]) {
158 sk_memset32(colors, 0, 16);
159 }
160
161 // Much of readPixels is exercised by copyTo testing, since readPixels is the backend for that
162 // method. Here we explicitly test subset copies.
163 //
DEF_TEST(BitmapReadPixels,reporter)164 DEF_TEST(BitmapReadPixels, reporter) {
165 const int W = 4;
166 const int H = 4;
167 const size_t rowBytes = W * sizeof(SkPMColor);
168 const SkImageInfo srcInfo = SkImageInfo::MakeN32Premul(W, H);
169 SkPMColor srcPixels[16];
170 fill_4x4_pixels(srcPixels);
171 SkBitmap srcBM;
172 srcBM.installPixels(srcInfo, srcPixels, rowBytes);
173
174 SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(W, H);
175 SkPMColor dstPixels[16];
176
177 const struct {
178 bool fExpectedSuccess;
179 SkIPoint fRequestedSrcLoc;
180 SkISize fRequestedDstSize;
181 // If fExpectedSuccess, check these, otherwise ignore
182 SkIPoint fExpectedDstLoc;
183 SkIRect fExpectedSrcR;
184 } gRec[] = {
185 { true, { 0, 0 }, { 4, 4 }, { 0, 0 }, { 0, 0, 4, 4 } },
186 { true, { 1, 1 }, { 2, 2 }, { 0, 0 }, { 1, 1, 3, 3 } },
187 { true, { 2, 2 }, { 4, 4 }, { 0, 0 }, { 2, 2, 4, 4 } },
188 { true, {-1,-1 }, { 2, 2 }, { 1, 1 }, { 0, 0, 1, 1 } },
189 { false, {-1,-1 }, { 1, 1 }, { 0, 0 }, { 0, 0, 0, 0 } },
190 };
191
192 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
193 clear_4x4_pixels(dstPixels);
194
195 dstInfo = dstInfo.makeWH(gRec[i].fRequestedDstSize.width(),
196 gRec[i].fRequestedDstSize.height());
197 bool success = srcBM.readPixels(dstInfo, dstPixels, rowBytes,
198 gRec[i].fRequestedSrcLoc.x(), gRec[i].fRequestedSrcLoc.y());
199
200 REPORTER_ASSERT(reporter, gRec[i].fExpectedSuccess == success);
201 if (success) {
202 const SkIRect srcR = gRec[i].fExpectedSrcR;
203 const int dstX = gRec[i].fExpectedDstLoc.x();
204 const int dstY = gRec[i].fExpectedDstLoc.y();
205 // Walk the dst pixels, and check if we got what we expected
206 for (int y = 0; y < H; ++y) {
207 for (int x = 0; x < W; ++x) {
208 SkPMColor dstC = dstPixels[y*4+x];
209 // get into src coordinates
210 int sx = x - dstX + srcR.x();
211 int sy = y - dstY + srcR.y();
212 if (srcR.contains(sx, sy)) {
213 REPORTER_ASSERT(reporter, check_4x4_pixel(dstC, sx, sy));
214 } else {
215 REPORTER_ASSERT(reporter, 0 == dstC);
216 }
217 }
218 }
219 }
220 }
221 }
222