OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 #include "SkAddIntersections.h" | 7 #include "SkAddIntersections.h" |
8 #include "SkOpEdgeBuilder.h" | 8 #include "SkOpEdgeBuilder.h" |
9 #include "SkPathOpsCommon.h" | 9 #include "SkPathOpsCommon.h" |
10 #include "SkPathWriter.h" | 10 #include "SkPathWriter.h" |
11 | 11 |
12 // FIXME: this and find chase should be merge together, along with | 12 static SkOpSegment* findChaseOp(SkTDArray<SkOpSpan*>& chase, int* tIndex, int* e
ndIndex) { |
13 // other code that walks winding in angles | |
14 // OPTIMIZATION: Probably, the walked winding should be rolled into the angle st
ructure | |
15 // so it isn't duplicated by walkers like this one | |
16 static SkOpSegment* findChaseOp(SkTDArray<SkOpSpan*>& chase, int& nextStart, int
& nextEnd) { | |
17 while (chase.count()) { | 13 while (chase.count()) { |
18 SkOpSpan* span; | 14 SkOpSpan* span; |
19 chase.pop(&span); | 15 chase.pop(&span); |
20 const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex); | 16 const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex); |
21 SkOpSegment* segment = backPtr.fOther; | 17 SkOpSegment* segment = backPtr.fOther; |
22 nextStart = backPtr.fOtherIndex; | 18 *tIndex = backPtr.fOtherIndex; |
23 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; | 19 bool sortable = true; |
24 int done = 0; | 20 bool done = true; |
25 if (segment->activeAngle(nextStart, &done, &angles)) { | 21 *endIndex = -1; |
26 SkOpAngle* last = angles.end() - 1; | 22 if (const SkOpAngle* last = segment->activeAngle(*tIndex, tIndex, endInd
ex, &done, |
27 nextStart = last->start(); | 23 &sortable)) { |
28 nextEnd = last->end(); | 24 *tIndex = last->start(); |
| 25 *endIndex = last->end(); |
29 #if TRY_ROTATE | 26 #if TRY_ROTATE |
30 *chase.insert(0) = span; | 27 *chase.insert(0) = span; |
31 #else | 28 #else |
32 *chase.append() = span; | 29 *chase.append() = span; |
33 #endif | 30 #endif |
34 return last->segment(); | 31 return last->segment(); |
35 } | 32 } |
36 if (done == angles.count()) { | 33 if (done) { |
37 continue; | 34 continue; |
38 } | 35 } |
39 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; | |
40 bool sortable = SkOpSegment::SortAngles(angles, &sorted, | |
41 SkOpSegment::kMayBeUnordered_SortAngleKind); | |
42 int angleCount = sorted.count(); | |
43 #if DEBUG_SORT | |
44 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, sortable); | |
45 #endif | |
46 if (!sortable) { | 36 if (!sortable) { |
47 continue; | 37 continue; |
48 } | 38 } |
49 // find first angle, initialize winding to computed fWindSum | 39 // find first angle, initialize winding to computed fWindSum |
50 int firstIndex = -1; | 40 const SkOpAngle* angle = segment->spanToAngle(*tIndex, *endIndex); |
51 const SkOpAngle* angle; | 41 const SkOpAngle* firstAngle = angle; |
52 bool foundAngle = true; | 42 SkDEBUGCODE(bool loop = false); |
| 43 int winding; |
53 do { | 44 do { |
54 ++firstIndex; | 45 angle = angle->next(); |
55 if (firstIndex >= angleCount) { | 46 SkASSERT(angle != firstAngle || !loop); |
56 foundAngle = false; | 47 SkDEBUGCODE(loop |= angle == firstAngle); |
57 break; | |
58 } | |
59 angle = sorted[firstIndex]; | |
60 segment = angle->segment(); | 48 segment = angle->segment(); |
61 } while (segment->windSum(angle) == SK_MinS32); | 49 winding = segment->windSum(angle); |
62 if (!foundAngle) { | 50 } while (winding == SK_MinS32); |
63 continue; | |
64 } | |
65 #if DEBUG_SORT | |
66 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, sortable); | |
67 #endif | |
68 int sumMiWinding = segment->updateWindingReverse(angle); | 51 int sumMiWinding = segment->updateWindingReverse(angle); |
69 int sumSuWinding = segment->updateOppWindingReverse(angle); | 52 int sumSuWinding = segment->updateOppWindingReverse(angle); |
70 if (segment->operand()) { | 53 if (segment->operand()) { |
71 SkTSwap<int>(sumMiWinding, sumSuWinding); | 54 SkTSwap<int>(sumMiWinding, sumSuWinding); |
72 } | 55 } |
73 int nextIndex = firstIndex + 1; | |
74 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; | |
75 SkOpSegment* first = NULL; | 56 SkOpSegment* first = NULL; |
76 do { | 57 while ((angle = angle->next()) != firstAngle) { |
77 SkASSERT(nextIndex != firstIndex); | |
78 if (nextIndex == angleCount) { | |
79 nextIndex = 0; | |
80 } | |
81 angle = sorted[nextIndex]; | |
82 segment = angle->segment(); | 58 segment = angle->segment(); |
83 int start = angle->start(); | 59 int start = angle->start(); |
84 int end = angle->end(); | 60 int end = angle->end(); |
85 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; | 61 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; |
86 segment->setUpWindings(start, end, &sumMiWinding, &sumSuWinding, | 62 segment->setUpWindings(start, end, &sumMiWinding, &sumSuWinding, |
87 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); | 63 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); |
88 if (!segment->done(angle)) { | 64 if (!segment->done(angle)) { |
89 if (!first) { | 65 if (!first) { |
90 first = segment; | 66 first = segment; |
91 nextStart = start; | 67 *tIndex = start; |
92 nextEnd = end; | 68 *endIndex = end; |
93 } | 69 } |
94 (void) segment->markAngle(maxWinding, sumWinding, oppMaxWinding, | 70 (void) segment->markAngle(maxWinding, sumWinding, oppMaxWinding, |
95 oppSumWinding, angle); | 71 oppSumWinding, angle); |
96 } | 72 } |
97 } while (++nextIndex != lastIndex); | 73 } |
98 if (first) { | 74 if (first) { |
99 #if TRY_ROTATE | 75 #if TRY_ROTATE |
100 *chase.insert(0) = span; | 76 *chase.insert(0) = span; |
101 #else | 77 #else |
102 *chase.append() = span; | 78 *chase.append() = span; |
103 #endif | 79 #endif |
104 return first; | 80 return first; |
105 } | 81 } |
106 } | 82 } |
107 return NULL; | 83 return NULL; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 topLeft.fX = topLeft.fY = SK_ScalarMin; | 129 topLeft.fX = topLeft.fY = SK_ScalarMin; |
154 continue; | 130 continue; |
155 } | 131 } |
156 break; | 132 break; |
157 } | 133 } |
158 SkTDArray<SkOpSpan*> chaseArray; | 134 SkTDArray<SkOpSpan*> chaseArray; |
159 do { | 135 do { |
160 if (current->activeOp(index, endIndex, xorMask, xorOpMask, op)) { | 136 if (current->activeOp(index, endIndex, xorMask, xorOpMask, op)) { |
161 do { | 137 do { |
162 if (!unsortable && current->done()) { | 138 if (!unsortable && current->done()) { |
163 #if DEBUG_ACTIVE_SPANS | |
164 DebugShowActiveSpans(contourList); | |
165 #endif | |
166 if (simple->isEmpty()) { | 139 if (simple->isEmpty()) { |
167 simple->init(); | 140 simple->init(); |
168 } | 141 } |
169 break; | 142 break; |
170 } | 143 } |
171 SkASSERT(unsortable || !current->done()); | 144 SkASSERT(unsortable || !current->done()); |
172 int nextStart = index; | 145 int nextStart = index; |
173 int nextEnd = endIndex; | 146 int nextEnd = endIndex; |
174 SkOpSegment* next = current->findNextOp(&chaseArray, &nextSt
art, &nextEnd, | 147 SkOpSegment* next = current->findNextOp(&chaseArray, &nextSt
art, &nextEnd, |
175 &unsortable, op, xorMask, xorOpMask); | 148 &unsortable, op, xorMask, xorOpMask); |
(...skipping 16 matching lines...) Expand all Loading... |
192 index = nextStart; | 165 index = nextStart; |
193 endIndex = nextEnd; | 166 endIndex = nextEnd; |
194 } while (!simple->isClosed() && (!unsortable | 167 } while (!simple->isClosed() && (!unsortable |
195 || !current->done(SkMin32(index, endIndex)))); | 168 || !current->done(SkMin32(index, endIndex)))); |
196 if (current->activeWinding(index, endIndex) && !simple->isClosed
()) { | 169 if (current->activeWinding(index, endIndex) && !simple->isClosed
()) { |
197 // FIXME : add to simplify, xor cpaths | 170 // FIXME : add to simplify, xor cpaths |
198 int min = SkMin32(index, endIndex); | 171 int min = SkMin32(index, endIndex); |
199 if (!unsortable && !simple->isEmpty()) { | 172 if (!unsortable && !simple->isEmpty()) { |
200 unsortable = current->checkSmall(min); | 173 unsortable = current->checkSmall(min); |
201 } | 174 } |
202 SkASSERT(unsortable || simple->isEmpty()); | |
203 if (!current->done(min)) { | 175 if (!current->done(min)) { |
204 current->addCurveTo(index, endIndex, simple, true); | 176 current->addCurveTo(index, endIndex, simple, true); |
205 current->markDoneBinary(min); | 177 current->markDoneBinary(min); |
206 } | 178 } |
207 } | 179 } |
208 simple->close(); | 180 simple->close(); |
209 } else { | 181 } else { |
210 SkOpSpan* last = current->markAndChaseDoneBinary(index, endIndex
); | 182 SkOpSpan* last = current->markAndChaseDoneBinary(index, endIndex
); |
211 if (last && !last->fLoop) { | 183 if (last && !last->fChased && !last->fLoop) { |
| 184 last->fChased = true; |
| 185 SkASSERT(!SkPathOpsDebug::ChaseContains(chaseArray, last)); |
212 *chaseArray.append() = last; | 186 *chaseArray.append() = last; |
213 } | 187 } |
214 } | 188 } |
215 current = findChaseOp(chaseArray, index, endIndex); | 189 current = findChaseOp(chaseArray, &index, &endIndex); |
216 #if DEBUG_ACTIVE_SPANS | 190 #if DEBUG_ACTIVE_SPANS |
217 DebugShowActiveSpans(contourList); | 191 DebugShowActiveSpans(contourList); |
218 #endif | 192 #endif |
219 if (!current) { | 193 if (!current) { |
220 break; | 194 break; |
221 } | 195 } |
222 } while (true); | 196 } while (true); |
223 } while (true); | 197 } while (true); |
224 return simple->someAssemblyRequired(); | 198 return simple->someAssemblyRequired(); |
225 } | 199 } |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 next = *nextPtr++; | 271 next = *nextPtr++; |
298 } while (AddIntersectTs(current, next) && nextPtr != listEnd); | 272 } while (AddIntersectTs(current, next) && nextPtr != listEnd); |
299 } while (currentPtr != listEnd); | 273 } while (currentPtr != listEnd); |
300 // eat through coincident edges | 274 // eat through coincident edges |
301 | 275 |
302 int total = 0; | 276 int total = 0; |
303 int index; | 277 int index; |
304 for (index = 0; index < contourList.count(); ++index) { | 278 for (index = 0; index < contourList.count(); ++index) { |
305 total += contourList[index]->segments().count(); | 279 total += contourList[index]->segments().count(); |
306 } | 280 } |
307 HandleCoincidence(&contourList, total); | 281 if (!HandleCoincidence(&contourList, total)) { |
| 282 return false; |
| 283 } |
308 // construct closed contours | 284 // construct closed contours |
309 SkPathWriter wrapper(*result); | 285 SkPathWriter wrapper(*result); |
310 bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper); | 286 bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper); |
311 { // if some edges could not be resolved, assemble remaining fragments | 287 { // if some edges could not be resolved, assemble remaining fragments |
312 SkPath temp; | 288 SkPath temp; |
313 temp.setFillType(fillType); | 289 temp.setFillType(fillType); |
314 SkPathWriter assembled(temp); | 290 SkPathWriter assembled(temp); |
315 Assemble(wrapper, &assembled); | 291 Assemble(wrapper, &assembled); |
316 *result = *assembled.nativePath(); | 292 *result = *assembled.nativePath(); |
317 result->setFillType(fillType); | 293 result->setFillType(fillType); |
318 } | 294 } |
319 return true; | 295 return true; |
320 } | 296 } |
OLD | NEW |