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 "SkCanvas.h"
      9 #include "SkColorData.h"
     10 #include "SkMathPriv.h"
     11 #include "SkSurface.h"
     12 #include "Test.h"
     13 #include "sk_tool_utils.h"
     14 
     15 #if SK_SUPPORT_GPU
     16 #include "GrBackendSurface.h"
     17 #include "GrContext.h"
     18 #include "GrContextPriv.h"
     19 #include "GrGpu.h"
     20 #include "GrProxyProvider.h"
     21 #include "GrTest.h"
     22 #endif
     23 
     24 #include <initializer_list>
     25 
     26 static const int DEV_W = 100, DEV_H = 100;
     27 static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
     28 static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1,
     29                                                 DEV_H * SK_Scalar1);
     30 static const U8CPU DEV_PAD = 0xee;
     31 
     32 static SkPMColor get_canvas_color(int x, int y) {
     33     SkASSERT(x >= 0 && x < DEV_W);
     34     SkASSERT(y >= 0 && y < DEV_H);
     35 
     36     U8CPU r = x;
     37     U8CPU g = y;
     38     U8CPU b = 0xc;
     39 
     40     U8CPU a = 0x0;
     41     switch ((x+y) % 5) {
     42         case 0:
     43             a = 0xff;
     44             break;
     45         case 1:
     46             a = 0x80;
     47             break;
     48         case 2:
     49             a = 0xCC;
     50             break;
     51         case 3:
     52             a = 0x00;
     53             break;
     54         case 4:
     55             a = 0x01;
     56             break;
     57     }
     58     return SkPremultiplyARGBInline(a, r, g, b);
     59 }
     60 
     61 // assumes any premu/.unpremul has been applied
     62 static uint32_t pack_color_type(SkColorType ct, U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
     63     uint32_t r32;
     64     uint8_t* result = reinterpret_cast<uint8_t*>(&r32);
     65     switch (ct) {
     66         case kBGRA_8888_SkColorType:
     67             result[0] = b;
     68             result[1] = g;
     69             result[2] = r;
     70             result[3] = a;
     71             break;
     72         case kRGBA_8888_SkColorType:
     73             result[0] = r;
     74             result[1] = g;
     75             result[2] = b;
     76             result[3] = a;
     77             break;
     78         default:
     79             SkASSERT(0);
     80             return 0;
     81     }
     82     return r32;
     83 }
     84 
     85 static uint32_t get_bitmap_color(int x, int y, int w, SkColorType ct, SkAlphaType at) {
     86     int n = y * w + x;
     87     U8CPU b = n & 0xff;
     88     U8CPU g = (n >> 8) & 0xff;
     89     U8CPU r = (n >> 16) & 0xff;
     90     U8CPU a = 0;
     91     switch ((x+y) % 5) {
     92         case 4:
     93             a = 0xff;
     94             break;
     95         case 3:
     96             a = 0x80;
     97             break;
     98         case 2:
     99             a = 0xCC;
    100             break;
    101         case 1:
    102             a = 0x01;
    103             break;
    104         case 0:
    105             a = 0x00;
    106             break;
    107     }
    108     if (kPremul_SkAlphaType == at) {
    109         r = SkMulDiv255Ceiling(r, a);
    110         g = SkMulDiv255Ceiling(g, a);
    111         b = SkMulDiv255Ceiling(b, a);
    112     }
    113     return pack_color_type(ct, a, r, g , b);
    114 }
    115 
    116 static void fill_canvas(SkCanvas* canvas) {
    117     SkBitmap bmp;
    118     if (bmp.isNull()) {
    119         bmp.allocN32Pixels(DEV_W, DEV_H);
    120         for (int y = 0; y < DEV_H; ++y) {
    121             for (int x = 0; x < DEV_W; ++x) {
    122                 *bmp.getAddr32(x, y) = get_canvas_color(x, y);
    123             }
    124         }
    125     }
    126     canvas->save();
    127     canvas->setMatrix(SkMatrix::I());
    128     canvas->clipRect(DEV_RECT_S, kReplace_SkClipOp);
    129     SkPaint paint;
    130     paint.setBlendMode(SkBlendMode::kSrc);
    131     canvas->drawBitmap(bmp, 0, 0, &paint);
    132     canvas->restore();
    133 }
    134 
    135 /**
    136  *  Lucky for us, alpha is always in the same spot (SK_A32_SHIFT), for both RGBA and BGRA.
    137  *  Thus this routine doesn't need to know the exact colortype
    138  */
    139 static uint32_t premul(uint32_t color) {
    140     unsigned a = SkGetPackedA32(color);
    141     // these next three are not necessarily r,g,b in that order, but they are r,g,b in some order.
    142     unsigned c0 = SkGetPackedR32(color);
    143     unsigned c1 = SkGetPackedG32(color);
    144     unsigned c2 = SkGetPackedB32(color);
    145     c0 = SkMulDiv255Ceiling(c0, a);
    146     c1 = SkMulDiv255Ceiling(c1, a);
    147     c2 = SkMulDiv255Ceiling(c2, a);
    148     return SkPackARGB32NoCheck(a, c0, c1, c2);
    149 }
    150 
    151 static SkPMColor convert_to_PMColor(SkColorType ct, SkAlphaType at, uint32_t color) {
    152     if (kUnpremul_SkAlphaType == at) {
    153         color = premul(color);
    154     }
    155     switch (ct) {
    156         case kRGBA_8888_SkColorType:
    157             color = SkSwizzle_RGBA_to_PMColor(color);
    158             break;
    159         case kBGRA_8888_SkColorType:
    160             color = SkSwizzle_BGRA_to_PMColor(color);
    161             break;
    162         default:
    163             SkASSERT(0);
    164             break;
    165     }
    166     return color;
    167 }
    168 
    169 static bool check_pixel(SkPMColor a, SkPMColor b, bool didPremulConversion) {
    170     if (!didPremulConversion) {
    171         return a == b;
    172     }
    173     int32_t aA = static_cast<int32_t>(SkGetPackedA32(a));
    174     int32_t aR = static_cast<int32_t>(SkGetPackedR32(a));
    175     int32_t aG = static_cast<int32_t>(SkGetPackedG32(a));
    176     int32_t aB = SkGetPackedB32(a);
    177 
    178     int32_t bA = static_cast<int32_t>(SkGetPackedA32(b));
    179     int32_t bR = static_cast<int32_t>(SkGetPackedR32(b));
    180     int32_t bG = static_cast<int32_t>(SkGetPackedG32(b));
    181     int32_t bB = static_cast<int32_t>(SkGetPackedB32(b));
    182 
    183     return aA == bA &&
    184            SkAbs32(aR - bR) <= 1 &&
    185            SkAbs32(aG - bG) <= 1 &&
    186            SkAbs32(aB - bB) <= 1;
    187 }
    188 
    189 static bool check_write(skiatest::Reporter* reporter, SkSurface* surf, const SkBitmap& bitmap,
    190                        int writeX, int writeY) {
    191     size_t canvasRowBytes;
    192     const uint32_t* canvasPixels;
    193 
    194     // Can't use canvas->peekPixels(), as we are trying to look at GPU pixels sometimes as well.
    195     // At some point this will be unsupported, as we won't allow accessBitmap() to magically call
    196     // readPixels for the client.
    197     SkBitmap secretDevBitmap;
    198     secretDevBitmap.allocN32Pixels(surf->width(), surf->height());
    199     if (!surf->readPixels(secretDevBitmap, 0, 0)) {
    200         return false;
    201     }
    202 
    203     canvasRowBytes = secretDevBitmap.rowBytes();
    204     canvasPixels = static_cast<const uint32_t*>(secretDevBitmap.getPixels());
    205 
    206     if (nullptr == canvasPixels) {
    207         return false;
    208     }
    209 
    210     if (surf->width() != DEV_W || surf->height() != DEV_H) {
    211         return false;
    212     }
    213 
    214     const SkImageInfo bmInfo = bitmap.info();
    215 
    216     SkIRect writeRect = SkIRect::MakeXYWH(writeX, writeY, bitmap.width(), bitmap.height());
    217     for (int cy = 0; cy < DEV_H; ++cy) {
    218         for (int cx = 0; cx < DEV_W; ++cx) {
    219             SkPMColor canvasPixel = canvasPixels[cx];
    220             if (writeRect.contains(cx, cy)) {
    221                 int bx = cx - writeX;
    222                 int by = cy - writeY;
    223                 uint32_t bmpColor8888 = get_bitmap_color(bx, by, bitmap.width(),
    224                                                        bmInfo.colorType(), bmInfo.alphaType());
    225                 bool mul = (kUnpremul_SkAlphaType == bmInfo.alphaType());
    226                 SkPMColor bmpPMColor = convert_to_PMColor(bmInfo.colorType(), bmInfo.alphaType(),
    227                                                           bmpColor8888);
    228                 if (!check_pixel(bmpPMColor, canvasPixel, mul)) {
    229                     ERRORF(reporter, "Expected canvas pixel at %d, %d to be 0x%08x, got 0x%08x. "
    230                            "Write performed premul: %d", cx, cy, bmpPMColor, canvasPixel, mul);
    231                     return false;
    232                 }
    233             } else {
    234                 SkPMColor testColor = get_canvas_color(cx, cy);
    235                 if (canvasPixel != testColor) {
    236                     ERRORF(reporter, "Canvas pixel outside write rect at %d, %d changed."
    237                            " Should be 0x%08x, got 0x%08x. ", cx, cy, testColor, canvasPixel);
    238                     return false;
    239                 }
    240             }
    241         }
    242         if (cy != DEV_H -1) {
    243             const char* pad = reinterpret_cast<const char*>(canvasPixels + DEV_W);
    244             for (size_t px = 0; px < canvasRowBytes - 4 * DEV_W; ++px) {
    245                 bool check;
    246                 REPORTER_ASSERT(reporter, check = (pad[px] == static_cast<char>(DEV_PAD)));
    247                 if (!check) {
    248                     return false;
    249                 }
    250             }
    251         }
    252         canvasPixels += canvasRowBytes/4;
    253     }
    254 
    255     return true;
    256 }
    257 
    258 #include "SkMallocPixelRef.h"
    259 
    260 // This is a tricky pattern, because we have to setConfig+rowBytes AND specify
    261 // a custom pixelRef (which also has to specify its rowBytes), so we have to be
    262 // sure that the two rowBytes match (and the infos match).
    263 //
    264 static bool alloc_row_bytes(SkBitmap* bm, const SkImageInfo& info, size_t rowBytes) {
    265     if (!bm->setInfo(info, rowBytes)) {
    266         return false;
    267     }
    268     sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, rowBytes);
    269     bm->setPixelRef(std::move(pr), 0, 0);
    270     return true;
    271 }
    272 
    273 static void free_pixels(void* pixels, void* ctx) {
    274     sk_free(pixels);
    275 }
    276 
    277 static bool setup_bitmap(SkBitmap* bm, SkColorType ct, SkAlphaType at, int w, int h, int tightRB) {
    278     size_t rowBytes = tightRB ? 0 : 4 * w + 60;
    279     SkImageInfo info = SkImageInfo::Make(w, h, ct, at);
    280     if (!alloc_row_bytes(bm, info, rowBytes)) {
    281         return false;
    282     }
    283     for (int y = 0; y < h; ++y) {
    284         for (int x = 0; x < w; ++x) {
    285             *bm->getAddr32(x, y) = get_bitmap_color(x, y, w, ct, at);
    286         }
    287     }
    288     return true;
    289 }
    290 
    291 static void call_writepixels(SkCanvas* canvas) {
    292     const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
    293     SkPMColor pixel = 0;
    294     canvas->writePixels(info, &pixel, sizeof(SkPMColor), 0, 0);
    295 }
    296 
    297 DEF_TEST(WritePixelsSurfaceGenID, reporter) {
    298     const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
    299     auto surface(SkSurface::MakeRaster(info));
    300     uint32_t genID1 = surface->generationID();
    301     call_writepixels(surface->getCanvas());
    302     uint32_t genID2 = surface->generationID();
    303     REPORTER_ASSERT(reporter, genID1 != genID2);
    304 }
    305 
    306 static void test_write_pixels(skiatest::Reporter* reporter, SkSurface* surface) {
    307     const SkIRect testRects[] = {
    308         // entire thing
    309         DEV_RECT,
    310         // larger on all sides
    311         SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10),
    312         // fully contained
    313         SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4),
    314         // outside top left
    315         SkIRect::MakeLTRB(-10, -10, -1, -1),
    316         // touching top left corner
    317         SkIRect::MakeLTRB(-10, -10, 0, 0),
    318         // overlapping top left corner
    319         SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4),
    320         // overlapping top left and top right corners
    321         SkIRect::MakeLTRB(-10, -10, DEV_W  + 10, DEV_H / 4),
    322         // touching entire top edge
    323         SkIRect::MakeLTRB(-10, -10, DEV_W  + 10, 0),
    324         // overlapping top right corner
    325         SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W  + 10, DEV_H / 4),
    326         // contained in x, overlapping top edge
    327         SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W  / 4, DEV_H / 4),
    328         // outside top right corner
    329         SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1),
    330         // touching top right corner
    331         SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0),
    332         // overlapping top left and bottom left corners
    333         SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10),
    334         // touching entire left edge
    335         SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10),
    336         // overlapping bottom left corner
    337         SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10),
    338         // contained in y, overlapping left edge
    339         SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4),
    340         // outside bottom left corner
    341         SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10),
    342         // touching bottom left corner
    343         SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10),
    344         // overlapping bottom left and bottom right corners
    345         SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
    346         // touching entire left edge
    347         SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10),
    348         // overlapping bottom right corner
    349         SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
    350         // overlapping top right and bottom right corners
    351         SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10),
    352     };
    353 
    354     SkCanvas* canvas = surface->getCanvas();
    355 
    356     static const struct {
    357         SkColorType fColorType;
    358         SkAlphaType fAlphaType;
    359     } gSrcConfigs[] = {
    360         { kRGBA_8888_SkColorType, kPremul_SkAlphaType },
    361         { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType },
    362         { kBGRA_8888_SkColorType, kPremul_SkAlphaType },
    363         { kBGRA_8888_SkColorType, kUnpremul_SkAlphaType },
    364     };
    365     for (size_t r = 0; r < SK_ARRAY_COUNT(testRects); ++r) {
    366         const SkIRect& rect = testRects[r];
    367         for (int tightBmp = 0; tightBmp < 2; ++tightBmp) {
    368             for (size_t c = 0; c < SK_ARRAY_COUNT(gSrcConfigs); ++c) {
    369                 const SkColorType ct = gSrcConfigs[c].fColorType;
    370                 const SkAlphaType at = gSrcConfigs[c].fAlphaType;
    371 
    372                 fill_canvas(canvas);
    373                 SkBitmap bmp;
    374                 REPORTER_ASSERT(reporter, setup_bitmap(&bmp, ct, at, rect.width(),
    375                                                        rect.height(), SkToBool(tightBmp)));
    376                 uint32_t idBefore = surface->generationID();
    377 
    378                 // sk_tool_utils::write_pixels(&canvas, bmp, rect.fLeft, rect.fTop, ct, at);
    379                 canvas->writePixels(bmp, rect.fLeft, rect.fTop);
    380 
    381                 uint32_t idAfter = surface->generationID();
    382                 REPORTER_ASSERT(reporter, check_write(reporter, surface, bmp,
    383                                                       rect.fLeft, rect.fTop));
    384 
    385                 // we should change the genID iff pixels were actually written.
    386                 SkIRect canvasRect = SkIRect::MakeSize(canvas->getBaseLayerSize());
    387                 SkIRect writeRect = SkIRect::MakeXYWH(rect.fLeft, rect.fTop,
    388                                                       bmp.width(), bmp.height());
    389                 bool intersects = SkIRect::Intersects(canvasRect, writeRect) ;
    390                 REPORTER_ASSERT(reporter, intersects == (idBefore != idAfter));
    391             }
    392         }
    393     }
    394 }
    395 DEF_TEST(WritePixels, reporter) {
    396     const SkImageInfo info = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
    397     for (auto& tightRowBytes : { true, false }) {
    398         const size_t rowBytes = tightRowBytes ? info.minRowBytes() : 4 * DEV_W + 100;
    399         const size_t size = info.computeByteSize(rowBytes);
    400         void* pixels = sk_malloc_throw(size);
    401         // if rowBytes isn't tight then set the padding to a known value
    402         if (!tightRowBytes) {
    403             memset(pixels, DEV_PAD, size);
    404         }
    405         auto surface(SkSurface::MakeRasterDirectReleaseProc(info, pixels, rowBytes,
    406                                                             free_pixels, nullptr));
    407         test_write_pixels(reporter, surface.get());
    408     }
    409 }
    410 #if SK_SUPPORT_GPU
    411 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixels_Gpu, reporter, ctxInfo) {
    412     const SkImageInfo ii = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
    413 
    414     for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
    415         for (int sampleCnt : {1, 4}) {
    416             sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
    417                                                                  SkBudgeted::kNo, ii, sampleCnt,
    418                                                                  origin, nullptr));
    419             if (!surface && sampleCnt > 1) {
    420                 // Some platforms don't support MSAA
    421                 continue;
    422             }
    423             test_write_pixels(reporter, surface.get());
    424         }
    425     }
    426 }
    427 
    428 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsNonTexture_Gpu, reporter, ctxInfo) {
    429     GrContext* context = ctxInfo.grContext();
    430     GrGpu* gpu = context->contextPriv().getGpu();
    431 
    432     for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
    433         for (int sampleCnt : {1, 4}) {
    434             GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
    435                     nullptr, DEV_W, DEV_H, kSkia8888_GrPixelConfig, true, GrMipMapped::kNo);
    436             SkColorType colorType;
    437             if (kRGBA_8888_GrPixelConfig == kSkia8888_GrPixelConfig) {
    438                 colorType = kRGBA_8888_SkColorType;
    439             } else {
    440                 colorType = kBGRA_8888_SkColorType;
    441             }
    442             sk_sp<SkSurface> surface(SkSurface::MakeFromBackendTextureAsRenderTarget(
    443                     context, backendTex, origin, sampleCnt, colorType, nullptr, nullptr));
    444             if (!surface) {
    445                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    446                 continue;
    447             }
    448 
    449             test_write_pixels(reporter, surface.get());
    450 
    451             surface.reset();
    452             gpu->deleteTestingOnlyBackendTexture(&backendTex);
    453         }
    454     }
    455 }
    456 
    457 static sk_sp<SkSurface> create_surf(GrContext* context, int width, int height) {
    458     const SkImageInfo ii = SkImageInfo::Make(width, height,
    459                                              kRGBA_8888_SkColorType, kPremul_SkAlphaType);
    460 
    461     sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, ii);
    462     surf->flush();
    463     return surf;
    464 }
    465 
    466 static sk_sp<SkImage> upload(const sk_sp<SkSurface>& surf, SkColor color) {
    467     const SkImageInfo smII = SkImageInfo::Make(16, 16, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
    468     SkBitmap bm;
    469     bm.allocPixels(smII);
    470     bm.eraseColor(color);
    471 
    472     surf->getCanvas()->writePixels(bm, 0, 0);
    473 
    474     return surf->makeImageSnapshot();
    475 }
    476 
    477 // This is tests whether the first writePixels is completed before the
    478 // second writePixels takes effect (i.e., that writePixels correctly flushes
    479 // in between uses of the shared backing resource).
    480 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsPendingIO, reporter, ctxInfo) {
    481     GrContext* context = ctxInfo.grContext();
    482     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
    483 
    484     static const int kFullSize = 62;
    485     static const int kHalfSize = 31;
    486 
    487     static const uint32_t kLeftColor = 0xFF222222;
    488     static const uint32_t kRightColor = 0xFFAAAAAA;
    489 
    490     const SkImageInfo fullII = SkImageInfo::Make(kFullSize, kFullSize,
    491                                                  kRGBA_8888_SkColorType, kPremul_SkAlphaType);
    492     const SkImageInfo halfII = SkImageInfo::Make(kHalfSize, kFullSize,
    493                                                  kRGBA_8888_SkColorType, kPremul_SkAlphaType);
    494 
    495     sk_sp<SkSurface> dest = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, fullII);
    496 
    497     {
    498         // Seed the resource cached with a scratch texture that will be
    499         // reused by writeSurfacePixels
    500         GrSurfaceDesc desc;
    501         desc.fFlags = kNone_GrSurfaceFlags;
    502         desc.fWidth = 32;
    503         desc.fHeight = 64;
    504         desc.fConfig = kRGBA_8888_GrPixelConfig;
    505 
    506         sk_sp<GrTextureProxy> temp = proxyProvider->createProxy(desc, SkBackingFit::kApprox,
    507                                                                 SkBudgeted::kYes);
    508         temp->instantiate(context->contextPriv().resourceProvider());
    509     }
    510 
    511     // Create the surfaces and flush them to ensure there is no lingering pendingIO
    512     sk_sp<SkSurface> leftSurf = create_surf(context, kHalfSize, kFullSize);
    513     sk_sp<SkSurface> rightSurf = create_surf(context, kHalfSize, kFullSize);
    514 
    515     sk_sp<SkImage> leftImg = upload(std::move(leftSurf), kLeftColor);
    516     dest->getCanvas()->drawImage(std::move(leftImg), 0, 0);
    517 
    518     sk_sp<SkImage> rightImg = upload(std::move(rightSurf), kRightColor);
    519     dest->getCanvas()->drawImage(std::move(rightImg), kHalfSize, 0);
    520 
    521     SkBitmap bm;
    522     bm.allocPixels(fullII);
    523     SkAssertResult(dest->readPixels(bm, 0, 0));
    524 
    525     bool isCorrect = true;
    526     for (int y = 0; isCorrect && y < 16; ++y) {
    527         const uint32_t* sl = bm.getAddr32(0, y);
    528 
    529         for (int x = 0; x < 16; ++x) {
    530             if (kLeftColor != sl[x]) {
    531                 isCorrect = false;
    532                 break;
    533             }
    534         }
    535         for (int x = kHalfSize; x < kHalfSize+16; ++x) {
    536             if (kRightColor != sl[x]) {
    537                 isCorrect = false;
    538                 break;
    539             }
    540         }
    541     }
    542 
    543     REPORTER_ASSERT(reporter, isCorrect);
    544 }
    545 
    546 
    547 #endif
    548