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