• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
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 
15 static const int DEV_W = 100, DEV_H = 100;
16 static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
17 static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1,
18                                                 DEV_H * SK_Scalar1);
19 
20 namespace {
getCanvasColor(int x,int y)21 SkPMColor getCanvasColor(int x, int y) {
22     SkASSERT(x >= 0 && x < DEV_W);
23     SkASSERT(y >= 0 && y < DEV_H);
24 
25     U8CPU r = x;
26     U8CPU g = y;
27     U8CPU b = 0xc;
28 
29     U8CPU a = 0xff;
30     switch ((x+y) % 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);
48 }
49 
getBitmapColor(int x,int y,int w,int h)50 SkPMColor getBitmapColor(int x, int y, int w, int h) {
51     int n = y * w + x;
52 
53     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 
convertConfig8888ToPMColor(SkCanvas::Config8888 config8888,uint32_t color,bool * premul)59 SkPMColor convertConfig8888ToPMColor(SkCanvas::Config8888 config8888,
60                                      uint32_t color,
61                                      bool* premul) {
62     const uint8_t* c = reinterpret_cast<uint8_t*>(&color);
63     U8CPU a,r,g,b;
64     *premul = false;
65     switch (config8888) {
66         case SkCanvas::kNative_Premul_Config8888:
67             return color;
68         case SkCanvas::kNative_Unpremul_Config8888:
69             *premul = true;
70             a = SkGetPackedA32(color);
71             r = SkGetPackedR32(color);
72             g = SkGetPackedG32(color);
73             b = SkGetPackedB32(color);
74             break;
75         case SkCanvas::kBGRA_Unpremul_Config8888:
76             *premul = true; // fallthru
77         case SkCanvas::kBGRA_Premul_Config8888:
78             a = static_cast<U8CPU>(c[3]);
79             r = static_cast<U8CPU>(c[2]);
80             g = static_cast<U8CPU>(c[1]);
81             b = static_cast<U8CPU>(c[0]);
82             break;
83         case SkCanvas::kRGBA_Unpremul_Config8888:
84             *premul = true; // fallthru
85         case SkCanvas::kRGBA_Premul_Config8888:
86             a = static_cast<U8CPU>(c[3]);
87             r = static_cast<U8CPU>(c[0]);
88             g = static_cast<U8CPU>(c[1]);
89             b = static_cast<U8CPU>(c[2]);
90             break;
91     }
92     if (*premul) {
93         r = SkMulDiv255Ceiling(r, a);
94         g = SkMulDiv255Ceiling(g, a);
95         b = SkMulDiv255Ceiling(b, a);
96     }
97     return SkPackARGB32(a, r, g, b);
98 }
99 
fillCanvas(SkCanvas * canvas)100 void fillCanvas(SkCanvas* canvas) {
101     static SkBitmap bmp;
102     if (bmp.isNull()) {
103         bmp.setConfig(SkBitmap::kARGB_8888_Config, DEV_W, DEV_H);
104         bool alloc = bmp.allocPixels();
105         SkASSERT(alloc);
106         SkAutoLockPixels alp(bmp);
107         intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels());
108         for (int y = 0; y < DEV_H; ++y) {
109             for (int x = 0; x < DEV_W; ++x) {
110                 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel());
111                 *pixel = getCanvasColor(x, y);
112             }
113         }
114     }
115     canvas->save();
116     canvas->setMatrix(SkMatrix::I());
117     canvas->clipRect(DEV_RECT_S, SkRegion::kReplace_Op);
118     SkPaint paint;
119     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
120     canvas->drawBitmap(bmp, 0, 0, &paint);
121     canvas->restore();
122 }
123 
fillBitmap(SkBitmap * bitmap)124 void fillBitmap(SkBitmap* bitmap) {
125     SkASSERT(bitmap->lockPixelsAreWritable());
126     SkAutoLockPixels alp(*bitmap);
127     int w = bitmap->width();
128     int h = bitmap->height();
129     intptr_t pixels = reinterpret_cast<intptr_t>(bitmap->getPixels());
130     for (int y = 0; y < h; ++y) {
131         for (int x = 0; x < w; ++x) {
132             SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel());
133             *pixel = getBitmapColor(x, y, w, h);
134         }
135     }
136 }
137 
checkPixel(SkPMColor a,SkPMColor b,bool didPremulConversion)138 bool checkPixel(SkPMColor a, SkPMColor b, bool didPremulConversion) {
139     if (!didPremulConversion) {
140         return a == b;
141     }
142     int32_t aA = static_cast<int32_t>(SkGetPackedA32(a));
143     int32_t aR = static_cast<int32_t>(SkGetPackedR32(a));
144     int32_t aG = static_cast<int32_t>(SkGetPackedG32(a));
145     int32_t aB = SkGetPackedB32(a);
146 
147     int32_t bA = static_cast<int32_t>(SkGetPackedA32(b));
148     int32_t bR = static_cast<int32_t>(SkGetPackedR32(b));
149     int32_t bG = static_cast<int32_t>(SkGetPackedG32(b));
150     int32_t bB = static_cast<int32_t>(SkGetPackedB32(b));
151 
152     return aA == bA &&
153            SkAbs32(aR - bR) <= 1 &&
154            SkAbs32(aG - bG) <= 1 &&
155            SkAbs32(aB - bB) <= 1;
156 }
157 
158 // checks the bitmap contains correct pixels after the readPixels
159 // if the bitmap was prefilled with pixels it checks that these weren't
160 // overwritten in the area outside the readPixels.
checkRead(skiatest::Reporter * reporter,const SkBitmap & bitmap,int x,int y,bool checkCanvasPixels,bool checkBitmapPixels,SkCanvas::Config8888 config8888)161 bool checkRead(skiatest::Reporter* reporter,
162                const SkBitmap& bitmap,
163                int x, int y,
164                bool checkCanvasPixels,
165                bool checkBitmapPixels,
166                SkCanvas::Config8888 config8888) {
167     SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
168     SkASSERT(!bitmap.isNull());
169     SkASSERT(checkCanvasPixels || checkBitmapPixels);
170 
171     int bw = bitmap.width();
172     int bh = bitmap.height();
173 
174     SkIRect srcRect = SkIRect::MakeXYWH(x, y, bw, bh);
175     SkIRect clippedSrcRect = DEV_RECT;
176     if (!clippedSrcRect.intersect(srcRect)) {
177         clippedSrcRect.setEmpty();
178     }
179     bool failed = false;
180     SkAutoLockPixels alp(bitmap);
181     intptr_t pixels = reinterpret_cast<intptr_t>(bitmap.getPixels());
182     for (int by = 0; by < bh; ++by) {
183         for (int bx = 0; bx < bw; ++bx) {
184             int devx = bx + srcRect.fLeft;
185             int devy = by + srcRect.fTop;
186 
187             uint32_t pixel = *reinterpret_cast<SkPMColor*>(pixels + by * bitmap.rowBytes() + bx * bitmap.bytesPerPixel());
188 
189             if (clippedSrcRect.contains(devx, devy)) {
190                 if (checkCanvasPixels) {
191                     SkPMColor canvasPixel = getCanvasColor(devx, devy);
192                     bool didPremul;
193                     SkPMColor pmPixel = convertConfig8888ToPMColor(config8888, pixel, &didPremul);
194                     bool check;
195                     REPORTER_ASSERT(reporter, check = checkPixel(pmPixel, canvasPixel, didPremul));
196                     if (!check) {
197                         failed = true;
198                     }
199                 }
200             } else if (checkBitmapPixels) {
201                 REPORTER_ASSERT(reporter, getBitmapColor(bx, by, bw, bh) == pixel);
202                 if (getBitmapColor(bx, by, bw, bh) != pixel) {
203                     failed = true;
204                 }
205             }
206         }
207     }
208     return !failed;
209 }
210 
211 enum BitmapInit {
212     kFirstBitmapInit = 0,
213 
214     kNoPixels_BitmapInit = kFirstBitmapInit,
215     kTight_BitmapInit,
216     kRowBytes_BitmapInit,
217 
218     kBitmapInitCnt
219 };
220 
nextBMI(BitmapInit bmi)221 BitmapInit nextBMI(BitmapInit bmi) {
222     int x = bmi;
223     return static_cast<BitmapInit>(++x);
224 }
225 
226 
init_bitmap(SkBitmap * bitmap,const SkIRect & rect,BitmapInit init)227 void init_bitmap(SkBitmap* bitmap, const SkIRect& rect, BitmapInit init) {
228     int w = rect.width();
229     int h = rect.height();
230     int rowBytes = 0;
231     bool alloc = true;
232     switch (init) {
233         case kNoPixels_BitmapInit:
234             alloc = false;
235         case kTight_BitmapInit:
236             break;
237         case kRowBytes_BitmapInit:
238             rowBytes = w * sizeof(SkPMColor) + 16 * sizeof(SkPMColor);
239             break;
240         default:
241             SkASSERT(0);
242             break;
243     }
244     bitmap->setConfig(SkBitmap::kARGB_8888_Config, w, h, rowBytes);
245     if (alloc) {
246         bitmap->allocPixels();
247     }
248 }
249 
ReadPixelsTest(skiatest::Reporter * reporter,GrContext * context)250 void ReadPixelsTest(skiatest::Reporter* reporter, GrContext* context) {
251     SkCanvas canvas;
252 
253     const SkIRect testRects[] = {
254         // entire thing
255         DEV_RECT,
256         // larger on all sides
257         SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10),
258         // fully contained
259         SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4),
260         // outside top left
261         SkIRect::MakeLTRB(-10, -10, -1, -1),
262         // touching top left corner
263         SkIRect::MakeLTRB(-10, -10, 0, 0),
264         // overlapping top left corner
265         SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4),
266         // overlapping top left and top right corners
267         SkIRect::MakeLTRB(-10, -10, DEV_W  + 10, DEV_H / 4),
268         // touching entire top edge
269         SkIRect::MakeLTRB(-10, -10, DEV_W  + 10, 0),
270         // overlapping top right corner
271         SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W  + 10, DEV_H / 4),
272         // contained in x, overlapping top edge
273         SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W  / 4, DEV_H / 4),
274         // outside top right corner
275         SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1),
276         // touching top right corner
277         SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0),
278         // overlapping top left and bottom left corners
279         SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10),
280         // touching entire left edge
281         SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10),
282         // overlapping bottom left corner
283         SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10),
284         // contained in y, overlapping left edge
285         SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4),
286         // outside bottom left corner
287         SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10),
288         // touching bottom left corner
289         SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10),
290         // overlapping bottom left and bottom right corners
291         SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
292         // touching entire left edge
293         SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10),
294         // overlapping bottom right corner
295         SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
296         // overlapping top right and bottom right corners
297         SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10),
298     };
299 
300     for (int dtype = 0; dtype < 2; ++dtype) {
301 
302         if (0 == dtype) {
303             canvas.setDevice(new SkDevice(SkBitmap::kARGB_8888_Config,
304                                           DEV_W,
305                                           DEV_H,
306                                           false))->unref();
307         } else {
308 #if SK_SCALAR_IS_FIXED
309             // GPU device known not to work in the fixed pt build.
310             continue;
311 #endif
312             canvas.setDevice(new SkGpuDevice(context,
313                                              SkBitmap::kARGB_8888_Config,
314                                              DEV_W,
315                                              DEV_H))->unref();
316         }
317         fillCanvas(&canvas);
318 
319         static const SkCanvas::Config8888 gReadConfigs[] = {
320             SkCanvas::kNative_Premul_Config8888,
321             SkCanvas::kNative_Unpremul_Config8888,
322 /**
323  * There is a bug in Ganesh (http://code.google.com/p/skia/issues/detail?id=438)
324  * that causes the readback of pixels from BGRA canvas to an RGBA bitmap to
325  * fail. This should be removed as soon as the issue above is resolved.
326  */
327 #if !defined(SK_BUILD_FOR_ANDROID)
328             SkCanvas::kBGRA_Premul_Config8888,
329             SkCanvas::kBGRA_Unpremul_Config8888,
330 #endif
331             SkCanvas::kRGBA_Premul_Config8888,
332             SkCanvas::kRGBA_Unpremul_Config8888,
333         };
334         for (size_t rect = 0; rect < SK_ARRAY_COUNT(testRects); ++rect) {
335             const SkIRect& srcRect = testRects[rect];
336             for (BitmapInit bmi = kFirstBitmapInit;
337                  bmi < kBitmapInitCnt;
338                  bmi = nextBMI(bmi)) {
339                 for (size_t c = 0; c < SK_ARRAY_COUNT(gReadConfigs); ++c) {
340                     SkCanvas::Config8888 config8888 = gReadConfigs[c];
341                     SkBitmap bmp;
342                     init_bitmap(&bmp, srcRect, bmi);
343 
344                     // if the bitmap has pixels allocated before the readPixels,
345                     // note that and fill them with pattern
346                     bool startsWithPixels = !bmp.isNull();
347                     if (startsWithPixels) {
348                         fillBitmap(&bmp);
349                     }
350 
351                     bool success =
352                         canvas.readPixels(&bmp, srcRect.fLeft,
353                                           srcRect.fTop, config8888);
354 
355                     // we expect to succeed when the read isn't fully clipped
356                     // out.
357                     bool expectSuccess = SkIRect::Intersects(srcRect, DEV_RECT);
358                     // determine whether we expected the read to succeed.
359                     REPORTER_ASSERT(reporter, success == expectSuccess);
360 
361                     if (success || startsWithPixels) {
362                         checkRead(reporter, bmp, srcRect.fLeft, srcRect.fTop,
363                                   success, startsWithPixels, config8888);
364                     } else {
365                         // if we had no pixels beforehand and the readPixels
366                         // failed then our bitmap should still not have pixels
367                         REPORTER_ASSERT(reporter, bmp.isNull());
368                     }
369                 }
370                 // check the old webkit version of readPixels that clips the
371                 // bitmap size
372                 SkBitmap wkbmp;
373                 bool success = canvas.readPixels(srcRect, &wkbmp);
374                 SkIRect clippedRect = DEV_RECT;
375                 if (clippedRect.intersect(srcRect)) {
376                     REPORTER_ASSERT(reporter, success);
377                     checkRead(reporter, wkbmp, clippedRect.fLeft,
378                               clippedRect.fTop, true, false,
379                               SkCanvas::kNative_Premul_Config8888);
380                 } else {
381                     REPORTER_ASSERT(reporter, !success);
382                 }
383             }
384         }
385     }
386 }
387 }
388 
389 #include "TestClassDef.h"
390 DEFINE_GPUTESTCLASS("ReadPixels", ReadPixelsTestClass, ReadPixelsTest)
391 
392