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