Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkBitmapDevice.h"
      9 #include "SkCanvas.h"
     10 #include "SkColorPriv.h"
     11 #include "SkMathPriv.h"
     12 #include "SkRegion.h"
     13 #include "Test.h"
     14 
     15 #if SK_SUPPORT_GPU
     16 #include "GrContextFactory.h"
     17 #include "SkGpuDevice.h"
     18 #endif
     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 static SkPMColor getCanvasColor(int x, int y) {
     26     SkASSERT(x >= 0 && x < DEV_W);
     27     SkASSERT(y >= 0 && y < DEV_H);
     28 
     29     U8CPU r = x;
     30     U8CPU g = y;
     31     U8CPU b = 0xc;
     32 
     33     U8CPU a = 0xff;
     34     switch ((x+y) % 5) {
     35         case 0:
     36             a = 0xff;
     37             break;
     38         case 1:
     39             a = 0x80;
     40             break;
     41         case 2:
     42             a = 0xCC;
     43             break;
     44         case 4:
     45             a = 0x01;
     46             break;
     47         case 3:
     48             a = 0x00;
     49             break;
     50     }
     51     return SkPremultiplyARGBInline(a, r, g, b);
     52 }
     53 
     54 static SkPMColor getBitmapColor(int x, int y, int w) {
     55     int n = y * w + x;
     56 
     57     U8CPU b = n & 0xff;
     58     U8CPU g = (n >> 8) & 0xff;
     59     U8CPU r = (n >> 16) & 0xff;
     60     return SkPackARGB32(0xff, r, g , b);
     61 }
     62 
     63 static SkPMColor convertToPMColor(SkColorType ct, SkAlphaType at, const uint32_t* addr,
     64                                   bool* doUnpremul) {
     65     *doUnpremul = (kUnpremul_SkAlphaType == at);
     66 
     67     const uint8_t* c = reinterpret_cast<const uint8_t*>(addr);
     68     U8CPU a,r,g,b;
     69     switch (ct) {
     70         case kBGRA_8888_SkColorType:
     71             b = static_cast<U8CPU>(c[0]);
     72             g = static_cast<U8CPU>(c[1]);
     73             r = static_cast<U8CPU>(c[2]);
     74             a = static_cast<U8CPU>(c[3]);
     75             break;
     76         case kRGBA_8888_SkColorType:
     77             r = static_cast<U8CPU>(c[0]);
     78             g = static_cast<U8CPU>(c[1]);
     79             b = static_cast<U8CPU>(c[2]);
     80             a = static_cast<U8CPU>(c[3]);
     81             break;
     82         default:
     83             SkDEBUGFAIL("Unexpected colortype");
     84             return 0;
     85     }
     86 
     87     if (*doUnpremul) {
     88         r = SkMulDiv255Ceiling(r, a);
     89         g = SkMulDiv255Ceiling(g, a);
     90         b = SkMulDiv255Ceiling(b, a);
     91     }
     92     return SkPackARGB32(a, r, g, b);
     93 }
     94 
     95 static void fillCanvas(SkCanvas* canvas) {
     96     static SkBitmap bmp;
     97     if (bmp.isNull()) {
     98         SkDEBUGCODE(bool alloc =) bmp.allocN32Pixels(DEV_W, DEV_H);
     99         SkASSERT(alloc);
    100         SkAutoLockPixels alp(bmp);
    101         intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels());
    102         for (int y = 0; y < DEV_H; ++y) {
    103             for (int x = 0; x < DEV_W; ++x) {
    104                 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel());
    105                 *pixel = getCanvasColor(x, y);
    106             }
    107         }
    108     }
    109     canvas->save();
    110     canvas->setMatrix(SkMatrix::I());
    111     canvas->clipRect(DEV_RECT_S, SkRegion::kReplace_Op);
    112     SkPaint paint;
    113     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
    114     canvas->drawBitmap(bmp, 0, 0, &paint);
    115     canvas->restore();
    116 }
    117 
    118 static void fillBitmap(SkBitmap* bitmap) {
    119     SkASSERT(bitmap->lockPixelsAreWritable());
    120     SkAutoLockPixels alp(*bitmap);
    121     int w = bitmap->width();
    122     int h = bitmap->height();
    123     intptr_t pixels = reinterpret_cast<intptr_t>(bitmap->getPixels());
    124     for (int y = 0; y < h; ++y) {
    125         for (int x = 0; x < w; ++x) {
    126             SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel());
    127             *pixel = getBitmapColor(x, y, w);
    128         }
    129     }
    130 }
    131 
    132 static bool checkPixel(SkPMColor a, SkPMColor b, bool didPremulConversion) {
    133     if (!didPremulConversion) {
    134         return a == b;
    135     }
    136     int32_t aA = static_cast<int32_t>(SkGetPackedA32(a));
    137     int32_t aR = static_cast<int32_t>(SkGetPackedR32(a));
    138     int32_t aG = static_cast<int32_t>(SkGetPackedG32(a));
    139     int32_t aB = SkGetPackedB32(a);
    140 
    141     int32_t bA = static_cast<int32_t>(SkGetPackedA32(b));
    142     int32_t bR = static_cast<int32_t>(SkGetPackedR32(b));
    143     int32_t bG = static_cast<int32_t>(SkGetPackedG32(b));
    144     int32_t bB = static_cast<int32_t>(SkGetPackedB32(b));
    145 
    146     return aA == bA &&
    147            SkAbs32(aR - bR) <= 1 &&
    148            SkAbs32(aG - bG) <= 1 &&
    149            SkAbs32(aB - bB) <= 1;
    150 }
    151 
    152 // checks the bitmap contains correct pixels after the readPixels
    153 // if the bitmap was prefilled with pixels it checks that these weren't
    154 // overwritten in the area outside the readPixels.
    155 static bool checkRead(skiatest::Reporter* reporter,
    156                       const SkBitmap& bitmap,
    157                       int x, int y,
    158                       bool checkCanvasPixels,
    159                       bool checkBitmapPixels) {
    160     SkASSERT(4 == bitmap.bytesPerPixel());
    161     SkASSERT(!bitmap.isNull());
    162     SkASSERT(checkCanvasPixels || checkBitmapPixels);
    163 
    164     const SkColorType ct = bitmap.colorType();
    165     const SkAlphaType at = bitmap.alphaType();
    166 
    167     int bw = bitmap.width();
    168     int bh = bitmap.height();
    169 
    170     SkIRect srcRect = SkIRect::MakeXYWH(x, y, bw, bh);
    171     SkIRect clippedSrcRect = DEV_RECT;
    172     if (!clippedSrcRect.intersect(srcRect)) {
    173         clippedSrcRect.setEmpty();
    174     }
    175     SkAutoLockPixels alp(bitmap);
    176     for (int by = 0; by < bh; ++by) {
    177         for (int bx = 0; bx < bw; ++bx) {
    178             int devx = bx + srcRect.fLeft;
    179             int devy = by + srcRect.fTop;
    180 
    181             const uint32_t* pixel = bitmap.getAddr32(bx, by);
    182 
    183             if (clippedSrcRect.contains(devx, devy)) {
    184                 if (checkCanvasPixels) {
    185                     SkPMColor canvasPixel = getCanvasColor(devx, devy);
    186                     bool didPremul;
    187                     SkPMColor pmPixel = convertToPMColor(ct, at, pixel, &didPremul);
    188                     bool check;
    189                     REPORTER_ASSERT(reporter, check = checkPixel(pmPixel, canvasPixel, didPremul));
    190                     if (!check) {
    191                         return false;
    192                     }
    193                 }
    194             } else if (checkBitmapPixels) {
    195                 REPORTER_ASSERT(reporter, getBitmapColor(bx, by, bw) == *pixel);
    196                 if (getBitmapColor(bx, by, bw) != *pixel) {
    197                     return false;
    198                 }
    199             }
    200         }
    201     }
    202     return true;
    203 }
    204 
    205 enum BitmapInit {
    206     kFirstBitmapInit = 0,
    207 
    208     kNoPixels_BitmapInit = kFirstBitmapInit,
    209     kTight_BitmapInit,
    210     kRowBytes_BitmapInit,
    211 
    212     kBitmapInitCnt
    213 };
    214 
    215 static BitmapInit nextBMI(BitmapInit bmi) {
    216     int x = bmi;
    217     return static_cast<BitmapInit>(++x);
    218 }
    219 
    220 static void init_bitmap(SkBitmap* bitmap, const SkIRect& rect, BitmapInit init, SkColorType ct,
    221                         SkAlphaType at) {
    222     SkImageInfo info = SkImageInfo::Make(rect.width(), rect.height(), ct, at);
    223     size_t rowBytes = 0;
    224     bool alloc = true;
    225     switch (init) {
    226         case kNoPixels_BitmapInit:
    227             alloc = false;
    228         case kTight_BitmapInit:
    229             break;
    230         case kRowBytes_BitmapInit:
    231             rowBytes = (info.width() + 16) * sizeof(SkPMColor);
    232             break;
    233         default:
    234             SkASSERT(0);
    235             break;
    236     }
    237 
    238     if (alloc) {
    239         bitmap->allocPixels(info);
    240     } else {
    241         bitmap->setInfo(info, rowBytes);
    242     }
    243 }
    244 
    245 DEF_GPUTEST(ReadPixels, reporter, factory) {
    246     const SkIRect testRects[] = {
    247         // entire thing
    248         DEV_RECT,
    249         // larger on all sides
    250         SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10),
    251         // fully contained
    252         SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4),
    253         // outside top left
    254         SkIRect::MakeLTRB(-10, -10, -1, -1),
    255         // touching top left corner
    256         SkIRect::MakeLTRB(-10, -10, 0, 0),
    257         // overlapping top left corner
    258         SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4),
    259         // overlapping top left and top right corners
    260         SkIRect::MakeLTRB(-10, -10, DEV_W  + 10, DEV_H / 4),
    261         // touching entire top edge
    262         SkIRect::MakeLTRB(-10, -10, DEV_W  + 10, 0),
    263         // overlapping top right corner
    264         SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W  + 10, DEV_H / 4),
    265         // contained in x, overlapping top edge
    266         SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W  / 4, DEV_H / 4),
    267         // outside top right corner
    268         SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1),
    269         // touching top right corner
    270         SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0),
    271         // overlapping top left and bottom left corners
    272         SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10),
    273         // touching entire left edge
    274         SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10),
    275         // overlapping bottom left corner
    276         SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10),
    277         // contained in y, overlapping left edge
    278         SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4),
    279         // outside bottom left corner
    280         SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10),
    281         // touching bottom left corner
    282         SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10),
    283         // overlapping bottom left and bottom right corners
    284         SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
    285         // touching entire left edge
    286         SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10),
    287         // overlapping bottom right corner
    288         SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
    289         // overlapping top right and bottom right corners
    290         SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10),
    291     };
    292 
    293     for (int dtype = 0; dtype < 3; ++dtype) {
    294         int glCtxTypeCnt = 1;
    295 #if SK_SUPPORT_GPU
    296         if (0 != dtype)  {
    297             glCtxTypeCnt = GrContextFactory::kGLContextTypeCnt;
    298         }
    299 #endif
    300         for (int glCtxType = 0; glCtxType < glCtxTypeCnt; ++glCtxType) {
    301             SkAutoTUnref<SkBaseDevice> device;
    302             if (0 == dtype) {
    303                 SkImageInfo info = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
    304                 device.reset(SkBitmapDevice::Create(info));
    305             } else {
    306 #if SK_SUPPORT_GPU
    307                 GrContextFactory::GLContextType type =
    308                     static_cast<GrContextFactory::GLContextType>(glCtxType);
    309                 if (!GrContextFactory::IsRenderingGLContext(type)) {
    310                     continue;
    311                 }
    312                 GrContext* context = factory->get(type);
    313                 if (NULL == context) {
    314                     continue;
    315                 }
    316                 GrTextureDesc desc;
    317                 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
    318                 desc.fWidth = DEV_W;
    319                 desc.fHeight = DEV_H;
    320                 desc.fConfig = kSkia8888_GrPixelConfig;
    321                 desc.fOrigin = 1 == dtype ? kBottomLeft_GrSurfaceOrigin
    322                                           : kTopLeft_GrSurfaceOrigin;
    323                 GrAutoScratchTexture ast(context, desc, GrContext::kExact_ScratchTexMatch);
    324                 SkAutoTUnref<GrTexture> tex(ast.detach());
    325                 device.reset(new SkGpuDevice(context, tex));
    326 #else
    327                 continue;
    328 #endif
    329             }
    330             SkCanvas canvas(device);
    331             fillCanvas(&canvas);
    332 
    333             static const struct {
    334                 SkColorType fColorType;
    335                 SkAlphaType fAlphaType;
    336             } gReadConfigs[] = {
    337                 { kRGBA_8888_SkColorType,   kPremul_SkAlphaType },
    338                 { kRGBA_8888_SkColorType,   kUnpremul_SkAlphaType },
    339                 { kBGRA_8888_SkColorType,   kPremul_SkAlphaType },
    340                 { kBGRA_8888_SkColorType,   kUnpremul_SkAlphaType },
    341             };
    342             for (size_t rect = 0; rect < SK_ARRAY_COUNT(testRects); ++rect) {
    343                 const SkIRect& srcRect = testRects[rect];
    344                 for (BitmapInit bmi = kFirstBitmapInit; bmi < kBitmapInitCnt; bmi = nextBMI(bmi)) {
    345                     for (size_t c = 0; c < SK_ARRAY_COUNT(gReadConfigs); ++c) {
    346                         SkBitmap bmp;
    347                         init_bitmap(&bmp, srcRect, bmi,
    348                                     gReadConfigs[c].fColorType, gReadConfigs[c].fAlphaType);
    349 
    350                         // if the bitmap has pixels allocated before the readPixels,
    351                         // note that and fill them with pattern
    352                         bool startsWithPixels = !bmp.isNull();
    353                         if (startsWithPixels) {
    354                             fillBitmap(&bmp);
    355                         }
    356                         uint32_t idBefore = canvas.getDevice()->accessBitmap(false).getGenerationID();
    357                         bool success = canvas.readPixels(&bmp, srcRect.fLeft, srcRect.fTop);
    358                         uint32_t idAfter = canvas.getDevice()->accessBitmap(false).getGenerationID();
    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                         // read pixels should never change the gen id
    366                         REPORTER_ASSERT(reporter, idBefore == idAfter);
    367 
    368                         if (success || startsWithPixels) {
    369                             checkRead(reporter, bmp, srcRect.fLeft, srcRect.fTop,
    370                                       success, startsWithPixels);
    371                         } else {
    372                             // if we had no pixels beforehand and the readPixels
    373                             // failed then our bitmap should still not have pixels
    374                             REPORTER_ASSERT(reporter, bmp.isNull());
    375                         }
    376                     }
    377                     // check the old webkit version of readPixels that clips the
    378                     // bitmap size
    379                     SkBitmap wkbmp;
    380                     bool success = canvas.readPixels(srcRect, &wkbmp);
    381                     SkIRect clippedRect = DEV_RECT;
    382                     if (clippedRect.intersect(srcRect)) {
    383                         REPORTER_ASSERT(reporter, success);
    384                         REPORTER_ASSERT(reporter, kN32_SkColorType == wkbmp.colorType());
    385                         REPORTER_ASSERT(reporter, kPremul_SkAlphaType == wkbmp.alphaType());
    386                         checkRead(reporter, wkbmp, clippedRect.fLeft,
    387                                   clippedRect.fTop, true, false);
    388                     } else {
    389                         REPORTER_ASSERT(reporter, !success);
    390                     }
    391                 }
    392             }
    393         }
    394     }
    395 }
    396