Change SkTileGride geometry calculations to match the Chromium compositor.

This patch changes the semantics of tileWidth/Height to include the border region, and
uses an offset to take into account the fact that there is no outer border for outer
tiles. This patch also fixes a previous bug where the right column and bottom row were
considered to be included in bounds that are expressed as an SkIRect.

Companion Chromium CL required for roll: https://codereview.chromium.org/12221077/

TEST=TileGrid unit test
Review URL: https://codereview.appspot.com/7350050

git-svn-id: http://skia.googlecode.com/svn/trunk@7885 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tests/TileGridTest.cpp b/tests/TileGridTest.cpp
index a72fd69..8ff629c 100644
--- a/tests/TileGridTest.cpp
+++ b/tests/TileGridTest.cpp
@@ -41,7 +41,11 @@
 public:
     static void verifyTileHits(skiatest::Reporter* reporter, SkIRect rect, uint32_t tileMask,
                                int borderPixels = 0) {
-        SkTileGrid grid(10, 10, 2, 2, borderPixels, NULL);
+        SkTileGridPicture::TileGridInfo info;
+        info.fMargin.set(borderPixels, borderPixels);
+        info.fOffset.setZero();
+        info.fTileInterval.set(10 - 2 * borderPixels, 10 - 2 * borderPixels);
+        SkTileGrid grid(2, 2, info, NULL);
         grid.insert(NULL, rect, false);
         REPORTER_ASSERT(reporter, grid.tile(0,0).count() ==
             ((tileMask & kTopLeft_Tile)? 1 : 0));
@@ -55,7 +59,11 @@
 
     static void TestUnalignedQuery(skiatest::Reporter* reporter) {
         // Use SkTileGridPicture to generate a SkTileGrid with a helper
-        SkTileGridPicture picture(10, 10, 20, 20);
+        SkTileGridPicture::TileGridInfo info;
+        info.fMargin.setEmpty();
+        info.fOffset.setZero();
+        info.fTileInterval.set(10, 10);
+        SkTileGridPicture picture(20, 20, info);
         SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
             SkIntToScalar(8), SkIntToScalar(8));
         SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(11), SkIntToScalar(11),
@@ -107,6 +115,86 @@
         }
     }
 
+    static void TestOverlapOffsetQueryAlignment(skiatest::Reporter* reporter) {
+        // Use SkTileGridPicture to generate a SkTileGrid with a helper
+        SkTileGridPicture::TileGridInfo info;
+        info.fMargin.set(1, 1);
+        info.fOffset.set(-1, -1);
+        info.fTileInterval.set(8, 8);
+        SkTileGridPicture picture(20, 20, info);
+
+        // rect landing entirely in top left tile
+        SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
+            SkIntToScalar(1), SkIntToScalar(1));
+        // rect landing entirely in center tile
+        SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(12), SkIntToScalar(12),
+            SkIntToScalar(1), SkIntToScalar(1));
+                // rect landing entirely in bottomright tile
+        SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(19), SkIntToScalar(19),
+            SkIntToScalar(1), SkIntToScalar(1));
+        SkCanvas* canvas = picture.beginRecording(20, 20, SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
+        SkPaint paint;
+        canvas->drawRect(rect1, paint);
+        canvas->drawRect(rect2, paint);
+        canvas->drawRect(rect3, paint);
+        picture.endRecording();
+
+        SkBitmap tileBitmap;
+        tileBitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
+        tileBitmap.allocPixels();
+        SkBitmap moreThanATileBitmap;
+        moreThanATileBitmap.setConfig(SkBitmap::kARGB_8888_Config, 11, 11);
+        moreThanATileBitmap.allocPixels();
+        // Test parts of top-left tile
+        {
+            // The offset should cancel the top and left borders of the top left tile
+            // So a look-up at interval 0-10 should be grid aligned,
+            SkDevice device(tileBitmap);
+            MockCanvas mockCanvas(&device);
+            picture.draw(&mockCanvas);
+            REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
+            REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
+        }
+        {
+            // Encroaching border by one pixel
+            SkDevice device(moreThanATileBitmap);
+            MockCanvas mockCanvas(&device);
+            picture.draw(&mockCanvas);
+            REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
+            REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
+            REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[1]);
+        }
+        {
+            // Tile stride is 8 (tileWidth - 2 * border pixels
+            // so translating by 8, should make query grid-aligned
+            // with middle tile.
+            SkDevice device(tileBitmap);
+            MockCanvas mockCanvas(&device);
+            mockCanvas.translate(SkIntToScalar(-8), SkIntToScalar(-8));
+            picture.draw(&mockCanvas);
+            REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
+            REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
+        }
+        {
+            SkDevice device(tileBitmap);
+            MockCanvas mockCanvas(&device);
+            mockCanvas.translate(SkFloatToScalar(-7.9f), SkFloatToScalar(-7.9f));
+            picture.draw(&mockCanvas);
+            REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
+            REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
+            REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[1]);
+        }
+        {
+            SkDevice device(tileBitmap);
+            MockCanvas mockCanvas(&device);
+            mockCanvas.translate(SkFloatToScalar(-8.1f), SkFloatToScalar(-8.1f));
+            picture.draw(&mockCanvas);
+            REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
+            REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
+            REPORTER_ASSERT(reporter, rect3 == mockCanvas.fRects[1]);
+        }
+    }
+
     static void Test(skiatest::Reporter* reporter) {
         // Out of bounds
         verifyTileHits(reporter, SkIRect::MakeXYWH(30, 0, 1, 1),  0);
@@ -115,16 +203,19 @@
         verifyTileHits(reporter, SkIRect::MakeXYWH(0, -10, 1, 1),  0);
 
         // Dilation for AA consideration
-        verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 8, 8),  kTopLeft_Tile);
-        verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 9, 9),  kAll_Tile);
+        verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 9, 9),  kTopLeft_Tile);
+        verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 10, 10),  kAll_Tile);
+        verifyTileHits(reporter, SkIRect::MakeXYWH(9, 9, 1, 1),  kAll_Tile);
         verifyTileHits(reporter, SkIRect::MakeXYWH(10, 10, 1, 1),  kAll_Tile);
         verifyTileHits(reporter, SkIRect::MakeXYWH(11, 11, 1, 1),  kBottomRight_Tile);
-
+        
         // BorderPixels
-        verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 7, 7),  kTopLeft_Tile, 1);
-        verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 8, 8),  kAll_Tile, 1);
-        verifyTileHits(reporter, SkIRect::MakeXYWH(11, 11, 1, 1),  kAll_Tile, 1);
-        verifyTileHits(reporter, SkIRect::MakeXYWH(12, 12, 1, 1),  kBottomRight_Tile, 1);
+        verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 6, 6),  kTopLeft_Tile, 1);
+        verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 7, 7),  kAll_Tile, 1);
+        verifyTileHits(reporter, SkIRect::MakeXYWH(9, 9, 1, 1),  kAll_Tile, 1);
+        verifyTileHits(reporter, SkIRect::MakeXYWH(10, 10, 1, 1),  kBottomRight_Tile, 1);
+        verifyTileHits(reporter, SkIRect::MakeXYWH(17, 17, 1, 1),  kBottomRight_Tile, 1);
+        verifyTileHits(reporter, SkIRect::MakeXYWH(18, 18, 1, 1),  0, 1);
 
         // BBoxes that overlap tiles
         verifyTileHits(reporter, SkIRect::MakeXYWH(5, 5, 10, 1),  kTopLeft_Tile | kTopRight_Tile);
@@ -134,6 +225,7 @@
         verifyTileHits(reporter, SkIRect::MakeXYWH(-10, -10, 40, 40),  kAll_Tile);
 
         TestUnalignedQuery(reporter);
+        TestOverlapOffsetQueryAlignment(reporter);
     }
 };