|
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 |
|
11 SkTileGrid::SkTileGrid(int xTileCount, int yTileCount, const SkTileGridPicture::TileGridInfo& info, |
|
12 SkTileGridNextDatumFunctionPtr nextDatumFunction) |
|
13 { |
|
14 fXTileCount = xTileCount; |
|
15 fYTileCount = yTileCount; |
|
16 fInfo = info; |
|
17 // Margin is offset by 1 as a provision for AA and |
|
18 // to cancel-out the outset applied by getClipDeviceBounds. |
|
19 fInfo.fMargin.fHeight++; |
|
20 fInfo.fMargin.fWidth++; |
|
21 fTileCount = fXTileCount * fYTileCount; |
|
22 fInsertionCount = 0; |
|
23 fGridBounds = SkIRect::MakeXYWH(0, 0, fInfo.fTileInterval.width() * fXTileCount, |
|
24 fInfo.fTileInterval.height() * fYTileCount); |
|
25 fNextDatumFunction = nextDatumFunction; |
|
26 fTileData = SkNEW_ARRAY(SkTDArray<void *>, fTileCount); |
|
27 } |
|
28 |
|
29 SkTileGrid::~SkTileGrid() { |
|
30 SkDELETE_ARRAY(fTileData); |
|
31 } |
|
32 |
|
33 int SkTileGrid::tileCount(int x, int y) { |
|
34 return this->tile(x, y).count(); |
|
35 } |
|
36 |
|
37 SkTDArray<void *>& SkTileGrid::tile(int x, int y) { |
|
38 return fTileData[y * fXTileCount + x]; |
|
39 } |
|
40 |
|
41 void SkTileGrid::insert(void* data, const SkIRect& bounds, bool) { |
|
42 SkASSERT(!bounds.isEmpty()); |
|
43 SkIRect dilatedBounds = bounds; |
|
44 dilatedBounds.outset(fInfo.fMargin.width(), fInfo.fMargin.height()); |
|
45 dilatedBounds.offset(fInfo.fOffset); |
|
46 if (!SkIRect::Intersects(dilatedBounds, fGridBounds)) { |
|
47 return; |
|
48 } |
|
49 |
|
50 // Note: SkIRects are non-inclusive of the right() column and bottom() row, |
|
51 // hence the "-1"s in the computations of maxTileX and maxTileY. |
|
52 int minTileX = SkMax32(SkMin32(dilatedBounds.left() / fInfo.fTileInterval.width(), |
|
53 fXTileCount - 1), 0); |
|
54 int maxTileX = SkMax32(SkMin32((dilatedBounds.right() - 1) / fInfo.fTileInterval.width(), |
|
55 fXTileCount - 1), 0); |
|
56 int minTileY = SkMax32(SkMin32(dilatedBounds.top() / fInfo.fTileInterval.height(), |
|
57 fYTileCount -1), 0); |
|
58 int maxTileY = SkMax32(SkMin32((dilatedBounds.bottom() -1) / fInfo.fTileInterval.height(), |
|
59 fYTileCount -1), 0); |
|
60 |
|
61 for (int x = minTileX; x <= maxTileX; x++) { |
|
62 for (int y = minTileY; y <= maxTileY; y++) { |
|
63 this->tile(x, y).push(data); |
|
64 } |
|
65 } |
|
66 fInsertionCount++; |
|
67 } |
|
68 |
|
69 void SkTileGrid::search(const SkIRect& query, SkTDArray<void*>* results) { |
|
70 SkIRect adjustedQuery = query; |
|
71 // The inset is to counteract the outset that was applied in 'insert' |
|
72 // The outset/inset is to optimize for lookups of size |
|
73 // 'tileInterval + 2 * margin' that are aligned with the tile grid. |
|
74 adjustedQuery.inset(fInfo.fMargin.width(), fInfo.fMargin.height()); |
|
75 adjustedQuery.offset(fInfo.fOffset); |
|
76 adjustedQuery.sort(); // in case the inset inverted the rectangle |
|
77 // Convert the query rectangle from device coordinates to tile coordinates |
|
78 // by rounding outwards to the nearest tile boundary so that the resulting tile |
|
79 // region includes the query rectangle. (using truncating division to "floor") |
|
80 int tileStartX = adjustedQuery.left() / fInfo.fTileInterval.width(); |
|
81 int tileEndX = (adjustedQuery.right() + fInfo.fTileInterval.width() - 1) / |
|
82 fInfo.fTileInterval.width(); |
|
83 int tileStartY = adjustedQuery.top() / fInfo.fTileInterval.height(); |
|
84 int tileEndY = (adjustedQuery.bottom() + fInfo.fTileInterval.height() - 1) / |
|
85 fInfo.fTileInterval.height(); |
|
86 |
|
87 tileStartX = SkPin32(tileStartX, 0, fXTileCount - 1); |
|
88 tileEndX = SkPin32(tileEndX, tileStartX+1, fXTileCount); |
|
89 tileStartY = SkPin32(tileStartY, 0, fYTileCount - 1); |
|
90 tileEndY = SkPin32(tileEndY, tileStartY+1, fYTileCount); |
|
91 |
|
92 int queryTileCount = (tileEndX - tileStartX) * (tileEndY - tileStartY); |
|
93 SkASSERT(queryTileCount); |
|
94 if (queryTileCount == 1) { |
|
95 *results = this->tile(tileStartX, tileStartY); |
|
96 } else { |
|
97 results->reset(); |
|
98 SkAutoSTArray<kStackAllocationTileCount, int> curPositions(queryTileCount); |
|
99 SkAutoSTArray<kStackAllocationTileCount, SkTDArray<void *>*> storage(queryTileCount); |
|
100 SkTDArray<void *>** tileRange = storage.get(); |
|
101 int tile = 0; |
|
102 for (int x = tileStartX; x < tileEndX; ++x) { |
|
103 for (int y = tileStartY; y < tileEndY; ++y) { |
|
104 tileRange[tile] = &this->tile(x, y); |
|
105 curPositions[tile] = tileRange[tile]->count() ? 0 : kTileFinished; |
|
106 ++tile; |
|
107 } |
|
108 } |
|
109 void *nextElement; |
|
110 while(NULL != (nextElement = fNextDatumFunction(tileRange, curPositions))) { |
|
111 results->push(nextElement); |
|
112 } |
|
113 } |
|
114 } |
|
115 |
|
116 void SkTileGrid::clear() { |
|
117 for (int i = 0; i < fTileCount; i++) { |
|
118 fTileData[i].reset(); |
|
119 } |
|
120 } |
|
121 |
|
122 int SkTileGrid::getCount() const { |
|
123 return fInsertionCount; |
|
124 } |
|
125 |
|
126 void SkTileGrid::rewindInserts() { |
|
127 SkASSERT(fClient); |
|
128 for (int i = 0; i < fTileCount; ++i) { |
|
129 while (!fTileData[i].isEmpty() && fClient->shouldRewind(fTileData[i].top())) { |
|
130 fTileData[i].pop(); |
|
131 } |
|
132 } |
|
133 } |