SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList, SkOpAngle::IncludeType angleIncludeType, bool* firstContour, int* indexPtr, int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool* onlyVertical, bool firstPass) { SkOpSegment* current = findTopSegment(contourList, indexPtr, endIndexPtr, topLeft, unsortable, done, firstPass); if (!current) { return NULL; } const int startIndex = *indexPtr; const int endIndex = *endIndexPtr; if (*firstContour) { current->initWinding(startIndex, endIndex, angleIncludeType); *firstContour = false; return current; } int minIndex = SkMin32(startIndex, endIndex); int sumWinding = current->windSum(minIndex); if (sumWinding == SK_MinS32) { int index = endIndex; int oIndex = startIndex; do { const SkOpSpan& span = current->span(index); if ((oIndex < index ? span.fFromAngle : span.fToAngle) == NULL) { current->addSimpleAngle(index); } sumWinding = current->computeSum(oIndex, index, angleIncludeType); SkTSwap(index, oIndex); } while (sumWinding == SK_MinS32 && index == startIndex); } if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) { return current; } int contourWinding; int oppContourWinding = 0; // the simple upward projection of the unresolved points hit unsortable angles // shoot rays at right angles to the segment to find its winding, ignoring angle cases bool tryAgain; double tHit; SkScalar hitDx = 0; SkScalar hitOppDx = 0; // keep track of subsequent returns to detect infinite loops SkTDArray<SortableTop> sortableTops; do { // if current is vertical, find another candidate which is not // if only remaining candidates are vertical, then they can be marked done SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0); skipVertical(contourList, ¤t, indexPtr, endIndexPtr); SkASSERT(current); // FIXME: if null, all remaining are vertical SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0); tryAgain = false; contourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endIndexPtr, &tHit, &hitDx, &tryAgain, onlyVertical, false); if (tryAgain) { bool giveUp = false; int count = sortableTops.count(); for (int index = 0; index < count; ++index) { const SortableTop& prev = sortableTops[index]; if (giveUp) { prev.fSegment->markDoneFinal(prev.fIndex); } else if (prev.fSegment == current && (prev.fIndex == *indexPtr || prev.fEndIndex == *endIndexPtr)) { // remaining edges are non-vertical and cannot have their winding computed // mark them as done and return, and hope that assembly can fill the holes giveUp = true; index = -1; } } if (giveUp) { *done = true; return NULL; } } SortableTop* sortableTop = sortableTops.append(); sortableTop->fSegment = current; sortableTop->fIndex = *indexPtr; sortableTop->fEndIndex = *endIndexPtr; #if DEBUG_SORT SkDebugf("%s current=%d index=%d endIndex=%d tHit=%1.9g hitDx=%1.9g try=%d vert=%d\n", __FUNCTION__, current->debugID(), *indexPtr, *endIndexPtr, tHit, hitDx, tryAgain, *onlyVertical); #endif if (*onlyVertical) { return current; } if (tryAgain) { continue; } if (angleIncludeType < SkOpAngle::kBinarySingle) { break; } oppContourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endIndexPtr, &tHit, &hitOppDx, &tryAgain, NULL, true); } while (tryAgain); bool success = current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx); if (current->done()) { return NULL; } else if (!success) { // check if the span has a valid winding int min = SkTMin(*indexPtr, *endIndexPtr); const SkOpSpan& span = current->span(min); if (span.fWindSum == SK_MinS32) { return NULL; } } return current; }
SkOpSegment* FindChase(SkTDArray<SkOpSpan*>& chase, int& tIndex, int& endIndex) { while (chase.count()) { SkOpSpan* span; chase.pop(&span); const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex); SkOpSegment* segment = backPtr.fOther; tIndex = backPtr.fOtherIndex; SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; int done = 0; if (segment->activeAngle(tIndex, &done, &angles)) { SkOpAngle* last = angles.end() - 1; tIndex = last->start(); endIndex = last->end(); #if TRY_ROTATE *chase.insert(0) = span; #else *chase.append() = span; #endif return last->segment(); } if (done == angles.count()) { continue; } SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; bool sortable = SkOpSegment::SortAngles(angles, &sorted, SkOpSegment::kMayBeUnordered_SortAngleKind); int angleCount = sorted.count(); #if DEBUG_SORT sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0, sortable); #endif if (!sortable) { continue; } // find first angle, initialize winding to computed fWindSum int firstIndex = -1; const SkOpAngle* angle; int winding; do { angle = sorted[++firstIndex]; segment = angle->segment(); winding = segment->windSum(angle); } while (winding == SK_MinS32); int spanWinding = segment->spanSign(angle->start(), angle->end()); #if DEBUG_WINDING SkDebugf("%s winding=%d spanWinding=%d\n", __FUNCTION__, winding, spanWinding); #endif // turn span winding into contour winding if (spanWinding * winding < 0) { winding += spanWinding; } #if DEBUG_SORT segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0, sortable); #endif // we care about first sign and whether wind sum indicates this // edge is inside or outside. Maybe need to pass span winding // or first winding or something into this function? // advance to first undone angle, then return it and winding // (to set whether edges are active or not) int nextIndex = firstIndex + 1; int lastIndex = firstIndex != 0 ? firstIndex : angleCount; angle = sorted[firstIndex]; winding -= angle->segment()->spanSign(angle); do { SkASSERT(nextIndex != firstIndex); if (nextIndex == angleCount) { nextIndex = 0; } angle = sorted[nextIndex]; segment = angle->segment(); int maxWinding = winding; winding -= segment->spanSign(angle); #if DEBUG_SORT SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__, segment->debugID(), maxWinding, winding, angle->sign()); #endif tIndex = angle->start(); endIndex = angle->end(); int lesser = SkMin32(tIndex, endIndex); const SkOpSpan& nextSpan = segment->span(lesser); if (!nextSpan.fDone) { // FIXME: this be wrong? assign startWinding if edge is in // same direction. If the direction is opposite, winding to // assign is flipped sign or +/- 1? if (SkOpSegment::UseInnerWinding(maxWinding, winding)) { maxWinding = winding; } segment->markAndChaseWinding(angle, maxWinding, 0); break; } } while (++nextIndex != lastIndex); *chase.insert(0) = span; return segment; } return NULL; }
SkOpSegment* FindChase(SkTDArray<SkOpSpan*>* chase, int* tIndex, int* endIndex) { while (chase->count()) { SkOpSpan* span; chase->pop(&span); const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex); SkOpSegment* segment = backPtr.fOther; *tIndex = backPtr.fOtherIndex; bool sortable = true; bool done = true; *endIndex = -1; if (const SkOpAngle* last = segment->activeAngle(*tIndex, tIndex, endIndex, &done, &sortable)) { *tIndex = last->start(); *endIndex = last->end(); #if TRY_ROTATE *chase->insert(0) = span; #else *chase->append() = span; #endif return last->segment(); } if (done) { continue; } if (!sortable) { continue; } // find first angle, initialize winding to computed wind sum const SkOpAngle* angle = segment->spanToAngle(*tIndex, *endIndex); const SkOpAngle* firstAngle; SkDEBUGCODE(firstAngle = angle); SkDEBUGCODE(bool loop = false); int winding; do { angle = angle->next(); SkASSERT(angle != firstAngle || !loop); SkDEBUGCODE(loop |= angle == firstAngle); segment = angle->segment(); winding = segment->windSum(angle); } while (winding == SK_MinS32); int spanWinding = segment->spanSign(angle->start(), angle->end()); #if DEBUG_WINDING SkDebugf("%s winding=%d spanWinding=%d\n", __FUNCTION__, winding, spanWinding); #endif // turn span winding into contour winding if (spanWinding * winding < 0) { winding += spanWinding; } // we care about first sign and whether wind sum indicates this // edge is inside or outside. Maybe need to pass span winding // or first winding or something into this function? // advance to first undone angle, then return it and winding // (to set whether edges are active or not) firstAngle = angle; winding -= firstAngle->segment()->spanSign(firstAngle); while ((angle = angle->next()) != firstAngle) { segment = angle->segment(); int maxWinding = winding; winding -= segment->spanSign(angle); #if DEBUG_SORT SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__, segment->debugID(), maxWinding, winding, angle->sign()); #endif *tIndex = angle->start(); *endIndex = angle->end(); int lesser = SkMin32(*tIndex, *endIndex); const SkOpSpan& nextSpan = segment->span(lesser); if (!nextSpan.fDone) { // FIXME: this be wrong? assign startWinding if edge is in // same direction. If the direction is opposite, winding to // assign is flipped sign or +/- 1? if (SkOpSegment::UseInnerWinding(maxWinding, winding)) { maxWinding = winding; } // allowed to do nothing (void) segment->markAndChaseWinding(angle, maxWinding, 0, NULL); break; } } *chase->insert(0) = span; return segment; } return NULL; }