|
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 #ifndef SkTileGrid_DEFINED |
|
10 #define SkTileGrid_DEFINED |
|
11 |
|
12 #include "SkBBoxHierarchy.h" |
|
13 #include "SkPictureStateTree.h" |
|
14 #include "SkTileGridPicture.h" // for TileGridInfo |
|
15 |
|
16 /** |
|
17 * Subclass of SkBBoxHierarchy that stores elements in buckets that correspond |
|
18 * to tile regions, disposed in a regular grid. This is useful when the tile |
|
19 * structure that will be use in search() calls is known prior to insertion. |
|
20 * Calls to search will return in constant time. |
|
21 * |
|
22 * Note: Current implementation of search() only supports looking-up regions |
|
23 * that are an exact match to a single tile. Implementation could be augmented |
|
24 * to support arbitrary rectangles, but performance would be sub-optimal. |
|
25 */ |
|
26 class SkTileGrid : public SkBBoxHierarchy { |
|
27 public: |
|
28 enum { |
|
29 // Number of tiles for which data is allocated on the stack in |
|
30 // SkTileGrid::search. If malloc becomes a bottleneck, we may consider |
|
31 // increasing this number. Typical large web page, say 2k x 16k, would |
|
32 // require 512 tiles of size 256 x 256 pixels. |
|
33 kStackAllocationTileCount = 1024 |
|
34 }; |
|
35 |
|
36 typedef void* (*SkTileGridNextDatumFunctionPtr)(SkTDArray<void*>** tileData, SkAutoSTArray<kStackAllocationTileCount, int>& tileIndices); |
|
37 |
|
38 SkTileGrid(int xTileCount, int yTileCount, const SkTileGridPicture::TileGridInfo& info, |
|
39 SkTileGridNextDatumFunctionPtr nextDatumFunction); |
|
40 |
|
41 virtual ~SkTileGrid(); |
|
42 |
|
43 /** |
|
44 * Insert a data pointer and corresponding bounding box |
|
45 * @param data The data pointer, may be NULL |
|
46 * @param bounds The bounding box, should not be empty |
|
47 * @param defer Ignored, TileArray does not defer insertions |
|
48 */ |
|
49 virtual void insert(void* data, const SkIRect& bounds, bool) SK_OVERRIDE; |
|
50 |
|
51 virtual void flushDeferredInserts() SK_OVERRIDE {}; |
|
52 |
|
53 /** |
|
54 * Populate 'results' with data pointers corresponding to bounding boxes that intersect 'query' |
|
55 * The query argument is expected to be an exact match to a tile of the grid |
|
56 */ |
|
57 virtual void search(const SkIRect& query, SkTDArray<void*>* results) SK_OVERRIDE; |
|
58 |
|
59 virtual void clear() SK_OVERRIDE; |
|
60 |
|
61 /** |
|
62 * Gets the number of insertions |
|
63 */ |
|
64 virtual int getCount() const SK_OVERRIDE; |
|
65 |
|
66 virtual int getDepth() const SK_OVERRIDE { return -1; } |
|
67 |
|
68 virtual void rewindInserts() SK_OVERRIDE; |
|
69 |
|
70 // Used by search() and in SkTileGridHelper implementations |
|
71 enum { |
|
72 kTileFinished = -1, |
|
73 }; |
|
74 |
|
75 int tileCount(int x, int y); // For testing only. |
|
76 |
|
77 private: |
|
78 SkTDArray<void*>& tile(int x, int y); |
|
79 |
|
80 int fXTileCount, fYTileCount, fTileCount; |
|
81 SkTileGridPicture::TileGridInfo fInfo; |
|
82 SkTDArray<void*>* fTileData; |
|
83 int fInsertionCount; |
|
84 SkIRect fGridBounds; |
|
85 SkTileGridNextDatumFunctionPtr fNextDatumFunction; |
|
86 |
|
87 typedef SkBBoxHierarchy INHERITED; |
|
88 }; |
|
89 |
|
90 /** |
|
91 * Generic implementation for SkTileGridNextDatumFunctionPtr. user code may instantiate |
|
92 * this template to get a valid SkTileGridNextDatumFunction implementation |
|
93 * |
|
94 * Returns the next element of tileData[i][tileIndices[i]] for all i and advances |
|
95 * tileIndices[] past them. The order in which data are returned by successive |
|
96 * calls to this method must reflect the order in which the were originally |
|
97 * recorded into the tile grid. |
|
98 * |
|
99 * \param tileData array of pointers to arrays of tile data |
|
100 * \param tileIndices per-tile data indices, indices are incremented for tiles that contain |
|
101 * the next datum. |
|
102 * \tparam T a type to which it is safe to cast a datum and that has an operator < |
|
103 * such that 'a < b' is true if 'a' was inserted into the tile grid before 'b'. |
|
104 */ |
|
105 template <typename T> |
|
106 void* SkTileGridNextDatum(SkTDArray<void*>** tileData, SkAutoSTArray<SkTileGrid::kStackAllocationTileCount, int>& tileIndices) { |
|
107 T* minVal = NULL; |
|
108 int tileCount = tileIndices.count(); |
|
109 int minIndex = tileCount; |
|
110 int maxIndex = 0; |
|
111 // Find the next Datum; track where it's found so we reduce the size of the second loop. |
|
112 for (int tile = 0; tile < tileCount; ++tile) { |
|
113 int pos = tileIndices[tile]; |
|
114 if (pos != SkTileGrid::kTileFinished) { |
|
115 T* candidate = (T*)(*tileData[tile])[pos]; |
|
116 if (NULL == minVal || (*candidate) < (*minVal)) { |
|
117 minVal = candidate; |
|
118 minIndex = tile; |
|
119 maxIndex = tile; |
|
120 } else if (!((*minVal) < (*candidate))) { |
|
121 // We don't require operator==; if !(candidate<minVal) && !(minVal<candidate), |
|
122 // candidate==minVal and we have to add this tile to the range searched. |
|
123 maxIndex = tile; |
|
124 } |
|
125 } |
|
126 } |
|
127 // Increment indices past the next datum |
|
128 if (minVal != NULL) { |
|
129 for (int tile = minIndex; tile <= maxIndex; ++tile) { |
|
130 int pos = tileIndices[tile]; |
|
131 if (pos != SkTileGrid::kTileFinished && (*tileData[tile])[pos] == minVal) { |
|
132 if (++(tileIndices[tile]) >= tileData[tile]->count()) { |
|
133 tileIndices[tile] = SkTileGrid::kTileFinished; |
|
134 } |
|
135 } |
|
136 } |
|
137 return minVal; |
|
138 } |
|
139 return NULL; |
|
140 } |
|
141 |
|
142 #endif |