blob: 2b885c9f1fc48d60fc8cc431d0653853d81d069b [file] [log] [blame]
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkTileGrid.h"
SkTileGrid::SkTileGrid(int tileWidth, int tileHeight, int xTileCount, int yTileCount, SkTileGridNextDatumFunctionPtr nextDatumFunction)
{
fTileWidth = tileWidth;
fTileHeight = tileHeight;
fXTileCount = xTileCount;
fYTileCount = yTileCount;
fTileCount = fXTileCount * fYTileCount;
fInsertionCount = 0;
fGridBounds = SkIRect::MakeXYWH(0, 0, fTileWidth * fXTileCount, fTileHeight * fYTileCount);
fNextDatumFunction = nextDatumFunction;
fTileData = SkNEW_ARRAY(SkTDArray<void *>, fTileCount);
}
SkTileGrid::~SkTileGrid() {
SkDELETE_ARRAY(fTileData);
}
SkTDArray<void *>& SkTileGrid::tile(int x, int y) {
return fTileData[y * fXTileCount + x];
}
void SkTileGrid::insert(void* data, const SkIRect& bounds, bool) {
SkASSERT(!bounds.isEmpty());
SkIRect dilatedBounds = bounds;
dilatedBounds.outset(1,1); // Consideration for filtering and AA
if (!SkIRect::Intersects(dilatedBounds, fGridBounds)) {
return;
}
int minTileX = SkMax32(SkMin32(dilatedBounds.left() / fTileWidth, fXTileCount - 1), 0);
int maxTileX = SkMax32(SkMin32(dilatedBounds.right() / fTileWidth, fXTileCount - 1), 0);
int minTileY = SkMax32(SkMin32(dilatedBounds.top() / fTileHeight, fYTileCount -1), 0);
int maxTileY = SkMax32(SkMin32(dilatedBounds.bottom() / fTileHeight, fYTileCount -1), 0);
for (int x = minTileX; x <= maxTileX; x++) {
for (int y = minTileY; y <= maxTileY; y++) {
this->tile(x, y).push(data);
}
}
fInsertionCount++;
}
void SkTileGrid::search(const SkIRect& query, SkTDArray<void*>* results) {
// The +1/-1 is to compensate for the outset in applied SkCanvas::getClipBounds
int tileStartX = (query.left() + 1) / fTileWidth;
int tileEndX = (query.right() + fTileWidth - 1) / fTileWidth;
int tileStartY = (query.top() + 1) / fTileHeight;
int tileEndY = (query.bottom() + fTileHeight - 1) / fTileHeight;
if (tileStartX >= fXTileCount || tileStartY >= fYTileCount || tileEndX <= 0 || tileEndY <= 0) {
return; // query does not intersect the grid
}
// clamp to grid
if (tileStartX < 0) tileStartX = 0;
if (tileStartY < 0) tileStartY = 0;
if (tileEndX > fXTileCount) tileEndX = fXTileCount;
if (tileEndY > fYTileCount) tileEndY = fYTileCount;
int queryTileCount = (tileEndX - tileStartX) * (tileEndY - tileStartY);
if (queryTileCount == 1) {
*results = this->tile(tileStartX, tileStartY);
} else {
results->reset();
SkTDArray<int> curPositions;
curPositions.setCount(queryTileCount);
// Note: Reserving space for 1024 tile pointers on the stack. If the
// malloc becomes a bottleneck, we may consider increasing that number.
// Typical large web page, say 2k x 16k, would require 512 tiles of
// size 256 x 256 pixels.
SkAutoSTArray<1024, SkTDArray<void *>*> storage(queryTileCount);
SkTDArray<void *>** tileRange = storage.get();
int tile = 0;
for (int x = tileStartX; x < tileEndX; ++x) {
for (int y = tileStartY; y < tileEndY; ++y) {
tileRange[tile] = &this->tile(x, y);
curPositions[tile] = tileRange[tile]->count() ? 0 : kTileFinished;
++tile;
}
}
void *nextElement;
while(NULL != (nextElement = fNextDatumFunction(tileRange, curPositions))) {
results->push(nextElement);
}
}
}
void SkTileGrid::clear() {
for (int i = 0; i < fTileCount; i++) {
fTileData[i].reset();
}
}
int SkTileGrid::getCount() const {
return fInsertionCount;
}