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
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
index 67f9fb2..0e48b3f 100644
--- a/src/pathops/SkOpSegment.cpp
+++ b/src/pathops/SkOpSegment.cpp
@@ -70,16 +70,12 @@
     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 @@
     // 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 @@
     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 @@
         }
 next:
         lastDone = span.fDone;
-        lastUnsortable = span.fUnsortableEnd;
     }
     return topPt;
 }
@@ -345,16 +332,19 @@
         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 @@
     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 @@
         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 @@
     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 @@
                 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 @@
 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 @@
     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 @@
     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 @@
             if (!foundAngle || (foundDone && activeCount & 1)) {
                 if (nextSegment->isTiny(nextAngle)) {
                     *unsortable = true;
+                    markDoneBinary(SkMin32(startIndex, endIndex));
                     return NULL;
                 }
                 foundAngle = nextAngle;
@@ -2393,6 +2403,7 @@
     bool sortable = calcWinding != SK_NaN32;
     if (!sortable) {
         *unsortable = true;
+        markDoneUnary(SkMin32(startIndex, endIndex));
         return NULL;
     }
     SkOpAngle* angle = spanToAngle(end, startIndex);
@@ -2415,6 +2426,7 @@
             if (!foundAngle || (foundDone && activeCount & 1)) {
                 if (nextSegment->isTiny(nextAngle)) {
                     *unsortable = true;
+                    markDoneUnary(SkMin32(startIndex, endIndex));
                     return NULL;
                 }
                 foundAngle = nextAngle;
@@ -2433,7 +2445,6 @@
         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 @@
     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 @@
             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 @@
 #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 @@
             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 @@
 #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 @@
 // 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 @@
     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 @@
     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::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 @@
     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 @@
         *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 @@
     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 @@
                     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 @@
                     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::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) {