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