• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
291