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 "SkOpCoincidence.h" | 8 #include "SkOpCoincidence.h" |
9 #include "SkOpEdgeBuilder.h" | 9 #include "SkOpEdgeBuilder.h" |
10 #include "SkPathOpsCommon.h" | 10 #include "SkPathOpsCommon.h" |
11 #include "SkPathWriter.h" | 11 #include "SkPathWriter.h" |
12 | 12 |
13 static bool bridgeWinding(SkTDArray<SkOpContour* >& contourList, SkPathWriter* s
imple, | 13 static bool bridgeWinding(SkOpContourHead* contourList, SkPathWriter* simple, |
14 SkChunkAlloc* allocator) { | 14 SkChunkAlloc* allocator) { |
15 bool firstContour = true; | |
16 bool unsortable = false; | 15 bool unsortable = false; |
17 bool topUnsortable = false; | |
18 bool firstPass = true; | |
19 SkDPoint lastTopLeft; | |
20 SkDPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; | |
21 do { | 16 do { |
22 SkOpSpanBase* start = NULL; | 17 SkOpSpan* span = FindSortableTop(contourList); |
23 SkOpSpanBase* end = NULL; | 18 if (!span) { |
24 bool topDone; | |
25 bool onlyVertical = false; | |
26 lastTopLeft = topLeft; | |
27 SkOpSegment* current = FindSortableTop(contourList, firstPass, SkOpAngle
::kUnaryWinding, | |
28 &firstContour, &start, &end, &topLeft, &topUnsortable, &topDone,
&onlyVertical, | |
29 allocator); | |
30 if (!current) { | |
31 if ((!topUnsortable || firstPass) && !topDone) { | |
32 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMi
n); | |
33 if (lastTopLeft.fX == SK_ScalarMin && lastTopLeft.fY == SK_Scala
rMin) { | |
34 if (firstPass) { | |
35 firstPass = false; | |
36 } else { | |
37 break; | |
38 } | |
39 } | |
40 topLeft.fX = topLeft.fY = SK_ScalarMin; | |
41 continue; | |
42 } | |
43 break; | |
44 } else if (onlyVertical) { | |
45 break; | 19 break; |
46 } | 20 } |
47 firstPass = !topUnsortable || lastTopLeft != topLeft; | 21 SkOpSegment* current = span->segment(); |
| 22 SkOpSpanBase* start = span->next(); |
| 23 SkOpSpanBase* end = span; |
48 SkTDArray<SkOpSpanBase*> chase; | 24 SkTDArray<SkOpSpanBase*> chase; |
49 do { | 25 do { |
50 if (current->activeWinding(start, end)) { | 26 if (current->activeWinding(start, end)) { |
51 do { | 27 do { |
52 if (!unsortable && current->done()) { | 28 if (!unsortable && current->done()) { |
53 break; | 29 break; |
54 } | 30 } |
55 SkASSERT(unsortable || !current->done()); | 31 SkASSERT(unsortable || !current->done()); |
56 SkOpSpanBase* nextStart = start; | 32 SkOpSpanBase* nextStart = start; |
57 SkOpSpanBase* nextEnd = end; | 33 SkOpSpanBase* nextEnd = end; |
(...skipping 28 matching lines...) Expand all Loading... |
86 current->addCurveTo(start, end, simple, true); | 62 current->addCurveTo(start, end, simple, true); |
87 current->markDone(spanStart); | 63 current->markDone(spanStart); |
88 } | 64 } |
89 } | 65 } |
90 simple->close(); | 66 simple->close(); |
91 } else { | 67 } else { |
92 SkOpSpanBase* last = current->markAndChaseDone(start, end); | 68 SkOpSpanBase* last = current->markAndChaseDone(start, end); |
93 if (last && !last->chased()) { | 69 if (last && !last->chased()) { |
94 last->setChased(true); | 70 last->setChased(true); |
95 SkASSERT(!SkPathOpsDebug::ChaseContains(chase, last)); | 71 SkASSERT(!SkPathOpsDebug::ChaseContains(chase, last)); |
96 // assert that last isn't already in array | |
97 *chase.append() = last; | 72 *chase.append() = last; |
98 #if DEBUG_WINDING | 73 #if DEBUG_WINDING |
99 SkDebugf("%s chase.append id=%d", __FUNCTION__, last->segmen
t()->debugID()); | 74 SkDebugf("%s chase.append id=%d", __FUNCTION__, last->segmen
t()->debugID()); |
100 if (!last->final()) { | 75 if (!last->final()) { |
101 SkDebugf(" windSum=%d", last->upCast()->windSum()); | 76 SkDebugf(" windSum=%d", last->upCast()->windSum()); |
102 } | 77 } |
103 SkDebugf("\n"); | 78 SkDebugf("\n"); |
104 #endif | 79 #endif |
105 } | 80 } |
106 } | 81 } |
107 current = FindChase(&chase, &start, &end); | 82 current = FindChase(&chase, &start, &end); |
108 #if DEBUG_ACTIVE_SPANS | 83 #if DEBUG_ACTIVE_SPANS |
109 DebugShowActiveSpans(contourList); | 84 DebugShowActiveSpans(contourList); |
110 #endif | 85 #endif |
111 if (!current) { | 86 if (!current) { |
112 break; | 87 break; |
113 } | 88 } |
114 } while (true); | 89 } while (true); |
115 } while (true); | 90 } while (true); |
116 return simple->someAssemblyRequired(); | 91 return simple->someAssemblyRequired(); |
117 } | 92 } |
118 | 93 |
119 // returns true if all edges were processed | 94 // returns true if all edges were processed |
120 static bool bridgeXor(SkTDArray<SkOpContour* >& contourList, SkPathWriter* simpl
e, | 95 static bool bridgeXor(SkOpContourHead* contourList, SkPathWriter* simple, |
121 SkChunkAlloc* allocator) { | 96 SkChunkAlloc* allocator) { |
122 SkOpSegment* current; | 97 SkOpSegment* current; |
123 SkOpSpanBase* start; | 98 SkOpSpanBase* start; |
124 SkOpSpanBase* end; | 99 SkOpSpanBase* end; |
125 bool unsortable = false; | 100 bool unsortable = false; |
126 bool closable = true; | 101 bool closable = true; |
127 while ((current = FindUndone(contourList, &start, &end))) { | 102 while ((current = FindUndone(contourList, &start, &end))) { |
128 do { | 103 do { |
129 #if DEBUG_ACTIVE_SPANS | 104 #if DEBUG_ACTIVE_SPANS |
130 if (!unsortable && current->done()) { | 105 if (!unsortable && current->done()) { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
184 if (path.isConvex()) { | 159 if (path.isConvex()) { |
185 if (result != &path) { | 160 if (result != &path) { |
186 *result = path; | 161 *result = path; |
187 } | 162 } |
188 result->setFillType(fillType); | 163 result->setFillType(fillType); |
189 return true; | 164 return true; |
190 } | 165 } |
191 // turn path into list of segments | 166 // turn path into list of segments |
192 SkOpCoincidence coincidence; | 167 SkOpCoincidence coincidence; |
193 SkOpContour contour; | 168 SkOpContour contour; |
194 SkOpGlobalState globalState(&coincidence SkDEBUGPARAMS(&contour)); | 169 SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour); |
195 #if DEBUG_SORT || DEBUG_SWAP_TOP | 170 SkOpGlobalState globalState(&coincidence, contourList); |
| 171 #if DEBUG_SORT |
196 SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault; | 172 SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault; |
197 #endif | 173 #endif |
198 SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState); | 174 SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState); |
199 if (!builder.finish(&allocator)) { | 175 if (!builder.finish(&allocator)) { |
200 return false; | 176 return false; |
201 } | 177 } |
202 #if DEBUG_DUMP_SEGMENTS | 178 #if DEBUG_DUMP_SEGMENTS |
203 contour.dumpSegments((SkPathOp) -1); | 179 contour.dumpSegments((SkPathOp) -1); |
204 #endif | 180 #endif |
205 SkTDArray<SkOpContour* > contourList; | 181 if (!SortContourList(&contourList, false, false)) { |
206 MakeContourList(&contour, contourList, false, false); | |
207 SkOpContour** currentPtr = contourList.begin(); | |
208 if (!currentPtr) { | |
209 result->reset(); | 182 result->reset(); |
210 result->setFillType(fillType); | 183 result->setFillType(fillType); |
211 return true; | 184 return true; |
212 } | 185 } |
213 if ((*currentPtr)->count() == 0) { | |
214 SkASSERT((*currentPtr)->next() == NULL); | |
215 result->reset(); | |
216 result->setFillType(fillType); | |
217 return true; | |
218 } | |
219 SkOpContour** listEnd2 = contourList.end(); | |
220 // find all intersections between segments | 186 // find all intersections between segments |
| 187 SkOpContour* current = contourList; |
221 do { | 188 do { |
222 SkOpContour** nextPtr = currentPtr; | 189 SkOpContour* next = current; |
223 SkOpContour* current = *currentPtr++; | 190 while (AddIntersectTs(current, next, &coincidence, &allocator) |
224 SkOpContour* next; | 191 && (next = next->next())); |
225 do { | 192 } while ((current = current->next())); |
226 next = *nextPtr++; | |
227 } while (AddIntersectTs(current, next, &coincidence, &allocator) && next
Ptr != listEnd2); | |
228 } while (currentPtr != listEnd2); | |
229 #if DEBUG_VALIDATE | 193 #if DEBUG_VALIDATE |
230 globalState.setPhase(SkOpGlobalState::kWalking); | 194 globalState.setPhase(SkOpGlobalState::kWalking); |
231 #endif | 195 #endif |
232 if (!HandleCoincidence(&contourList, &coincidence, &allocator, &globalState)
) { | 196 if (!HandleCoincidence(contourList, &coincidence, &allocator)) { |
233 return false; | 197 return false; |
234 } | 198 } |
235 // construct closed contours | 199 // construct closed contours |
236 result->reset(); | 200 result->reset(); |
237 result->setFillType(fillType); | 201 result->setFillType(fillType); |
238 SkPathWriter wrapper(*result); | 202 SkPathWriter wrapper(*result); |
239 if (builder.xorMask() == kWinding_PathOpsMask ? bridgeWinding(contourList, &
wrapper, &allocator) | 203 if (builder.xorMask() == kWinding_PathOpsMask ? bridgeWinding(contourList, &
wrapper, &allocator) |
240 : !bridgeXor(contourList, &wrapper, &allocator)) | 204 : !bridgeXor(contourList, &wrapper, &allocator)) |
241 { // if some edges could not be resolved, assemble remaining fragments | 205 { // if some edges could not be resolved, assemble remaining fragments |
242 SkPath temp; | 206 SkPath temp; |
243 temp.setFillType(fillType); | 207 temp.setFillType(fillType); |
244 SkPathWriter assembled(temp); | 208 SkPathWriter assembled(temp); |
245 Assemble(wrapper, &assembled); | 209 Assemble(wrapper, &assembled); |
246 *result = *assembled.nativePath(); | 210 *result = *assembled.nativePath(); |
247 result->setFillType(fillType); | 211 result->setFillType(fillType); |
248 } | 212 } |
249 return true; | 213 return true; |
250 } | 214 } |
OLD | NEW |