Home | History | Annotate | Download | only in tests
      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 {
     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 
     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 
     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 
    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 
    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 
    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.
    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 
    221 BitmapInit nextBMI(BitmapInit bmi) {
    222     int x = bmi;
    223     return static_cast<BitmapInit>(++x);
    224 }
    225 
    226 
    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 
    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