SkTileGrid.cpp revision f507c410e3a2a7ef7dab84152d836da5e5a8a5e9
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 "SkTileGrid.h" 10 11SkTileGrid::SkTileGrid(int tileWidth, int tileHeight, int xTileCount, int yTileCount, 12 int borderPixels, SkTileGridNextDatumFunctionPtr nextDatumFunction) 13{ 14 fTileWidth = tileWidth; 15 fTileHeight = tileHeight; 16 fXTileCount = xTileCount; 17 fYTileCount = yTileCount; 18 // Border padding is offset by 1 as a provision for AA and 19 // to cancel-out the outset applied by getClipDeviceBounds. 20 fBorderPixels = borderPixels + 1; 21 fTileCount = fXTileCount * fYTileCount; 22 fInsertionCount = 0; 23 fGridBounds = SkIRect::MakeXYWH(0, 0, fTileWidth * fXTileCount, fTileHeight * fYTileCount); 24 fNextDatumFunction = nextDatumFunction; 25 fTileData = SkNEW_ARRAY(SkTDArray<void *>, fTileCount); 26} 27 28SkTileGrid::~SkTileGrid() { 29 SkDELETE_ARRAY(fTileData); 30} 31 32SkTDArray<void *>& SkTileGrid::tile(int x, int y) { 33 return fTileData[y * fXTileCount + x]; 34} 35 36void SkTileGrid::insert(void* data, const SkIRect& bounds, bool) { 37 SkASSERT(!bounds.isEmpty()); 38 SkIRect dilatedBounds = bounds; 39 dilatedBounds.outset(fBorderPixels, fBorderPixels); 40 41 if (!SkIRect::Intersects(dilatedBounds, fGridBounds)) { 42 return; 43 } 44 45 int minTileX = SkMax32(SkMin32(dilatedBounds.left() / fTileWidth, fXTileCount - 1), 0); 46 int maxTileX = SkMax32(SkMin32(dilatedBounds.right() / fTileWidth, fXTileCount - 1), 0); 47 int minTileY = SkMax32(SkMin32(dilatedBounds.top() / fTileHeight, fYTileCount -1), 0); 48 int maxTileY = SkMax32(SkMin32(dilatedBounds.bottom() / fTileHeight, fYTileCount -1), 0); 49 50 for (int x = minTileX; x <= maxTileX; x++) { 51 for (int y = minTileY; y <= maxTileY; y++) { 52 this->tile(x, y).push(data); 53 } 54 } 55 fInsertionCount++; 56} 57 58void SkTileGrid::search(const SkIRect& query, SkTDArray<void*>* results) { 59 int tileStartX = (query.left() + fBorderPixels) / fTileWidth; 60 int tileEndX = (query.right() + fTileWidth - fBorderPixels) / fTileWidth; 61 int tileStartY = (query.top() + fBorderPixels) / fTileHeight; 62 int tileEndY = (query.bottom() + fTileHeight - fBorderPixels) / fTileHeight; 63 if (tileStartX >= fXTileCount || tileStartY >= fYTileCount || tileEndX <= 0 || tileEndY <= 0) { 64 return; // query does not intersect the grid 65 } 66 // clamp to grid 67 if (tileStartX < 0) tileStartX = 0; 68 if (tileStartY < 0) tileStartY = 0; 69 if (tileEndX > fXTileCount) tileEndX = fXTileCount; 70 if (tileEndY > fYTileCount) tileEndY = fYTileCount; 71 72 int queryTileCount = (tileEndX - tileStartX) * (tileEndY - tileStartY); 73 if (queryTileCount == 1) { 74 *results = this->tile(tileStartX, tileStartY); 75 } else { 76 results->reset(); 77 SkTDArray<int> curPositions; 78 curPositions.setCount(queryTileCount); 79 // Note: Reserving space for 1024 tile pointers on the stack. If the 80 // malloc becomes a bottleneck, we may consider increasing that number. 81 // Typical large web page, say 2k x 16k, would require 512 tiles of 82 // size 256 x 256 pixels. 83 SkAutoSTArray<1024, SkTDArray<void *>*> storage(queryTileCount); 84 SkTDArray<void *>** tileRange = storage.get(); 85 int tile = 0; 86 for (int x = tileStartX; x < tileEndX; ++x) { 87 for (int y = tileStartY; y < tileEndY; ++y) { 88 tileRange[tile] = &this->tile(x, y); 89 curPositions[tile] = tileRange[tile]->count() ? 0 : kTileFinished; 90 ++tile; 91 } 92 } 93 void *nextElement; 94 while(NULL != (nextElement = fNextDatumFunction(tileRange, curPositions))) { 95 results->push(nextElement); 96 } 97 } 98} 99 100void SkTileGrid::clear() { 101 for (int i = 0; i < fTileCount; i++) { 102 fTileData[i].reset(); 103 } 104} 105 106int SkTileGrid::getCount() const { 107 return fInsertionCount; 108} 109