Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2012 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 "SkTileGrid.h"
     12 #include "SkTileGridPicture.h"
     13 
     14 enum Tile {
     15     kTopLeft_Tile = 0x1,
     16     kTopRight_Tile = 0x2,
     17     kBottomLeft_Tile = 0x4,
     18     kBottomRight_Tile = 0x8,
     19 
     20     kAll_Tile = kTopLeft_Tile | kTopRight_Tile | kBottomLeft_Tile | kBottomRight_Tile,
     21 };
     22 
     23 class MockCanvas : public SkCanvas {
     24 public:
     25     MockCanvas(SkBaseDevice* device) : SkCanvas(device)
     26     {}
     27 
     28     virtual void drawRect(const SkRect& rect, const SkPaint&)
     29     {
     30         // This capture occurs before quick reject.
     31         fRects.push(rect);
     32     }
     33 
     34     SkTDArray<SkRect> fRects;
     35 };
     36 
     37 class TileGridTest {
     38 public:
     39     static void verifyTileHits(skiatest::Reporter* reporter, SkIRect rect, uint32_t tileMask,
     40                                int borderPixels = 0) {
     41         SkTileGridPicture::TileGridInfo info;
     42         info.fMargin.set(borderPixels, borderPixels);
     43         info.fOffset.setZero();
     44         info.fTileInterval.set(10 - 2 * borderPixels, 10 - 2 * borderPixels);
     45         SkTileGrid grid(2, 2, info, NULL);
     46         grid.insert(NULL, rect, false);
     47         REPORTER_ASSERT(reporter, grid.tile(0,0).count() ==
     48             ((tileMask & kTopLeft_Tile)? 1 : 0));
     49         REPORTER_ASSERT(reporter, grid.tile(1,0).count() ==
     50             ((tileMask & kTopRight_Tile)? 1 : 0));
     51         REPORTER_ASSERT(reporter, grid.tile(0,1).count() ==
     52             ((tileMask & kBottomLeft_Tile)? 1 : 0));
     53         REPORTER_ASSERT(reporter, grid.tile(1,1).count() ==
     54             ((tileMask & kBottomRight_Tile)? 1 : 0));
     55     }
     56 
     57     static void TestUnalignedQuery(skiatest::Reporter* reporter) {
     58         // Use SkTileGridPicture to generate a SkTileGrid with a helper
     59         SkTileGridPicture::TileGridInfo info;
     60         info.fMargin.setEmpty();
     61         info.fOffset.setZero();
     62         info.fTileInterval.set(10, 10);
     63         SkTileGridPicture picture(20, 20, info);
     64         SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
     65             SkIntToScalar(8), SkIntToScalar(8));
     66         SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(11), SkIntToScalar(11),
     67             SkIntToScalar(1), SkIntToScalar(1));
     68         SkCanvas* canvas = picture.beginRecording(20, 20, SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
     69         SkPaint paint;
     70         canvas->drawRect(rect1, paint);
     71         canvas->drawRect(rect2, paint);
     72         picture.endRecording();
     73 
     74         SkBitmap store;
     75         store.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
     76         store.allocPixels();
     77 
     78         // Test parts of top-left tile
     79         {
     80             SkBitmapDevice device(store);
     81             MockCanvas mockCanvas(&device);
     82             picture.draw(&mockCanvas);
     83             REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
     84             REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
     85         }
     86         {
     87             SkBitmapDevice device(store);
     88             MockCanvas mockCanvas(&device);
     89             mockCanvas.translate(-7.99f, -7.99f);
     90             picture.draw(&mockCanvas);
     91             REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
     92             REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
     93         }
     94         // Corner overlap
     95         {
     96             SkBitmapDevice device(store);
     97             MockCanvas mockCanvas(&device);
     98             mockCanvas.translate(-9.5f, -9.5f);
     99             picture.draw(&mockCanvas);
    100             REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
    101             REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
    102             REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[1]);
    103         }
    104         // Intersect bottom right tile, but does not overlap rect 2
    105         {
    106             SkBitmapDevice device(store);
    107             MockCanvas mockCanvas(&device);
    108             mockCanvas.translate(-16.0f, -16.0f);
    109             picture.draw(&mockCanvas);
    110             REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
    111             REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
    112         }
    113         // Out of bounds queries, snap to border tiles
    114         {
    115             SkBitmapDevice device(store);
    116             MockCanvas mockCanvas(&device);
    117             mockCanvas.translate(2.0f, 0.0f);
    118             picture.draw(&mockCanvas);
    119             REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
    120             REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
    121         }
    122         {
    123             SkBitmapDevice device(store);
    124             MockCanvas mockCanvas(&device);
    125             mockCanvas.translate(0.0f, 2.0f);
    126             picture.draw(&mockCanvas);
    127             REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
    128             REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
    129         }
    130         {
    131             SkBitmapDevice device(store);
    132             MockCanvas mockCanvas(&device);
    133             mockCanvas.translate(-22.0f, -16.0f);
    134             picture.draw(&mockCanvas);
    135             REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
    136             REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
    137         }
    138         {
    139             SkBitmapDevice device(store);
    140             MockCanvas mockCanvas(&device);
    141             mockCanvas.translate(-16.0f, -22.0f);
    142             picture.draw(&mockCanvas);
    143             REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
    144             REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
    145         }
    146     }
    147 
    148     static void TestOverlapOffsetQueryAlignment(skiatest::Reporter* reporter) {
    149         // Use SkTileGridPicture to generate a SkTileGrid with a helper
    150         SkTileGridPicture::TileGridInfo info;
    151         info.fMargin.set(1, 1);
    152         info.fOffset.set(-1, -1);
    153         info.fTileInterval.set(8, 8);
    154         SkTileGridPicture picture(20, 20, info);
    155 
    156         // rect landing entirely in top left tile
    157         SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
    158             SkIntToScalar(1), SkIntToScalar(1));
    159         // rect landing entirely in center tile
    160         SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(12), SkIntToScalar(12),
    161             SkIntToScalar(1), SkIntToScalar(1));
    162                 // rect landing entirely in bottomright tile
    163         SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(19), SkIntToScalar(19),
    164             SkIntToScalar(1), SkIntToScalar(1));
    165         SkCanvas* canvas = picture.beginRecording(20, 20, SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
    166         SkPaint paint;
    167         canvas->drawRect(rect1, paint);
    168         canvas->drawRect(rect2, paint);
    169         canvas->drawRect(rect3, paint);
    170         picture.endRecording();
    171 
    172         SkBitmap tileBitmap;
    173         tileBitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
    174         tileBitmap.allocPixels();
    175         SkBitmap moreThanATileBitmap;
    176         moreThanATileBitmap.setConfig(SkBitmap::kARGB_8888_Config, 11, 11);
    177         moreThanATileBitmap.allocPixels();
    178         SkBitmap tinyBitmap;
    179         tinyBitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
    180         tinyBitmap.allocPixels();
    181         // Test parts of top-left tile
    182         {
    183             // The offset should cancel the top and left borders of the top left tile
    184             // So a look-up at interval 0-10 should be grid aligned,
    185             SkBitmapDevice device(tileBitmap);
    186             MockCanvas mockCanvas(&device);
    187             picture.draw(&mockCanvas);
    188             REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
    189             REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
    190         }
    191         {
    192             // Encroaching border by one pixel
    193             SkBitmapDevice device(moreThanATileBitmap);
    194             MockCanvas mockCanvas(&device);
    195             picture.draw(&mockCanvas);
    196             REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
    197             REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
    198             REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[1]);
    199         }
    200         {
    201             // Tile stride is 8 (tileWidth - 2 * border pixels
    202             // so translating by 8, should make query grid-aligned
    203             // with middle tile.
    204             SkBitmapDevice device(tileBitmap);
    205             MockCanvas mockCanvas(&device);
    206             mockCanvas.translate(SkIntToScalar(-8), SkIntToScalar(-8));
    207             picture.draw(&mockCanvas);
    208             REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
    209             REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
    210         }
    211         {
    212             SkBitmapDevice device(tileBitmap);
    213             MockCanvas mockCanvas(&device);
    214             mockCanvas.translate(-7.9f, -7.9f);
    215             picture.draw(&mockCanvas);
    216             REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
    217             REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
    218             REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[1]);
    219         }
    220         {
    221             SkBitmapDevice device(tileBitmap);
    222             MockCanvas mockCanvas(&device);
    223             mockCanvas.translate(-8.1f, -8.1f);
    224             picture.draw(&mockCanvas);
    225             REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
    226             REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
    227             REPORTER_ASSERT(reporter, rect3 == mockCanvas.fRects[1]);
    228         }
    229         {
    230             // Regression test for crbug.com/234688
    231             // Once the 2x2 device region is inset by margin, it yields an empty
    232             // adjusted region, sitting right on top of the tile boundary.
    233             SkBitmapDevice device(tinyBitmap);
    234             MockCanvas mockCanvas(&device);
    235             mockCanvas.translate(-8.0f, -8.0f);
    236             picture.draw(&mockCanvas);
    237             // This test passes by not asserting. We do not validate the rects recorded
    238             // because the result is numerically unstable (floating point equality).
    239             // The content of any one of the four tiles of the tilegrid would be a valid
    240             // result since any bbox that covers the center point of the canvas will be
    241             // recorded in all four tiles.
    242         }
    243     }
    244 
    245     static void Test(skiatest::Reporter* reporter) {
    246         // Out of bounds
    247         verifyTileHits(reporter, SkIRect::MakeXYWH(30, 0, 1, 1),  0);
    248         verifyTileHits(reporter, SkIRect::MakeXYWH(0, 30, 1, 1),  0);
    249         verifyTileHits(reporter, SkIRect::MakeXYWH(-10, 0, 1, 1),  0);
    250         verifyTileHits(reporter, SkIRect::MakeXYWH(0, -10, 1, 1),  0);
    251 
    252         // Dilation for AA consideration
    253         verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 9, 9),  kTopLeft_Tile);
    254         verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 10, 10),  kAll_Tile);
    255         verifyTileHits(reporter, SkIRect::MakeXYWH(9, 9, 1, 1),  kAll_Tile);
    256         verifyTileHits(reporter, SkIRect::MakeXYWH(10, 10, 1, 1),  kAll_Tile);
    257         verifyTileHits(reporter, SkIRect::MakeXYWH(11, 11, 1, 1),  kBottomRight_Tile);
    258 
    259         // BorderPixels
    260         verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 6, 6),  kTopLeft_Tile, 1);
    261         verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 7, 7),  kAll_Tile, 1);
    262         verifyTileHits(reporter, SkIRect::MakeXYWH(9, 9, 1, 1),  kAll_Tile, 1);
    263         verifyTileHits(reporter, SkIRect::MakeXYWH(10, 10, 1, 1),  kBottomRight_Tile, 1);
    264         verifyTileHits(reporter, SkIRect::MakeXYWH(17, 17, 1, 1),  kBottomRight_Tile, 1);
    265 
    266         // BBoxes that overlap tiles
    267         verifyTileHits(reporter, SkIRect::MakeXYWH(5, 5, 10, 1),  kTopLeft_Tile | kTopRight_Tile);
    268         verifyTileHits(reporter, SkIRect::MakeXYWH(5, 5, 1, 10),  kTopLeft_Tile |
    269                        kBottomLeft_Tile);
    270         verifyTileHits(reporter, SkIRect::MakeXYWH(5, 5, 10, 10),  kAll_Tile);
    271         verifyTileHits(reporter, SkIRect::MakeXYWH(-10, -10, 40, 40),  kAll_Tile);
    272 
    273         TestUnalignedQuery(reporter);
    274         TestOverlapOffsetQueryAlignment(reporter);
    275     }
    276 };
    277 
    278 #include "TestClassDef.h"
    279 DEFINE_TESTCLASS("TileGrid", TileGridTestClass, TileGridTest::Test)
    280