| Index: src/pathops/SkOpSegment.cpp
|
| diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
|
| index 0e48b3f913155ccfaff90855ce2c32bec6bd2410..59e6d344a5cca459472245be3c50f7cfc10d49c0 100644
|
| --- a/src/pathops/SkOpSegment.cpp
|
| +++ b/src/pathops/SkOpSegment.cpp
|
| @@ -5,6 +5,7 @@
|
| * found in the LICENSE file.
|
| */
|
| #include "SkIntersections.h"
|
| +#include "SkOpContour.h"
|
| #include "SkOpSegment.h"
|
| #include "SkPathWriter.h"
|
| #include "SkTSort.h"
|
| @@ -187,7 +188,8 @@ bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, int index, int endIndex
|
| }
|
| bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
|
| #if DEBUG_ACTIVE_OP
|
| - SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__,
|
| + SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n",
|
| + __FUNCTION__, debugID(), span(index).fT, span(endIndex).fT,
|
| SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
|
| #endif
|
| return result;
|
| @@ -404,25 +406,24 @@ void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active
|
|
|
| void SkOpSegment::addEndSpan(int endIndex) {
|
| int spanCount = fTs.count();
|
| - int angleIndex = fAngles.count();
|
| int startIndex = endIndex - 1;
|
| while (fTs[startIndex].fT == 1 || fTs[startIndex].fTiny) {
|
| ++startIndex;
|
| SkASSERT(startIndex < spanCount - 1);
|
| ++endIndex;
|
| }
|
| - fAngles.push_back().set(this, spanCount - 1, startIndex);
|
| + SkOpAngle& angle = fAngles.push_back();
|
| + angle.set(this, spanCount - 1, startIndex);
|
| #if DEBUG_ANGLE
|
| - fAngles.back().setID(angleIndex);
|
| debugCheckPointsEqualish(endIndex, spanCount);
|
| #endif
|
| - setFromAngleIndex(endIndex, angleIndex);
|
| + setFromAngle(endIndex, &angle);
|
| }
|
|
|
| -void SkOpSegment::setFromAngleIndex(int endIndex, int angleIndex) {
|
| +void SkOpSegment::setFromAngle(int endIndex, SkOpAngle* angle) {
|
| int spanCount = fTs.count();
|
| do {
|
| - fTs[endIndex].fFromAngleIndex = angleIndex;
|
| + fTs[endIndex].fFromAngle = angle;
|
| } while (++endIndex < spanCount);
|
| }
|
|
|
| @@ -448,89 +449,92 @@ void SkOpSegment::addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
|
| fBounds.setQuadBounds(pts);
|
| }
|
|
|
| -int SkOpSegment::addSingletonAngleDown(int endIndex, SkOpSegment** otherPtr) {
|
| - int startIndex = findEndSpan(endIndex);
|
| - SkASSERT(startIndex > 0);
|
| - int spanIndex = endIndex - 1;
|
| - fSingletonAngles.push_back().set(this, spanIndex, startIndex - 1);
|
| - setFromAngleIndex(startIndex, fAngles.count() + fSingletonAngles.count() - 1);
|
| +SkOpAngle* SkOpSegment::addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle** anglePtr) {
|
| + int spanIndex = count() - 1;
|
| + int startIndex = nextExactSpan(spanIndex, -1);
|
| + SkASSERT(startIndex >= 0);
|
| + SkOpAngle& angle = fAngles.push_back();
|
| + *anglePtr = ∠
|
| + angle.set(this, spanIndex, startIndex);
|
| + setFromAngle(spanIndex, &angle);
|
| SkOpSegment* other;
|
| + int oStartIndex, oEndIndex;
|
| do {
|
| - other = fTs[spanIndex].fOther;
|
| - if (other->fTs[0].fWindValue) {
|
| + const SkOpSpan& span = fTs[spanIndex];
|
| + SkASSERT(span.fT > 0);
|
| + other = span.fOther;
|
| + oStartIndex = span.fOtherIndex;
|
| + oEndIndex = other->nextExactSpan(oStartIndex, 1);
|
| + if (oEndIndex > 0 && other->span(oStartIndex).fWindValue) {
|
| break;
|
| }
|
| + oEndIndex = oStartIndex;
|
| + oStartIndex = other->nextExactSpan(oEndIndex, -1);
|
| --spanIndex;
|
| - SkASSERT(fTs[spanIndex].fT == 1);
|
| - } while (true);
|
| - int oEndIndex = other->findStartSpan(0);
|
| - SkASSERT(oEndIndex > 0);
|
| - int otherIndex = other->fSingletonAngles.count();
|
| - other->fSingletonAngles.push_back().set(other, 0, oEndIndex);
|
| - other->setToAngleIndex(oEndIndex, other->fAngles.count() + otherIndex);
|
| + } while (oStartIndex < 0 || !other->span(oStartIndex).fWindSum);
|
| + SkOpAngle& oAngle = other->fAngles.push_back();
|
| + oAngle.set(other, oStartIndex, oEndIndex);
|
| + other->setToAngle(oEndIndex, &oAngle);
|
| *otherPtr = other;
|
| - return otherIndex;
|
| + return &oAngle;
|
| }
|
|
|
| -int SkOpSegment::addSingletonAngleUp(int start, SkOpSegment** otherPtr) {
|
| - int endIndex = findStartSpan(start);
|
| +SkOpAngle* SkOpSegment::addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** anglePtr) {
|
| + int endIndex = nextExactSpan(0, 1);
|
| SkASSERT(endIndex > 0);
|
| - int thisIndex = fSingletonAngles.count();
|
| - fSingletonAngles.push_back().set(this, start, endIndex);
|
| - setToAngleIndex(endIndex, fAngles.count() + thisIndex);
|
| - int spanIndex = start;
|
| + SkOpAngle& angle = fAngles.push_back();
|
| + *anglePtr = ∠
|
| + angle.set(this, 0, endIndex);
|
| + setToAngle(endIndex, &angle);
|
| + int spanIndex = 0;
|
| SkOpSegment* other;
|
| - int oCount, oStartIndex;
|
| + int oStartIndex, oEndIndex;
|
| do {
|
| - other = fTs[spanIndex].fOther;
|
| - oCount = other->count();
|
| - oStartIndex = other->findEndSpan(oCount);
|
| - SkASSERT(oStartIndex > 0);
|
| - if (other->fTs[oStartIndex - 1].fWindValue) {
|
| + const SkOpSpan& span = fTs[spanIndex];
|
| + SkASSERT(span.fT < 1);
|
| + other = span.fOther;
|
| + oEndIndex = span.fOtherIndex;
|
| + oStartIndex = other->nextExactSpan(oEndIndex, -1);
|
| + if (oStartIndex >= 0 && other->span(oStartIndex).fWindValue) {
|
| break;
|
| }
|
| + oStartIndex = oEndIndex;
|
| + oEndIndex = other->nextExactSpan(oStartIndex, 1);
|
| ++spanIndex;
|
| - SkASSERT(fTs[spanIndex].fT == 0);
|
| - } while (true);
|
| - int otherIndex = other->fSingletonAngles.count();
|
| - other->fSingletonAngles.push_back().set(other, oCount - 1, oStartIndex - 1);
|
| - other->setFromAngleIndex(oStartIndex, other->fAngles.count() + otherIndex);
|
| + } while (oEndIndex < 0 || !other->span(oStartIndex).fWindValue);
|
| + SkOpAngle& oAngle = other->fAngles.push_back();
|
| + oAngle.set(other, oEndIndex, oStartIndex);
|
| + other->setFromAngle(oEndIndex, &oAngle);
|
| *otherPtr = other;
|
| - return otherIndex;
|
| + return &oAngle;
|
| }
|
|
|
| -SkOpAngle* SkOpSegment::addSingletonAngles(int start, int step) {
|
| - int thisIndex = fSingletonAngles.count();
|
| +SkOpAngle* SkOpSegment::addSingletonAngles(int step) {
|
| SkOpSegment* other;
|
| - int otherIndex;
|
| + SkOpAngle* angle, * otherAngle;
|
| if (step > 0) {
|
| - otherIndex = addSingletonAngleUp(start, &other);
|
| + otherAngle = addSingletonAngleUp(&other, &angle);
|
| } else {
|
| - otherIndex = addSingletonAngleDown(start + 1, &other);
|
| + otherAngle = addSingletonAngleDown(&other, &angle);
|
| }
|
| - fSingletonAngles[thisIndex].insert(&other->fSingletonAngles[otherIndex]);
|
| -#if DEBUG_ANGLE
|
| - fSingletonAngles[thisIndex].setID(fAngles.count() + thisIndex);
|
| - other->fSingletonAngles[otherIndex].setID(other->fAngles.count() + otherIndex);
|
| -#endif
|
| - return &fSingletonAngles[thisIndex];
|
| + angle->insert(otherAngle);
|
| + return angle;
|
| }
|
|
|
| void SkOpSegment::addStartSpan(int endIndex) {
|
| - int angleIndex = fAngles.count();
|
| int index = 0;
|
| - fAngles.push_back().set(this, index, endIndex);
|
| + SkOpAngle& angle = fAngles.push_back();
|
| + angle.set(this, index, endIndex);
|
| #if DEBUG_ANGLE
|
| - fAngles.back().setID(angleIndex);
|
| debugCheckPointsEqualish(index, endIndex);
|
| #endif
|
| - setToAngleIndex(endIndex, angleIndex);
|
| + setToAngle(endIndex, &angle);
|
| }
|
|
|
| -void SkOpSegment::setToAngleIndex(int endIndex, int angleIndex) {
|
| +void SkOpSegment::setToAngle(int endIndex, SkOpAngle* angle) {
|
| int index = 0;
|
| do {
|
| - fTs[index].fToAngleIndex = angleIndex;
|
| + fTs[index].fToAngle = angle;
|
| } while (++index < endIndex);
|
| }
|
|
|
| @@ -546,17 +550,14 @@ int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) {
|
| #if 0 // this needs an even rougher association to be useful
|
| SkASSERT(SkDPoint::RoughlyEqual(ptAtT(newT), pt));
|
| #endif
|
| - if (precisely_zero(newT)) {
|
| - newT = 0;
|
| - } else if (precisely_equal(newT, 1)) {
|
| - newT = 1;
|
| - }
|
| + const SkPoint& firstPt = fPts[0];
|
| + const SkPoint& lastPt = fPts[SkPathOpsVerbToPoints(fVerb)];
|
| + SkASSERT(newT == 0 || !precisely_zero(newT));
|
| + SkASSERT(newT == 1 || !precisely_equal(newT, 1));
|
| // FIXME: in the pathological case where there is a ton of intercepts,
|
| // binary search?
|
| int insertedAt = -1;
|
| int tCount = fTs.count();
|
| - const SkPoint& firstPt = fPts[0];
|
| - const SkPoint& lastPt = fPts[SkPathOpsVerbToPoints(fVerb)];
|
| for (int index = 0; index < tCount; ++index) {
|
| // OPTIMIZATION: if there are three or more identical Ts, then
|
| // the fourth and following could be further insertion-sorted so
|
| @@ -588,6 +589,9 @@ int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) {
|
| span = fTs.append();
|
| }
|
| span->fT = newT;
|
| +#if SK_DEBUG
|
| + span->fOtherT = -1;
|
| +#endif
|
| span->fOther = other;
|
| span->fPt = pt;
|
| #if 0
|
| @@ -595,20 +599,24 @@ int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) {
|
| SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX)
|
| && approximately_equal(xyAtT(newT).fY, pt.fY));
|
| #endif
|
| - span->fFromAngleIndex = -1;
|
| - span->fToAngleIndex = -1;
|
| + span->fFromAngle = NULL;
|
| + span->fToAngle = NULL;
|
| span->fWindSum = SK_MinS32;
|
| span->fOppSum = SK_MinS32;
|
| span->fWindValue = 1;
|
| span->fOppValue = 0;
|
| span->fChased = false;
|
| - if ((span->fDone = newT == 1)) {
|
| - ++fDoneSpans;
|
| - }
|
| + span->fCoincident = false;
|
| span->fLoop = false;
|
| + span->fNear = false;
|
| + span->fMultiple = false;
|
| span->fSmall = false;
|
| span->fTiny = false;
|
| + if ((span->fDone = newT == 1)) {
|
| + ++fDoneSpans;
|
| + }
|
| int less = -1;
|
| +// FIXME: note that this relies on spans being a continguous array
|
| // find range of spans with nearly the same point as this one
|
| while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt, pt)) {
|
| if (fVerb == SkPath::kCubic_Verb) {
|
| @@ -687,6 +695,7 @@ void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpS
|
| while (index > 0 && precisely_equal(fTs[index].fT, fTs[index - 1].fT)) {
|
| --index;
|
| }
|
| + bool oFoundEnd = false;
|
| int oIndex = other->fTs.count();
|
| while (startPt != other->fTs[--oIndex].fPt) { // look for startPt match
|
| SkASSERT(oIndex > 0);
|
| @@ -700,15 +709,19 @@ void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpS
|
| SkOpSpan* oTest = &other->fTs[oIndex];
|
| SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
|
| SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
|
| + bool decrement, track, bigger;
|
| + int originalWindValue;
|
| + const SkPoint* testPt;
|
| + const SkPoint* oTestPt;
|
| do {
|
| SkASSERT(test->fT < 1);
|
| SkASSERT(oTest->fT < 1);
|
| - bool decrement = test->fWindValue && oTest->fWindValue;
|
| - bool track = test->fWindValue || oTest->fWindValue;
|
| - bool bigger = test->fWindValue >= oTest->fWindValue;
|
| - const SkPoint& testPt = test->fPt;
|
| + decrement = test->fWindValue && oTest->fWindValue;
|
| + track = test->fWindValue || oTest->fWindValue;
|
| + bigger = test->fWindValue >= oTest->fWindValue;
|
| + testPt = &test->fPt;
|
| double testT = test->fT;
|
| - const SkPoint& oTestPt = oTest->fPt;
|
| + oTestPt = &oTest->fPt;
|
| double oTestT = oTest->fT;
|
| do {
|
| if (decrement) {
|
| @@ -718,12 +731,12 @@ void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpS
|
| decrementSpan(test);
|
| }
|
| } else if (track) {
|
| - TrackOutsidePair(&outsidePts, testPt, oTestPt);
|
| + TrackOutsidePair(&outsidePts, *testPt, *oTestPt);
|
| }
|
| SkASSERT(index < fTs.count() - 1);
|
| test = &fTs[++index];
|
| - } while (testPt == test->fPt || precisely_equal(testT, test->fT));
|
| - SkDEBUGCODE(int originalWindValue = oTest->fWindValue);
|
| + } while (*testPt == test->fPt || precisely_equal(testT, test->fT));
|
| + originalWindValue = oTest->fWindValue;
|
| do {
|
| SkASSERT(oTest->fT < 1);
|
| SkASSERT(originalWindValue == oTest->fWindValue);
|
| @@ -734,15 +747,48 @@ void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpS
|
| other->decrementSpan(oTest);
|
| }
|
| } else if (track) {
|
| - TrackOutsidePair(&oOutsidePts, oTestPt, testPt);
|
| + TrackOutsidePair(&oOutsidePts, *oTestPt, *testPt);
|
| }
|
| if (!oIndex) {
|
| break;
|
| }
|
| + oFoundEnd |= endPt == oTest->fPt;
|
| oTest = &other->fTs[--oIndex];
|
| - } while (oTestPt == oTest->fPt || precisely_equal(oTestT, oTest->fT));
|
| + } while (*oTestPt == oTest->fPt || precisely_equal(oTestT, oTest->fT));
|
| } while (endPt != test->fPt && test->fT < 1);
|
| // FIXME: determine if canceled edges need outside ts added
|
| + if (!oFoundEnd) {
|
| + for (int oIdx2 = oIndex; oIdx2 >= 0; --oIdx2) {
|
| + SkOpSpan* oTst2 = &other->fTs[oIdx2];
|
| + if (originalWindValue != oTst2->fWindValue) {
|
| + goto skipAdvanceOtherCancel;
|
| + }
|
| + if (!oTst2->fWindValue) {
|
| + goto skipAdvanceOtherCancel;
|
| + }
|
| + if (endPt == other->fTs[oIdx2].fPt) {
|
| + break;
|
| + }
|
| + }
|
| + do {
|
| + SkASSERT(originalWindValue == oTest->fWindValue);
|
| + if (decrement) {
|
| + if (binary && !bigger) {
|
| + oTest->fOppValue--;
|
| + } else {
|
| + other->decrementSpan(oTest);
|
| + }
|
| + } else if (track) {
|
| + TrackOutsidePair(&oOutsidePts, *oTestPt, *testPt);
|
| + }
|
| + if (!oIndex) {
|
| + break;
|
| + }
|
| + oTest = &other->fTs[--oIndex];
|
| + oFoundEnd |= endPt == oTest->fPt;
|
| + } while (!oFoundEnd || endPt == oTest->fPt);
|
| + }
|
| +skipAdvanceOtherCancel:
|
| int outCount = outsidePts.count();
|
| if (!done() && outCount) {
|
| addCancelOutsides(outsidePts[0], outsidePts[1], other);
|
| @@ -753,6 +799,8 @@ void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpS
|
| if (!other->done() && oOutsidePts.count()) {
|
| other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this);
|
| }
|
| + setCoincidentRange(startPt, endPt, other);
|
| + other->setCoincidentRange(startPt, endPt, this);
|
| }
|
|
|
| int SkOpSegment::addSelfT(const SkPoint& pt, double newT) {
|
| @@ -763,48 +811,153 @@ int SkOpSegment::addSelfT(const SkPoint& pt, double newT) {
|
| return result;
|
| }
|
|
|
| +// find the starting or ending span with an existing loop of angles
|
| +// FIXME? replicate for all identical starting/ending spans?
|
| +// OPTIMIZE? remove the spans pointing to windValue==0 here or earlier?
|
| +// FIXME? assert that only one other span has a valid windValue or oppValue
|
| void SkOpSegment::addSimpleAngle(int index) {
|
| + SkOpSpan* span = &fTs[index];
|
| if (index == 0) {
|
| - SkASSERT(!fTs[index].fTiny && fTs[index + 1].fT > 0);
|
| + do {
|
| + if (span->fToAngle) {
|
| + SkASSERT(span->fToAngle->loopCount() == 2);
|
| + SkASSERT(!span->fFromAngle);
|
| + span->fFromAngle = span->fToAngle->next();
|
| + return;
|
| + }
|
| + span = &fTs[++index];
|
| + } while (span->fT == 0);
|
| + SkASSERT(index == 1);
|
| + index = 0;
|
| + SkASSERT(!fTs[0].fTiny && fTs[1].fT > 0);
|
| addStartSpan(1);
|
| } else {
|
| + do {
|
| + if (span->fFromAngle) {
|
| + SkASSERT(span->fFromAngle->loopCount() == 2);
|
| + SkASSERT(!span->fToAngle);
|
| + span->fToAngle = span->fFromAngle->next();
|
| + return;
|
| + }
|
| + span = &fTs[--index];
|
| + } while (span->fT == 1);
|
| + SkASSERT(index == count() - 2);
|
| + index = count() - 1;
|
| SkASSERT(!fTs[index - 1].fTiny && fTs[index - 1].fT < 1);
|
| addEndSpan(index);
|
| }
|
| - SkOpSpan& span = fTs[index];
|
| - SkOpSegment* other = span.fOther;
|
| - SkOpSpan& oSpan = other->fTs[span.fOtherIndex];
|
| + span = &fTs[index];
|
| + SkOpSegment* other = span->fOther;
|
| + SkOpSpan& oSpan = other->fTs[span->fOtherIndex];
|
| SkOpAngle* angle, * oAngle;
|
| if (index == 0) {
|
| - SkASSERT(span.fOtherIndex - 1 >= 0);
|
| - SkASSERT(span.fOtherT == 1);
|
| - SkDEBUGCODE(SkOpSpan& oPrior = other->fTs[span.fOtherIndex - 1]);
|
| + SkASSERT(span->fOtherIndex - 1 >= 0);
|
| + SkASSERT(span->fOtherT == 1);
|
| + SkDEBUGCODE(SkOpSpan& oPrior = other->fTs[span->fOtherIndex - 1]);
|
| SkASSERT(!oPrior.fTiny && oPrior.fT < 1);
|
| - other->addEndSpan(span.fOtherIndex);
|
| - angle = &this->angle(span.fToAngleIndex);
|
| - oAngle = &other->angle(oSpan.fFromAngleIndex);
|
| + other->addEndSpan(span->fOtherIndex);
|
| + angle = span->fToAngle;
|
| + oAngle = oSpan.fFromAngle;
|
| } else {
|
| - SkASSERT(span.fOtherIndex + 1 < other->count());
|
| - SkASSERT(span.fOtherT == 0);
|
| - SkASSERT(!oSpan.fTiny && (other->fTs[span.fOtherIndex + 1].fT > 0
|
| - || (other->fTs[span.fOtherIndex + 1].fFromAngleIndex < 0
|
| - && other->fTs[span.fOtherIndex + 1].fToAngleIndex < 0)));
|
| + SkASSERT(span->fOtherIndex + 1 < other->count());
|
| + SkASSERT(span->fOtherT == 0);
|
| + SkASSERT(!oSpan.fTiny && (other->fTs[span->fOtherIndex + 1].fT > 0
|
| + || (other->fTs[span->fOtherIndex + 1].fFromAngle == NULL
|
| + && other->fTs[span->fOtherIndex + 1].fToAngle == NULL)));
|
| int oIndex = 1;
|
| do {
|
| const SkOpSpan& osSpan = other->span(oIndex);
|
| - if (osSpan.fFromAngleIndex >= 0 || osSpan.fT > 0) {
|
| + if (osSpan.fFromAngle || osSpan.fT > 0) {
|
| break;
|
| }
|
| ++oIndex;
|
| SkASSERT(oIndex < other->count());
|
| } while (true);
|
| other->addStartSpan(oIndex);
|
| - angle = &this->angle(span.fFromAngleIndex);
|
| - oAngle = &other->angle(oSpan.fToAngleIndex);
|
| + angle = span->fFromAngle;
|
| + oAngle = oSpan.fToAngle;
|
| }
|
| angle->insert(oAngle);
|
| }
|
|
|
| +void SkOpSegment::alignMultiples(SkTDArray<AlignedSpan>* alignedArray) {
|
| + debugValidate();
|
| + int count = this->count();
|
| + for (int index = 0; index < count; ++index) {
|
| + SkOpSpan& span = fTs[index];
|
| + if (!span.fMultiple) {
|
| + continue;
|
| + }
|
| + int end = nextExactSpan(index, 1);
|
| + SkASSERT(end > index + 1);
|
| + const SkPoint& thisPt = span.fPt;
|
| + while (index < end - 1) {
|
| + SkOpSegment* other1 = span.fOther;
|
| + int oCnt = other1->count();
|
| + for (int idx2 = index + 1; idx2 < end; ++idx2) {
|
| + SkOpSpan& span2 = fTs[idx2];
|
| + SkOpSegment* other2 = span2.fOther;
|
| + for (int oIdx = 0; oIdx < oCnt; ++oIdx) {
|
| + SkOpSpan& oSpan = other1->fTs[oIdx];
|
| + if (oSpan.fOther != other2) {
|
| + continue;
|
| + }
|
| + if (oSpan.fPt == thisPt) {
|
| + goto skipExactMatches;
|
| + }
|
| + }
|
| + for (int oIdx = 0; oIdx < oCnt; ++oIdx) {
|
| + SkOpSpan& oSpan = other1->fTs[oIdx];
|
| + if (oSpan.fOther != other2) {
|
| + continue;
|
| + }
|
| + if (SkDPoint::RoughlyEqual(oSpan.fPt, thisPt)) {
|
| + SkOpSpan& oSpan2 = other2->fTs[oSpan.fOtherIndex];
|
| + if (zero_or_one(span.fOtherT) || zero_or_one(oSpan.fT)
|
| + || zero_or_one(span2.fOtherT) || zero_or_one(oSpan2.fT)) {
|
| + return;
|
| + }
|
| + if (!way_roughly_equal(span.fOtherT, oSpan.fT)
|
| + || !way_roughly_equal(span2.fOtherT, oSpan2.fT)
|
| + || !way_roughly_equal(span2.fOtherT, oSpan.fOtherT)
|
| + || !way_roughly_equal(span.fOtherT, oSpan2.fOtherT)) {
|
| + return;
|
| + }
|
| + alignSpan(thisPt, span.fOtherT, other1, span2.fOtherT,
|
| + other2, &oSpan, alignedArray);
|
| + alignSpan(thisPt, span2.fOtherT, other2, span.fOtherT,
|
| + other1, &oSpan2, alignedArray);
|
| + break;
|
| + }
|
| + }
|
| + skipExactMatches:
|
| + ;
|
| + }
|
| + ++index;
|
| + }
|
| + }
|
| + debugValidate();
|
| +}
|
| +
|
| +void SkOpSegment::alignSpan(const SkPoint& newPt, double newT, const SkOpSegment* other,
|
| + double otherT, const SkOpSegment* other2, SkOpSpan* oSpan,
|
| + SkTDArray<AlignedSpan>* alignedArray) {
|
| + AlignedSpan* aligned = alignedArray->append();
|
| + aligned->fOldPt = oSpan->fPt;
|
| + aligned->fPt = newPt;
|
| + aligned->fOldT = oSpan->fT;
|
| + aligned->fT = newT;
|
| + aligned->fSegment = this; // OPTIMIZE: may be unused, can remove
|
| + aligned->fOther1 = other;
|
| + aligned->fOther2 = other2;
|
| + SkASSERT(SkDPoint::RoughlyEqual(oSpan->fPt, newPt));
|
| + oSpan->fPt = newPt;
|
| +// SkASSERT(way_roughly_equal(oSpan->fT, newT));
|
| + oSpan->fT = newT;
|
| +// SkASSERT(way_roughly_equal(oSpan->fOtherT, otherT));
|
| + oSpan->fOtherT = otherT;
|
| +}
|
| +
|
| bool SkOpSegment::alignSpan(int index, double thisT, const SkPoint& thisPt) {
|
| bool aligned = false;
|
| SkOpSpan* span = &fTs[index];
|
| @@ -877,6 +1030,156 @@ void SkOpSegment::alignSpanState(int start, int end) {
|
| }
|
| }
|
|
|
| +void SkOpSegment::blindCancel(const SkCoincidence& coincidence, SkOpSegment* other) {
|
| + bool binary = fOperand != other->fOperand;
|
| + int index = 0;
|
| + int last = this->count();
|
| + do {
|
| + SkOpSpan& span = this->fTs[--last];
|
| + if (span.fT != 1 && !span.fSmall) {
|
| + break;
|
| + }
|
| + span.fCoincident = true;
|
| + } while (true);
|
| + int oIndex = other->count();
|
| + do {
|
| + SkOpSpan& oSpan = other->fTs[--oIndex];
|
| + if (oSpan.fT != 1 && !oSpan.fSmall) {
|
| + break;
|
| + }
|
| + oSpan.fCoincident = true;
|
| + } while (true);
|
| + do {
|
| + SkOpSpan* test = &this->fTs[index];
|
| + int baseWind = test->fWindValue;
|
| + int baseOpp = test->fOppValue;
|
| + int endIndex = index;
|
| + while (++endIndex <= last) {
|
| + SkOpSpan* endSpan = &this->fTs[endIndex];
|
| + SkASSERT(endSpan->fT < 1);
|
| + if (endSpan->fWindValue != baseWind || endSpan->fOppValue != baseOpp) {
|
| + break;
|
| + }
|
| + endSpan->fCoincident = true;
|
| + }
|
| + SkOpSpan* oTest = &other->fTs[oIndex];
|
| + int oBaseWind = oTest->fWindValue;
|
| + int oBaseOpp = oTest->fOppValue;
|
| + int oStartIndex = oIndex;
|
| + while (--oStartIndex >= 0) {
|
| + SkOpSpan* oStartSpan = &other->fTs[oStartIndex];
|
| + if (oStartSpan->fWindValue != oBaseWind || oStartSpan->fOppValue != oBaseOpp) {
|
| + break;
|
| + }
|
| + oStartSpan->fCoincident = true;
|
| + }
|
| + bool decrement = baseWind && oBaseWind;
|
| + bool bigger = baseWind >= oBaseWind;
|
| + do {
|
| + SkASSERT(test->fT < 1);
|
| + if (decrement) {
|
| + if (binary && bigger) {
|
| + test->fOppValue--;
|
| + } else {
|
| + decrementSpan(test);
|
| + }
|
| + }
|
| + test->fCoincident = true;
|
| + test = &fTs[++index];
|
| + } while (index < endIndex);
|
| + do {
|
| + SkASSERT(oTest->fT < 1);
|
| + if (decrement) {
|
| + if (binary && !bigger) {
|
| + oTest->fOppValue--;
|
| + } else {
|
| + other->decrementSpan(oTest);
|
| + }
|
| + }
|
| + oTest->fCoincident = true;
|
| + oTest = &other->fTs[--oIndex];
|
| + } while (oIndex > oStartIndex);
|
| + } while (index <= last && oIndex >= 0);
|
| + SkASSERT(index > last);
|
| + SkASSERT(oIndex < 0);
|
| +}
|
| +
|
| +void SkOpSegment::blindCoincident(const SkCoincidence& coincidence, SkOpSegment* other) {
|
| + bool binary = fOperand != other->fOperand;
|
| + int index = 0;
|
| + int last = this->count();
|
| + do {
|
| + SkOpSpan& span = this->fTs[--last];
|
| + if (span.fT != 1 && !span.fSmall) {
|
| + break;
|
| + }
|
| + span.fCoincident = true;
|
| + } while (true);
|
| + int oIndex = 0;
|
| + int oLast = other->count();
|
| + do {
|
| + SkOpSpan& oSpan = other->fTs[--oLast];
|
| + if (oSpan.fT != 1 && !oSpan.fSmall) {
|
| + break;
|
| + }
|
| + oSpan.fCoincident = true;
|
| + } while (true);
|
| + do {
|
| + SkOpSpan* test = &this->fTs[index];
|
| + int baseWind = test->fWindValue;
|
| + int baseOpp = test->fOppValue;
|
| + int endIndex = index;
|
| + SkOpSpan* endSpan;
|
| + while (++endIndex <= last) {
|
| + endSpan = &this->fTs[endIndex];
|
| + SkASSERT(endSpan->fT < 1);
|
| + if (endSpan->fWindValue != baseWind || endSpan->fOppValue != baseOpp) {
|
| + break;
|
| + }
|
| + endSpan->fCoincident = true;
|
| + }
|
| + SkOpSpan* oTest = &other->fTs[oIndex];
|
| + int oBaseWind = oTest->fWindValue;
|
| + int oBaseOpp = oTest->fOppValue;
|
| + int oEndIndex = oIndex;
|
| + SkOpSpan* oEndSpan;
|
| + while (++oEndIndex <= oLast) {
|
| + oEndSpan = &this->fTs[oEndIndex];
|
| + SkASSERT(oEndSpan->fT < 1);
|
| + if (oEndSpan->fWindValue != oBaseWind || oEndSpan->fOppValue != oBaseOpp) {
|
| + break;
|
| + }
|
| + oEndSpan->fCoincident = true;
|
| + }
|
| + // consolidate the winding count even if done
|
| + if ((test->fWindValue || test->fOppValue) && (oTest->fWindValue || oTest->fOppValue)) {
|
| + if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
|
| + bumpCoincidentBlind(binary, index, endIndex);
|
| + other->bumpCoincidentOBlind(oIndex, oEndIndex);
|
| + } else {
|
| + other->bumpCoincidentBlind(binary, oIndex, oEndIndex);
|
| + bumpCoincidentOBlind(index, endIndex);
|
| + }
|
| + }
|
| + index = endIndex;
|
| + oIndex = oEndIndex;
|
| + } while (index <= last && oIndex <= oLast);
|
| + SkASSERT(index > last);
|
| + SkASSERT(oIndex > oLast);
|
| +}
|
| +
|
| +void SkOpSegment::bumpCoincidentBlind(bool binary, int index, int endIndex) {
|
| + const SkOpSpan& oTest = fTs[index];
|
| + int oWindValue = oTest.fWindValue;
|
| + int oOppValue = oTest.fOppValue;
|
| + if (binary) {
|
| + SkTSwap<int>(oWindValue, oOppValue);
|
| + }
|
| + do {
|
| + (void) bumpSpan(&fTs[index], oWindValue, oOppValue);
|
| + } while (++index < endIndex);
|
| +}
|
| +
|
| void SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* indexPtr,
|
| SkTArray<SkPoint, true>* outsideTs) {
|
| int index = *indexPtr;
|
| @@ -897,6 +1200,12 @@ void SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* in
|
| *indexPtr = index;
|
| }
|
|
|
| +void SkOpSegment::bumpCoincidentOBlind(int index, int endIndex) {
|
| + do {
|
| + zeroSpan(&fTs[index]);
|
| + } while (++index < endIndex);
|
| +}
|
| +
|
| // because of the order in which coincidences are resolved, this and other
|
| // may not have the same intermediate points. Compute the corresponding
|
| // intermediate T values (using this as the master, other as the follower)
|
| @@ -1025,13 +1334,13 @@ void SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, d
|
| int oPeekIndex = oIndex;
|
| bool success = true;
|
| SkOpSpan* oPeek;
|
| + int oCount = other->count();
|
| do {
|
| oPeek = &other->fTs[oPeekIndex];
|
| - if (oPeek->fT == 1) {
|
| + if (++oPeekIndex == oCount) {
|
| success = false;
|
| break;
|
| }
|
| - ++oPeekIndex;
|
| } while (endPt != oPeek->fPt);
|
| if (success) {
|
| // make sure the matching point completes the coincidence span
|
| @@ -1063,12 +1372,14 @@ void SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, d
|
| if (!other->done() && oOutsidePts.count()) {
|
| other->addCoinOutsides(oOutsidePts[0], endPt, this);
|
| }
|
| + setCoincidentRange(startPt, endPt, other);
|
| + other->setCoincidentRange(startPt, endPt, this);
|
| }
|
|
|
| // FIXME: this doesn't prevent the same span from being added twice
|
| // fix in caller, SkASSERT here?
|
| const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
|
| - const SkPoint& pt) {
|
| + const SkPoint& pt, const SkPoint& pt2) {
|
| int tCount = fTs.count();
|
| for (int tIndex = 0; tIndex < tCount; ++tIndex) {
|
| const SkOpSpan& span = fTs[tIndex];
|
| @@ -1089,24 +1400,23 @@ const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double other
|
| __FUNCTION__, fID, t, other->fID, otherT);
|
| #endif
|
| int insertedAt = addT(other, pt, t);
|
| - int otherInsertedAt = other->addT(this, pt, otherT);
|
| + int otherInsertedAt = other->addT(this, pt2, otherT);
|
| addOtherT(insertedAt, otherT, otherInsertedAt);
|
| other->addOtherT(otherInsertedAt, t, insertedAt);
|
| matchWindingValue(insertedAt, t, borrowWind);
|
| other->matchWindingValue(otherInsertedAt, otherT, borrowWind);
|
| - return &span(insertedAt);
|
| + SkOpSpan& span = this->fTs[insertedAt];
|
| + if (pt != pt2) {
|
| + span.fNear = true;
|
| + SkOpSpan& oSpan = other->fTs[otherInsertedAt];
|
| + oSpan.fNear = true;
|
| + }
|
| + return &span;
|
| }
|
|
|
| -const SkOpAngle& SkOpSegment::angle(int index) const {
|
| - SkASSERT(index >= 0);
|
| - int count = fAngles.count();
|
| - if (index < count) {
|
| - return fAngles[index];
|
| - }
|
| - index -= count;
|
| - count = fSingletonAngles.count();
|
| - SkASSERT(index < count);
|
| - return fSingletonAngles[index];
|
| +const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
|
| + const SkPoint& pt) {
|
| + return addTPair(t, other, otherT, borrowWind, pt, pt);
|
| }
|
|
|
| bool SkOpSegment::betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const {
|
| @@ -1138,9 +1448,7 @@ bool SkOpSegment::calcAngles() {
|
| const SkOpSpan* span = &fTs[0];
|
| if (firstSpan->fT == 0 || span->fTiny || span->fOtherT != 1 || span->fOther->multipleEnds()) {
|
| index = findStartSpan(0); // curve start intersects
|
| - if (index < 0) {
|
| - return false;
|
| - }
|
| + SkASSERT(index > 0);
|
| if (activePrior >= 0) {
|
| addStartSpan(index);
|
| }
|
| @@ -1150,9 +1458,7 @@ bool SkOpSegment::calcAngles() {
|
| span = &fTs[endIndex - 1];
|
| if ((addEnd = span->fT == 1 || span->fTiny)) { // if curve end intersects
|
| endIndex = findEndSpan(endIndex);
|
| - if (endIndex < 0) {
|
| - return false;
|
| - }
|
| + SkASSERT(endIndex > 0);
|
| } else {
|
| addEnd = fTs[endIndex].fOtherT != 0 || fTs[endIndex].fOther->multipleStarts();
|
| }
|
| @@ -1174,24 +1480,19 @@ bool SkOpSegment::calcAngles() {
|
| return false;
|
| }
|
| } while (true);
|
| - int angleIndex = fAngles.count();
|
| - int priorAngleIndex;
|
| + SkOpAngle* angle = NULL;
|
| + SkOpAngle* priorAngle;
|
| if (activePrior >= 0) {
|
| int pActive = firstActive(prior);
|
| SkASSERT(pActive < start);
|
| - fAngles.push_back().set(this, start, pActive);
|
| - priorAngleIndex = angleIndex++;
|
| - #if DEBUG_ANGLE
|
| - fAngles.back().setID(priorAngleIndex);
|
| - #endif
|
| + priorAngle = &fAngles.push_back();
|
| + priorAngle->set(this, start, pActive);
|
| }
|
| int active = checkSetAngle(start);
|
| if (active >= 0) {
|
| SkASSERT(active < index);
|
| - fAngles.push_back().set(this, active, index);
|
| - #if DEBUG_ANGLE
|
| - fAngles.back().setID(angleIndex);
|
| - #endif
|
| + angle = &fAngles.push_back();
|
| + angle->set(this, active, index);
|
| }
|
| #if DEBUG_ANGLE
|
| debugCheckPointsEqualish(start, index);
|
| @@ -1199,20 +1500,20 @@ bool SkOpSegment::calcAngles() {
|
| prior = start;
|
| do {
|
| const SkOpSpan* startSpan = &fTs[start - 1];
|
| - if (!startSpan->fSmall || startSpan->fFromAngleIndex >= 0
|
| - || startSpan->fToAngleIndex >= 0) {
|
| + if (!startSpan->fSmall || isCanceled(start - 1) || startSpan->fFromAngle
|
| + || startSpan->fToAngle) {
|
| break;
|
| }
|
| --start;
|
| } while (start > 0);
|
| do {
|
| if (activePrior >= 0) {
|
| - SkASSERT(fTs[start].fFromAngleIndex == -1);
|
| - fTs[start].fFromAngleIndex = priorAngleIndex;
|
| + SkASSERT(fTs[start].fFromAngle == NULL);
|
| + fTs[start].fFromAngle = priorAngle;
|
| }
|
| if (active >= 0) {
|
| - SkASSERT(fTs[start].fToAngleIndex == -1);
|
| - fTs[start].fToAngleIndex = angleIndex;
|
| + SkASSERT(fTs[start].fToAngle == NULL);
|
| + fTs[start].fToAngle = angle;
|
| }
|
| } while (++start < index);
|
| activePrior = active;
|
| @@ -1231,7 +1532,7 @@ int SkOpSegment::checkSetAngle(int tIndex) const {
|
| return isCanceled(tIndex) ? -1 : tIndex;
|
| }
|
|
|
| -// at this point, the span is already ordered, or unorderable, or unsortable
|
| +// at this point, the span is already ordered, or unorderable
|
| int SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType) {
|
| SkASSERT(includeType != SkOpAngle::kUnaryXor);
|
| SkOpAngle* firstAngle = spanToAngle(endIndex, startIndex);
|
| @@ -1242,50 +1543,61 @@ int SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType
|
| // or if no adjacent angles are orderable,
|
| // or if adjacent orderable angles have no computed winding,
|
| // there's nothing to do
|
| - // if two orderable angles are adjacent, and one has winding computed, transfer to the other
|
| + // if two orderable angles are adjacent, and both are next to orderable angles,
|
| + // and one has winding computed, transfer to the other
|
| SkOpAngle* baseAngle = NULL;
|
| bool tryReverse = false;
|
| // look for counterclockwise transfers
|
| - SkOpAngle* angle = firstAngle;
|
| + SkOpAngle* angle = firstAngle->previous();
|
| + SkOpAngle* next = angle->next();
|
| + firstAngle = next;
|
| do {
|
| - int testWinding = angle->segment()->windSum(angle);
|
| - if (SK_MinS32 != testWinding && !angle->unorderable()) {
|
| - baseAngle = angle;
|
| + SkOpAngle* prior = angle;
|
| + angle = next;
|
| + next = angle->next();
|
| + SkASSERT(prior->next() == angle);
|
| + SkASSERT(angle->next() == next);
|
| + if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
|
| + baseAngle = NULL;
|
| continue;
|
| }
|
| - if (angle->unorderable()) {
|
| - baseAngle = NULL;
|
| + int testWinding = angle->segment()->windSum(angle);
|
| + if (SK_MinS32 != testWinding) {
|
| + baseAngle = angle;
|
| tryReverse = true;
|
| continue;
|
| }
|
| if (baseAngle) {
|
| ComputeOneSum(baseAngle, angle, includeType);
|
| baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle : NULL;
|
| - tryReverse |= !baseAngle;
|
| }
|
| - } while ((angle = angle->next()) != firstAngle);
|
| - if (baseAngle && SK_MinS32 == firstAngle->segment()->windSum(angle)) {
|
| + } while (next != firstAngle);
|
| + if (baseAngle && SK_MinS32 == firstAngle->segment()->windSum(firstAngle)) {
|
| firstAngle = baseAngle;
|
| tryReverse = true;
|
| }
|
| if (tryReverse) {
|
| baseAngle = NULL;
|
| - angle = firstAngle;
|
| + SkOpAngle* prior = firstAngle;
|
| do {
|
| + angle = prior;
|
| + prior = angle->previous();
|
| + SkASSERT(prior->next() == angle);
|
| + next = angle->next();
|
| + if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
|
| + baseAngle = NULL;
|
| + continue;
|
| + }
|
| int testWinding = angle->segment()->windSum(angle);
|
| if (SK_MinS32 != testWinding) {
|
| baseAngle = angle;
|
| continue;
|
| }
|
| - if (angle->unorderable()) {
|
| - baseAngle = NULL;
|
| - continue;
|
| - }
|
| if (baseAngle) {
|
| ComputeOneSumReverse(baseAngle, angle, includeType);
|
| baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle : NULL;
|
| }
|
| - } while ((angle = angle->previous()) != firstAngle);
|
| + } while (prior != firstAngle);
|
| }
|
| int minIndex = SkMin32(startIndex, endIndex);
|
| return windSum(minIndex);
|
| @@ -1362,6 +1674,31 @@ bool SkOpSegment::containsPt(const SkPoint& pt, int index, int endIndex) const {
|
| return false;
|
| }
|
|
|
| +bool SkOpSegment::containsT(double t, const SkOpSegment* other, double otherT) const {
|
| + int count = this->count();
|
| + for (int index = 0; index < count; ++index) {
|
| + const SkOpSpan& span = fTs[index];
|
| + if (t < span.fT) {
|
| + return false;
|
| + }
|
| + if (t == span.fT) {
|
| + if (other != span.fOther) {
|
| + continue;
|
| + }
|
| + if (other->fVerb != SkPath::kCubic_Verb) {
|
| + return true;
|
| + }
|
| + if (!other->fLoop) {
|
| + return true;
|
| + }
|
| + double otherMidT = (otherT + span.fOtherT) / 2;
|
| + SkPoint otherPt = other->ptAtT(otherMidT);
|
| + return SkDPoint::ApproximatelyEqual(span.fPt, otherPt);
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT,
|
| bool* hitSomething, double mid, bool opp, bool current) const {
|
| SkScalar bottom = fBounds.fBottom;
|
| @@ -1542,6 +1879,58 @@ bool SkOpSegment::calcLoopSpanCount(const SkOpSpan& thisSpan, int* smallCounts)
|
| return true;
|
| }
|
|
|
| +double SkOpSegment::calcMissingTEnd(const SkOpSegment* ref, double loEnd, double min, double max,
|
| + double hiEnd, const SkOpSegment* other, int thisStart) {
|
| + if (max >= hiEnd) {
|
| + return -1;
|
| + }
|
| + int end = findOtherT(hiEnd, ref);
|
| + if (end < 0) {
|
| + return -1;
|
| + }
|
| + double tHi = span(end).fT;
|
| + double tLo, refLo;
|
| + if (thisStart >= 0) {
|
| + tLo = span(thisStart).fT;
|
| + refLo = min;
|
| + } else {
|
| + int start1 = findOtherT(loEnd, ref);
|
| + SkASSERT(start1 >= 0);
|
| + tLo = span(start1).fT;
|
| + refLo = loEnd;
|
| + }
|
| + double missingT = (max - refLo) / (hiEnd - refLo);
|
| + missingT = tLo + missingT * (tHi - tLo);
|
| + return missingT;
|
| +}
|
| +
|
| +double SkOpSegment::calcMissingTStart(const SkOpSegment* ref, double loEnd, double min, double max,
|
| + double hiEnd, const SkOpSegment* other, int thisEnd) {
|
| + if (min <= loEnd) {
|
| + return -1;
|
| + }
|
| + int start = findOtherT(loEnd, ref);
|
| + if (start < 0) {
|
| + return -1;
|
| + }
|
| + double tLo = span(start).fT;
|
| + double tHi, refHi;
|
| + if (thisEnd >= 0) {
|
| + tHi = span(thisEnd).fT;
|
| + refHi = max;
|
| + } else {
|
| + int end1 = findOtherT(hiEnd, ref);
|
| + if (end1 < 0) {
|
| + return -1;
|
| + }
|
| + tHi = span(end1).fT;
|
| + refHi = hiEnd;
|
| + }
|
| + double missingT = (min - loEnd) / (refHi - loEnd);
|
| + missingT = tLo + missingT * (tHi - tLo);
|
| + return missingT;
|
| +}
|
| +
|
| // see if spans with two or more intersections have the same number on the other end
|
| void SkOpSegment::checkDuplicates() {
|
| debugValidate();
|
| @@ -1561,6 +1950,9 @@ void SkOpSegment::checkDuplicates() {
|
| }
|
| do {
|
| const SkOpSpan* thisSpan = &fTs[index];
|
| + if (thisSpan->fNear) {
|
| + continue;
|
| + }
|
| SkOpSegment* other = thisSpan->fOther;
|
| int oIndex = thisSpan->fOtherIndex;
|
| int oStart = other->nextExactSpan(oIndex, -1) + 1;
|
| @@ -1602,6 +1994,33 @@ void SkOpSegment::checkDuplicates() {
|
| if (missing.fSegment == missing.fOther) {
|
| continue;
|
| }
|
| +#if 0 // FIXME: this eliminates spurious data from skpwww_argus_presse_fr_41 but breaks
|
| + // skpwww_fashionscandal_com_94 -- calcAngles complains, but I don't understand why
|
| + if (missing.fSegment->containsT(missing.fT, missing.fOther, missing.fOtherT)) {
|
| +#if DEBUG_DUPLICATES
|
| + SkDebugf("skip 1 id=%d t=%1.9g other=%d otherT=%1.9g\n", missing.fSegment->fID,
|
| + missing.fT, missing.fOther->fID, missing.fOtherT);
|
| +#endif
|
| + continue;
|
| + }
|
| + if (missing.fOther->containsT(missing.fOtherT, missing.fSegment, missing.fT)) {
|
| +#if DEBUG_DUPLICATES
|
| + SkDebugf("skip 2 id=%d t=%1.9g other=%d otherT=%1.9g\n", missing.fOther->fID,
|
| + missing.fOtherT, missing.fSegment->fID, missing.fT);
|
| +#endif
|
| + continue;
|
| + }
|
| +#endif
|
| + // skip if adding would insert point into an existing coincindent span
|
| + if (missing.fSegment->inCoincidentSpan(missing.fT, missingOther)
|
| + && missingOther->inCoincidentSpan(missing.fOtherT, this)) {
|
| + continue;
|
| + }
|
| + // skip if the created coincident spans are small
|
| + if (missing.fSegment->coincidentSmall(missing.fPt, missing.fT, missingOther)
|
| + && missingOther->coincidentSmall(missing.fPt, missing.fOtherT, missing.fSegment)) {
|
| + continue;
|
| + }
|
| const SkOpSpan* added = missing.fSegment->addTPair(missing.fT, missingOther,
|
| missing.fOtherT, false, missing.fPt);
|
| if (added && added->fSmall) {
|
| @@ -1777,8 +2196,10 @@ void SkOpSegment::checkMultiples() {
|
| continue;
|
| }
|
| // force the duplicates to agree on t and pt if not on the end
|
| - double thisT = fTs[index].fT;
|
| - const SkPoint& thisPt = fTs[index].fPt;
|
| + SkOpSpan& span = fTs[index];
|
| + double thisT = span.fT;
|
| + const SkPoint& thisPt = span.fPt;
|
| + span.fMultiple = true;
|
| bool aligned = false;
|
| while (++index < end) {
|
| aligned |= alignSpan(index, thisT, thisPt);
|
| @@ -1786,6 +2207,7 @@ void SkOpSegment::checkMultiples() {
|
| if (aligned) {
|
| alignSpanState(start, end);
|
| }
|
| + fMultiples = true;
|
| }
|
| debugValidate();
|
| }
|
| @@ -2146,6 +2568,30 @@ void SkOpSegment::checkTiny() {
|
| }
|
| }
|
|
|
| +bool SkOpSegment::coincidentSmall(const SkPoint& pt, double t, const SkOpSegment* other) const {
|
| + int count = this->count();
|
| + for (int index = 0; index < count; ++index) {
|
| + const SkOpSpan& span = this->span(index);
|
| + if (span.fOther != other) {
|
| + continue;
|
| + }
|
| + if (span.fPt == pt) {
|
| + continue;
|
| + }
|
| + if (!AlmostEqualUlps(span.fPt, pt)) {
|
| + continue;
|
| + }
|
| + if (fVerb != SkPath::kCubic_Verb) {
|
| + return true;
|
| + }
|
| + double tInterval = t - span.fT;
|
| + double tMid = t - tInterval / 2;
|
| + SkDPoint midPt = dcubic_xy_at_t(fPts, tMid);
|
| + return midPt.approximatelyEqual(xyAtT(t));
|
| + }
|
| + return false;
|
| +}
|
| +
|
| bool SkOpSegment::findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int oStart,
|
| int oEnd, int step, SkPoint* startPt, SkPoint* endPt, double* endT) const {
|
| SkASSERT(span->fT == 0 || span->fT == 1);
|
| @@ -2235,12 +2681,11 @@ SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
|
| SkASSERT(startIndex != endIndex);
|
| SkDEBUGCODE(const int count = fTs.count());
|
| SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
|
| - const int step = SkSign32(endIndex - startIndex);
|
| - const int end = nextExactSpan(startIndex, step);
|
| - SkASSERT(end >= 0);
|
| - SkOpSpan* endSpan = &fTs[end];
|
| - SkOpSegment* other;
|
| - if (isSimple(end)) {
|
| + int step = SkSign32(endIndex - startIndex);
|
| + *nextStart = startIndex;
|
| + SkOpSegment* other = isSimple(nextStart, &step);
|
| + if (other)
|
| + {
|
| // mark the smaller of startIndex, endIndex done, and all adjacent
|
| // spans with the same T value (but not 'other' spans)
|
| #if DEBUG_WINDING
|
| @@ -2251,8 +2696,6 @@ SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
|
| return NULL;
|
| }
|
| markDoneBinary(min);
|
| - other = endSpan->fOther;
|
| - *nextStart = endSpan->fOtherIndex;
|
| double startT = other->fTs[*nextStart].fT;
|
| *nextEnd = *nextStart;
|
| do {
|
| @@ -2265,6 +2708,8 @@ SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
|
| }
|
| return other;
|
| }
|
| + const int end = nextExactSpan(startIndex, step);
|
| + SkASSERT(end >= 0);
|
| SkASSERT(startIndex - endIndex != 0);
|
| SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
|
| // more than one viable candidate -- measure angles to find best
|
| @@ -2325,7 +2770,7 @@ SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
|
| continue;
|
| }
|
| if (!activeAngle) {
|
| - nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextAngle->end());
|
| + (void) nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextAngle->end());
|
| }
|
| SkOpSpan* last = nextAngle->lastMarked();
|
| if (last) {
|
| @@ -2365,12 +2810,11 @@ SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next
|
| SkASSERT(startIndex != endIndex);
|
| SkDEBUGCODE(const int count = fTs.count());
|
| SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
|
| - const int step = SkSign32(endIndex - startIndex);
|
| - const int end = nextExactSpan(startIndex, step);
|
| - SkASSERT(end >= 0);
|
| - SkOpSpan* endSpan = &fTs[end];
|
| - SkOpSegment* other;
|
| - if (isSimple(end)) {
|
| + int step = SkSign32(endIndex - startIndex);
|
| + *nextStart = startIndex;
|
| + SkOpSegment* other = isSimple(nextStart, &step);
|
| + if (other)
|
| + {
|
| // mark the smaller of startIndex, endIndex done, and all adjacent
|
| // spans with the same T value (but not 'other' spans)
|
| #if DEBUG_WINDING
|
| @@ -2381,8 +2825,6 @@ SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next
|
| return NULL;
|
| }
|
| markDoneUnary(min);
|
| - other = endSpan->fOther;
|
| - *nextStart = endSpan->fOtherIndex;
|
| double startT = other->fTs[*nextStart].fT;
|
| *nextEnd = *nextStart;
|
| do {
|
| @@ -2395,6 +2837,8 @@ SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next
|
| }
|
| return other;
|
| }
|
| + const int end = nextExactSpan(startIndex, step);
|
| + SkASSERT(end >= 0);
|
| SkASSERT(startIndex - endIndex != 0);
|
| SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
|
| // more than one viable candidate -- measure angles to find best
|
| @@ -2474,13 +2918,12 @@ SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsort
|
| SkDEBUGCODE(int count = fTs.count());
|
| SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
|
| int step = SkSign32(endIndex - startIndex);
|
| - int end = nextExactSpan(startIndex, step);
|
| - SkASSERT(end >= 0);
|
| - SkOpSpan* endSpan = &fTs[end];
|
| - SkOpSegment* other;
|
| // Detect cases where all the ends canceled out (e.g.,
|
| -// there is no angle) and therefore there's only one valid connection
|
| - if (isSimple(end) || !spanToAngle(end, startIndex)) {
|
| +// there is no angle) and therefore there's only one valid connection
|
| + *nextStart = startIndex;
|
| + SkOpSegment* other = isSimple(nextStart, &step);
|
| + if (other)
|
| + {
|
| #if DEBUG_WINDING
|
| SkDebugf("%s simple\n", __FUNCTION__);
|
| #endif
|
| @@ -2489,8 +2932,6 @@ SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsort
|
| return NULL;
|
| }
|
| markDone(min, 1);
|
| - other = endSpan->fOther;
|
| - *nextStart = endSpan->fOtherIndex;
|
| double startT = other->fTs[*nextStart].fT;
|
| // FIXME: I don't know why the logic here is difference from the winding case
|
| SkDEBUGCODE(bool firstLoop = true;)
|
| @@ -2517,6 +2958,8 @@ SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsort
|
| SkASSERT(startIndex - endIndex != 0);
|
| SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
|
| // parallel block above with presorted version
|
| + int end = nextExactSpan(startIndex, step);
|
| + SkASSERT(end >= 0);
|
| SkOpAngle* angle = spanToAngle(end, startIndex);
|
| SkASSERT(angle);
|
| #if DEBUG_SORT
|
| @@ -2562,24 +3005,12 @@ int SkOpSegment::findStartSpan(int startIndex) const {
|
| const SkOpSpan* span = &fTs[index];
|
| const SkPoint& firstPt = span->fPt;
|
| double firstT = span->fT;
|
| + const SkOpSpan* prior;
|
| do {
|
| - if (index > 0) {
|
| - if (span->fT != firstT) {
|
| - break;
|
| - }
|
| - if (!SkDPoint::ApproximatelyEqual(firstPt, fTs[index].fPt)) {
|
| - return -1;
|
| - }
|
| - }
|
| - ++index;
|
| - if (span->fTiny) {
|
| - if (!SkDPoint::ApproximatelyEqual(firstPt, fTs[index].fPt)) {
|
| - return -1;
|
| - }
|
| - firstT = fTs[index++].fT;
|
| - }
|
| - span = &fTs[index];
|
| - } while (true);
|
| + prior = span;
|
| + span = &fTs[++index];
|
| + } while (SkDPoint::ApproximatelyEqual(span->fPt, firstPt)
|
| + && (span->fT == firstT || prior->fTiny));
|
| return index;
|
| }
|
|
|
| @@ -2595,6 +3026,17 @@ int SkOpSegment::findExactT(double t, const SkOpSegment* match) const {
|
| return -1;
|
| }
|
|
|
| +int SkOpSegment::findOtherT(double t, const SkOpSegment* match) const {
|
| + int count = this->count();
|
| + for (int index = 0; index < count; ++index) {
|
| + const SkOpSpan& span = fTs[index];
|
| + if (span.fOtherT == t && span.fOther == match) {
|
| + return index;
|
| + }
|
| + }
|
| + return -1;
|
| +}
|
| +
|
| int SkOpSegment::findT(double t, const SkPoint& pt, const SkOpSegment* match) const {
|
| int count = this->count();
|
| for (int index = 0; index < count; ++index) {
|
| @@ -2647,7 +3089,7 @@ SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort
|
| SkASSERT(firstT - end != 0);
|
| SkOpAngle* markAngle = spanToAngle(firstT, end);
|
| if (!markAngle) {
|
| - markAngle = addSingletonAngles(firstT, step);
|
| + markAngle = addSingletonAngles(step);
|
| }
|
| markAngle->markStops();
|
| const SkOpAngle* baseAngle = markAngle->findFirst();
|
| @@ -2754,13 +3196,26 @@ void SkOpSegment::fixOtherTIndex() {
|
| }
|
| }
|
|
|
| +bool SkOpSegment::inCoincidentSpan(double t, const SkOpSegment* other) const {
|
| + int foundEnds = 0;
|
| + int count = this->count();
|
| + for (int index = 0; index < count; ++index) {
|
| + const SkOpSpan& span = this->span(index);
|
| + if (span.fCoincident) {
|
| + foundEnds |= (span.fOther == other) << ((t > span.fT) + (t >= span.fT));
|
| + }
|
| + }
|
| + SkASSERT(foundEnds != 7);
|
| + return foundEnds == 0x3 || foundEnds == 0x5 || foundEnds == 0x6; // two bits set
|
| +}
|
| +
|
| void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
|
| fDoneSpans = 0;
|
| fOperand = operand;
|
| fXor = evenOdd;
|
| fPts = pts;
|
| fVerb = verb;
|
| - fLoop = fSmall = fTiny = false;
|
| + fLoop = fMultiples = fSmall = fTiny = false;
|
| }
|
|
|
| void SkOpSegment::initWinding(int start, int end, SkOpAngle::IncludeType angleIncludeType) {
|
| @@ -2793,16 +3248,13 @@ void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkSc
|
| SkASSERT(dx);
|
| int windVal = windValue(SkMin32(start, end));
|
| #if DEBUG_WINDING_AT_T
|
| - SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
|
| + SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, debugID(), winding,
|
| hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
|
| #endif
|
| int sideWind = winding + (dx < 0 ? windVal : -windVal);
|
| if (abs(winding) < abs(sideWind)) {
|
| winding = sideWind;
|
| }
|
| -#if DEBUG_WINDING_AT_T
|
| - SkDebugf(" winding=%d\n", winding);
|
| -#endif
|
| SkDEBUGCODE(int oppLocal = oppSign(start, end));
|
| SkASSERT(hitOppDx || !oppWind || !oppLocal);
|
| int oppWindVal = oppValue(SkMin32(start, end));
|
| @@ -2814,6 +3266,9 @@ void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkSc
|
| oppWind = oppSideWind;
|
| }
|
| }
|
| +#if DEBUG_WINDING_AT_T
|
| + SkDebugf(" winding=%d oppWind=%d\n", winding, oppWind);
|
| +#endif
|
| (void) markAndChaseWinding(start, end, winding, oppWind);
|
| // OPTIMIZATION: the reverse mark and chase could skip the first marking
|
| (void) markAndChaseWinding(end, start, winding, oppWind);
|
| @@ -2824,12 +3279,12 @@ bool SkOpSegment::inLoop(const SkOpAngle* baseAngle, int spanCount, int* indexPt
|
| return false;
|
| }
|
| int index = *indexPtr;
|
| - int froIndex = fTs[index].fFromAngleIndex;
|
| - int toIndex = fTs[index].fToAngleIndex;
|
| + SkOpAngle* from = fTs[index].fFromAngle;
|
| + SkOpAngle* to = fTs[index].fToAngle;
|
| while (++index < spanCount) {
|
| - int nextFro = fTs[index].fFromAngleIndex;
|
| - int nextTo = fTs[index].fToAngleIndex;
|
| - if (froIndex != nextFro || toIndex != nextTo) {
|
| + SkOpAngle* nextFrom = fTs[index].fFromAngle;
|
| + SkOpAngle* nextTo = fTs[index].fToAngle;
|
| + if (from != nextFrom || to != nextTo) {
|
| break;
|
| }
|
| }
|
| @@ -2850,26 +3305,9 @@ bool SkOpSegment::isMissing(double startT, const SkPoint& pt) const {
|
| return true;
|
| }
|
|
|
| -bool SkOpSegment::isSimple(int end) const {
|
| -#if 1
|
| - int count = fTs.count();
|
| - if (count == 2) {
|
| - return true;
|
| - }
|
| - double t = fTs[end].fT;
|
| - if (approximately_less_than_zero(t)) {
|
| - return !approximately_less_than_zero(fTs[1].fT);
|
| - }
|
| - if (approximately_greater_than_one(t)) {
|
| - return !approximately_greater_than_one(fTs[count - 2].fT);
|
| - }
|
| - return false;
|
| -#else
|
| - // OPTIMIZE: code could be rejiggered to use this simpler test. To make this work, a little
|
| - // more logic is required to ignore the dangling canceled out spans
|
| - const SkOpSpan& span = fTs[end];
|
| - return span.fFromAngleIndex < 0 && span.fToAngleIndex < 0;
|
| -#endif
|
| +
|
| +SkOpSegment* SkOpSegment::isSimple(int* end, int* step) {
|
| + return nextChase(end, step, NULL, NULL);
|
| }
|
|
|
| bool SkOpSegment::isTiny(const SkOpAngle* angle) const {
|
| @@ -2928,11 +3366,12 @@ SkOpSpan* SkOpSegment::markAndChaseDoneBinary(int index, int endIndex) {
|
| int step = SkSign32(endIndex - index);
|
| int min = SkMin32(index, endIndex);
|
| markDoneBinary(min);
|
| - SkOpSpan* last;
|
| + SkOpSpan* last = NULL;
|
| SkOpSegment* other = this;
|
| - while ((other = other->nextChase(&index, step, &min, &last))) {
|
| + while ((other = other->nextChase(&index, &step, &min, &last))) {
|
| if (other->done()) {
|
| - return NULL;
|
| + SkASSERT(!last);
|
| + break;
|
| }
|
| other->markDoneBinary(min);
|
| }
|
| @@ -2943,11 +3382,12 @@ SkOpSpan* SkOpSegment::markAndChaseDoneUnary(int index, int endIndex) {
|
| int step = SkSign32(endIndex - index);
|
| int min = SkMin32(index, endIndex);
|
| markDoneUnary(min);
|
| - SkOpSpan* last;
|
| + SkOpSpan* last = NULL;
|
| SkOpSegment* other = this;
|
| - while ((other = other->nextChase(&index, step, &min, &last))) {
|
| + while ((other = other->nextChase(&index, &step, &min, &last))) {
|
| if (other->done()) {
|
| - return NULL;
|
| + SkASSERT(!last);
|
| + break;
|
| }
|
| other->markDoneUnary(min);
|
| }
|
| @@ -2960,12 +3400,13 @@ SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding)
|
| int step = SkSign32(endIndex - index);
|
| int min = SkMin32(index, endIndex);
|
| markWinding(min, winding);
|
| - SkOpSpan* last;
|
| + SkOpSpan* last = NULL;
|
| SkOpSegment* other = this;
|
| - while ((other = other->nextChase(&index, step, &min, &last))) {
|
| + while ((other = other->nextChase(&index, &step, &min, &last))) {
|
| if (other->fTs[min].fWindSum != SK_MinS32) {
|
| SkASSERT(other->fTs[min].fWindSum == winding);
|
| - return NULL;
|
| + SkASSERT(!last);
|
| + break;
|
| }
|
| other->markWinding(min, winding);
|
| }
|
| @@ -2976,12 +3417,13 @@ SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding)
|
| int min = SkMin32(index, endIndex);
|
| int step = SkSign32(endIndex - index);
|
| markWinding(min, winding);
|
| - SkOpSpan* last;
|
| + SkOpSpan* last = NULL;
|
| SkOpSegment* other = this;
|
| - while ((other = other->nextChase(&index, step, &min, &last))) {
|
| + while ((other = other->nextChase(&index, &step, &min, &last))) {
|
| if (other->fTs[min].fWindSum != SK_MinS32) {
|
| SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
|
| - return NULL;
|
| + SkASSERT(!last);
|
| + break;
|
| }
|
| other->markWinding(min, winding);
|
| }
|
| @@ -2992,14 +3434,32 @@ SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding,
|
| int min = SkMin32(index, endIndex);
|
| int step = SkSign32(endIndex - index);
|
| markWinding(min, winding, oppWinding);
|
| - SkOpSpan* last;
|
| + SkOpSpan* last = NULL;
|
| SkOpSegment* other = this;
|
| - while ((other = other->nextChase(&index, step, &min, &last))) {
|
| + while ((other = other->nextChase(&index, &step, &min, &last))) {
|
| if (other->fTs[min].fWindSum != SK_MinS32) {
|
| - SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
|
| - return NULL;
|
| +#if SK_DEBUG
|
| + if (!other->fTs[min].fLoop) {
|
| + if (fOperand == other->fOperand) {
|
| +// FIXME: this is probably a bug -- rects4 asserts here
|
| +// SkASSERT(other->fTs[min].fWindSum == winding);
|
| +// FIXME: this is probably a bug -- rects3 asserts here
|
| +// SkASSERT(other->fTs[min].fOppSum == oppWinding);
|
| + } else {
|
| + SkASSERT(other->fTs[min].fWindSum == oppWinding);
|
| +// FIXME: this is probably a bug -- skpwww_joomla_org_23 asserts here
|
| +// SkASSERT(other->fTs[min].fOppSum == winding);
|
| + }
|
| + }
|
| + SkASSERT(!last);
|
| +#endif
|
| + break;
|
| + }
|
| + if (fOperand == other->fOperand) {
|
| + other->markWinding(min, winding, oppWinding);
|
| + } else {
|
| + other->markWinding(min, oppWinding, winding);
|
| }
|
| - other->markWinding(min, winding, oppWinding);
|
| }
|
| return last;
|
| }
|
| @@ -3316,15 +3776,6 @@ void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) {
|
| }
|
| }
|
|
|
| -// return span if when chasing, two or more radiating spans are not done
|
| -// OPTIMIZATION: ? multiple spans is detected when there is only one valid
|
| -// candidate and the remaining spans have windValue == 0 (canceled by
|
| -// coincidence). The coincident edges could either be removed altogether,
|
| -// or this code could be more complicated in detecting this case. Worth it?
|
| -bool SkOpSegment::multipleSpans(int end) const {
|
| - return end > 0 && end < fTs.count() - 1;
|
| -}
|
| -
|
| bool SkOpSegment::nextCandidate(int* start, int* end) const {
|
| while (fTs[*end].fDone) {
|
| if (fTs[*end].fT == 1) {
|
| @@ -3337,27 +3788,67 @@ bool SkOpSegment::nextCandidate(int* start, int* end) const {
|
| return true;
|
| }
|
|
|
| -SkOpSegment* SkOpSegment::nextChase(int* index, const int step, int* min, SkOpSpan** last) {
|
| - int end = nextExactSpan(*index, step);
|
| +static SkOpSegment* set_last(SkOpSpan** last, SkOpSpan* endSpan) {
|
| + if (last && !endSpan->fSmall) {
|
| + *last = endSpan;
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +SkOpSegment* SkOpSegment::nextChase(int* indexPtr, int* stepPtr, int* minPtr, SkOpSpan** last) {
|
| + int origIndex = *indexPtr;
|
| + int step = *stepPtr;
|
| + int end = nextExactSpan(origIndex, step);
|
| SkASSERT(end >= 0);
|
| - if (fTs[end].fSmall) {
|
| - *last = NULL;
|
| - return NULL;
|
| + SkOpSpan& endSpan = fTs[end];
|
| + SkOpAngle* angle = step > 0 ? endSpan.fFromAngle : endSpan.fToAngle;
|
| + int foundIndex;
|
| + int otherEnd;
|
| + SkOpSegment* other;
|
| + if (angle == NULL) {
|
| + if (endSpan.fT != 0 && endSpan.fT != 1) {
|
| + return NULL;
|
| + }
|
| + other = endSpan.fOther;
|
| + foundIndex = endSpan.fOtherIndex;
|
| + otherEnd = other->nextExactSpan(foundIndex, step);
|
| + } else {
|
| + int loopCount = angle->loopCount();
|
| + if (loopCount > 2) {
|
| + return set_last(last, &endSpan);
|
| + }
|
| + const SkOpAngle* next = angle->next();
|
| + if (angle->sign() != next->sign()) {
|
| +#if DEBUG_WINDING
|
| + SkDebugf("%s mismatched signs\n", __FUNCTION__);
|
| +#endif
|
| + // return set_last(last, &endSpan);
|
| + }
|
| + other = next->segment();
|
| + foundIndex = end = next->start();
|
| + otherEnd = next->end();
|
| }
|
| - if (multipleSpans(end)) {
|
| - *last = &fTs[end];
|
| - return NULL;
|
| + int foundStep = foundIndex < otherEnd ? 1 : -1;
|
| + if (*stepPtr != foundStep) {
|
| + return set_last(last, &endSpan);
|
| }
|
| - const SkOpSpan& endSpan = fTs[end];
|
| - SkOpSegment* other = endSpan.fOther;
|
| - *index = endSpan.fOtherIndex;
|
| - SkASSERT(*index >= 0);
|
| - int otherEnd = other->nextExactSpan(*index, step);
|
| + SkASSERT(*indexPtr >= 0);
|
| SkASSERT(otherEnd >= 0);
|
| - *min = SkMin32(*index, otherEnd);
|
| - if (other->fTs[*min].fSmall) {
|
| - *last = NULL;
|
| - return NULL;
|
| +#if 1
|
| + int origMin = origIndex + (step < 0 ? step : 0);
|
| + const SkOpSpan& orig = this->span(origMin);
|
| +#endif
|
| + int foundMin = SkMin32(foundIndex, otherEnd);
|
| +#if 1
|
| + const SkOpSpan& found = other->span(foundMin);
|
| + if (found.fWindValue != orig.fWindValue || found.fOppValue != orig.fOppValue) {
|
| + return set_last(last, &endSpan);
|
| + }
|
| +#endif
|
| + *indexPtr = foundIndex;
|
| + *stepPtr = foundStep;
|
| + if (minPtr) {
|
| + *minPtr = foundMin;
|
| }
|
| return other;
|
| }
|
| @@ -3414,6 +3905,27 @@ int SkOpSegment::nextExactSpan(int from, int step) const {
|
| return -1;
|
| }
|
|
|
| +void SkOpSegment::pinT(const SkPoint& pt, double* t) {
|
| + if (pt == fPts[0]) {
|
| + *t = 0;
|
| + }
|
| + int count = SkPathOpsVerbToPoints(fVerb);
|
| + if (pt == fPts[count]) {
|
| + *t = 1;
|
| + }
|
| +}
|
| +
|
| +void SkOpSegment::setCoincidentRange(const SkPoint& startPt, const SkPoint& endPt,
|
| + SkOpSegment* other) {
|
| + int count = this->count();
|
| + for (int index = 0; index < count; ++index) {
|
| + SkOpSpan &span = fTs[index];
|
| + if ((startPt == span.fPt || endPt == span.fPt) && other == span.fOther) {
|
| + span.fCoincident = true;
|
| + }
|
| + }
|
| +}
|
| +
|
| void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
|
| int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) {
|
| int deltaSum = spanSign(index, endIndex);
|
| @@ -3452,15 +3964,15 @@ void SkOpSegment::sortAngles() {
|
| }
|
| int index = 0;
|
| do {
|
| - int fromIndex = fTs[index].fFromAngleIndex;
|
| - int toIndex = fTs[index].fToAngleIndex;
|
| - if (fromIndex < 0 && toIndex < 0) {
|
| + SkOpAngle* fromAngle = fTs[index].fFromAngle;
|
| + SkOpAngle* toAngle = fTs[index].fToAngle;
|
| + if (!fromAngle && !toAngle) {
|
| index += 1;
|
| continue;
|
| }
|
| SkOpAngle* baseAngle = NULL;
|
| - if (fromIndex >= 0) {
|
| - baseAngle = &this->angle(fromIndex);
|
| + if (fromAngle) {
|
| + baseAngle = fromAngle;
|
| if (inLoop(baseAngle, spanCount, &index)) {
|
| continue;
|
| }
|
| @@ -3468,8 +3980,7 @@ void SkOpSegment::sortAngles() {
|
| #if DEBUG_ANGLE
|
| bool wroteAfterHeader = false;
|
| #endif
|
| - if (toIndex >= 0) {
|
| - SkOpAngle* toAngle = &this->angle(toIndex);
|
| + if (toAngle) {
|
| if (!baseAngle) {
|
| baseAngle = toAngle;
|
| if (inLoop(baseAngle, spanCount, &index)) {
|
| @@ -3486,14 +3997,14 @@ void SkOpSegment::sortAngles() {
|
| baseAngle->insert(toAngle);
|
| }
|
| }
|
| - int nextFrom, nextTo;
|
| + SkOpAngle* nextFrom, * nextTo;
|
| int firstIndex = index;
|
| do {
|
| SkOpSpan& span = fTs[index];
|
| SkOpSegment* other = span.fOther;
|
| SkOpSpan& oSpan = other->fTs[span.fOtherIndex];
|
| - int otherAngleIndex = oSpan.fFromAngleIndex;
|
| - if (otherAngleIndex >= 0) {
|
| + SkOpAngle* oAngle = oSpan.fFromAngle;
|
| + if (oAngle) {
|
| #if DEBUG_ANGLE
|
| if (!wroteAfterHeader) {
|
| SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT,
|
| @@ -3501,13 +4012,12 @@ void SkOpSegment::sortAngles() {
|
| wroteAfterHeader = true;
|
| }
|
| #endif
|
| - SkOpAngle* oAngle = &other->angle(otherAngleIndex);
|
| if (!oAngle->loopContains(*baseAngle)) {
|
| baseAngle->insert(oAngle);
|
| }
|
| }
|
| - otherAngleIndex = oSpan.fToAngleIndex;
|
| - if (otherAngleIndex >= 0) {
|
| + oAngle = oSpan.fToAngle;
|
| + if (oAngle) {
|
| #if DEBUG_ANGLE
|
| if (!wroteAfterHeader) {
|
| SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT,
|
| @@ -3515,7 +4025,6 @@ void SkOpSegment::sortAngles() {
|
| wroteAfterHeader = true;
|
| }
|
| #endif
|
| - SkOpAngle* oAngle = &other->angle(otherAngleIndex);
|
| if (!oAngle->loopContains(*baseAngle)) {
|
| baseAngle->insert(oAngle);
|
| }
|
| @@ -3523,20 +4032,20 @@ void SkOpSegment::sortAngles() {
|
| if (++index == spanCount) {
|
| break;
|
| }
|
| - nextFrom = fTs[index].fFromAngleIndex;
|
| - nextTo = fTs[index].fToAngleIndex;
|
| - } while (fromIndex == nextFrom && toIndex == nextTo);
|
| + nextFrom = fTs[index].fFromAngle;
|
| + nextTo = fTs[index].fToAngle;
|
| + } while (fromAngle == nextFrom && toAngle == nextTo);
|
| if (baseAngle && baseAngle->loopCount() == 1) {
|
| index = firstIndex;
|
| do {
|
| SkOpSpan& span = fTs[index];
|
| - span.fFromAngleIndex = span.fToAngleIndex = -1;
|
| + span.fFromAngle = span.fToAngle = NULL;
|
| if (++index == spanCount) {
|
| break;
|
| }
|
| - nextFrom = fTs[index].fFromAngleIndex;
|
| - nextTo = fTs[index].fToAngleIndex;
|
| - } while (fromIndex == nextFrom && toIndex == nextTo);
|
| + nextFrom = fTs[index].fFromAngle;
|
| + nextTo = fTs[index].fToAngle;
|
| + } while (fromAngle == nextFrom && toAngle == nextTo);
|
| baseAngle = NULL;
|
| }
|
| #if DEBUG_SORT
|
| @@ -3749,7 +4258,8 @@ int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx
|
| SkASSERT(winding != SK_MinS32);
|
| int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
|
| #if DEBUG_WINDING_AT_T
|
| - SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
|
| + SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __FUNCTION__,
|
| + debugID(), crossOpp, tHit, t(tIndex), winding, windVal);
|
| #endif
|
| // see if a + change in T results in a +/- change in X (compute x'(T))
|
| *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
|
|
|