Index: src/pathops/SkOpSegment.cpp |
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp |
index de813cb7c9c3ba022b1b6f4331124d462109f1b4..01417d6b8f492257c8bca934e1a55dc756320a5a 100644 |
--- a/src/pathops/SkOpSegment.cpp |
+++ b/src/pathops/SkOpSegment.cpp |
@@ -43,18 +43,18 @@ static const bool gActiveEdge[kXOR_SkPathOp + 1][2][2][2][2] = { |
#undef T |
SkOpAngle* SkOpSegment::activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr, |
- SkOpSpanBase** endPtr, bool* done, bool* sortable) { |
- if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done, sortable)) { |
+ SkOpSpanBase** endPtr, bool* done) { |
+ if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done)) { |
return result; |
} |
- if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done, sortable)) { |
+ if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done)) { |
return result; |
} |
return NULL; |
} |
SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** startPtr, |
- SkOpSpanBase** endPtr, bool* done, bool* sortable) { |
+ SkOpSpanBase** endPtr, bool* done) { |
SkOpSpan* upSpan = start->upCastable(); |
if (upSpan) { |
if (upSpan->windValue() || upSpan->oppValue()) { |
@@ -95,11 +95,11 @@ SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** sta |
} |
SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** startPtr, |
- SkOpSpanBase** endPtr, bool* done, bool* sortable) { |
+ SkOpSpanBase** endPtr, bool* done) { |
SkOpPtT* oPtT = start->ptT()->next(); |
SkOpSegment* other = oPtT->segment(); |
SkOpSpanBase* oSpan = oPtT->span(); |
- return other->activeAngleInner(oSpan, startPtr, endPtr, done, sortable); |
+ return other->activeAngleInner(oSpan, startPtr, endPtr, done); |
} |
bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xorSuMask, |
@@ -311,6 +311,14 @@ void SkOpSegment::align() { |
if (!span->aligned()) { |
span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]); |
} |
+ if (this->collapsed()) { |
+ SkOpSpan* span = &fHead; |
+ do { |
+ span->setWindValue(0); |
+ span->setOppValue(0); |
+ this->markDone(span); |
+ } while ((span = span->next()->upCastable())); |
+ } |
debugValidate(); |
} |
@@ -363,6 +371,10 @@ void SkOpSegment::checkAngleCoin(SkOpCoincidence* coincidences, SkChunkAlloc* al |
} while ((base = span->next())); |
} |
+bool SkOpSegment::collapsed() const { |
+ return fVerb == SkPath::kLine_Verb && fHead.pt() == fTail.pt(); |
+} |
+ |
void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, |
SkOpAngle::IncludeType includeType) { |
SkOpSegment* baseSegment = baseAngle->segment(); |
@@ -1078,7 +1090,7 @@ SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS |
return other; |
} |
-static void clear_visited(SkOpSpan* span) { |
+static void clear_visited(SkOpSpanBase* span) { |
// reset visited flag back to false |
do { |
SkOpPtT* ptT = span->ptT(), * stopPtT = ptT; |
@@ -1086,7 +1098,7 @@ static void clear_visited(SkOpSpan* span) { |
SkOpSegment* opp = ptT->segment(); |
opp->resetVisited(); |
} |
- } while ((span = span->next()->upCastable())); |
+ } while (!span->final() && (span = span->upCast()->next())); |
} |
// look for pairs of undetected coincident curves |
@@ -1098,50 +1110,59 @@ void SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc |
if (this->verb() != SkPath::kLine_Verb) { |
return; |
} |
+ if (this->done()) { |
+ return; |
+ } |
SkOpSpan* prior = NULL; |
- SkOpSpan* span = &fHead; |
+ SkOpSpanBase* spanBase = &fHead; |
do { |
- SkOpPtT* ptT = span->ptT(), * spanStopPtT = ptT; |
- SkASSERT(ptT->span() == span); |
+ SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT; |
+ SkASSERT(ptT->span() == spanBase); |
while ((ptT = ptT->next()) != spanStopPtT) { |
SkOpSegment* opp = ptT->span()->segment(); |
- if (!opp->setVisited()) { |
+ if (opp->verb() == SkPath::kLine_Verb) { |
continue; |
} |
- if (opp->verb() == SkPath::kLine_Verb) { |
+ if (opp->done()) { |
continue; |
} |
- if (span->containsCoincidence(opp)) { // FIXME: this assumes that if the opposite |
- // segment is coincident then no more coincidence |
- // needs to be detected. This may not be true. |
+ // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence |
+ if (!opp->visited()) { |
continue; |
} |
- if (span->containsCoinEnd(opp)) { |
+ if (spanBase == &fHead) { |
continue; |
- } |
- // if already visited and visited again, check for coin |
- if (span == &fHead) { |
+ } |
+ SkOpSpan* span = spanBase->upCastable(); |
+ // FIXME?: this assumes that if the opposite segment is coincident then no more |
+ // coincidence needs to be detected. This may not be true. |
+ if (span && span->containsCoincidence(opp)) { |
continue; |
} |
+ if (spanBase->containsCoinEnd(opp)) { |
+ continue; |
+ } |
SkOpPtT* priorPtT = NULL, * priorStopPtT; |
// find prior span containing opp segment |
SkOpSegment* priorOpp = NULL; |
- prior = span; |
- while (!priorOpp && (prior = prior->prev())) { |
- priorStopPtT = priorPtT = prior->ptT(); |
+ SkOpSpan* priorTest = spanBase->prev(); |
+ while (!priorOpp && priorTest) { |
+ priorStopPtT = priorPtT = priorTest->ptT(); |
while ((priorPtT = priorPtT->next()) != priorStopPtT) { |
SkOpSegment* segment = priorPtT->span()->segment(); |
if (segment == opp) { |
+ prior = priorTest; |
priorOpp = opp; |
break; |
} |
} |
+ priorTest = priorTest->prev(); |
} |
if (!priorOpp) { |
continue; |
} |
SkOpPtT* oppStart = prior->ptT(); |
- SkOpPtT* oppEnd = span->ptT(); |
+ SkOpPtT* oppEnd = spanBase->ptT(); |
bool swapped = priorPtT->fT > ptT->fT; |
if (swapped) { |
SkTSwap(priorPtT, ptT); |
@@ -1154,7 +1175,7 @@ void SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc |
} |
{ |
// average t, find mid pt |
- double midT = (prior->t() + span->t()) / 2; |
+ double midT = (prior->t() + spanBase->t()) / 2; |
SkPoint midPt = this->ptAtT(midT); |
coincident = true; |
// if the mid pt is not near either end pt, project perpendicular through opp seg |
@@ -1182,9 +1203,10 @@ void SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc |
} |
if (coincident) { |
// mark coincidence |
- coincidences->add(priorPtT, ptT, oppStart, oppEnd, allocator); |
+ if (!coincidences->extend(priorPtT, ptT, oppStart, oppEnd)) { |
+ coincidences->add(priorPtT, ptT, oppStart, oppEnd, allocator); |
+ } |
clear_visited(&fHead); |
- missingCoincidence(coincidences, allocator); |
return; |
} |
swapBack: |
@@ -1192,7 +1214,7 @@ void SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc |
SkTSwap(priorPtT, ptT); |
} |
} |
- } while ((span = span->next()->upCastable())); |
+ } while ((spanBase = spanBase->final() ? NULL : spanBase->upCast()->next())); |
clear_visited(&fHead); |
} |
@@ -1610,13 +1632,7 @@ int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) { |
SkOpSpan* lesser = start->starter(end); |
int winding = lesser->windSum(); |
if (winding == SK_MinS32) { |
- SkOpGlobalState* globals = this->globalState(); |
- SkOpContour* contourHead = globals->contourHead(); |
- int windTry = 0; |
- while (!lesser->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxWindingTries) { |
- ; |
- } |
- winding = lesser->windSum(); |
+ winding = lesser->computeWindSum(); |
} |
if (winding == SK_MinS32) { |
return winding; |