aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pathops/SkOpSegment.cpp
diff options
context:
space:
mode:
authorGravatar caryclark <caryclark@google.com>2014-06-17 05:15:38 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-06-17 05:15:38 -0700
commitdac1d17027dcaa5596885a9f333979418b35001c (patch)
tree923c6ca762654144254565240de5e9ec6598c41f /src/pathops/SkOpSegment.cpp
parentd6043b20b63f895d384b4794205ac914abfafa71 (diff)
Enabling the canvas bit to turn the clip stack into a flat replace exposed around 100 failures when testing the 800K skp set generated from the top 1M web sites.
This fixes all but one of those failures. Major changes include: - Replace angle indices with angle pointers. This was motivated by the need to add angles later but not renumber existing angles. - Aggressive segment chase. When the winding is known on a segment, more aggressively passing that winding to adjacent segments allows fragmented data sets to succeed. - Line segments with ends nearly the same are treated as coincident first. - Transfer partial coincidence by observing that if segment A is partially coincident to B and C then B and C may be partially coincident. TBR=reed Author: caryclark@google.com Review URL: https://codereview.chromium.org/272153002
Diffstat (limited to 'src/pathops/SkOpSegment.cpp')
-rw-r--r--src/pathops/SkOpSegment.cpp1096
1 files changed, 803 insertions, 293 deletions
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
index 0e48b3f913..59e6d344a5 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;
+ 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;
+ 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;