blob: e2b21c4fa3eaad32b981da383d9cad053ea65daf [file] [log] [blame]
bsalomon@google.comc6980972011-11-02 19:57:21 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "Test.h"
10#include "SkCanvas.h"
11#include "SkRegion.h"
12#include "SkGpuDevice.h"
13
14
15static const int DEV_W = 100, DEV_H = 100;
16static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
17static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1,
18 DEV_H * SK_Scalar1);
19
20namespace {
21SkPMColor getCanvasColor(int x, int y) {
22 SkASSERT(x >= 0 && x < DEV_W);
23 SkASSERT(y >= 0 && y < DEV_H);
bsalomon@google.com6850eab2011-11-03 20:29:47 +000024
25 U8CPU r = x;
26 U8CPU g = y;
27 U8CPU b = 0xc;
28
29 U8CPU a = 0xff;
30 switch (x % 5) {
31 case 0:
32 a = 0xff;
33 break;
34 case 1:
35 a = 0x80;
36 break;
37 case 2:
38 a = 0xCC;
39 break;
40 case 4:
41 a = 0x01;
42 break;
43 case 3:
44 a = 0x00;
45 break;
46 }
47 return SkPremultiplyARGBInline(a, r, g, b);
bsalomon@google.comc6980972011-11-02 19:57:21 +000048}
49
50SkPMColor getBitmapColor(int x, int y, int w, int h) {
51 int n = y * w + x;
bsalomon@google.com6850eab2011-11-03 20:29:47 +000052
bsalomon@google.comc6980972011-11-02 19:57:21 +000053 U8CPU b = n & 0xff;
54 U8CPU g = (n >> 8) & 0xff;
55 U8CPU r = (n >> 16) & 0xff;
56 return SkPackARGB32(0xff, r, g , b);
57}
58
bsalomon@google.com6850eab2011-11-03 20:29:47 +000059SkPMColor convertConfig8888ToPMColor(SkCanvas::Config8888 config8888,
60 uint32_t color) {
61 const uint8_t* c = reinterpret_cast<uint8_t*>(&color);
62 U8CPU a,r,g,b;
63 bool mul = false;
64 switch (config8888) {
65 case SkCanvas::kNative_Premul_Config8888:
66 return color;
67 case SkCanvas::kNative_Unpremul_Config8888:
68 mul = true;
69 a = SkGetPackedA32(color);
70 r = SkGetPackedR32(color);
71 g = SkGetPackedG32(color);
72 b = SkGetPackedB32(color);
73 break;
74 case SkCanvas::kBGRA_Unpremul_Config8888:
75 mul = true; // fallthru
76 case SkCanvas::kBGRA_Premul_Config8888:
77 a = static_cast<U8CPU>(c[3]);
78 r = static_cast<U8CPU>(c[2]);
79 g = static_cast<U8CPU>(c[1]);
80 b = static_cast<U8CPU>(c[0]);
81 break;
82 case SkCanvas::kRGBA_Unpremul_Config8888:
83 mul = true; // fallthru
84 case SkCanvas::kRGBA_Premul_Config8888:
85 a = static_cast<U8CPU>(c[3]);
86 r = static_cast<U8CPU>(c[0]);
87 g = static_cast<U8CPU>(c[1]);
88 b = static_cast<U8CPU>(c[2]);
89 break;
90 }
91 if (mul) {
92 r = SkMulDiv255Ceiling(r, a);
93 g = SkMulDiv255Ceiling(g, a);
94 b = SkMulDiv255Ceiling(b, a);
95 }
96 return SkPackARGB32(a, r, g, b);
97}
98
bsalomon@google.comc6980972011-11-02 19:57:21 +000099void fillCanvas(SkCanvas* canvas) {
100 static SkBitmap bmp;
101 if (bmp.isNull()) {
102 bmp.setConfig(SkBitmap::kARGB_8888_Config, DEV_W, DEV_H);
103 bool alloc = bmp.allocPixels();
104 SkASSERT(alloc);
105 SkAutoLockPixels alp(bmp);
106 intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels());
107 for (int y = 0; y < DEV_H; ++y) {
108 for (int x = 0; x < DEV_W; ++x) {
109 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel());
110 *pixel = getCanvasColor(x, y);
111 }
112 }
113 }
114 canvas->save();
115 canvas->setMatrix(SkMatrix::I());
116 canvas->clipRect(DEV_RECT_S, SkRegion::kReplace_Op);
117 SkPaint paint;
118 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
119 canvas->drawBitmap(bmp, 0, 0, &paint);
120 canvas->restore();
121}
122
123void fillBitmap(SkBitmap* bitmap) {
124 SkASSERT(bitmap->lockPixelsAreWritable());
125 SkAutoLockPixels alp(*bitmap);
126 int w = bitmap->width();
127 int h = bitmap->height();
128 intptr_t pixels = reinterpret_cast<intptr_t>(bitmap->getPixels());
129 for (int y = 0; y < h; ++y) {
130 for (int x = 0; x < w; ++x) {
131 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel());
132 *pixel = getBitmapColor(x, y, w, h);
133 }
134 }
135}
136
137// checks the bitmap contains correct pixels after the readPixels
138// if the bitmap was prefilled with pixels it checks that these weren't
139// overwritten in the area outside the readPixels.
140bool checkRead(skiatest::Reporter* reporter,
141 const SkBitmap& bitmap,
142 int x, int y,
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000143 bool checkCanvasPixels,
144 bool checkBitmapPixels,
145 SkCanvas::Config8888 config8888) {
bsalomon@google.comc6980972011-11-02 19:57:21 +0000146 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
147 SkASSERT(!bitmap.isNull());
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000148 SkASSERT(checkCanvasPixels || checkBitmapPixels);
bsalomon@google.comc6980972011-11-02 19:57:21 +0000149
150 int bw = bitmap.width();
151 int bh = bitmap.height();
152
153 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bw, bh);
154 SkIRect clippedSrcRect = DEV_RECT;
155 if (!clippedSrcRect.intersect(srcRect)) {
156 clippedSrcRect.setEmpty();
157 }
158
159 SkAutoLockPixels alp(bitmap);
160 intptr_t pixels = reinterpret_cast<intptr_t>(bitmap.getPixels());
161 for (int by = 0; by < bh; ++by) {
162 for (int bx = 0; bx < bw; ++bx) {
163 int devx = bx + srcRect.fLeft;
164 int devy = by + srcRect.fTop;
165
166 SkPMColor pixel = *reinterpret_cast<SkPMColor*>(pixels + by * bitmap.rowBytes() + bx * bitmap.bytesPerPixel());
167
168 if (clippedSrcRect.contains(devx, devy)) {
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000169 if (checkCanvasPixels) {
170 SkPMColor canvasPixel = getCanvasColor(devx, devy);
171 pixel = convertConfig8888ToPMColor(config8888, pixel);
172 REPORTER_ASSERT(reporter, canvasPixel == pixel);
173 if (getCanvasColor(devx, devy) != pixel) {
174 return false;
175 }
bsalomon@google.comc6980972011-11-02 19:57:21 +0000176 }
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000177 } else if (checkBitmapPixels) {
bsalomon@google.comc6980972011-11-02 19:57:21 +0000178 REPORTER_ASSERT(reporter, getBitmapColor(bx, by, bw, bh) == pixel);
179 if (getBitmapColor(bx, by, bw, bh) != pixel) {
180 return false;
181 }
182 }
183 }
184 }
185 return true;
186}
187
188enum BitmapInit {
189 kFirstBitmapInit = 0,
190
191 kNoPixels_BitmapInit = kFirstBitmapInit,
192 kTight_BitmapInit,
193 kRowBytes_BitmapInit,
194
195 kBitmapInitCnt
196};
197
198BitmapInit nextBMI(BitmapInit bmi) {
199 int x = bmi;
200 return static_cast<BitmapInit>(++x);
201}
202
203
204void init_bitmap(SkBitmap* bitmap, const SkIRect& rect, BitmapInit init) {
205 int w = rect.width();
206 int h = rect.height();
207 int rowBytes = 0;
208 bool alloc = true;
209 switch (init) {
210 case kNoPixels_BitmapInit:
211 alloc = false;
212 case kTight_BitmapInit:
213 break;
214 case kRowBytes_BitmapInit:
215 rowBytes = w * sizeof(SkPMColor) + 16 * sizeof(SkPMColor);
216 break;
217 default:
218 SkASSERT(0);
219 break;
220 }
221 bitmap->setConfig(SkBitmap::kARGB_8888_Config, w, h, rowBytes);
222 if (alloc) {
223 bitmap->allocPixels();
224 }
225}
226
227void ReadPixelsTest(skiatest::Reporter* reporter, GrContext* context) {
228 SkCanvas canvas;
229
230 const SkIRect testRects[] = {
231 // entire thing
232 DEV_RECT,
233 // larger on all sides
234 SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10),
235 // fully contained
236 SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4),
237 // outside top left
238 SkIRect::MakeLTRB(-10, -10, -1, -1),
239 // touching top left corner
240 SkIRect::MakeLTRB(-10, -10, 0, 0),
241 // overlapping top left corner
242 SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4),
243 // overlapping top left and top right corners
244 SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H / 4),
245 // touching entire top edge
246 SkIRect::MakeLTRB(-10, -10, DEV_W + 10, 0),
247 // overlapping top right corner
248 SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H / 4),
249 // contained in x, overlapping top edge
250 SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W / 4, DEV_H / 4),
251 // outside top right corner
252 SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1),
253 // touching top right corner
254 SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0),
255 // overlapping top left and bottom left corners
256 SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10),
257 // touching entire left edge
258 SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10),
259 // overlapping bottom left corner
260 SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10),
261 // contained in y, overlapping left edge
262 SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4),
263 // outside bottom left corner
264 SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10),
265 // touching bottom left corner
266 SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10),
267 // overlapping bottom left and bottom right corners
268 SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
269 // touching entire left edge
270 SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10),
271 // overlapping bottom right corner
272 SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
273 // overlapping top right and bottom right corners
274 SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10),
275 };
276
277 for (int dtype = 0; dtype < 2; ++dtype) {
278
279 if (0 == dtype) {
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000280 canvas.setDevice(new SkDevice(SkBitmap::kARGB_8888_Config,
281 DEV_W,
282 DEV_H,
283 false))->unref();
bsalomon@google.comc6980972011-11-02 19:57:21 +0000284 } else {
285#if SK_SCALAR_IS_FIXED
286 // GPU device known not to work in the fixed pt build.
287 continue;
288#endif
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000289 canvas.setDevice(new SkGpuDevice(context,
290 SkBitmap::kARGB_8888_Config,
291 DEV_W,
292 DEV_H))->unref();
bsalomon@google.comc6980972011-11-02 19:57:21 +0000293 }
294 fillCanvas(&canvas);
295
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000296 static const SkCanvas::Config8888 gReadConfigs[] = {
297 SkCanvas::kNative_Premul_Config8888,
298 SkCanvas::kNative_Unpremul_Config8888,
299 SkCanvas::kBGRA_Premul_Config8888,
300 SkCanvas::kBGRA_Unpremul_Config8888,
301 SkCanvas::kRGBA_Premul_Config8888,
302 SkCanvas::kRGBA_Unpremul_Config8888,
303 };
bsalomon@google.comc6980972011-11-02 19:57:21 +0000304 for (int rect = 0; rect < SK_ARRAY_COUNT(testRects); ++rect) {
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000305 const SkIRect& srcRect = testRects[rect];
306 for (BitmapInit bmi = kFirstBitmapInit;
307 bmi < kBitmapInitCnt;
308 bmi = nextBMI(bmi)) {
309 for (int c = 0; c < SK_ARRAY_COUNT(gReadConfigs); ++c) {
310 SkCanvas::Config8888 config8888 = gReadConfigs[c];
311 SkBitmap bmp;
312 init_bitmap(&bmp, srcRect, bmi);
bsalomon@google.comc6980972011-11-02 19:57:21 +0000313
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000314 // if the bitmap has pixels allocated before the readPixels,
315 // note that and fill them with pattern
316 bool startsWithPixels = !bmp.isNull();
317 if (startsWithPixels) {
318 fillBitmap(&bmp);
319 }
bsalomon@google.comc6980972011-11-02 19:57:21 +0000320
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000321 bool success =
322 canvas.readPixels(&bmp, srcRect.fLeft,
323 srcRect.fTop, config8888);
bsalomon@google.comc6980972011-11-02 19:57:21 +0000324
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000325 // non-native not implemented on GPU yet
326 bool expectSuccess =
327 SkIRect::Intersects(srcRect, DEV_RECT) &&
328 !(1 == dtype &&
329 config8888 != SkCanvas::kNative_Premul_Config8888);
330
331 // determine whether we expected the read to succeed.
332 REPORTER_ASSERT(reporter, success == expectSuccess);
333
334 if (success || startsWithPixels) {
335 checkRead(reporter, bmp, srcRect.fLeft, srcRect.fTop,
336 success, startsWithPixels, config8888);
337 } else {
338 // if we had no pixels beforehand and the readPixels
339 // failed then our bitmap should still not have pixels
340 REPORTER_ASSERT(reporter, bmp.isNull());
341 }
bsalomon@google.comc6980972011-11-02 19:57:21 +0000342 }
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000343 // check the old webkit version of readPixels that clips the
344 // bitmap size
bsalomon@google.comc6980972011-11-02 19:57:21 +0000345 SkBitmap wkbmp;
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000346 bool success = canvas.readPixels(srcRect, &wkbmp);
bsalomon@google.comc6980972011-11-02 19:57:21 +0000347 SkIRect clippedRect = DEV_RECT;
348 if (clippedRect.intersect(srcRect)) {
349 REPORTER_ASSERT(reporter, success);
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000350 checkRead(reporter, wkbmp, clippedRect.fLeft,
351 clippedRect.fTop, true, false,
352 SkCanvas::kNative_Premul_Config8888);
bsalomon@google.comc6980972011-11-02 19:57:21 +0000353 } else {
354 REPORTER_ASSERT(reporter, !success);
355 }
356 }
357 }
358 }
359}
360}
361
362#include "TestClassDef.h"
363DEFINE_GPUTESTCLASS("ReadPixels", ReadPixelsTestClass, ReadPixelsTest)
364