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