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 "SkOpEdgeBuilder.h" | 9 #include "SkOpEdgeBuilder.h" |
9 #include "SkPathOpsCommon.h" | 10 #include "SkPathOpsCommon.h" |
10 #include "SkPathWriter.h" | 11 #include "SkPathWriter.h" |
11 #include "SkTSort.h" | 12 #include "SkTSort.h" |
12 | 13 |
13 static void alignMultiples(SkTArray<SkOpContour*, true>* contourList, | 14 static int contourRangeCheckY(const SkTDArray<SkOpContour* >& contourList, |
14 SkTDArray<SkOpSegment::AlignedSpan>* aligned) { | 15 SkOpSegment** currentPtr, SkOpSpanBase** startPtr, SkOpSpanBase** endPtr
, |
15 int contourCount = (*contourList).count(); | 16 double* bestHit, SkScalar* bestDx, bool* tryAgain, double* midPtr, bool
opp) { |
16 for (int cTest = 0; cTest < contourCount; ++cTest) { | 17 SkOpSpanBase* start = *startPtr; |
17 SkOpContour* contour = (*contourList)[cTest]; | 18 SkOpSpanBase* end = *endPtr; |
18 if (contour->hasMultiples()) { | |
19 contour->alignMultiples(aligned); | |
20 } | |
21 } | |
22 } | |
23 | |
24 static void alignCoincidence(SkTArray<SkOpContour*, true>* contourList, | |
25 const SkTDArray<SkOpSegment::AlignedSpan>& aligned) { | |
26 int contourCount = (*contourList).count(); | |
27 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
28 SkOpContour* contour = (*contourList)[cTest]; | |
29 int count = aligned.count(); | |
30 for (int index = 0; index < count; ++index) { | |
31 contour->alignCoincidence(aligned[index]); | |
32 } | |
33 } | |
34 } | |
35 | |
36 static int contourRangeCheckY(const SkTArray<SkOpContour*, true>& contourList, S
kOpSegment** currentPtr, | |
37 int* indexPtr, int* endIndexPtr, double* bestHit,
SkScalar* bestDx, | |
38 bool* tryAgain, double* midPtr, bool opp) { | |
39 const int index = *indexPtr; | |
40 const int endIndex = *endIndexPtr; | |
41 const double mid = *midPtr; | 19 const double mid = *midPtr; |
42 const SkOpSegment* current = *currentPtr; | 20 const SkOpSegment* current = *currentPtr; |
43 double tAtMid = current->tAtMid(index, endIndex, mid); | 21 double tAtMid = SkOpSegment::TAtMid(start, end, mid); |
44 SkPoint basePt = current->ptAtT(tAtMid); | 22 SkPoint basePt = current->ptAtT(tAtMid); |
45 int contourCount = contourList.count(); | 23 int contourCount = contourList.count(); |
46 SkScalar bestY = SK_ScalarMin; | 24 SkScalar bestY = SK_ScalarMin; |
47 SkOpSegment* bestSeg = NULL; | 25 SkOpSegment* bestSeg = NULL; |
48 int bestTIndex = 0; | 26 SkOpSpan* bestTSpan = NULL; |
49 bool bestOpp; | 27 bool bestOpp; |
50 bool hitSomething = false; | 28 bool hitSomething = false; |
51 for (int cTest = 0; cTest < contourCount; ++cTest) { | 29 for (int cTest = 0; cTest < contourCount; ++cTest) { |
52 SkOpContour* contour = contourList[cTest]; | 30 SkOpContour* contour = contourList[cTest]; |
53 bool testOpp = contour->operand() ^ current->operand() ^ opp; | 31 bool testOpp = contour->operand() ^ current->operand() ^ opp; |
54 if (basePt.fY < contour->bounds().fTop) { | 32 if (basePt.fY < contour->bounds().fTop) { |
55 continue; | 33 continue; |
56 } | 34 } |
57 if (bestY > contour->bounds().fBottom) { | 35 if (bestY > contour->bounds().fBottom) { |
58 continue; | 36 continue; |
59 } | 37 } |
60 int segmentCount = contour->segments().count(); | 38 SkOpSegment* testSeg = contour->first(); |
61 for (int test = 0; test < segmentCount; ++test) { | 39 SkASSERT(testSeg); |
62 SkOpSegment* testSeg = &contour->segments()[test]; | 40 do { |
63 SkScalar testY = bestY; | 41 SkScalar testY = bestY; |
64 double testHit; | 42 double testHit; |
65 int testTIndex = testSeg->crossedSpanY(basePt, &testY, &testHit, &hi
tSomething, tAtMid, | 43 bool vertical; |
66 testOpp, testSeg == current); | 44 SkOpSpan* testTSpan = testSeg->crossedSpanY(basePt, tAtMid, testOpp, |
67 if (testTIndex < 0) { | 45 testSeg == current, &testY, &testHit, &hitSomething, &vertic
al); |
68 if (testTIndex == SK_MinS32) { | 46 if (!testTSpan) { |
| 47 if (vertical) { |
69 hitSomething = true; | 48 hitSomething = true; |
70 bestSeg = NULL; | 49 bestSeg = NULL; |
71 goto abortContours; // vertical encountered, return and try
different point | 50 goto abortContours; // vertical encountered, return and try
different point |
72 } | 51 } |
73 continue; | 52 continue; |
74 } | 53 } |
75 if (testSeg == current && current->betweenTs(index, testHit, endInde
x)) { | 54 if (testSeg == current && SkOpSegment::BetweenTs(start, testHit, end
)) { |
76 double baseT = current->t(index); | 55 double baseT = start->t(); |
77 double endT = current->t(endIndex); | 56 double endT = end->t(); |
78 double newMid = (testHit - baseT) / (endT - baseT); | 57 double newMid = (testHit - baseT) / (endT - baseT); |
79 #if DEBUG_WINDING | 58 #if DEBUG_WINDING |
80 double midT = current->tAtMid(index, endIndex, mid); | 59 double midT = SkOpSegment::TAtMid(start, end, mid); |
81 SkPoint midXY = current->xyAtT(midT); | 60 SkPoint midXY = current->ptAtT(midT); |
82 double newMidT = current->tAtMid(index, endIndex, newMid); | 61 double newMidT = SkOpSegment::TAtMid(start, end, newMid); |
83 SkPoint newXY = current->xyAtT(newMidT); | 62 SkPoint newXY = current->ptAtT(newMidT); |
84 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g
(%1.9g,%1.9g)" | 63 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g
(%1.9g,%1.9g)" |
85 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNC
TION__, | 64 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNC
TION__, |
86 current->debugID(), mid, newMid, | 65 current->debugID(), mid, newMid, |
87 baseT, current->xAtT(index), current->yAtT(index), | 66 baseT, start->pt().fX, start->pt().fY, |
88 baseT + mid * (endT - baseT), midXY.fX, midXY.fY, | 67 baseT + mid * (endT - baseT), midXY.fX, midXY.fY, |
89 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY, | 68 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY, |
90 endT, current->xAtT(endIndex), current->yAtT(endIndex)); | 69 endT, end->pt().fX, end->pt().fY); |
91 #endif | 70 #endif |
92 *midPtr = newMid * 2; // calling loop with divide by 2 before c
ontinuing | 71 *midPtr = newMid * 2; // calling loop with divide by 2 before c
ontinuing |
93 return SK_MinS32; | 72 return SK_MinS32; |
94 } | 73 } |
95 bestSeg = testSeg; | 74 bestSeg = testSeg; |
96 *bestHit = testHit; | 75 *bestHit = testHit; |
97 bestOpp = testOpp; | 76 bestOpp = testOpp; |
98 bestTIndex = testTIndex; | 77 bestTSpan = testTSpan; |
99 bestY = testY; | 78 bestY = testY; |
100 } | 79 } while ((testSeg = testSeg->next())); |
101 } | 80 } |
102 abortContours: | 81 abortContours: |
103 int result; | 82 int result; |
104 if (!bestSeg) { | 83 if (!bestSeg) { |
105 result = hitSomething ? SK_MinS32 : 0; | 84 result = hitSomething ? SK_MinS32 : 0; |
106 } else { | 85 } else { |
107 if (bestSeg->windSum(bestTIndex) == SK_MinS32) { | 86 if (bestTSpan->windSum() == SK_MinS32) { |
108 *currentPtr = bestSeg; | 87 *currentPtr = bestSeg; |
109 *indexPtr = bestTIndex; | 88 *startPtr = bestTSpan; |
110 *endIndexPtr = bestSeg->nextSpan(bestTIndex, 1); | 89 *endPtr = bestTSpan->next(); |
111 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr
>= 0); | 90 SkASSERT(*startPtr != *endPtr && *startPtr && *endPtr); |
112 *tryAgain = true; | 91 *tryAgain = true; |
113 return 0; | 92 return 0; |
114 } | 93 } |
115 result = bestSeg->windingAtT(*bestHit, bestTIndex, bestOpp, bestDx); | 94 result = bestSeg->windingAtT(*bestHit, bestTSpan, bestOpp, bestDx); |
116 SkASSERT(result == SK_MinS32 || *bestDx); | 95 SkASSERT(result == SK_MinS32 || *bestDx); |
117 } | 96 } |
118 double baseT = current->t(index); | 97 double baseT = (*startPtr)->t(); |
119 double endT = current->t(endIndex); | 98 double endT = (*endPtr)->t(); |
120 *bestHit = baseT + mid * (endT - baseT); | 99 *bestHit = baseT + mid * (endT - baseT); |
121 return result; | 100 return result; |
122 } | 101 } |
123 | 102 |
124 SkOpSegment* FindUndone(SkTArray<SkOpContour*, true>& contourList, int* start, i
nt* end) { | 103 SkOpSegment* FindUndone(SkTDArray<SkOpContour* >& contourList, SkOpSpanBase** st
artPtr, |
| 104 SkOpSpanBase** endPtr) { |
125 int contourCount = contourList.count(); | 105 int contourCount = contourList.count(); |
126 SkOpSegment* result; | 106 SkOpSegment* result; |
127 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | 107 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
128 SkOpContour* contour = contourList[cIndex]; | 108 SkOpContour* contour = contourList[cIndex]; |
129 result = contour->undoneSegment(start, end); | 109 result = contour->undoneSegment(startPtr, endPtr); |
130 if (result) { | 110 if (result) { |
131 return result; | 111 return result; |
132 } | 112 } |
133 } | 113 } |
134 return NULL; | 114 return NULL; |
135 } | 115 } |
136 | 116 |
137 SkOpSegment* FindChase(SkTDArray<SkOpSpan*>* chase, int* tIndex, int* endIndex)
{ | 117 SkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr, |
| 118 SkOpSpanBase** endPtr) { |
138 while (chase->count()) { | 119 while (chase->count()) { |
139 SkOpSpan* span; | 120 SkOpSpanBase* span; |
140 chase->pop(&span); | 121 chase->pop(&span); |
141 const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex); | 122 SkOpSegment* segment = span->segment(); |
142 SkOpSegment* segment = backPtr.fOther; | 123 *startPtr = span->ptT()->next()->span(); |
143 *tIndex = backPtr.fOtherIndex; | |
144 bool sortable = true; | 124 bool sortable = true; |
145 bool done = true; | 125 bool done = true; |
146 *endIndex = -1; | 126 *endPtr = NULL; |
147 if (const SkOpAngle* last = segment->activeAngle(*tIndex, tIndex, endInd
ex, &done, | 127 if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr,
&done, |
148 &sortable)) { | 128 &sortable)) { |
149 *tIndex = last->start(); | 129 if (last->unorderable()) { |
150 *endIndex = last->end(); | 130 continue; |
| 131 } |
| 132 *startPtr = last->start(); |
| 133 *endPtr = last->end(); |
151 #if TRY_ROTATE | 134 #if TRY_ROTATE |
152 *chase->insert(0) = span; | 135 *chase->insert(0) = span; |
153 #else | 136 #else |
154 *chase->append() = span; | 137 *chase->append() = span; |
155 #endif | 138 #endif |
156 return last->segment(); | 139 return last->segment(); |
157 } | 140 } |
158 if (done) { | 141 if (done) { |
159 continue; | 142 continue; |
160 } | 143 } |
161 if (!sortable) { | 144 if (!sortable) { |
162 continue; | 145 continue; |
163 } | 146 } |
164 // find first angle, initialize winding to computed wind sum | 147 // find first angle, initialize winding to computed wind sum |
165 const SkOpAngle* angle = segment->spanToAngle(*tIndex, *endIndex); | 148 const SkOpAngle* angle = segment->spanToAngle(*startPtr, *endPtr); |
166 const SkOpAngle* firstAngle; | 149 if (!angle) { |
167 SkDEBUGCODE(firstAngle = angle); | 150 continue; |
168 SkDEBUGCODE(bool loop = false); | 151 } |
169 int winding; | 152 const SkOpAngle* firstAngle = angle; |
| 153 bool loop = false; |
| 154 int winding = SK_MinS32; |
170 do { | 155 do { |
171 angle = angle->next(); | 156 angle = angle->next(); |
172 SkASSERT(angle != firstAngle || !loop); | 157 if (angle == firstAngle && loop) { |
173 SkDEBUGCODE(loop |= angle == firstAngle); | 158 break; // if we get here, there's no winding, loop is unorder
able |
| 159 } |
| 160 loop |= angle == firstAngle; |
174 segment = angle->segment(); | 161 segment = angle->segment(); |
175 winding = segment->windSum(angle); | 162 winding = segment->windSum(angle); |
176 } while (winding == SK_MinS32); | 163 } while (winding == SK_MinS32); |
177 int spanWinding = segment->spanSign(angle->start(), angle->end()); | 164 if (winding == SK_MinS32) { |
178 #if DEBUG_WINDING | 165 continue; |
179 SkDebugf("%s winding=%d spanWinding=%d\n", __FUNCTION__, winding, spanWi
nding); | |
180 #endif | |
181 // turn span winding into contour winding | |
182 if (spanWinding * winding < 0) { | |
183 winding += spanWinding; | |
184 } | 166 } |
185 // we care about first sign and whether wind sum indicates this | 167 int sumWinding = segment->updateWindingReverse(angle); |
186 // edge is inside or outside. Maybe need to pass span winding | 168 SkOpSegment* first = NULL; |
187 // or first winding or something into this function? | |
188 // advance to first undone angle, then return it and winding | |
189 // (to set whether edges are active or not) | |
190 firstAngle = angle; | 169 firstAngle = angle; |
191 winding -= firstAngle->segment()->spanSign(firstAngle); | |
192 while ((angle = angle->next()) != firstAngle) { | 170 while ((angle = angle->next()) != firstAngle) { |
193 segment = angle->segment(); | 171 segment = angle->segment(); |
194 int maxWinding = winding; | 172 SkOpSpanBase* start = angle->start(); |
195 winding -= segment->spanSign(angle); | 173 SkOpSpanBase* end = angle->end(); |
196 #if DEBUG_SORT | 174 int maxWinding; |
197 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__
, | 175 segment->setUpWinding(start, end, &maxWinding, &sumWinding); |
198 segment->debugID(), maxWinding, winding, angle->sign()); | 176 if (!segment->done(angle)) { |
199 #endif | 177 if (!first) { |
200 *tIndex = angle->start(); | 178 first = segment; |
201 *endIndex = angle->end(); | 179 *startPtr = start; |
202 int lesser = SkMin32(*tIndex, *endIndex); | 180 *endPtr = end; |
203 const SkOpSpan& nextSpan = segment->span(lesser); | |
204 if (!nextSpan.fDone) { | |
205 // FIXME: this be wrong? assign startWinding if edge is in | |
206 // same direction. If the direction is opposite, winding to | |
207 // assign is flipped sign or +/- 1? | |
208 if (SkOpSegment::UseInnerWinding(maxWinding, winding)) { | |
209 maxWinding = winding; | |
210 } | 181 } |
211 // allowed to do nothing | 182 // OPTIMIZATION: should this also add to the chase? |
212 (void) segment->markAndChaseWinding(angle, maxWinding, 0, NULL); | 183 (void) segment->markAngle(maxWinding, sumWinding, angle); |
213 break; | |
214 } | 184 } |
215 } | 185 } |
216 *chase->insert(0) = span; | 186 if (first) { |
217 return segment; | 187 #if TRY_ROTATE |
| 188 *chase->insert(0) = span; |
| 189 #else |
| 190 *chase->append() = span; |
| 191 #endif |
| 192 return first; |
| 193 } |
218 } | 194 } |
219 return NULL; | 195 return NULL; |
220 } | 196 } |
221 | 197 |
222 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY | 198 #if DEBUG_ACTIVE_SPANS |
223 void DebugShowActiveSpans(SkTArray<SkOpContour*, true>& contourList) { | 199 void DebugShowActiveSpans(SkTDArray<SkOpContour* >& contourList) { |
224 int index; | 200 int index; |
225 for (index = 0; index < contourList.count(); ++ index) { | 201 for (index = 0; index < contourList.count(); ++ index) { |
226 contourList[index]->debugShowActiveSpans(); | 202 contourList[index]->debugShowActiveSpans(); |
227 } | 203 } |
228 } | 204 } |
229 #endif | 205 #endif |
230 | 206 |
231 static SkOpSegment* findTopSegment(const SkTArray<SkOpContour*, true>& contourLi
st, int* index, | 207 static SkOpSegment* findTopSegment(const SkTDArray<SkOpContour* >& contourList, |
232 int* endIndex, SkPoint* topLeft, bool* unsortable, bool* done, bool firs
tPass) { | 208 bool firstPass, SkOpSpanBase** start, SkOpSpanBase** end, SkPoint* topLe
ft, |
| 209 bool* unsortable, bool* done, SkChunkAlloc* allocator) { |
233 SkOpSegment* result; | 210 SkOpSegment* result; |
234 const SkOpSegment* lastTopStart = NULL; | 211 const SkOpSegment* lastTopStart = NULL; |
235 int lastIndex = -1, lastEndIndex = -1; | 212 SkOpSpanBase* lastStart = NULL, * lastEnd = NULL; |
236 do { | 213 do { |
237 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax}; | 214 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax}; |
238 int contourCount = contourList.count(); | 215 int contourCount = contourList.count(); |
239 SkOpSegment* topStart = NULL; | 216 SkOpSegment* topStart = NULL; |
240 *done = true; | 217 *done = true; |
241 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | 218 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
242 SkOpContour* contour = contourList[cIndex]; | 219 SkOpContour* contour = contourList[cIndex]; |
243 if (contour->done()) { | 220 if (contour->done()) { |
244 continue; | 221 continue; |
245 } | 222 } |
246 const SkPathOpsBounds& bounds = contour->bounds(); | 223 const SkPathOpsBounds& bounds = contour->bounds(); |
247 if (bounds.fBottom < topLeft->fY) { | 224 if (bounds.fBottom < topLeft->fY) { |
248 *done = false; | 225 *done = false; |
249 continue; | 226 continue; |
250 } | 227 } |
251 if (bounds.fBottom == topLeft->fY && bounds.fRight < topLeft->fX) { | 228 if (bounds.fBottom == topLeft->fY && bounds.fRight < topLeft->fX) { |
252 *done = false; | 229 *done = false; |
253 continue; | 230 continue; |
254 } | 231 } |
255 contour->topSortableSegment(*topLeft, &bestXY, &topStart); | 232 contour->topSortableSegment(*topLeft, &bestXY, &topStart); |
256 if (!contour->done()) { | 233 if (!contour->done()) { |
257 *done = false; | 234 *done = false; |
258 } | 235 } |
259 } | 236 } |
260 if (!topStart) { | 237 if (!topStart) { |
261 return NULL; | 238 return NULL; |
262 } | 239 } |
263 *topLeft = bestXY; | 240 *topLeft = bestXY; |
264 result = topStart->findTop(index, endIndex, unsortable, firstPass); | 241 result = topStart->findTop(firstPass, start, end, unsortable, allocator)
; |
265 if (!result) { | 242 if (!result) { |
266 if (lastTopStart == topStart && lastIndex == *index && lastEndIndex
== *endIndex) { | 243 if (lastTopStart == topStart && lastStart == *start && lastEnd == *e
nd) { |
267 *done = true; | 244 *done = true; |
268 return NULL; | 245 return NULL; |
269 } | 246 } |
270 lastTopStart = topStart; | 247 lastTopStart = topStart; |
271 lastIndex = *index; | 248 lastStart = *start; |
272 lastEndIndex = *endIndex; | 249 lastEnd = *end; |
273 } | 250 } |
274 } while (!result); | 251 } while (!result); |
275 return result; | 252 return result; |
276 } | 253 } |
277 | 254 |
278 static int rightAngleWinding(const SkTArray<SkOpContour*, true>& contourList, | 255 static int rightAngleWinding(const SkTDArray<SkOpContour* >& contourList, |
279 SkOpSegment** currentPtr, int* indexPtr, int* endIndexPtr, double* tHit, | 256 SkOpSegment** currentPtr, SkOpSpanBase** start, SkOpSpanBase** end, doub
le* tHit, |
280 SkScalar* hitDx, bool* tryAgain, bool* onlyVertical, bool opp) { | 257 SkScalar* hitDx, bool* tryAgain, bool* onlyVertical, bool opp) { |
281 double test = 0.9; | 258 double test = 0.9; |
282 int contourWinding; | 259 int contourWinding; |
283 do { | 260 do { |
284 contourWinding = contourRangeCheckY(contourList, currentPtr, indexPtr, e
ndIndexPtr, | 261 contourWinding = contourRangeCheckY(contourList, currentPtr, start, end, |
285 tHit, hitDx, tryAgain, &test, opp); | 262 tHit, hitDx, tryAgain, &test, opp); |
286 if (contourWinding != SK_MinS32 || *tryAgain) { | 263 if (contourWinding != SK_MinS32 || *tryAgain) { |
287 return contourWinding; | 264 return contourWinding; |
288 } | 265 } |
289 if (*currentPtr && (*currentPtr)->isVertical()) { | 266 if (*currentPtr && (*currentPtr)->isVertical()) { |
290 *onlyVertical = true; | 267 *onlyVertical = true; |
291 return contourWinding; | 268 return contourWinding; |
292 } | 269 } |
293 test /= 2; | 270 test /= 2; |
294 } while (!approximately_negative(test)); | 271 } while (!approximately_negative(test)); |
295 SkASSERT(0); // FIXME: incomplete functionality | 272 SkASSERT(0); // FIXME: incomplete functionality |
296 return contourWinding; | 273 return contourWinding; |
297 } | 274 } |
298 | 275 |
299 static void skipVertical(const SkTArray<SkOpContour*, true>& contourList, | 276 static void skipVertical(const SkTDArray<SkOpContour* >& contourList, |
300 SkOpSegment** current, int* index, int* endIndex) { | 277 SkOpSegment** current, SkOpSpanBase** start, SkOpSpanBase** end) { |
301 if (!(*current)->isVertical(*index, *endIndex)) { | 278 if (!(*current)->isVertical(*start, *end)) { |
302 return; | 279 return; |
303 } | 280 } |
304 int contourCount = contourList.count(); | 281 int contourCount = contourList.count(); |
305 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | 282 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
306 SkOpContour* contour = contourList[cIndex]; | 283 SkOpContour* contour = contourList[cIndex]; |
307 if (contour->done()) { | 284 if (contour->done()) { |
308 continue; | 285 continue; |
309 } | 286 } |
310 SkOpSegment* nonVertical = contour->nonVerticalSegment(index, endIndex); | 287 SkOpSegment* nonVertical = contour->nonVerticalSegment(start, end); |
311 if (nonVertical) { | 288 if (nonVertical) { |
312 *current = nonVertical; | 289 *current = nonVertical; |
313 return; | 290 return; |
314 } | 291 } |
315 } | 292 } |
316 return; | 293 return; |
317 } | 294 } |
318 | 295 |
319 struct SortableTop { // error if local in pre-C++11 | 296 struct SortableTop2 { // error if local in pre-C++11 |
320 SkOpSegment* fSegment; | 297 SkOpSpanBase* fStart; |
321 int fIndex; | 298 SkOpSpanBase* fEnd; |
322 int fEndIndex; | |
323 }; | 299 }; |
324 | 300 |
325 SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList, | 301 SkOpSegment* FindSortableTop(const SkTDArray<SkOpContour* >& contourList, bool f
irstPass, |
326 SkOpAngle::IncludeType angleIncludeType, bool* firstContour, int* indexP
tr, | 302 SkOpAngle::IncludeType angleIncludeType, bool* firstContour, SkOpSpanBas
e** startPtr, |
327 int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool*
onlyVertical, | 303 SkOpSpanBase** endPtr, SkPoint* topLeft, bool* unsortable, bool* done, b
ool* onlyVertical, |
328 bool firstPass) { | 304 SkChunkAlloc* allocator) { |
329 SkOpSegment* current = findTopSegment(contourList, indexPtr, endIndexPtr, to
pLeft, unsortable, | 305 SkOpSegment* current = findTopSegment(contourList, firstPass, startPtr, endP
tr, topLeft, |
330 done, firstPass); | 306 unsortable, done, allocator); |
331 if (!current) { | 307 if (!current) { |
332 return NULL; | 308 return NULL; |
333 } | 309 } |
334 const int startIndex = *indexPtr; | 310 SkOpSpanBase* start = *startPtr; |
335 const int endIndex = *endIndexPtr; | 311 SkOpSpanBase* end = *endPtr; |
| 312 SkASSERT(current == start->segment()); |
336 if (*firstContour) { | 313 if (*firstContour) { |
337 current->initWinding(startIndex, endIndex, angleIncludeType); | 314 current->initWinding(start, end, angleIncludeType); |
338 *firstContour = false; | 315 *firstContour = false; |
339 return current; | 316 return current; |
340 } | 317 } |
341 int minIndex = SkMin32(startIndex, endIndex); | 318 SkOpSpan* minSpan = start->starter(end); |
342 int sumWinding = current->windSum(minIndex); | 319 int sumWinding = minSpan->windSum(); |
343 if (sumWinding == SK_MinS32) { | 320 if (sumWinding == SK_MinS32) { |
344 int index = endIndex; | 321 SkOpSpanBase* iSpan = end; |
345 int oIndex = startIndex; | 322 SkOpSpanBase* oSpan = start; |
346 do { | 323 do { |
347 const SkOpSpan& span = current->span(index); | 324 bool checkFrom = oSpan->t() < iSpan->t(); |
348 if ((oIndex < index ? span.fFromAngle : span.fToAngle) == NULL) { | 325 if ((checkFrom ? iSpan->fromAngle() : iSpan->upCast()->toAngle()) ==
NULL) { |
349 current->addSimpleAngle(index); | 326 iSpan->addSimpleAngle(checkFrom, allocator); |
350 } | 327 } |
351 sumWinding = current->computeSum(oIndex, index, angleIncludeType); | 328 sumWinding = current->computeSum(oSpan, iSpan, angleIncludeType); |
352 SkTSwap(index, oIndex); | 329 SkTSwap(iSpan, oSpan); |
353 } while (sumWinding == SK_MinS32 && index == startIndex); | 330 } while (sumWinding == SK_MinS32 && iSpan == start); |
354 } | 331 } |
355 if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) { | 332 if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) { |
356 return current; | 333 return current; |
357 } | 334 } |
358 int contourWinding; | 335 int contourWinding; |
359 int oppContourWinding = 0; | 336 int oppContourWinding = 0; |
360 // the simple upward projection of the unresolved points hit unsortable angl
es | 337 // the simple upward projection of the unresolved points hit unsortable angl
es |
361 // shoot rays at right angles to the segment to find its winding, ignoring a
ngle cases | 338 // shoot rays at right angles to the segment to find its winding, ignoring a
ngle cases |
362 bool tryAgain; | 339 bool tryAgain; |
363 double tHit; | 340 double tHit; |
364 SkScalar hitDx = 0; | 341 SkScalar hitDx = 0; |
365 SkScalar hitOppDx = 0; | 342 SkScalar hitOppDx = 0; |
366 // keep track of subsequent returns to detect infinite loops | 343 // keep track of subsequent returns to detect infinite loops |
367 SkTDArray<SortableTop> sortableTops; | 344 SkTDArray<SortableTop2> sortableTops; |
368 do { | 345 do { |
369 // if current is vertical, find another candidate which is not | 346 // if current is vertical, find another candidate which is not |
370 // if only remaining candidates are vertical, then they can be marked do
ne | 347 // if only remaining candidates are vertical, then they can be marked do
ne |
371 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >=
0); | 348 SkASSERT(*startPtr != *endPtr && *startPtr && *endPtr); |
372 skipVertical(contourList, ¤t, indexPtr, endIndexPtr); | 349 SkASSERT(current == (*startPtr)->segment()); |
| 350 skipVertical(contourList, ¤t, startPtr, endPtr); |
373 SkASSERT(current); // FIXME: if null, all remaining are vertical | 351 SkASSERT(current); // FIXME: if null, all remaining are vertical |
374 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >=
0); | 352 SkASSERT(*startPtr != *endPtr && *startPtr && *endPtr); |
| 353 SkASSERT(current == (*startPtr)->segment()); |
375 tryAgain = false; | 354 tryAgain = false; |
376 contourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endI
ndexPtr, &tHit, | 355 contourWinding = rightAngleWinding(contourList, ¤t, startPtr, endP
tr, &tHit, |
377 &hitDx, &tryAgain, onlyVertical, false); | 356 &hitDx, &tryAgain, onlyVertical, false); |
| 357 SkASSERT(current == (*startPtr)->segment()); |
378 if (tryAgain) { | 358 if (tryAgain) { |
379 bool giveUp = false; | 359 bool giveUp = false; |
380 int count = sortableTops.count(); | 360 int count = sortableTops.count(); |
381 for (int index = 0; index < count; ++index) { | 361 for (int index = 0; index < count; ++index) { |
382 const SortableTop& prev = sortableTops[index]; | 362 const SortableTop2& prev = sortableTops[index]; |
383 if (giveUp) { | 363 if (giveUp) { |
384 prev.fSegment->markDoneFinal(prev.fIndex); | 364 prev.fStart->segment()->markDone(prev.fStart->starter(prev.f
End)); |
385 } else if (prev.fSegment == current | 365 } else if (prev.fStart == *startPtr || prev.fEnd == *endPtr) { |
386 && (prev.fIndex == *indexPtr || prev.fEndIndex == *endIn
dexPtr)) { | |
387 // remaining edges are non-vertical and cannot have their wi
nding computed | 366 // remaining edges are non-vertical and cannot have their wi
nding computed |
388 // mark them as done and return, and hope that assembly can
fill the holes | 367 // mark them as done and return, and hope that assembly can
fill the holes |
389 giveUp = true; | 368 giveUp = true; |
390 index = -1; | 369 index = -1; |
391 } | 370 } |
392 } | 371 } |
393 if (giveUp) { | 372 if (giveUp) { |
394 *done = true; | 373 *done = true; |
395 return NULL; | 374 return NULL; |
396 } | 375 } |
397 } | 376 } |
398 SortableTop* sortableTop = sortableTops.append(); | 377 SortableTop2* sortableTop = sortableTops.append(); |
399 sortableTop->fSegment = current; | 378 sortableTop->fStart = *startPtr; |
400 sortableTop->fIndex = *indexPtr; | 379 sortableTop->fEnd = *endPtr; |
401 sortableTop->fEndIndex = *endIndexPtr; | |
402 #if DEBUG_SORT | 380 #if DEBUG_SORT |
403 SkDebugf("%s current=%d index=%d endIndex=%d tHit=%1.9g hitDx=%1.9g try=
%d vert=%d\n", | 381 SkDebugf("%s current=%d index=%d endIndex=%d tHit=%1.9g hitDx=%1.9g try=
%d vert=%d\n", |
404 __FUNCTION__, current->debugID(), *indexPtr, *endIndexPtr, tHit,
hitDx, tryAgain, | 382 __FUNCTION__, current->debugID(), (*startPtr)->debugID(), (*endP
tr)->debugID(), |
405 *onlyVertical); | 383 tHit, hitDx, tryAgain, *onlyVertical); |
406 #endif | 384 #endif |
407 if (*onlyVertical) { | 385 if (*onlyVertical) { |
408 return current; | 386 return current; |
409 } | 387 } |
410 if (tryAgain) { | 388 if (tryAgain) { |
411 continue; | 389 continue; |
412 } | 390 } |
413 if (angleIncludeType < SkOpAngle::kBinarySingle) { | 391 if (angleIncludeType < SkOpAngle::kBinarySingle) { |
414 break; | 392 break; |
415 } | 393 } |
416 oppContourWinding = rightAngleWinding(contourList, ¤t, indexPtr, e
ndIndexPtr, &tHit, | 394 oppContourWinding = rightAngleWinding(contourList, ¤t, startPtr, e
ndPtr, &tHit, |
417 &hitOppDx, &tryAgain, NULL, true); | 395 &hitOppDx, &tryAgain, NULL, true); |
| 396 SkASSERT(current == (*startPtr)->segment()); |
418 } while (tryAgain); | 397 } while (tryAgain); |
419 bool success = current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWi
nding, hitDx, | 398 bool success = current->initWinding(*startPtr, *endPtr, tHit, contourWinding
, hitDx, |
420 oppContourWinding, hitOppDx); | 399 oppContourWinding, hitOppDx); |
421 if (current->done()) { | 400 if (current->done()) { |
422 return NULL; | 401 return NULL; |
423 } else if (!success) { // check if the span has a valid winding | 402 } else if (!success) { // check if the span has a valid winding |
424 int min = SkTMin(*indexPtr, *endIndexPtr); | 403 SkOpSpan* minSpan = (*startPtr)->t() < (*endPtr)->t() ? (*startPtr)->upC
ast() |
425 const SkOpSpan& span = current->span(min); | 404 : (*endPtr)->upCast(); |
426 if (span.fWindSum == SK_MinS32) { | 405 if (minSpan->windSum() == SK_MinS32) { |
427 return NULL; | 406 return NULL; |
428 } | 407 } |
429 } | 408 } |
430 return current; | 409 return current; |
431 } | 410 } |
432 | 411 |
433 static bool calcAngles(SkTArray<SkOpContour*, true>* contourList) { | 412 void MakeContourList(SkOpContour* contour, SkTDArray<SkOpContour* >& list, |
434 int contourCount = (*contourList).count(); | 413 bool evenOdd, bool oppEvenOdd) { |
435 for (int cTest = 0; cTest < contourCount; ++cTest) { | 414 do { |
436 SkOpContour* contour = (*contourList)[cTest]; | 415 if (contour->count()) { |
437 if (!contour->calcAngles()) { | 416 contour->setOppXor(contour->operand() ? evenOdd : oppEvenOdd); |
438 return false; | 417 *list.append() = contour; |
439 } | 418 } |
440 } | 419 } while ((contour = contour->next())); |
441 return true; | 420 if (list.count() < 2) { |
442 } | |
443 | |
444 static void checkDuplicates(SkTArray<SkOpContour*, true>* contourList) { | |
445 int contourCount = (*contourList).count(); | |
446 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
447 SkOpContour* contour = (*contourList)[cTest]; | |
448 contour->checkDuplicates(); | |
449 } | |
450 } | |
451 | |
452 static bool checkEnds(SkTArray<SkOpContour*, true>* contourList) { | |
453 // it's hard to determine if the end of a cubic or conic nearly intersects a
nother curve. | |
454 // instead, look to see if the connecting curve intersected at that same end
. | |
455 int contourCount = (*contourList).count(); | |
456 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
457 SkOpContour* contour = (*contourList)[cTest]; | |
458 if (!contour->checkEnds()) { | |
459 return false; | |
460 } | |
461 } | |
462 return true; | |
463 } | |
464 | |
465 static bool checkMultiples(SkTArray<SkOpContour*, true>* contourList) { | |
466 bool hasMultiples = false; | |
467 int contourCount = (*contourList).count(); | |
468 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
469 SkOpContour* contour = (*contourList)[cTest]; | |
470 contour->checkMultiples(); | |
471 hasMultiples |= contour->hasMultiples(); | |
472 } | |
473 return hasMultiples; | |
474 } | |
475 | |
476 // A small interval of a pair of curves may collapse to lines for each, triggeri
ng coincidence | |
477 static void checkSmall(SkTArray<SkOpContour*, true>* contourList) { | |
478 int contourCount = (*contourList).count(); | |
479 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
480 SkOpContour* contour = (*contourList)[cTest]; | |
481 contour->checkSmall(); | |
482 } | |
483 } | |
484 | |
485 // A tiny interval may indicate an undiscovered coincidence. Find and fix. | |
486 static void checkTiny(SkTArray<SkOpContour*, true>* contourList) { | |
487 int contourCount = (*contourList).count(); | |
488 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
489 SkOpContour* contour = (*contourList)[cTest]; | |
490 contour->checkTiny(); | |
491 } | |
492 } | |
493 | |
494 static void fixOtherTIndex(SkTArray<SkOpContour*, true>* contourList) { | |
495 int contourCount = (*contourList).count(); | |
496 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
497 SkOpContour* contour = (*contourList)[cTest]; | |
498 contour->fixOtherTIndex(); | |
499 } | |
500 } | |
501 | |
502 static void joinCoincidence(SkTArray<SkOpContour*, true>* contourList) { | |
503 int contourCount = (*contourList).count(); | |
504 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
505 SkOpContour* contour = (*contourList)[cTest]; | |
506 contour->joinCoincidence(); | |
507 } | |
508 } | |
509 | |
510 static void sortAngles(SkTArray<SkOpContour*, true>* contourList) { | |
511 int contourCount = (*contourList).count(); | |
512 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
513 SkOpContour* contour = (*contourList)[cTest]; | |
514 contour->sortAngles(); | |
515 } | |
516 } | |
517 | |
518 static void sortSegments(SkTArray<SkOpContour*, true>* contourList) { | |
519 int contourCount = (*contourList).count(); | |
520 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
521 SkOpContour* contour = (*contourList)[cTest]; | |
522 contour->sortSegments(); | |
523 } | |
524 } | |
525 | |
526 void MakeContourList(SkTArray<SkOpContour>& contours, SkTArray<SkOpContour*, tru
e>& list, | |
527 bool evenOdd, bool oppEvenOdd) { | |
528 int count = contours.count(); | |
529 if (count == 0) { | |
530 return; | 421 return; |
531 } | 422 } |
532 for (int index = 0; index < count; ++index) { | |
533 SkOpContour& contour = contours[index]; | |
534 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd); | |
535 list.push_back(&contour); | |
536 } | |
537 SkTQSort<SkOpContour>(list.begin(), list.end() - 1); | 423 SkTQSort<SkOpContour>(list.begin(), list.end() - 1); |
538 } | 424 } |
539 | 425 |
540 class DistanceLessThan { | 426 class DistanceLessThan { |
541 public: | 427 public: |
542 DistanceLessThan(double* distances) : fDistances(distances) { } | 428 DistanceLessThan(double* distances) : fDistances(distances) { } |
543 double* fDistances; | 429 double* fDistances; |
544 bool operator()(const int one, const int two) { | 430 bool operator()(const int one, const int two) { |
545 return fDistances[one] < fDistances[two]; | 431 return fDistances[one] < fDistances[two]; |
546 } | 432 } |
547 }; | 433 }; |
548 | 434 |
549 /* | 435 /* |
550 check start and end of each contour | 436 check start and end of each contour |
551 if not the same, record them | 437 if not the same, record them |
552 match them up | 438 match them up |
553 connect closest | 439 connect closest |
554 reassemble contour pieces into new path | 440 reassemble contour pieces into new path |
555 */ | 441 */ |
556 void Assemble(const SkPathWriter& path, SkPathWriter* simple) { | 442 void Assemble(const SkPathWriter& path, SkPathWriter* simple) { |
| 443 SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune |
| 444 SkOpContour contour; |
| 445 SkOpGlobalState globalState(NULL PATH_OPS_DEBUG_PARAMS(&contour)); |
557 #if DEBUG_PATH_CONSTRUCTION | 446 #if DEBUG_PATH_CONSTRUCTION |
558 SkDebugf("%s\n", __FUNCTION__); | 447 SkDebugf("%s\n", __FUNCTION__); |
559 #endif | 448 #endif |
560 SkTArray<SkOpContour> contours; | 449 SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState); |
561 SkOpEdgeBuilder builder(path, contours); | 450 builder.finish(&allocator); |
562 builder.finish(); | 451 SkTDArray<const SkOpContour* > runs; // indices of partial contours |
563 int count = contours.count(); | 452 const SkOpContour* eContour = builder.head(); |
564 int outer; | 453 do { |
565 SkTArray<int, true> runs(count); // indices of partial contours | 454 if (!eContour->count()) { |
566 for (outer = 0; outer < count; ++outer) { | 455 continue; |
567 const SkOpContour& eContour = contours[outer]; | 456 } |
568 const SkPoint& eStart = eContour.start(); | 457 const SkPoint& eStart = eContour->start(); |
569 const SkPoint& eEnd = eContour.end(); | 458 const SkPoint& eEnd = eContour->end(); |
570 #if DEBUG_ASSEMBLE | 459 #if DEBUG_ASSEMBLE |
571 SkDebugf("%s contour", __FUNCTION__); | 460 SkDebugf("%s contour", __FUNCTION__); |
572 if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) { | 461 if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) { |
573 SkDebugf("[%d]", runs.count()); | 462 SkDebugf("[%d]", runs.count()); |
574 } else { | 463 } else { |
575 SkDebugf(" "); | 464 SkDebugf(" "); |
576 } | 465 } |
577 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n", | 466 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n", |
578 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY); | 467 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY); |
579 #endif | 468 #endif |
580 if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) { | 469 if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) { |
581 eContour.toPath(simple); | 470 eContour->toPath(simple); |
582 continue; | 471 continue; |
583 } | 472 } |
584 runs.push_back(outer); | 473 *runs.append() = eContour; |
585 } | 474 } while ((eContour = eContour->next())); |
586 count = runs.count(); | 475 int count = runs.count(); |
587 if (count == 0) { | 476 if (count == 0) { |
588 return; | 477 return; |
589 } | 478 } |
590 SkTArray<int, true> sLink, eLink; | 479 SkTDArray<int> sLink, eLink; |
591 sLink.push_back_n(count); | 480 sLink.append(count); |
592 eLink.push_back_n(count); | 481 eLink.append(count); |
593 int rIndex, iIndex; | 482 int rIndex, iIndex; |
594 for (rIndex = 0; rIndex < count; ++rIndex) { | 483 for (rIndex = 0; rIndex < count; ++rIndex) { |
595 sLink[rIndex] = eLink[rIndex] = SK_MaxS32; | 484 sLink[rIndex] = eLink[rIndex] = SK_MaxS32; |
596 } | 485 } |
597 const int ends = count * 2; // all starts and ends | 486 const int ends = count * 2; // all starts and ends |
598 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) /
2 | 487 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) /
2 |
599 SkTArray<double, true> distances; | 488 SkTDArray<double> distances; |
600 distances.push_back_n(entries); | 489 distances.append(entries); |
601 for (rIndex = 0; rIndex < ends - 1; ++rIndex) { | 490 for (rIndex = 0; rIndex < ends - 1; ++rIndex) { |
602 outer = runs[rIndex >> 1]; | 491 const SkOpContour* oContour = runs[rIndex >> 1]; |
603 const SkOpContour& oContour = contours[outer]; | 492 const SkPoint& oPt = rIndex & 1 ? oContour->end() : oContour->start(); |
604 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start(); | |
605 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2) | 493 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2) |
606 * ends - rIndex - 1; | 494 * ends - rIndex - 1; |
607 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) { | 495 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) { |
608 int inner = runs[iIndex >> 1]; | 496 const SkOpContour* iContour = runs[iIndex >> 1]; |
609 const SkOpContour& iContour = contours[inner]; | 497 const SkPoint& iPt = iIndex & 1 ? iContour->end() : iContour->start(
); |
610 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start(); | |
611 double dx = iPt.fX - oPt.fX; | 498 double dx = iPt.fX - oPt.fX; |
612 double dy = iPt.fY - oPt.fY; | 499 double dy = iPt.fY - oPt.fY; |
613 double dist = dx * dx + dy * dy; | 500 double dist = dx * dx + dy * dy; |
614 distances[row + iIndex] = dist; // oStart distance from iStart | 501 distances[row + iIndex] = dist; // oStart distance from iStart |
615 } | 502 } |
616 } | 503 } |
617 SkTArray<int, true> sortedDist; | 504 SkTDArray<int> sortedDist; |
618 sortedDist.push_back_n(entries); | 505 sortedDist.append(entries); |
619 for (rIndex = 0; rIndex < entries; ++rIndex) { | 506 for (rIndex = 0; rIndex < entries; ++rIndex) { |
620 sortedDist[rIndex] = rIndex; | 507 sortedDist[rIndex] = rIndex; |
621 } | 508 } |
622 SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(dis
tances.begin())); | 509 SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(dis
tances.begin())); |
623 int remaining = count; // number of start/end pairs | 510 int remaining = count; // number of start/end pairs |
624 for (rIndex = 0; rIndex < entries; ++rIndex) { | 511 for (rIndex = 0; rIndex < entries; ++rIndex) { |
625 int pair = sortedDist[rIndex]; | 512 int pair = sortedDist[rIndex]; |
626 int row = pair / ends; | 513 int row = pair / ends; |
627 int col = pair - row * ends; | 514 int col = pair - row * ends; |
628 int thingOne = row < col ? row : ends - row - 2; | 515 int thingOne = row < col ? row : ends - row - 2; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
671 eIndex = eLink[sIndex]; | 558 eIndex = eLink[sIndex]; |
672 eLink[sIndex] = SK_MaxS32; | 559 eLink[sIndex] = SK_MaxS32; |
673 } | 560 } |
674 SkASSERT(eIndex != SK_MaxS32); | 561 SkASSERT(eIndex != SK_MaxS32); |
675 #if DEBUG_ASSEMBLE | 562 #if DEBUG_ASSEMBLE |
676 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's'
: 'e', | 563 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's'
: 'e', |
677 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e', | 564 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e', |
678 eIndex < 0 ? ~eIndex : eIndex); | 565 eIndex < 0 ? ~eIndex : eIndex); |
679 #endif | 566 #endif |
680 do { | 567 do { |
681 outer = runs[rIndex]; | 568 const SkOpContour* contour = runs[rIndex]; |
682 const SkOpContour& contour = contours[outer]; | |
683 if (first) { | 569 if (first) { |
684 first = false; | 570 first = false; |
685 const SkPoint* startPtr = &contour.start(); | 571 const SkPoint* startPtr = &contour->start(); |
686 simple->deferredMove(startPtr[0]); | 572 simple->deferredMove(startPtr[0]); |
687 } | 573 } |
688 if (forward) { | 574 if (forward) { |
689 contour.toPartialForward(simple); | 575 contour->toPartialForward(simple); |
690 } else { | 576 } else { |
691 contour.toPartialBackward(simple); | 577 contour->toPartialBackward(simple); |
692 } | 578 } |
693 #if DEBUG_ASSEMBLE | 579 #if DEBUG_ASSEMBLE |
694 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex
, | 580 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex
, |
695 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex, | 581 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex, |
696 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)); | 582 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)); |
697 #endif | 583 #endif |
698 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) { | 584 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) { |
699 simple->close(); | 585 simple->close(); |
700 break; | 586 break; |
701 } | 587 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
735 } | 621 } |
736 } while (rIndex < count); | 622 } while (rIndex < count); |
737 #if DEBUG_ASSEMBLE | 623 #if DEBUG_ASSEMBLE |
738 for (rIndex = 0; rIndex < count; ++rIndex) { | 624 for (rIndex = 0; rIndex < count; ++rIndex) { |
739 SkASSERT(sLink[rIndex] == SK_MaxS32); | 625 SkASSERT(sLink[rIndex] == SK_MaxS32); |
740 SkASSERT(eLink[rIndex] == SK_MaxS32); | 626 SkASSERT(eLink[rIndex] == SK_MaxS32); |
741 } | 627 } |
742 #endif | 628 #endif |
743 } | 629 } |
744 | 630 |
745 bool HandleCoincidence(SkTArray<SkOpContour*, true>* contourList, int total) { | 631 static void align(SkTDArray<SkOpContour* >* contourList) { |
746 #if DEBUG_SHOW_WINDING | 632 int contourCount = (*contourList).count(); |
747 SkOpContour::debugShowWindingValues(contourList); | 633 for (int cTest = 0; cTest < contourCount; ++cTest) { |
748 #endif | 634 SkOpContour* contour = (*contourList)[cTest]; |
749 if (!CoincidenceCheck(contourList, total)) { | 635 contour->align(); |
| 636 } |
| 637 } |
| 638 |
| 639 static void calcAngles(SkTDArray<SkOpContour* >* contourList, SkChunkAlloc* allo
cator) { |
| 640 int contourCount = (*contourList).count(); |
| 641 for (int cTest = 0; cTest < contourCount; ++cTest) { |
| 642 SkOpContour* contour = (*contourList)[cTest]; |
| 643 contour->calcAngles(allocator); |
| 644 } |
| 645 } |
| 646 |
| 647 static void missingCoincidence(SkTDArray<SkOpContour* >* contourList, |
| 648 SkOpCoincidence* coincidence, SkChunkAlloc* allocator) { |
| 649 int contourCount = (*contourList).count(); |
| 650 for (int cTest = 0; cTest < contourCount; ++cTest) { |
| 651 SkOpContour* contour = (*contourList)[cTest]; |
| 652 contour->missingCoincidence(coincidence, allocator); |
| 653 } |
| 654 } |
| 655 |
| 656 static bool moveNearby(SkTDArray<SkOpContour* >* contourList) { |
| 657 int contourCount = (*contourList).count(); |
| 658 for (int cTest = 0; cTest < contourCount; ++cTest) { |
| 659 SkOpContour* contour = (*contourList)[cTest]; |
| 660 if (!contour->moveNearby()) { |
| 661 return false; |
| 662 } |
| 663 } |
| 664 return true; |
| 665 } |
| 666 |
| 667 static void sortAngles(SkTDArray<SkOpContour* >* contourList) { |
| 668 int contourCount = (*contourList).count(); |
| 669 for (int cTest = 0; cTest < contourCount; ++cTest) { |
| 670 SkOpContour* contour = (*contourList)[cTest]; |
| 671 contour->sortAngles(); |
| 672 } |
| 673 } |
| 674 |
| 675 static void sortSegments(SkTDArray<SkOpContour* >* contourList) { |
| 676 int contourCount = (*contourList).count(); |
| 677 for (int cTest = 0; cTest < contourCount; ++cTest) { |
| 678 SkOpContour* contour = (*contourList)[cTest]; |
| 679 contour->sortSegments(); |
| 680 } |
| 681 } |
| 682 |
| 683 bool HandleCoincidence(SkTDArray<SkOpContour* >* contourList, SkOpCoincidence* c
oincidence, |
| 684 SkChunkAlloc* allocator, SkOpGlobalState* globalState) { |
| 685 // move t values and points together to eliminate small/tiny gaps |
| 686 if (!moveNearby(contourList)) { |
750 return false; | 687 return false; |
751 } | 688 } |
752 #if DEBUG_SHOW_WINDING | 689 align(contourList); // give all span members common values |
753 SkOpContour::debugShowWindingValues(contourList); | 690 #if DEBUG_VALIDATE |
| 691 globalState->setPhase(SkOpGlobalState::kIntersecting); |
754 #endif | 692 #endif |
755 fixOtherTIndex(contourList); | 693 coincidence->addMissing(allocator); |
756 if (!checkEnds(contourList)) { // check if connecting curve intersected at
the same end | 694 #if DEBUG_VALIDATE |
| 695 globalState->setPhase(SkOpGlobalState::kWalking); |
| 696 #endif |
| 697 coincidence->expand(); // check to see if, loosely, coincident ranges may b
e expanded |
| 698 coincidence->mark(); // mark spans of coincident segments as coincident |
| 699 missingCoincidence(contourList, coincidence, allocator); // look for coinci
dence missed earlier |
| 700 if (!coincidence->apply()) { // adjust the winding value to account for coi
ncident edges |
757 return false; | 701 return false; |
758 } | 702 } |
759 bool hasM = checkMultiples(contourList); // check if intersections agree on
t and point values | 703 sortSegments(contourList); |
760 SkTDArray<SkOpSegment::AlignedSpan> aligned; | 704 calcAngles(contourList, allocator); |
761 if (hasM) { | 705 sortAngles(contourList); |
762 alignMultiples(contourList, &aligned); // align pairs of identical poin
ts | 706 if (globalState->angleCoincidence()) { |
763 alignCoincidence(contourList, aligned); | 707 missingCoincidence(contourList, coincidence, allocator); |
| 708 if (!coincidence->apply()) { |
| 709 return false; |
| 710 } |
764 } | 711 } |
765 checkDuplicates(contourList); // check if spans have the same number on the
other end | 712 #if DEBUG_ACTIVE_SPANS |
766 checkTiny(contourList); // if pair have the same end points, mark them as p
arallel | |
767 checkSmall(contourList); // a pair of curves with a small span may turn int
o coincident lines | |
768 joinCoincidence(contourList); // join curves that connect to a coincident p
air | |
769 sortSegments(contourList); | |
770 if (!calcAngles(contourList)) { | |
771 return false; | |
772 } | |
773 sortAngles(contourList); | |
774 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY | |
775 DebugShowActiveSpans(*contourList); | 713 DebugShowActiveSpans(*contourList); |
776 #endif | 714 #endif |
777 return true; | 715 return true; |
778 } | 716 } |
OLD | NEW |