OLD | NEW |
| (Empty) |
1 | |
2 /* | |
3 * Copyright 2011 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 #include "SkRegion.h" | |
9 #include "SkChunkAlloc.h" | |
10 #include "SkTDArray.h" | |
11 #include "SkTemplates.h" | |
12 | |
13 #if 0 | |
14 | |
15 struct VEdge { | |
16 VEdge* fPrev; | |
17 VEdge* fNext; | |
18 | |
19 SkRegion::RunType fX; | |
20 SkRegion::RunType fTop; | |
21 SkRegion::RunType fBottom; | |
22 int fWinding; | |
23 | |
24 void removeFromList() { | |
25 fPrev->fNext = fNext; | |
26 fNext->fPrev = fPrev; | |
27 } | |
28 | |
29 void backwardsInsert() { | |
30 while (fPrev->fX > fX) { | |
31 VEdge* prev = fPrev; | |
32 VEdge* next = this; | |
33 | |
34 // remove prev from the list | |
35 prev->fPrev->fNext = next; | |
36 next->fPrev = prev->fPrev; | |
37 | |
38 // insert prev after next | |
39 prev->fNext = next->fNext; | |
40 next->fNext->fPrev = prev; | |
41 next->fNext = prev; | |
42 prev->fPrev = next; | |
43 } | |
44 } | |
45 | |
46 static void SetFromRect(VEdge edges[], const SkIRect& r) { | |
47 edges[0].fX = r.fLeft; | |
48 edges[0].fTop = r.fTop; | |
49 edges[0].fBottom = r.fBottom; | |
50 edges[0].fWinding = -1; | |
51 | |
52 edges[1].fX = r.fRight; | |
53 edges[1].fTop = r.fTop; | |
54 edges[1].fBottom = r.fBottom; | |
55 edges[1].fWinding = 1; | |
56 } | |
57 }; | |
58 | |
59 class Accumulator { | |
60 public: | |
61 Accumulator(SkRegion::RunType top, int numRects); | |
62 ~Accumulator() {} | |
63 | |
64 SkRegion::RunType append(SkRegion::RunType top, const VEdge* edge); | |
65 | |
66 int count() const { return fTotalCount; } | |
67 void copyTo(SkRegion::RunType dst[]); | |
68 | |
69 private: | |
70 struct Row { | |
71 SkRegion::RunType* fPtr; | |
72 SkRegion::RunType fBottom; | |
73 int fCount; // just [L R] count | |
74 }; | |
75 SkChunkAlloc fAlloc; | |
76 SkTDArray<Row> fRows; | |
77 SkRegion::RunType fTop; | |
78 int fTotalCount; | |
79 int fRectCount; | |
80 }; | |
81 | |
82 Accumulator::Accumulator(SkRegion::RunType top, int numRects) | |
83 : fAlloc((1 + numRects * 2 + 1) * sizeof(int32_t)) { | |
84 fRectCount = numRects; | |
85 fTop = top; | |
86 fTotalCount = 2; // Top + final sentinel | |
87 } | |
88 | |
89 //#define TRACE_ROW(code) code | |
90 #define TRACE_ROW(code) | |
91 | |
92 SkRegion::RunType Accumulator::append(SkRegion::RunType currY, const VEdge* edge
) { | |
93 // worst-case size | |
94 size_t size = fRectCount * 2 * sizeof(SkRegion::RunType); | |
95 SkRegion::RunType* row = (SkRegion::RunType*)fAlloc.allocThrow(size); | |
96 SkRegion::RunType* rowHead = row; | |
97 | |
98 SkRegion::RunType nextY = SkRegion::kRunTypeSentinel; | |
99 int winding = edge->fWinding; | |
100 | |
101 // record the L R values for this row | |
102 | |
103 if (edge->fTop > currY) { | |
104 nextY = SkMin32(nextY, edge->fTop); | |
105 TRACE_ROW(SkDebugf("Y %d\n", currY);) | |
106 } else { | |
107 SkRegion::RunType currR; | |
108 *row++ = edge->fX; | |
109 TRACE_ROW(SkDebugf("Y %d [%d", currY, edge->fX);) | |
110 edge = edge->fNext; | |
111 for (;;) { | |
112 if (edge->fTop > currY) { | |
113 nextY = SkMin32(nextY, edge->fTop); | |
114 break; | |
115 } | |
116 | |
117 int prevWinding = winding; | |
118 winding += edge->fWinding; | |
119 if (0 == winding) { // we finished an interval | |
120 currR = edge->fX; | |
121 } else if (0 == prevWinding && edge->fX > currR) { | |
122 *row++ = currR; | |
123 *row++ = edge->fX; | |
124 TRACE_ROW(SkDebugf(" %d] [%d", currR, edge->fX);) | |
125 } | |
126 | |
127 nextY = SkMin32(nextY, edge->fBottom); | |
128 edge = edge->fNext; | |
129 } | |
130 SkASSERT(0 == winding); | |
131 *row++ = currR; | |
132 TRACE_ROW(SkDebugf(" %d]\n", currR);) | |
133 } | |
134 int rowCount = row - rowHead; | |
135 | |
136 // now see if we have already seen this row, or if its unique | |
137 | |
138 Row* r = fRows.count() ? &fRows[fRows.count() - 1] : NULL; | |
139 if (r && (r->fCount == rowCount) && | |
140 !memcmp(r->fPtr, rowHead, | |
141 rowCount * sizeof(SkRegion::RunType))) { | |
142 r->fBottom = nextY; // update bottom | |
143 fAlloc.unalloc(rowHead); | |
144 } else { | |
145 Row* r = fRows.append(); | |
146 r->fPtr = rowHead; | |
147 r->fBottom = nextY; | |
148 r->fCount = rowCount; | |
149 fTotalCount += 1 + rowCount + 1; | |
150 } | |
151 | |
152 return nextY; | |
153 } | |
154 | |
155 void Accumulator::copyTo(SkRegion::RunType dst[]) { | |
156 SkDEBUGCODE(SkRegion::RunType* startDst = dst;) | |
157 | |
158 *dst++ = fTop; | |
159 | |
160 const Row* curr = fRows.begin(); | |
161 const Row* stop = fRows.end(); | |
162 while (curr < stop) { | |
163 *dst++ = curr->fBottom; | |
164 memcpy(dst, curr->fPtr, curr->fCount * sizeof(SkRegion::RunType)); | |
165 dst += curr->fCount; | |
166 *dst++ = SkRegion::kRunTypeSentinel; | |
167 curr += 1; | |
168 } | |
169 *dst++ = SkRegion::kRunTypeSentinel; | |
170 SkASSERT(dst - startDst == fTotalCount); | |
171 } | |
172 | |
173 /////////////////////////////////////////////////////////////////////////////// | |
174 | |
175 template <typename T> int SkTCmp2Int(const T& a, const T& b) { | |
176 return (a < b) ? -1 : ((b < a) ? 1 : 0); | |
177 } | |
178 | |
179 static inline int SkCmp32(int32_t a, int32_t b) { | |
180 return (a < b) ? -1 : ((b < a) ? 1 : 0); | |
181 } | |
182 | |
183 static int compare_edgeptr(const void* p0, const void* p1) { | |
184 const VEdge* e0 = *static_cast<VEdge*const*>(p0); | |
185 const VEdge* e1 = *static_cast<VEdge*const*>(p1); | |
186 | |
187 SkRegion::RunType v0 = e0->fTop; | |
188 SkRegion::RunType v1 = e1->fTop; | |
189 | |
190 if (v0 == v1) { | |
191 v0 = e0->fX; | |
192 v1 = e1->fX; | |
193 } | |
194 return SkCmp32(v0, v1); | |
195 } | |
196 | |
197 // fillout edge[] from rects[], sorted. Return the head, and set the tail | |
198 // | |
199 static VEdge* sort_edges(VEdge** edgePtr, VEdge edge[], const SkIRect rects[], | |
200 int rectCount, VEdge** edgeTail) { | |
201 int i; | |
202 VEdge** ptr = edgePtr; | |
203 for (int i = 0; i < rectCount; i++) { | |
204 if (!rects[i].isEmpty()) { | |
205 VEdge::SetFromRect(edge, rects[i]); | |
206 *ptr++ = edge++; | |
207 *ptr++ = edge++; | |
208 } | |
209 } | |
210 | |
211 int edgeCount = ptr - edgePtr; | |
212 if (0 == edgeCount) { | |
213 // all the rects[] were empty | |
214 return NULL; | |
215 } | |
216 | |
217 qsort(edgePtr, edgeCount, sizeof(*edgePtr), compare_edgeptr); | |
218 for (i = 1; i < edgeCount; i++) { | |
219 edgePtr[i - 1]->fNext = edgePtr[i]; | |
220 edgePtr[i]->fPrev = edgePtr[i - 1]; | |
221 } | |
222 *edgeTail = edgePtr[edgeCount - 1]; | |
223 return edgePtr[0]; | |
224 } | |
225 | |
226 bool SkRegion::setRects(const SkIRect rects[], int rectCount) { | |
227 if (0 == rectCount) { | |
228 return this->setEmpty(); | |
229 } | |
230 if (1 == rectCount) { | |
231 return this->setRect(rects[0]); | |
232 } | |
233 | |
234 int edgeCount = rectCount * 2; | |
235 SkAutoMalloc memory((sizeof(VEdge) + sizeof(VEdge*)) * edgeCount); | |
236 VEdge** edgePtr = (VEdge**)memory.get(); | |
237 VEdge* tail, *head = (VEdge*)(edgePtr + edgeCount); | |
238 head = sort_edges(edgePtr, head, rects, rectCount, &tail); | |
239 // check if we have no edges | |
240 if (NULL == head) { | |
241 return this->setEmpty(); | |
242 } | |
243 | |
244 // at this stage, we don't really care about edgeCount, or if rectCount is | |
245 // larger that it should be (since sort_edges might have skipped some | |
246 // empty rects[]). rectCount now is just used for worst-case allocations | |
247 | |
248 VEdge headEdge, tailEdge; | |
249 headEdge.fPrev = NULL; | |
250 headEdge.fNext = head; | |
251 headEdge.fTop = SK_MinS32; | |
252 headEdge.fX = SK_MinS32; | |
253 head->fPrev = &headEdge; | |
254 | |
255 tailEdge.fPrev = tail; | |
256 tailEdge.fNext = NULL; | |
257 tailEdge.fTop = SK_MaxS32; | |
258 tail->fNext = &tailEdge; | |
259 | |
260 int32_t currY = head->fTop; | |
261 Accumulator accum(currY, rectCount); | |
262 | |
263 while (head->fNext) { | |
264 VEdge* edge = head; | |
265 // accumulate the current | |
266 SkRegion::RunType nextY = accum.append(currY, edge); | |
267 // remove the old | |
268 while (edge->fTop <= currY) { | |
269 VEdge* next = edge->fNext; | |
270 if (edge->fBottom <= nextY) { | |
271 edge->removeFromList(); | |
272 } | |
273 edge = next; | |
274 } | |
275 // insert (sorted) the new | |
276 while (edge->fTop == nextY) { | |
277 VEdge* next = edge->fNext; | |
278 edge->backwardsInsert(); | |
279 edge = next; | |
280 } | |
281 currY = nextY; | |
282 head = headEdge.fNext; | |
283 } | |
284 | |
285 SkAutoTArray<RunType> runs(accum.count()); | |
286 accum.copyTo(runs.get()); | |
287 return this->setRuns(runs.get(), accum.count()); | |
288 } | |
289 | |
290 #endif | |
OLD | NEW |