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