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