michael@0: michael@0: /* michael@0: * Copyright 2012 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #ifndef SkTileGrid_DEFINED michael@0: #define SkTileGrid_DEFINED michael@0: michael@0: #include "SkBBoxHierarchy.h" michael@0: #include "SkPictureStateTree.h" michael@0: #include "SkTileGridPicture.h" // for TileGridInfo michael@0: michael@0: /** michael@0: * Subclass of SkBBoxHierarchy that stores elements in buckets that correspond michael@0: * to tile regions, disposed in a regular grid. This is useful when the tile michael@0: * structure that will be use in search() calls is known prior to insertion. michael@0: * Calls to search will return in constant time. michael@0: * michael@0: * Note: Current implementation of search() only supports looking-up regions michael@0: * that are an exact match to a single tile. Implementation could be augmented michael@0: * to support arbitrary rectangles, but performance would be sub-optimal. michael@0: */ michael@0: class SkTileGrid : public SkBBoxHierarchy { michael@0: public: michael@0: enum { michael@0: // Number of tiles for which data is allocated on the stack in michael@0: // SkTileGrid::search. If malloc becomes a bottleneck, we may consider michael@0: // increasing this number. Typical large web page, say 2k x 16k, would michael@0: // require 512 tiles of size 256 x 256 pixels. michael@0: kStackAllocationTileCount = 1024 michael@0: }; michael@0: michael@0: typedef void* (*SkTileGridNextDatumFunctionPtr)(SkTDArray** tileData, SkAutoSTArray& tileIndices); michael@0: michael@0: SkTileGrid(int xTileCount, int yTileCount, const SkTileGridPicture::TileGridInfo& info, michael@0: SkTileGridNextDatumFunctionPtr nextDatumFunction); michael@0: michael@0: virtual ~SkTileGrid(); michael@0: michael@0: /** michael@0: * Insert a data pointer and corresponding bounding box michael@0: * @param data The data pointer, may be NULL michael@0: * @param bounds The bounding box, should not be empty michael@0: * @param defer Ignored, TileArray does not defer insertions michael@0: */ michael@0: virtual void insert(void* data, const SkIRect& bounds, bool) SK_OVERRIDE; michael@0: michael@0: virtual void flushDeferredInserts() SK_OVERRIDE {}; michael@0: michael@0: /** michael@0: * Populate 'results' with data pointers corresponding to bounding boxes that intersect 'query' michael@0: * The query argument is expected to be an exact match to a tile of the grid michael@0: */ michael@0: virtual void search(const SkIRect& query, SkTDArray* results) SK_OVERRIDE; michael@0: michael@0: virtual void clear() SK_OVERRIDE; michael@0: michael@0: /** michael@0: * Gets the number of insertions michael@0: */ michael@0: virtual int getCount() const SK_OVERRIDE; michael@0: michael@0: virtual int getDepth() const SK_OVERRIDE { return -1; } michael@0: michael@0: virtual void rewindInserts() SK_OVERRIDE; michael@0: michael@0: // Used by search() and in SkTileGridHelper implementations michael@0: enum { michael@0: kTileFinished = -1, michael@0: }; michael@0: michael@0: int tileCount(int x, int y); // For testing only. michael@0: michael@0: private: michael@0: SkTDArray& tile(int x, int y); michael@0: michael@0: int fXTileCount, fYTileCount, fTileCount; michael@0: SkTileGridPicture::TileGridInfo fInfo; michael@0: SkTDArray* fTileData; michael@0: int fInsertionCount; michael@0: SkIRect fGridBounds; michael@0: SkTileGridNextDatumFunctionPtr fNextDatumFunction; michael@0: michael@0: typedef SkBBoxHierarchy INHERITED; michael@0: }; michael@0: michael@0: /** michael@0: * Generic implementation for SkTileGridNextDatumFunctionPtr. user code may instantiate michael@0: * this template to get a valid SkTileGridNextDatumFunction implementation michael@0: * michael@0: * Returns the next element of tileData[i][tileIndices[i]] for all i and advances michael@0: * tileIndices[] past them. The order in which data are returned by successive michael@0: * calls to this method must reflect the order in which the were originally michael@0: * recorded into the tile grid. michael@0: * michael@0: * \param tileData array of pointers to arrays of tile data michael@0: * \param tileIndices per-tile data indices, indices are incremented for tiles that contain michael@0: * the next datum. michael@0: * \tparam T a type to which it is safe to cast a datum and that has an operator < michael@0: * such that 'a < b' is true if 'a' was inserted into the tile grid before 'b'. michael@0: */ michael@0: template michael@0: void* SkTileGridNextDatum(SkTDArray** tileData, SkAutoSTArray& tileIndices) { michael@0: T* minVal = NULL; michael@0: int tileCount = tileIndices.count(); michael@0: int minIndex = tileCount; michael@0: int maxIndex = 0; michael@0: // Find the next Datum; track where it's found so we reduce the size of the second loop. michael@0: for (int tile = 0; tile < tileCount; ++tile) { michael@0: int pos = tileIndices[tile]; michael@0: if (pos != SkTileGrid::kTileFinished) { michael@0: T* candidate = (T*)(*tileData[tile])[pos]; michael@0: if (NULL == minVal || (*candidate) < (*minVal)) { michael@0: minVal = candidate; michael@0: minIndex = tile; michael@0: maxIndex = tile; michael@0: } else if (!((*minVal) < (*candidate))) { michael@0: // We don't require operator==; if !(candidate= tileData[tile]->count()) { michael@0: tileIndices[tile] = SkTileGrid::kTileFinished; michael@0: } michael@0: } michael@0: } michael@0: return minVal; michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: #endif