|
1 /* |
|
2 * Copyright 2012 Google Inc. |
|
3 * |
|
4 * Use of this source code is governed by a BSD-style license that can be |
|
5 * found in the LICENSE file. |
|
6 */ |
|
7 #include "SkAddIntersections.h" |
|
8 #include "SkOpEdgeBuilder.h" |
|
9 #include "SkPathOpsCommon.h" |
|
10 #include "SkPathWriter.h" |
|
11 #include "SkTSort.h" |
|
12 |
|
13 static int contourRangeCheckY(const SkTArray<SkOpContour*, true>& contourList, SkOpSegment** currentPtr, |
|
14 int* indexPtr, int* endIndexPtr, double* bestHit, SkScalar* bestDx, |
|
15 bool* tryAgain, double* midPtr, bool opp) { |
|
16 const int index = *indexPtr; |
|
17 const int endIndex = *endIndexPtr; |
|
18 const double mid = *midPtr; |
|
19 const SkOpSegment* current = *currentPtr; |
|
20 double tAtMid = current->tAtMid(index, endIndex, mid); |
|
21 SkPoint basePt = current->ptAtT(tAtMid); |
|
22 int contourCount = contourList.count(); |
|
23 SkScalar bestY = SK_ScalarMin; |
|
24 SkOpSegment* bestSeg = NULL; |
|
25 int bestTIndex = 0; |
|
26 bool bestOpp; |
|
27 bool hitSomething = false; |
|
28 for (int cTest = 0; cTest < contourCount; ++cTest) { |
|
29 SkOpContour* contour = contourList[cTest]; |
|
30 bool testOpp = contour->operand() ^ current->operand() ^ opp; |
|
31 if (basePt.fY < contour->bounds().fTop) { |
|
32 continue; |
|
33 } |
|
34 if (bestY > contour->bounds().fBottom) { |
|
35 continue; |
|
36 } |
|
37 int segmentCount = contour->segments().count(); |
|
38 for (int test = 0; test < segmentCount; ++test) { |
|
39 SkOpSegment* testSeg = &contour->segments()[test]; |
|
40 SkScalar testY = bestY; |
|
41 double testHit; |
|
42 int testTIndex = testSeg->crossedSpanY(basePt, &testY, &testHit, &hitSomething, tAtMid, |
|
43 testOpp, testSeg == current); |
|
44 if (testTIndex < 0) { |
|
45 if (testTIndex == SK_MinS32) { |
|
46 hitSomething = true; |
|
47 bestSeg = NULL; |
|
48 goto abortContours; // vertical encountered, return and try different point |
|
49 } |
|
50 continue; |
|
51 } |
|
52 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) { |
|
53 double baseT = current->t(index); |
|
54 double endT = current->t(endIndex); |
|
55 double newMid = (testHit - baseT) / (endT - baseT); |
|
56 #if DEBUG_WINDING |
|
57 double midT = current->tAtMid(index, endIndex, mid); |
|
58 SkPoint midXY = current->xyAtT(midT); |
|
59 double newMidT = current->tAtMid(index, endIndex, newMid); |
|
60 SkPoint newXY = current->xyAtT(newMidT); |
|
61 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)" |
|
62 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__, |
|
63 current->debugID(), mid, newMid, |
|
64 baseT, current->xAtT(index), current->yAtT(index), |
|
65 baseT + mid * (endT - baseT), midXY.fX, midXY.fY, |
|
66 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY, |
|
67 endT, current->xAtT(endIndex), current->yAtT(endIndex)); |
|
68 #endif |
|
69 *midPtr = newMid * 2; // calling loop with divide by 2 before continuing |
|
70 return SK_MinS32; |
|
71 } |
|
72 bestSeg = testSeg; |
|
73 *bestHit = testHit; |
|
74 bestOpp = testOpp; |
|
75 bestTIndex = testTIndex; |
|
76 bestY = testY; |
|
77 } |
|
78 } |
|
79 abortContours: |
|
80 int result; |
|
81 if (!bestSeg) { |
|
82 result = hitSomething ? SK_MinS32 : 0; |
|
83 } else { |
|
84 if (bestSeg->windSum(bestTIndex) == SK_MinS32) { |
|
85 *currentPtr = bestSeg; |
|
86 *indexPtr = bestTIndex; |
|
87 *endIndexPtr = bestSeg->nextSpan(bestTIndex, 1); |
|
88 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0); |
|
89 *tryAgain = true; |
|
90 return 0; |
|
91 } |
|
92 result = bestSeg->windingAtT(*bestHit, bestTIndex, bestOpp, bestDx); |
|
93 SkASSERT(result == SK_MinS32 || *bestDx); |
|
94 } |
|
95 double baseT = current->t(index); |
|
96 double endT = current->t(endIndex); |
|
97 *bestHit = baseT + mid * (endT - baseT); |
|
98 return result; |
|
99 } |
|
100 |
|
101 SkOpSegment* FindUndone(SkTArray<SkOpContour*, true>& contourList, int* start, int* end) { |
|
102 int contourCount = contourList.count(); |
|
103 SkOpSegment* result; |
|
104 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
|
105 SkOpContour* contour = contourList[cIndex]; |
|
106 result = contour->undoneSegment(start, end); |
|
107 if (result) { |
|
108 return result; |
|
109 } |
|
110 } |
|
111 return NULL; |
|
112 } |
|
113 |
|
114 SkOpSegment* FindChase(SkTDArray<SkOpSpan*>& chase, int& tIndex, int& endIndex) { |
|
115 while (chase.count()) { |
|
116 SkOpSpan* span; |
|
117 chase.pop(&span); |
|
118 const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex); |
|
119 SkOpSegment* segment = backPtr.fOther; |
|
120 tIndex = backPtr.fOtherIndex; |
|
121 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; |
|
122 int done = 0; |
|
123 if (segment->activeAngle(tIndex, &done, &angles)) { |
|
124 SkOpAngle* last = angles.end() - 1; |
|
125 tIndex = last->start(); |
|
126 endIndex = last->end(); |
|
127 #if TRY_ROTATE |
|
128 *chase.insert(0) = span; |
|
129 #else |
|
130 *chase.append() = span; |
|
131 #endif |
|
132 return last->segment(); |
|
133 } |
|
134 if (done == angles.count()) { |
|
135 continue; |
|
136 } |
|
137 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; |
|
138 bool sortable = SkOpSegment::SortAngles(angles, &sorted, |
|
139 SkOpSegment::kMayBeUnordered_SortAngleKind); |
|
140 int angleCount = sorted.count(); |
|
141 #if DEBUG_SORT |
|
142 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0, sortable); |
|
143 #endif |
|
144 if (!sortable) { |
|
145 continue; |
|
146 } |
|
147 // find first angle, initialize winding to computed fWindSum |
|
148 int firstIndex = -1; |
|
149 const SkOpAngle* angle; |
|
150 int winding; |
|
151 do { |
|
152 angle = sorted[++firstIndex]; |
|
153 segment = angle->segment(); |
|
154 winding = segment->windSum(angle); |
|
155 } while (winding == SK_MinS32); |
|
156 int spanWinding = segment->spanSign(angle->start(), angle->end()); |
|
157 #if DEBUG_WINDING |
|
158 SkDebugf("%s winding=%d spanWinding=%d\n", |
|
159 __FUNCTION__, winding, spanWinding); |
|
160 #endif |
|
161 // turn span winding into contour winding |
|
162 if (spanWinding * winding < 0) { |
|
163 winding += spanWinding; |
|
164 } |
|
165 #if DEBUG_SORT |
|
166 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0, sortable); |
|
167 #endif |
|
168 // we care about first sign and whether wind sum indicates this |
|
169 // edge is inside or outside. Maybe need to pass span winding |
|
170 // or first winding or something into this function? |
|
171 // advance to first undone angle, then return it and winding |
|
172 // (to set whether edges are active or not) |
|
173 int nextIndex = firstIndex + 1; |
|
174 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; |
|
175 angle = sorted[firstIndex]; |
|
176 winding -= angle->segment()->spanSign(angle); |
|
177 do { |
|
178 SkASSERT(nextIndex != firstIndex); |
|
179 if (nextIndex == angleCount) { |
|
180 nextIndex = 0; |
|
181 } |
|
182 angle = sorted[nextIndex]; |
|
183 segment = angle->segment(); |
|
184 int maxWinding = winding; |
|
185 winding -= segment->spanSign(angle); |
|
186 #if DEBUG_SORT |
|
187 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__, |
|
188 segment->debugID(), maxWinding, winding, angle->sign()); |
|
189 #endif |
|
190 tIndex = angle->start(); |
|
191 endIndex = angle->end(); |
|
192 int lesser = SkMin32(tIndex, endIndex); |
|
193 const SkOpSpan& nextSpan = segment->span(lesser); |
|
194 if (!nextSpan.fDone) { |
|
195 // FIXME: this be wrong? assign startWinding if edge is in |
|
196 // same direction. If the direction is opposite, winding to |
|
197 // assign is flipped sign or +/- 1? |
|
198 if (SkOpSegment::UseInnerWinding(maxWinding, winding)) { |
|
199 maxWinding = winding; |
|
200 } |
|
201 segment->markAndChaseWinding(angle, maxWinding, 0); |
|
202 break; |
|
203 } |
|
204 } while (++nextIndex != lastIndex); |
|
205 *chase.insert(0) = span; |
|
206 return segment; |
|
207 } |
|
208 return NULL; |
|
209 } |
|
210 |
|
211 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY |
|
212 void DebugShowActiveSpans(SkTArray<SkOpContour*, true>& contourList) { |
|
213 int index; |
|
214 for (index = 0; index < contourList.count(); ++ index) { |
|
215 contourList[index]->debugShowActiveSpans(); |
|
216 } |
|
217 } |
|
218 #endif |
|
219 |
|
220 static SkOpSegment* findSortableTop(const SkTArray<SkOpContour*, true>& contourList, |
|
221 int* index, int* endIndex, SkPoint* topLeft, bool* unsortable, |
|
222 bool* done, bool onlySortable) { |
|
223 SkOpSegment* result; |
|
224 do { |
|
225 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax}; |
|
226 int contourCount = contourList.count(); |
|
227 SkOpSegment* topStart = NULL; |
|
228 *done = true; |
|
229 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
|
230 SkOpContour* contour = contourList[cIndex]; |
|
231 if (contour->done()) { |
|
232 continue; |
|
233 } |
|
234 const SkPathOpsBounds& bounds = contour->bounds(); |
|
235 if (bounds.fBottom < topLeft->fY) { |
|
236 *done = false; |
|
237 continue; |
|
238 } |
|
239 if (bounds.fBottom == topLeft->fY && bounds.fRight < topLeft->fX) { |
|
240 *done = false; |
|
241 continue; |
|
242 } |
|
243 contour->topSortableSegment(*topLeft, &bestXY, &topStart); |
|
244 if (!contour->done()) { |
|
245 *done = false; |
|
246 } |
|
247 } |
|
248 if (!topStart) { |
|
249 return NULL; |
|
250 } |
|
251 *topLeft = bestXY; |
|
252 result = topStart->findTop(index, endIndex, unsortable, onlySortable); |
|
253 } while (!result); |
|
254 if (result) { |
|
255 *unsortable = false; |
|
256 } |
|
257 return result; |
|
258 } |
|
259 |
|
260 static int rightAngleWinding(const SkTArray<SkOpContour*, true>& contourList, |
|
261 SkOpSegment** current, int* index, int* endIndex, double* tHit, |
|
262 SkScalar* hitDx, bool* tryAgain, bool opp) { |
|
263 double test = 0.9; |
|
264 int contourWinding; |
|
265 do { |
|
266 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx, |
|
267 tryAgain, &test, opp); |
|
268 if (contourWinding != SK_MinS32 || *tryAgain) { |
|
269 return contourWinding; |
|
270 } |
|
271 test /= 2; |
|
272 } while (!approximately_negative(test)); |
|
273 SkASSERT(0); // should be OK to comment out, but interested when this hits |
|
274 return contourWinding; |
|
275 } |
|
276 |
|
277 static void skipVertical(const SkTArray<SkOpContour*, true>& contourList, |
|
278 SkOpSegment** current, int* index, int* endIndex) { |
|
279 if (!(*current)->isVertical(*index, *endIndex)) { |
|
280 return; |
|
281 } |
|
282 int contourCount = contourList.count(); |
|
283 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
|
284 SkOpContour* contour = contourList[cIndex]; |
|
285 if (contour->done()) { |
|
286 continue; |
|
287 } |
|
288 *current = contour->nonVerticalSegment(index, endIndex); |
|
289 if (*current) { |
|
290 return; |
|
291 } |
|
292 } |
|
293 } |
|
294 |
|
295 SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList, |
|
296 SkOpAngle::IncludeType angleIncludeType, bool* firstContour, int* indexPtr, |
|
297 int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done) { |
|
298 SkOpSegment* current = findSortableTop(contourList, indexPtr, endIndexPtr, topLeft, unsortable, |
|
299 done, true); |
|
300 if (!current) { |
|
301 return NULL; |
|
302 } |
|
303 const int index = *indexPtr; |
|
304 const int endIndex = *endIndexPtr; |
|
305 if (*firstContour) { |
|
306 current->initWinding(index, endIndex); |
|
307 *firstContour = false; |
|
308 return current; |
|
309 } |
|
310 int minIndex = SkMin32(index, endIndex); |
|
311 int sumWinding = current->windSum(minIndex); |
|
312 if (sumWinding != SK_MinS32) { |
|
313 return current; |
|
314 } |
|
315 SkASSERT(current->windSum(SkMin32(index, endIndex)) == SK_MinS32); |
|
316 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; |
|
317 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; |
|
318 sumWinding = current->computeSum(index, endIndex, angleIncludeType, &angles, &sorted); |
|
319 if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) { |
|
320 return current; |
|
321 } |
|
322 int contourWinding; |
|
323 int oppContourWinding = 0; |
|
324 // the simple upward projection of the unresolved points hit unsortable angles |
|
325 // shoot rays at right angles to the segment to find its winding, ignoring angle cases |
|
326 bool tryAgain; |
|
327 double tHit; |
|
328 SkScalar hitDx = 0; |
|
329 SkScalar hitOppDx = 0; |
|
330 do { |
|
331 // if current is vertical, find another candidate which is not |
|
332 // if only remaining candidates are vertical, then they can be marked done |
|
333 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0); |
|
334 skipVertical(contourList, ¤t, indexPtr, endIndexPtr); |
|
335 |
|
336 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0); |
|
337 tryAgain = false; |
|
338 contourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endIndexPtr, &tHit, |
|
339 &hitDx, &tryAgain, false); |
|
340 if (tryAgain) { |
|
341 continue; |
|
342 } |
|
343 if (angleIncludeType < SkOpAngle::kBinarySingle) { |
|
344 break; |
|
345 } |
|
346 oppContourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endIndexPtr, &tHit, |
|
347 &hitOppDx, &tryAgain, true); |
|
348 } while (tryAgain); |
|
349 current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWinding, hitDx, oppContourWinding, |
|
350 hitOppDx); |
|
351 return current; |
|
352 } |
|
353 |
|
354 static void checkEnds(SkTArray<SkOpContour*, true>* contourList) { |
|
355 // it's hard to determine if the end of a cubic or conic nearly intersects another curve. |
|
356 // instead, look to see if the connecting curve intersected at that same end. |
|
357 int contourCount = (*contourList).count(); |
|
358 for (int cTest = 0; cTest < contourCount; ++cTest) { |
|
359 SkOpContour* contour = (*contourList)[cTest]; |
|
360 contour->checkEnds(); |
|
361 } |
|
362 } |
|
363 |
|
364 // A tiny interval may indicate an undiscovered coincidence. Find and fix. |
|
365 static void checkTiny(SkTArray<SkOpContour*, true>* contourList) { |
|
366 int contourCount = (*contourList).count(); |
|
367 for (int cTest = 0; cTest < contourCount; ++cTest) { |
|
368 SkOpContour* contour = (*contourList)[cTest]; |
|
369 contour->checkTiny(); |
|
370 } |
|
371 } |
|
372 |
|
373 static void fixOtherTIndex(SkTArray<SkOpContour*, true>* contourList) { |
|
374 int contourCount = (*contourList).count(); |
|
375 for (int cTest = 0; cTest < contourCount; ++cTest) { |
|
376 SkOpContour* contour = (*contourList)[cTest]; |
|
377 contour->fixOtherTIndex(); |
|
378 } |
|
379 } |
|
380 |
|
381 static void joinCoincidence(SkTArray<SkOpContour*, true>* contourList) { |
|
382 int contourCount = (*contourList).count(); |
|
383 for (int cTest = 0; cTest < contourCount; ++cTest) { |
|
384 SkOpContour* contour = (*contourList)[cTest]; |
|
385 contour->joinCoincidence(); |
|
386 } |
|
387 } |
|
388 |
|
389 static void sortSegments(SkTArray<SkOpContour*, true>* contourList) { |
|
390 int contourCount = (*contourList).count(); |
|
391 for (int cTest = 0; cTest < contourCount; ++cTest) { |
|
392 SkOpContour* contour = (*contourList)[cTest]; |
|
393 contour->sortSegments(); |
|
394 } |
|
395 } |
|
396 |
|
397 void MakeContourList(SkTArray<SkOpContour>& contours, SkTArray<SkOpContour*, true>& list, |
|
398 bool evenOdd, bool oppEvenOdd) { |
|
399 int count = contours.count(); |
|
400 if (count == 0) { |
|
401 return; |
|
402 } |
|
403 for (int index = 0; index < count; ++index) { |
|
404 SkOpContour& contour = contours[index]; |
|
405 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd); |
|
406 list.push_back(&contour); |
|
407 } |
|
408 SkTQSort<SkOpContour>(list.begin(), list.end() - 1); |
|
409 } |
|
410 |
|
411 class DistanceLessThan { |
|
412 public: |
|
413 DistanceLessThan(double* distances) : fDistances(distances) { } |
|
414 double* fDistances; |
|
415 bool operator()(const int one, const int two) { |
|
416 return fDistances[one] < fDistances[two]; |
|
417 } |
|
418 }; |
|
419 |
|
420 /* |
|
421 check start and end of each contour |
|
422 if not the same, record them |
|
423 match them up |
|
424 connect closest |
|
425 reassemble contour pieces into new path |
|
426 */ |
|
427 void Assemble(const SkPathWriter& path, SkPathWriter* simple) { |
|
428 #if DEBUG_PATH_CONSTRUCTION |
|
429 SkDebugf("%s\n", __FUNCTION__); |
|
430 #endif |
|
431 SkTArray<SkOpContour> contours; |
|
432 SkOpEdgeBuilder builder(path, contours); |
|
433 builder.finish(); |
|
434 int count = contours.count(); |
|
435 int outer; |
|
436 SkTArray<int, true> runs(count); // indices of partial contours |
|
437 for (outer = 0; outer < count; ++outer) { |
|
438 const SkOpContour& eContour = contours[outer]; |
|
439 const SkPoint& eStart = eContour.start(); |
|
440 const SkPoint& eEnd = eContour.end(); |
|
441 #if DEBUG_ASSEMBLE |
|
442 SkDebugf("%s contour", __FUNCTION__); |
|
443 if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) { |
|
444 SkDebugf("[%d]", runs.count()); |
|
445 } else { |
|
446 SkDebugf(" "); |
|
447 } |
|
448 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n", |
|
449 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY); |
|
450 #endif |
|
451 if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) { |
|
452 eContour.toPath(simple); |
|
453 continue; |
|
454 } |
|
455 runs.push_back(outer); |
|
456 } |
|
457 count = runs.count(); |
|
458 if (count == 0) { |
|
459 return; |
|
460 } |
|
461 SkTArray<int, true> sLink, eLink; |
|
462 sLink.push_back_n(count); |
|
463 eLink.push_back_n(count); |
|
464 int rIndex, iIndex; |
|
465 for (rIndex = 0; rIndex < count; ++rIndex) { |
|
466 sLink[rIndex] = eLink[rIndex] = SK_MaxS32; |
|
467 } |
|
468 const int ends = count * 2; // all starts and ends |
|
469 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2 |
|
470 SkTArray<double, true> distances; |
|
471 distances.push_back_n(entries); |
|
472 for (rIndex = 0; rIndex < ends - 1; ++rIndex) { |
|
473 outer = runs[rIndex >> 1]; |
|
474 const SkOpContour& oContour = contours[outer]; |
|
475 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start(); |
|
476 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2) |
|
477 * ends - rIndex - 1; |
|
478 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) { |
|
479 int inner = runs[iIndex >> 1]; |
|
480 const SkOpContour& iContour = contours[inner]; |
|
481 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start(); |
|
482 double dx = iPt.fX - oPt.fX; |
|
483 double dy = iPt.fY - oPt.fY; |
|
484 double dist = dx * dx + dy * dy; |
|
485 distances[row + iIndex] = dist; // oStart distance from iStart |
|
486 } |
|
487 } |
|
488 SkTArray<int, true> sortedDist; |
|
489 sortedDist.push_back_n(entries); |
|
490 for (rIndex = 0; rIndex < entries; ++rIndex) { |
|
491 sortedDist[rIndex] = rIndex; |
|
492 } |
|
493 SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(distances.begin())); |
|
494 int remaining = count; // number of start/end pairs |
|
495 for (rIndex = 0; rIndex < entries; ++rIndex) { |
|
496 int pair = sortedDist[rIndex]; |
|
497 int row = pair / ends; |
|
498 int col = pair - row * ends; |
|
499 int thingOne = row < col ? row : ends - row - 2; |
|
500 int ndxOne = thingOne >> 1; |
|
501 bool endOne = thingOne & 1; |
|
502 int* linkOne = endOne ? eLink.begin() : sLink.begin(); |
|
503 if (linkOne[ndxOne] != SK_MaxS32) { |
|
504 continue; |
|
505 } |
|
506 int thingTwo = row < col ? col : ends - row + col - 1; |
|
507 int ndxTwo = thingTwo >> 1; |
|
508 bool endTwo = thingTwo & 1; |
|
509 int* linkTwo = endTwo ? eLink.begin() : sLink.begin(); |
|
510 if (linkTwo[ndxTwo] != SK_MaxS32) { |
|
511 continue; |
|
512 } |
|
513 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]); |
|
514 bool flip = endOne == endTwo; |
|
515 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo; |
|
516 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne; |
|
517 if (!--remaining) { |
|
518 break; |
|
519 } |
|
520 } |
|
521 SkASSERT(!remaining); |
|
522 #if DEBUG_ASSEMBLE |
|
523 for (rIndex = 0; rIndex < count; ++rIndex) { |
|
524 int s = sLink[rIndex]; |
|
525 int e = eLink[rIndex]; |
|
526 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e', |
|
527 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e); |
|
528 } |
|
529 #endif |
|
530 rIndex = 0; |
|
531 do { |
|
532 bool forward = true; |
|
533 bool first = true; |
|
534 int sIndex = sLink[rIndex]; |
|
535 SkASSERT(sIndex != SK_MaxS32); |
|
536 sLink[rIndex] = SK_MaxS32; |
|
537 int eIndex; |
|
538 if (sIndex < 0) { |
|
539 eIndex = sLink[~sIndex]; |
|
540 sLink[~sIndex] = SK_MaxS32; |
|
541 } else { |
|
542 eIndex = eLink[sIndex]; |
|
543 eLink[sIndex] = SK_MaxS32; |
|
544 } |
|
545 SkASSERT(eIndex != SK_MaxS32); |
|
546 #if DEBUG_ASSEMBLE |
|
547 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e', |
|
548 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e', |
|
549 eIndex < 0 ? ~eIndex : eIndex); |
|
550 #endif |
|
551 do { |
|
552 outer = runs[rIndex]; |
|
553 const SkOpContour& contour = contours[outer]; |
|
554 if (first) { |
|
555 first = false; |
|
556 const SkPoint* startPtr = &contour.start(); |
|
557 simple->deferredMove(startPtr[0]); |
|
558 } |
|
559 if (forward) { |
|
560 contour.toPartialForward(simple); |
|
561 } else { |
|
562 contour.toPartialBackward(simple); |
|
563 } |
|
564 #if DEBUG_ASSEMBLE |
|
565 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex, |
|
566 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex, |
|
567 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)); |
|
568 #endif |
|
569 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) { |
|
570 simple->close(); |
|
571 break; |
|
572 } |
|
573 if (forward) { |
|
574 eIndex = eLink[rIndex]; |
|
575 SkASSERT(eIndex != SK_MaxS32); |
|
576 eLink[rIndex] = SK_MaxS32; |
|
577 if (eIndex >= 0) { |
|
578 SkASSERT(sLink[eIndex] == rIndex); |
|
579 sLink[eIndex] = SK_MaxS32; |
|
580 } else { |
|
581 SkASSERT(eLink[~eIndex] == ~rIndex); |
|
582 eLink[~eIndex] = SK_MaxS32; |
|
583 } |
|
584 } else { |
|
585 eIndex = sLink[rIndex]; |
|
586 SkASSERT(eIndex != SK_MaxS32); |
|
587 sLink[rIndex] = SK_MaxS32; |
|
588 if (eIndex >= 0) { |
|
589 SkASSERT(eLink[eIndex] == rIndex); |
|
590 eLink[eIndex] = SK_MaxS32; |
|
591 } else { |
|
592 SkASSERT(sLink[~eIndex] == ~rIndex); |
|
593 sLink[~eIndex] = SK_MaxS32; |
|
594 } |
|
595 } |
|
596 rIndex = eIndex; |
|
597 if (rIndex < 0) { |
|
598 forward ^= 1; |
|
599 rIndex = ~rIndex; |
|
600 } |
|
601 } while (true); |
|
602 for (rIndex = 0; rIndex < count; ++rIndex) { |
|
603 if (sLink[rIndex] != SK_MaxS32) { |
|
604 break; |
|
605 } |
|
606 } |
|
607 } while (rIndex < count); |
|
608 #if DEBUG_ASSEMBLE |
|
609 for (rIndex = 0; rIndex < count; ++rIndex) { |
|
610 SkASSERT(sLink[rIndex] == SK_MaxS32); |
|
611 SkASSERT(eLink[rIndex] == SK_MaxS32); |
|
612 } |
|
613 #endif |
|
614 } |
|
615 |
|
616 void HandleCoincidence(SkTArray<SkOpContour*, true>* contourList, int total) { |
|
617 #if DEBUG_SHOW_WINDING |
|
618 SkOpContour::debugShowWindingValues(contourList); |
|
619 #endif |
|
620 CoincidenceCheck(contourList, total); |
|
621 #if DEBUG_SHOW_WINDING |
|
622 SkOpContour::debugShowWindingValues(contourList); |
|
623 #endif |
|
624 fixOtherTIndex(contourList); |
|
625 checkEnds(contourList); |
|
626 checkTiny(contourList); |
|
627 joinCoincidence(contourList); |
|
628 sortSegments(contourList); |
|
629 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY |
|
630 DebugShowActiveSpans(*contourList); |
|
631 #endif |
|
632 } |