Index: src/pathops/SkOpSpan.cpp |
diff --git a/src/pathops/SkOpSpan.cpp b/src/pathops/SkOpSpan.cpp |
index 98165fcfc53c08458d942dfddff78c9a58e468d2..162bcad2937b74aa5e62b0999a499acf6fbee588 100755 |
--- a/src/pathops/SkOpSpan.cpp |
+++ b/src/pathops/SkOpSpan.cpp |
@@ -13,6 +13,21 @@ bool SkOpPtT::alias() const { |
return this->span()->ptT() != this; |
} |
+const SkOpPtT* SkOpPtT::active() const { |
+ if (!fDeleted) { |
+ return this; |
+ } |
+ const SkOpPtT* ptT = this; |
+ const SkOpPtT* stopPtT = ptT; |
+ while ((ptT = ptT->next()) != stopPtT) { |
+ if (ptT->fSpan == fSpan && !ptT->fDeleted) { |
+ return ptT; |
+ } |
+ } |
+ SkASSERT(0); // should never return deleted |
+ return this; |
+} |
+ |
bool SkOpPtT::collapsed(const SkOpPtT* check) const { |
if (fPt != check->fPt) { |
return false; |
@@ -177,27 +192,14 @@ void SkOpPtT::setDeleted() { |
fDeleted = true; |
} |
-// please keep this in sync with debugAddOppAndMerge |
-// If the added points envelop adjacent spans, merge them in. |
-void SkOpSpanBase::addOppAndMerge(SkOpSpanBase* opp) { |
+void SkOpSpanBase::addOpp(SkOpSpanBase* opp) { |
SkOpPtT* oppPrev = this->ptT()->oppPrev(opp->ptT()); |
- if (oppPrev) { |
- this->ptT()->addOpp(opp->ptT(), oppPrev); |
- this->checkForCollapsedCoincidence(); |
- } |
- // compute bounds of points in span |
- SkPathOpsBounds bounds; |
- bounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin); |
- const SkOpPtT* head = this->ptT(); |
- const SkOpPtT* nextPt = head; |
- do { |
- bounds.add(nextPt->fPt); |
- } while ((nextPt = nextPt->next()) != head); |
- if (!bounds.width() && !bounds.height()) { |
+ if (!oppPrev) { |
return; |
} |
- this->mergeContained(bounds); |
- opp->mergeContained(bounds); |
+ this->mergeMatches(opp); |
+ this->ptT()->addOpp(opp->ptT(), oppPrev); |
+ this->checkForCollapsedCoincidence(); |
} |
// Please keep this in sync with debugMergeContained() |
@@ -206,37 +208,39 @@ void SkOpSpanBase::mergeContained(const SkPathOpsBounds& bounds) { |
SkOpSpanBase* prev = this; |
SkOpSegment* seg = this->segment(); |
while ((prev = prev->prev()) && bounds.contains(prev->pt()) && !seg->ptsDisjoint(prev, this)) { |
- if (prev->prev()) { |
- this->merge(prev->upCast()); |
- prev = this; |
- } else if (this->final()) { |
- seg->clearAll(); |
- return; |
- } else { |
- prev->merge(this->upCast()); |
- } |
+ this->mergeMatches(prev); |
+ this->addOpp(prev); |
} |
- SkOpSpanBase* current = this; |
SkOpSpanBase* next = this; |
while (next->upCastable() && (next = next->upCast()->next()) |
&& bounds.contains(next->pt()) && !seg->ptsDisjoint(this, next)) { |
- if (!current->prev() && next->final()) { |
- seg->clearAll(); |
- return; |
- } |
- if (current->prev()) { |
- next->merge(current->upCast()); |
- current = next; |
- } else { |
- current->merge(next->upCast()); |
- // extra line in debug version |
- } |
+ this->mergeMatches(next); |
+ this->addOpp(next); |
} |
#if DEBUG_COINCIDENCE |
this->globalState()->coincidence()->debugValidate(); |
#endif |
} |
+bool SkOpSpanBase::collapsed(double s, double e) const { |
+ const SkOpPtT* start = &fPtT; |
+ const SkOpPtT* walk = start; |
+ double min = walk->fT; |
+ double max = min; |
+ const SkOpSegment* segment = this->segment(); |
+ while ((walk = walk->next()) != start) { |
+ if (walk->segment() != segment) { |
+ continue; |
+ } |
+ min = SkTMin(min, walk->fT); |
+ max = SkTMax(max, walk->fT); |
+ if (between(min, s, max) && between(min, e, max)) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
bool SkOpSpanBase::contains(const SkOpSpanBase* span) const { |
const SkOpPtT* start = &fPtT; |
const SkOpPtT* check = &span->fPtT; |
@@ -294,7 +298,7 @@ void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, cons |
fChased = false; |
SkDEBUGCODE(fCount = 1); |
SkDEBUGCODE(fID = globalState()->nextSpanID()); |
- SkDEBUGCODE(fDeleted = false); |
+ SkDEBUGCODE(fDebugDeleted = false); |
} |
// this pair of spans share a common t value or point; merge them and eliminate duplicates |
@@ -305,6 +309,7 @@ void SkOpSpanBase::merge(SkOpSpan* span) { |
SkASSERT(!zero_or_one(spanPtT->fT)); |
span->release(this->ptT()); |
if (this->contains(span)) { |
+ SkOPASSERT(0); // check to see if this ever happens -- should have been found earlier |
return; // merge is already in the ptT loop |
} |
SkOpPtT* remainder = spanPtT->next(); |
@@ -324,7 +329,12 @@ tryNextRemainder: |
remainder = next; |
} |
fSpanAdds += span->fSpanAdds; |
- this->checkForCollapsedCoincidence(); |
+} |
+ |
+SkOpSpanBase* SkOpSpanBase::active() { |
+ SkOpSpanBase* result = fPrev ? fPrev->next() : upCast()->next()->prev(); |
+ SkASSERT(this == result || fDebugDeleted); |
+ return result; |
} |
// please keep in sync with debugCheckForCollapsedCoincidence() |
@@ -344,6 +354,73 @@ void SkOpSpanBase::checkForCollapsedCoincidence() { |
} |
coins->markCollapsed(test); |
} while ((test = test->next()) != head); |
+ coins->releaseDeleted(); |
+} |
+ |
+// 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 { |
+ SkASSERT(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(); |
} |
int SkOpSpan::computeWindSum() { |
@@ -413,7 +490,7 @@ bool SkOpSpan::insertCoincidence(const SkOpSegment* segment, bool flipped) { |
} |
void SkOpSpan::release(const SkOpPtT* kept) { |
- SkDEBUGCODE(fDeleted = true); |
+ SkDEBUGCODE(fDebugDeleted = true); |
SkASSERT(kept->span() != this); |
SkASSERT(!final()); |
SkOpSpan* prev = this->prev(); |