void SkOpSpan::release(const SkOpPtT* kept) { SkDEBUGCODE(fDebugDeleted = true); SkOPASSERT(kept->span() != this); SkASSERT(!final()); SkOpSpan* prev = this->prev(); SkASSERT(prev); SkOpSpanBase* next = this->next(); SkASSERT(next); prev->setNext(next); next->setPrev(prev); this->segment()->release(this); SkOpCoincidence* coincidence = this->globalState()->coincidence(); if (coincidence) { coincidence->fixUp(this->ptT(), kept); } this->ptT()->setDeleted(); SkOpPtT* stopPtT = this->ptT(); SkOpPtT* testPtT = stopPtT; const SkOpSpanBase* keptSpan = kept->span(); do { if (this == testPtT->span()) { testPtT->setSpan(keptSpan); } } while ((testPtT = testPtT->next()) != stopPtT); }
// Please keep this in sync with debugInsertCoincidence() bool SkOpSpan::insertCoincidence(const SkOpSegment* segment, bool flipped, bool ordered) { if (this->containsCoincidence(segment)) { return true; } SkOpPtT* next = &fPtT; while ((next = next->next()) != &fPtT) { if (next->segment() == segment) { SkOpSpan* span; SkOpSpanBase* base = next->span(); if (!ordered) { const SkOpPtT* spanEndPtT = fNext->contains(segment); FAIL_IF(!spanEndPtT); const SkOpSpanBase* spanEnd = spanEndPtT->span(); const SkOpPtT* start = base->ptT()->starter(spanEnd->ptT()); FAIL_IF(!start->span()->upCastable()); span = const_cast<SkOpSpan*>(start->span()->upCast()); } else if (flipped) { span = base->prev(); FAIL_IF(!span); } else { FAIL_IF(!base->upCastable()); span = base->upCast(); } this->insertCoincidence(span); return true; } } #if DEBUG_COINCIDENCE SkASSERT(0); // FIXME? if we get here, the span is missing its opposite segment... #endif return true; }
const SkOpAngle* AngleWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* windingPtr, bool* sortablePtr) { // find first angle, initialize winding to computed fWindSum SkOpSegment* segment = start->segment(); const SkOpAngle* angle = segment->spanToAngle(start, end); if (!angle) { *windingPtr = SK_MinS32; return nullptr; } bool computeWinding = false; const SkOpAngle* firstAngle = angle; bool loop = false; bool unorderable = false; int winding = SK_MinS32; do { angle = angle->next(); if (!angle) { return nullptr; } unorderable |= angle->unorderable(); if ((computeWinding = unorderable || (angle == firstAngle && loop))) { break; // if we get here, there's no winding, loop is unorderable } loop |= angle == firstAngle; segment = angle->segment(); winding = segment->windSum(angle); } while (winding == SK_MinS32); // if the angle loop contains an unorderable span, the angle order may be useless // directly compute the winding in this case for each span if (computeWinding) { firstAngle = angle; winding = SK_MinS32; do { SkOpSpanBase* startSpan = angle->start(); SkOpSpanBase* endSpan = angle->end(); SkOpSpan* lesser = startSpan->starter(endSpan); int testWinding = lesser->windSum(); if (testWinding == SK_MinS32) { testWinding = lesser->computeWindSum(); } if (testWinding != SK_MinS32) { segment = angle->segment(); winding = testWinding; } angle = angle->next(); } while (angle != firstAngle); } *sortablePtr = !unorderable; *windingPtr = winding; return angle; }
// please keep in sync with debugMergeMatches() // Look to see if pt-t linked list contains same segment more than once // if so, and if each pt-t is directly pointed to by spans in that segment, // merge them // keep the points, but remove spans so that the segment doesn't have 2 or more // spans pointing to the same pt-t loop at different loop elements void SkOpSpanBase::mergeMatches(SkOpSpanBase* opp) { SkOpPtT* test = &fPtT; SkOpPtT* testNext; const SkOpPtT* stop = test; do { testNext = test->next(); if (test->deleted()) { continue; } SkOpSpanBase* testBase = test->span(); SkASSERT(testBase->ptT() == test); SkOpSegment* segment = test->segment(); if (segment->done()) { continue; } SkOpPtT* inner = opp->ptT(); const SkOpPtT* innerStop = inner; do { if (inner->segment() != segment) { continue; } if (inner->deleted()) { continue; } SkOpSpanBase* innerBase = inner->span(); SkASSERT(innerBase->ptT() == inner); // when the intersection is first detected, the span base is marked if there are // more than one point in the intersection. if (!zero_or_one(inner->fT)) { innerBase->upCast()->release(test); } else { SkOPASSERT(inner->fT != test->fT); if (!zero_or_one(test->fT)) { testBase->upCast()->release(inner); } else { segment->markAllDone(); // mark segment as collapsed SkDEBUGCODE(testBase->debugSetDeleted()); test->setDeleted(); SkDEBUGCODE(innerBase->debugSetDeleted()); inner->setDeleted(); } } #ifdef SK_DEBUG // assert if another undeleted entry points to segment const SkOpPtT* debugInner = inner; while ((debugInner = debugInner->next()) != innerStop) { if (debugInner->segment() != segment) { continue; } if (debugInner->deleted()) { continue; } SkOPASSERT(0); } #endif break; } while ((inner = inner->next()) != innerStop); } while ((test = testNext) != stop); this->checkForCollapsedCoincidence(); }
SkOpSegment* SkOpContour::nonVerticalSegment(SkOpSpanBase** start, SkOpSpanBase** end) { int segmentCount = fSortedSegments.count(); SkASSERT(segmentCount > 0); for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) { SkOpSegment* testSegment = fSortedSegments[sortedIndex]; if (testSegment->done()) { continue; } SkOpSpanBase* span = testSegment->head(); SkOpSpanBase* testS, * testE; while (SkOpSegment::NextCandidate(span, &testS, &testE)) { if (!testSegment->isVertical(testS, testE)) { *start = testS; *end = testE; return testSegment; } span = span->upCast()->next(); } } return NULL; }
SkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr, SkOpSpanBase** endPtr) { while (chase->count()) { SkOpSpanBase* span; chase->pop(&span); SkOpSegment* segment = span->segment(); *startPtr = span->ptT()->next()->span(); bool done = true; *endPtr = nullptr; if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr, &done)) { *startPtr = last->start(); *endPtr = last->end(); #if TRY_ROTATE *chase->insert(0) = span; #else *chase->append() = span; #endif return last->segment(); } if (done) { continue; } // find first angle, initialize winding to computed wind sum int winding; bool sortable; const SkOpAngle* angle = AngleWinding(*startPtr, *endPtr, &winding, &sortable); if (winding == SK_MinS32) { continue; } int sumWinding SK_INIT_TO_AVOID_WARNING; if (sortable) { segment = angle->segment(); sumWinding = segment->updateWindingReverse(angle); } SkOpSegment* first = nullptr; const SkOpAngle* firstAngle = angle; while ((angle = angle->next()) != firstAngle) { segment = angle->segment(); SkOpSpanBase* start = angle->start(); SkOpSpanBase* end = angle->end(); int maxWinding; if (sortable) { segment->setUpWinding(start, end, &maxWinding, &sumWinding); } if (!segment->done(angle)) { if (!first && (sortable || start->starter(end)->windSum() != SK_MinS32)) { first = segment; *startPtr = start; *endPtr = end; } // OPTIMIZATION: should this also add to the chase? if (sortable) { (void) segment->markAngle(maxWinding, sumWinding, angle); } } } if (first) { #if TRY_ROTATE *chase->insert(0) = span; #else *chase->append() = span; #endif return first; } } return nullptr; }