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