| Index: src/pathops/SkOpSegment.cpp
|
| diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
|
| index 67f9fb2f25cf15fabd2b9064207ba33c1213e918..0e48b3f913155ccfaff90855ce2c32bec6bd2410 100644
|
| --- a/src/pathops/SkOpSegment.cpp
|
| +++ b/src/pathops/SkOpSegment.cpp
|
| @@ -70,16 +70,12 @@ const SkOpAngle* SkOpSegment::activeAngleInner(int index, int* start, int* end,
|
| int next = nextExactSpan(index, 1);
|
| if (next > 0) {
|
| const SkOpSpan& upSpan = fTs[index];
|
| - if (upSpan.fUnsortableStart) {
|
| - *sortable = false;
|
| - return NULL;
|
| - }
|
| if (upSpan.fWindValue || upSpan.fOppValue) {
|
| if (*end < 0) {
|
| *start = index;
|
| *end = next;
|
| }
|
| - if (!upSpan.fDone && !upSpan.fUnsortableEnd) {
|
| + if (!upSpan.fDone) {
|
| if (upSpan.fWindSum != SK_MinS32) {
|
| return spanToAngle(index, next);
|
| }
|
| @@ -93,10 +89,6 @@ const SkOpAngle* SkOpSegment::activeAngleInner(int index, int* start, int* end,
|
| // edge leading into junction
|
| if (prev >= 0) {
|
| const SkOpSpan& downSpan = fTs[prev];
|
| - if (downSpan.fUnsortableEnd) {
|
| - *sortable = false;
|
| - return NULL;
|
| - }
|
| if (downSpan.fWindValue || downSpan.fOppValue) {
|
| if (*end < 0) {
|
| *start = index;
|
| @@ -123,19 +115,15 @@ const SkOpAngle* SkOpSegment::activeAngleOther(int index, int* start, int* end,
|
| return other->activeAngleInner(oIndex, start, end, done, sortable);
|
| }
|
|
|
| -SkPoint SkOpSegment::activeLeftTop(bool onlySortable, int* firstT) const {
|
| +SkPoint SkOpSegment::activeLeftTop(int* firstT) const {
|
| SkASSERT(!done());
|
| SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
|
| int count = fTs.count();
|
| // see if either end is not done since we want smaller Y of the pair
|
| bool lastDone = true;
|
| - bool lastUnsortable = false;
|
| double lastT = -1;
|
| for (int index = 0; index < count; ++index) {
|
| const SkOpSpan& span = fTs[index];
|
| - if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
|
| - goto next;
|
| - }
|
| if (span.fDone && lastDone) {
|
| goto next;
|
| }
|
| @@ -164,7 +152,6 @@ SkPoint SkOpSegment::activeLeftTop(bool onlySortable, int* firstT) const {
|
| }
|
| next:
|
| lastDone = span.fDone;
|
| - lastUnsortable = span.fUnsortableEnd;
|
| }
|
| return topPt;
|
| }
|
| @@ -345,16 +332,19 @@ void SkOpSegment::addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt,
|
| do {
|
| workPt = &fTs[++tIndex].fPt;
|
| } while (nextPt == *workPt);
|
| + const SkPoint* oWorkPt;
|
| do {
|
| - workPt = &other->fTs[++oIndex].fPt;
|
| - } while (nextPt == *workPt);
|
| + oWorkPt = &other->fTs[++oIndex].fPt;
|
| + } while (nextPt == *oWorkPt);
|
| nextPt = *workPt;
|
| double tStart = fTs[tIndex].fT;
|
| double oStart = other->fTs[oIndex].fT;
|
| if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) {
|
| break;
|
| }
|
| - addTPair(tStart, other, oStart, false, nextPt);
|
| + if (*workPt == *oWorkPt) {
|
| + addTPair(tStart, other, oStart, false, nextPt);
|
| + }
|
| } while (endPt != nextPt);
|
| }
|
|
|
| @@ -618,8 +608,6 @@ int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) {
|
| span->fLoop = false;
|
| span->fSmall = false;
|
| span->fTiny = false;
|
| - span->fUnsortableStart = false;
|
| - span->fUnsortableEnd = false;
|
| int less = -1;
|
| // find range of spans with nearly the same point as this one
|
| while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt, pt)) {
|
| @@ -834,18 +822,27 @@ bool SkOpSegment::alignSpan(int index, double thisT, const SkPoint& thisPt) {
|
| aligned = true;
|
| }
|
| double oT = oSpan->fT;
|
| - if (oT == 0 || oT == 1) {
|
| + if (oT == 0) {
|
| return aligned;
|
| }
|
| int oStart = other->nextSpan(oIndex, -1) + 1;
|
| - int oEnd = other->nextSpan(oIndex, 1);
|
| oSpan = &other->fTs[oStart];
|
| + int otherIndex = oStart;
|
| + if (oT == 1) {
|
| + if (aligned) {
|
| + while (oSpan->fPt == thisPt && oSpan->fT != 1) {
|
| + oSpan->fTiny = true;
|
| + ++oSpan;
|
| + }
|
| + }
|
| + return aligned;
|
| + }
|
| oT = oSpan->fT;
|
| + int oEnd = other->nextSpan(oIndex, 1);
|
| bool oAligned = false;
|
| if (oSpan->fPt != thisPt) {
|
| oAligned |= other->alignSpan(oStart, oT, thisPt);
|
| }
|
| - int otherIndex = oStart;
|
| while (++otherIndex < oEnd) {
|
| SkOpSpan* oNextSpan = &other->fTs[otherIndex];
|
| if (oNextSpan->fT != oT || oNextSpan->fPt != thisPt) {
|
| @@ -1352,14 +1349,17 @@ void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* ne
|
| nextAngle->setLastMarked(last);
|
| }
|
|
|
| -void SkOpSegment::constructLine(SkPoint shortLine[2]) {
|
| - addLine(shortLine, false, false);
|
| - addT(NULL, shortLine[0], 0);
|
| - addT(NULL, shortLine[1], 1);
|
| - addStartSpan(1);
|
| - addEndSpan(1);
|
| - SkOpAngle& angle = fAngles.push_back();
|
| - angle.set(this, 0, 1);
|
| +bool SkOpSegment::containsPt(const SkPoint& pt, int index, int endIndex) const {
|
| + int step = index < endIndex ? 1 : -1;
|
| + do {
|
| + const SkOpSpan& span = this->span(index);
|
| + if (span.fPt == pt) {
|
| + const SkOpSpan& endSpan = this->span(endIndex);
|
| + return span.fT == endSpan.fT && pt != endSpan.fPt;
|
| + }
|
| + index += step;
|
| + } while (index != endIndex);
|
| + return false;
|
| }
|
|
|
| int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT,
|
| @@ -1923,7 +1923,7 @@ nextSmallCheck:
|
| missing.fPt)) {
|
| continue;
|
| }
|
| - int otherTIndex = missingOther->findT(missing.fOtherT, missing.fSegment);
|
| + int otherTIndex = missingOther->findT(missing.fOtherT, missing.fPt, missing.fSegment);
|
| const SkOpSpan& otherSpan = missingOther->span(otherTIndex);
|
| if (otherSpan.fSmall) {
|
| const SkOpSpan* nextSpan = &otherSpan;
|
| @@ -1955,7 +1955,9 @@ nextSmallCheck:
|
| void SkOpSegment::checkSmallCoincidence(const SkOpSpan& span,
|
| SkTArray<MissingSpan, true>* checkMultiple) {
|
| SkASSERT(span.fSmall);
|
| - SkASSERT(span.fWindValue);
|
| + if (0 && !span.fWindValue) {
|
| + return;
|
| + }
|
| SkASSERT(&span < fTs.end() - 1);
|
| const SkOpSpan* next = &span + 1;
|
| SkASSERT(!next->fSmall || checkMultiple);
|
| @@ -2271,11 +2273,13 @@ SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
|
| bool sortable = calcWinding != SK_NaN32;
|
| if (!sortable) {
|
| *unsortable = true;
|
| + markDoneBinary(SkMin32(startIndex, endIndex));
|
| return NULL;
|
| }
|
| SkOpAngle* angle = spanToAngle(end, startIndex);
|
| if (angle->unorderable()) {
|
| *unsortable = true;
|
| + markDoneBinary(SkMin32(startIndex, endIndex));
|
| return NULL;
|
| }
|
| #if DEBUG_SORT
|
| @@ -2283,6 +2287,11 @@ SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
|
| angle->debugLoop();
|
| #endif
|
| int sumMiWinding = updateWinding(endIndex, startIndex);
|
| + if (sumMiWinding == SK_MinS32) {
|
| + *unsortable = true;
|
| + markDoneBinary(SkMin32(startIndex, endIndex));
|
| + return NULL;
|
| + }
|
| int sumSuWinding = updateOppWinding(endIndex, startIndex);
|
| if (operand()) {
|
| SkTSwap<int>(sumMiWinding, sumSuWinding);
|
| @@ -2302,6 +2311,7 @@ SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
|
| if (!foundAngle || (foundDone && activeCount & 1)) {
|
| if (nextSegment->isTiny(nextAngle)) {
|
| *unsortable = true;
|
| + markDoneBinary(SkMin32(startIndex, endIndex));
|
| return NULL;
|
| }
|
| foundAngle = nextAngle;
|
| @@ -2393,6 +2403,7 @@ SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next
|
| bool sortable = calcWinding != SK_NaN32;
|
| if (!sortable) {
|
| *unsortable = true;
|
| + markDoneUnary(SkMin32(startIndex, endIndex));
|
| return NULL;
|
| }
|
| SkOpAngle* angle = spanToAngle(end, startIndex);
|
| @@ -2415,6 +2426,7 @@ SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next
|
| if (!foundAngle || (foundDone && activeCount & 1)) {
|
| if (nextSegment->isTiny(nextAngle)) {
|
| *unsortable = true;
|
| + markDoneUnary(SkMin32(startIndex, endIndex));
|
| return NULL;
|
| }
|
| foundAngle = nextAngle;
|
| @@ -2433,7 +2445,6 @@ SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next
|
| SkOpSpan* last = nextAngle->lastMarked();
|
| if (last) {
|
| SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
|
| - // assert here that span isn't already in array
|
| *chase->append() = last;
|
| #if DEBUG_WINDING
|
| SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
|
| @@ -2584,7 +2595,7 @@ int SkOpSegment::findExactT(double t, const SkOpSegment* match) const {
|
| return -1;
|
| }
|
|
|
| -int SkOpSegment::findT(double t, const SkOpSegment* match) const {
|
| +int SkOpSegment::findT(double t, const SkPoint& pt, const SkOpSegment* match) const {
|
| int count = this->count();
|
| for (int index = 0; index < count; ++index) {
|
| const SkOpSpan& span = fTs[index];
|
| @@ -2592,18 +2603,28 @@ int SkOpSegment::findT(double t, const SkOpSegment* match) const {
|
| return index;
|
| }
|
| }
|
| + // Usually, the pair of ts are an exact match. It's possible that the t values have
|
| + // been adjusted to make multiple intersections align. In this rare case, look for a
|
| + // matching point / match pair instead.
|
| + for (int index = 0; index < count; ++index) {
|
| + const SkOpSpan& span = fTs[index];
|
| + if (span.fPt == pt && span.fOther == match) {
|
| + return index;
|
| + }
|
| + }
|
| SkASSERT(0);
|
| return -1;
|
| }
|
|
|
| -SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable) {
|
| +SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable,
|
| + bool firstPass) {
|
| // iterate through T intersections and return topmost
|
| // topmost tangent from y-min to first pt is closer to horizontal
|
| SkASSERT(!done());
|
| int firstT = -1;
|
| - /* SkPoint topPt = */ activeLeftTop(true, &firstT);
|
| + /* SkPoint topPt = */ activeLeftTop(&firstT);
|
| if (firstT < 0) {
|
| - *unsortable = true;
|
| + *unsortable = !firstPass;
|
| firstT = 0;
|
| while (fTs[firstT].fDone) {
|
| SkASSERT(firstT < fTs.count());
|
| @@ -2655,14 +2676,24 @@ SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort
|
| #endif
|
| // skip edges that have already been processed
|
| angle = firstAngle;
|
| - SkOpSegment* leftSegment;
|
| + SkOpSegment* leftSegment = NULL;
|
| + bool looped = false;
|
| do {
|
| -// SkASSERT(!angle->unsortable());
|
| - leftSegment = angle->segment();
|
| - *tIndexPtr = angle->end();
|
| - *endIndexPtr = angle->start();
|
| + *unsortable = angle->unorderable();
|
| + if (firstPass || !*unsortable) {
|
| + leftSegment = angle->segment();
|
| + *tIndexPtr = angle->end();
|
| + *endIndexPtr = angle->start();
|
| + if (!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone) {
|
| + break;
|
| + }
|
| + }
|
| angle = angle->next();
|
| - } while (leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone);
|
| + looped = true;
|
| + } while (angle != firstAngle);
|
| + if (angle == firstAngle && looped) {
|
| + return NULL;
|
| + }
|
| if (leftSegment->verb() >= SkPath::kQuad_Verb) {
|
| const int tIndex = *tIndexPtr;
|
| const int endIndex = *endIndexPtr;
|
| @@ -2670,8 +2701,9 @@ SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort
|
| bool swap = !leftSegment->monotonicInY(tIndex, endIndex)
|
| && !leftSegment->serpentine(tIndex, endIndex);
|
| #if DEBUG_SWAP_TOP
|
| - SkDebugf("%s swap=%d serpentine=%d containedByEnds=%d monotonic=%d\n", __FUNCTION__,
|
| - swap,
|
| + SkDebugf("%s swap=%d inflections=%d serpentine=%d controlledbyends=%d monotonic=%d\n",
|
| + __FUNCTION__,
|
| + swap, leftSegment->debugInflections(tIndex, endIndex),
|
| leftSegment->serpentine(tIndex, endIndex),
|
| leftSegment->controlsContainedByEnds(tIndex, endIndex),
|
| leftSegment->monotonicInY(tIndex, endIndex));
|
| @@ -2840,13 +2872,6 @@ bool SkOpSegment::isSimple(int end) const {
|
| #endif
|
| }
|
|
|
| -bool SkOpSegment::isSmall(const SkOpAngle* angle) const {
|
| - int start = angle->start();
|
| - int end = angle->end();
|
| - const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
|
| - return mSpan.fSmall;
|
| -}
|
| -
|
| bool SkOpSegment::isTiny(const SkOpAngle* angle) const {
|
| int start = angle->start();
|
| int end = angle->end();
|
| @@ -2863,8 +2888,9 @@ bool SkOpSegment::isTiny(int index) const {
|
| // if both are active, look to see if they both the connect to another coincident pair
|
| // if at least one is a line, then make the pair coincident
|
| // if neither is a line, test for coincidence
|
| -bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, int step, bool cancel) {
|
| - int otherTIndex = other->findT(otherT, this);
|
| +bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, const SkPoint& otherPt,
|
| + int step, bool cancel) {
|
| + int otherTIndex = other->findT(otherT, otherPt, this);
|
| int next = other->nextExactSpan(otherTIndex, step);
|
| int otherMin = SkMin32(otherTIndex, next);
|
| int otherWind = other->span(otherMin).fWindValue;
|
| @@ -3106,7 +3132,9 @@ SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi
|
| debugShowNewWinding(funName, span, winding);
|
| #endif
|
| SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
|
| - SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum);
|
| +#if DEBUG_LIMIT_WIND_SUM
|
| + SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM);
|
| +#endif
|
| span.fWindSum = winding;
|
| return &span;
|
| }
|
| @@ -3121,10 +3149,14 @@ SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi
|
| debugShowNewWinding(funName, span, winding, oppWinding);
|
| #endif
|
| SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
|
| - SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum);
|
| +#if DEBUG_LIMIT_WIND_SUM
|
| + SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM);
|
| +#endif
|
| span.fWindSum = winding;
|
| SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
|
| - SkASSERT(abs(oppWinding) <= SkPathOpsDebug::gMaxWindSum);
|
| +#if DEBUG_LIMIT_WIND_SUM
|
| + SkASSERT(abs(oppWinding) <= DEBUG_LIMIT_WIND_SUM);
|
| +#endif
|
| span.fOppSum = oppWinding;
|
| debugValidate();
|
| return &span;
|
| @@ -3157,9 +3189,7 @@ bool SkOpSegment::clockwise(int tStart, int tEnd) const {
|
| }
|
|
|
| bool SkOpSegment::monotonicInY(int tStart, int tEnd) const {
|
| - if (fVerb == SkPath::kLine_Verb) {
|
| - return false;
|
| - }
|
| + SkASSERT(fVerb != SkPath::kLine_Verb);
|
| if (fVerb == SkPath::kQuad_Verb) {
|
| SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
|
| return dst.monotonicInY();
|
| @@ -3210,33 +3240,6 @@ SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) {
|
| return &span;
|
| }
|
|
|
| -// note that just because a span has one end that is unsortable, that's
|
| -// not enough to mark it done. The other end may be sortable, allowing the
|
| -// span to be added.
|
| -// FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
|
| -void SkOpSegment::markUnsortable(int start, int end) {
|
| - SkOpSpan* span = &fTs[start];
|
| - if (start < end) {
|
| -#if DEBUG_UNSORTABLE
|
| - debugShowNewWinding(__FUNCTION__, *span, 0);
|
| -#endif
|
| - span->fUnsortableStart = true;
|
| - } else {
|
| - --span;
|
| -#if DEBUG_UNSORTABLE
|
| - debugShowNewWinding(__FUNCTION__, *span, 0);
|
| -#endif
|
| - span->fUnsortableEnd = true;
|
| - }
|
| - if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
|
| - debugValidate();
|
| - return;
|
| - }
|
| - span->fDone = true;
|
| - fDoneSpans++;
|
| - debugValidate();
|
| -}
|
| -
|
| void SkOpSegment::markWinding(int index, int winding) {
|
| // SkASSERT(!done());
|
| SkASSERT(winding);
|
| @@ -3426,8 +3429,10 @@ void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int*
|
| *oppMaxWinding = *sumSuWinding;
|
| *oppSumWinding = *sumSuWinding -= oppDeltaSum;
|
| }
|
| - SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum);
|
| - SkASSERT(abs(*oppSumWinding) <= SkPathOpsDebug::gMaxWindSum);
|
| +#if DEBUG_LIMIT_WIND_SUM
|
| + SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
|
| + SkASSERT(abs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
|
| +#endif
|
| }
|
|
|
| void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding,
|
| @@ -3435,7 +3440,9 @@ void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding,
|
| int deltaSum = spanSign(index, endIndex);
|
| *maxWinding = *sumMiWinding;
|
| *sumWinding = *sumMiWinding -= deltaSum;
|
| - SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum);
|
| +#if DEBUG_LIMIT_WIND_SUM
|
| + SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
|
| +#endif
|
| }
|
|
|
| void SkOpSegment::sortAngles() {
|
| @@ -3494,7 +3501,10 @@ void SkOpSegment::sortAngles() {
|
| wroteAfterHeader = true;
|
| }
|
| #endif
|
| - baseAngle->insert(&other->angle(otherAngleIndex));
|
| + SkOpAngle* oAngle = &other->angle(otherAngleIndex);
|
| + if (!oAngle->loopContains(*baseAngle)) {
|
| + baseAngle->insert(oAngle);
|
| + }
|
| }
|
| otherAngleIndex = oSpan.fToAngleIndex;
|
| if (otherAngleIndex >= 0) {
|
| @@ -3505,7 +3515,10 @@ void SkOpSegment::sortAngles() {
|
| wroteAfterHeader = true;
|
| }
|
| #endif
|
| - baseAngle->insert(&other->angle(otherAngleIndex));
|
| + SkOpAngle* oAngle = &other->angle(otherAngleIndex);
|
| + if (!oAngle->loopContains(*baseAngle)) {
|
| + baseAngle->insert(oAngle);
|
| + }
|
| }
|
| if (++index == spanCount) {
|
| break;
|
| @@ -3673,6 +3686,9 @@ int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
|
| int SkOpSegment::updateWinding(int index, int endIndex) const {
|
| int lesser = SkMin32(index, endIndex);
|
| int winding = windSum(lesser);
|
| + if (winding == SK_MinS32) {
|
| + return winding;
|
| + }
|
| int spanWinding = spanSign(index, endIndex);
|
| if (winding && UseInnerWinding(winding - spanWinding, winding)
|
| && winding != SK_MaxS32) {
|
|
|