| Index: src/pathops/SkPathOpsDebug.cpp | 
| diff --git a/src/pathops/SkPathOpsDebug.cpp b/src/pathops/SkPathOpsDebug.cpp | 
| index 0331f34e8a74d91ffb34f8b6d0b0d7f88f7cab25..7db93f5e969b5ba53689be47c5f9936f76601e20 100644 | 
| --- a/src/pathops/SkPathOpsDebug.cpp | 
| +++ b/src/pathops/SkPathOpsDebug.cpp | 
| @@ -7,13 +7,6 @@ | 
|  | 
| #include "SkPathOpsDebug.h" | 
| #include "SkPath.h" | 
| -#if DEBUG_ANGLE | 
| -#include "SkString.h" | 
| -#endif | 
| - | 
| -#if DEBUG_VALIDATE | 
| -extern bool FLAGS_runFail; | 
| -#endif | 
|  | 
| #if defined SK_DEBUG || !FORCE_RELEASE | 
|  | 
| @@ -33,10 +26,10 @@ | 
| const char* SkPathOpsDebug::kPathOpStr[] = {"diff", "sect", "union", "xor"}; | 
| #endif | 
|  | 
| -bool SkPathOpsDebug::ChaseContains(const SkTDArray<SkOpSpanBase* >& chaseArray, | 
| -        const SkOpSpanBase* span) { | 
| +bool SkPathOpsDebug::ChaseContains(const SkTDArray<SkOpSpan *>& chaseArray, | 
| +        const SkOpSpan* span) { | 
| for (int index = 0; index < chaseArray.count(); ++index) { | 
| -        const SkOpSpanBase* entry = chaseArray[index]; | 
| +        const SkOpSpan* entry = chaseArray[index]; | 
| if (entry == span) { | 
| return true; | 
| } | 
| @@ -72,8 +65,6 @@ | 
| SkDebugf("%d", wind); | 
| } | 
| } | 
| -#endif //  defined SK_DEBUG || !FORCE_RELEASE | 
| - | 
|  | 
| #if DEBUG_SHOW_TEST_NAME | 
| void* SkPathOpsDebug::CreateNameStr() { | 
| @@ -106,159 +97,10 @@ | 
| } | 
| #endif | 
|  | 
| +#endif //  defined SK_DEBUG || !FORCE_RELEASE | 
| + | 
| #include "SkOpAngle.h" | 
| #include "SkOpSegment.h" | 
| - | 
| -#if DEBUG_SWAP_TOP | 
| -int SkOpSegment::debugInflections(const SkOpSpanBase* start, const SkOpSpanBase* end) const { | 
| -    if (fVerb != SkPath::kCubic_Verb) { | 
| -        return false; | 
| -    } | 
| -    SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t()); | 
| -    double inflections[2]; | 
| -    return dst.findInflections(inflections); | 
| -} | 
| -#endif | 
| - | 
| -SkOpAngle* SkOpSegment::debugLastAngle() { | 
| -    SkOpAngle* result = NULL; | 
| -    SkOpSpan* span = this->head(); | 
| -    do { | 
| -        if (span->toAngle()) { | 
| -            SkASSERT(!result); | 
| -            result = span->toAngle(); | 
| -        } | 
| -    } while ((span = span->next()->upCastable())); | 
| -    SkASSERT(result); | 
| -    return result; | 
| -} | 
| - | 
| -void SkOpSegment::debugReset() { | 
| -    this->init(this->fPts, this->contour(), this->verb()); | 
| -} | 
| - | 
| -#if DEBUG_ACTIVE_SPANS | 
| -void SkOpSegment::debugShowActiveSpans() const { | 
| -    debugValidate(); | 
| -    if (done()) { | 
| -        return; | 
| -    } | 
| -    int lastId = -1; | 
| -    double lastT = -1; | 
| -    const SkOpSpan* span = &fHead; | 
| -    do { | 
| -        if (span->done()) { | 
| -            continue; | 
| -        } | 
| -        if (lastId == fID && lastT == span->t()) { | 
| -            continue; | 
| -        } | 
| -        lastId = fID; | 
| -        lastT = span->t(); | 
| -        SkDebugf("%s id=%d", __FUNCTION__, fID); | 
| -        SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | 
| -        for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | 
| -            SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | 
| -        } | 
| -        const SkOpPtT* ptT = span->ptT(); | 
| -        SkDebugf(") t=%1.9g (%1.9g,%1.9g)", ptT->fT, ptT->fPt.fX, ptT->fPt.fY); | 
| -        SkDebugf(" tEnd=%1.9g", span->next()->t()); | 
| -        SkDebugf(" windSum="); | 
| -        if (span->windSum() == SK_MinS32) { | 
| -            SkDebugf("?"); | 
| -        } else { | 
| -            SkDebugf("%d", span->windSum()); | 
| -        } | 
| -        SkDebugf(" windValue=%d oppValue=%d", span->windValue(), span->oppValue()); | 
| -        SkDebugf("\n"); | 
| -   } while ((span = span->next()->upCastable())); | 
| -} | 
| -#endif | 
| - | 
| -#if DEBUG_MARK_DONE | 
| -void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding) { | 
| -    const SkPoint& pt = span->ptT()->fPt; | 
| -    SkDebugf("%s id=%d", fun, fID); | 
| -    SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | 
| -    for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | 
| -        SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | 
| -    } | 
| -    SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=", | 
| -            span->t(), span->debugID(), pt.fX, pt.fY, span->next()->t()); | 
| -    if (winding == SK_MinS32) { | 
| -        SkDebugf("?"); | 
| -    } else { | 
| -        SkDebugf("%d", winding); | 
| -    } | 
| -    SkDebugf(" windSum="); | 
| -    if (span->windSum() == SK_MinS32) { | 
| -        SkDebugf("?"); | 
| -    } else { | 
| -        SkDebugf("%d", span->windSum()); | 
| -    } | 
| -    SkDebugf(" windValue=%d\n", span->windValue()); | 
| -} | 
| - | 
| -void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding, | 
| -                                      int oppWinding) { | 
| -    const SkPoint& pt = span->ptT()->fPt; | 
| -    SkDebugf("%s id=%d", fun, fID); | 
| -    SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | 
| -    for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | 
| -        SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | 
| -    } | 
| -    SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=", | 
| -            span->t(), span->debugID(), pt.fX, pt.fY, span->next()->t(), winding, oppWinding); | 
| -    if (winding == SK_MinS32) { | 
| -        SkDebugf("?"); | 
| -    } else { | 
| -        SkDebugf("%d", winding); | 
| -    } | 
| -    SkDebugf(" newOppSum="); | 
| -    if (oppWinding == SK_MinS32) { | 
| -        SkDebugf("?"); | 
| -    } else { | 
| -        SkDebugf("%d", oppWinding); | 
| -    } | 
| -    SkDebugf(" oppSum="); | 
| -    if (span->oppSum() == SK_MinS32) { | 
| -        SkDebugf("?"); | 
| -    } else { | 
| -        SkDebugf("%d", span->oppSum()); | 
| -    } | 
| -    SkDebugf(" windSum="); | 
| -    if (span->windSum() == SK_MinS32) { | 
| -        SkDebugf("?"); | 
| -    } else { | 
| -        SkDebugf("%d", span->windSum()); | 
| -    } | 
| -    SkDebugf(" windValue=%d oppValue=%d\n", span->windValue(), span->oppValue()); | 
| -} | 
| - | 
| -#endif | 
| - | 
| -#if DEBUG_ANGLE | 
| -SkString SkOpAngle::debugPart() const { | 
| -    SkString result; | 
| -    switch (this->segment()->verb()) { | 
| -        case SkPath::kLine_Verb: | 
| -            result.printf(LINE_DEBUG_STR " id=%d", LINE_DEBUG_DATA(fCurvePart), | 
| -                    this->segment()->debugID()); | 
| -            break; | 
| -        case SkPath::kQuad_Verb: | 
| -            result.printf(QUAD_DEBUG_STR " id=%d", QUAD_DEBUG_DATA(fCurvePart), | 
| -                    this->segment()->debugID()); | 
| -            break; | 
| -        case SkPath::kCubic_Verb: | 
| -            result.printf(CUBIC_DEBUG_STR " id=%d", CUBIC_DEBUG_DATA(fCurvePart), | 
| -                    this->segment()->debugID()); | 
| -            break; | 
| -        default: | 
| -            SkASSERT(0); | 
| -    } | 
| -    return result; | 
| -} | 
| -#endif | 
|  | 
| #if DEBUG_SORT | 
| void SkOpAngle::debugLoop() const { | 
| @@ -269,59 +111,25 @@ | 
| SkDebugf("\n"); | 
| next = next->fNext; | 
| } while (next && next != first); | 
| -    next = first; | 
| -    do { | 
| -        next->debugValidate(); | 
| -        next = next->fNext; | 
| -    } while (next && next != first); | 
| -} | 
| -#endif | 
| - | 
| -void SkOpAngle::debugValidate() const { | 
| +} | 
| +#endif | 
| + | 
| +#if DEBUG_ANGLE | 
| +void SkOpAngle::debugSameAs(const SkOpAngle* compare) const { | 
| +    SK_ALWAYSBREAK(fSegment == compare->fSegment); | 
| +    const SkOpSpan& startSpan = fSegment->span(fStart); | 
| +    const SkOpSpan& oStartSpan = fSegment->span(compare->fStart); | 
| +    SK_ALWAYSBREAK(startSpan.fToAngle == oStartSpan.fToAngle); | 
| +    SK_ALWAYSBREAK(startSpan.fFromAngle == oStartSpan.fFromAngle); | 
| +    const SkOpSpan& endSpan = fSegment->span(fEnd); | 
| +    const SkOpSpan& oEndSpan = fSegment->span(compare->fEnd); | 
| +    SK_ALWAYSBREAK(endSpan.fToAngle == oEndSpan.fToAngle); | 
| +    SK_ALWAYSBREAK(endSpan.fFromAngle == oEndSpan.fFromAngle); | 
| +} | 
| +#endif | 
| + | 
| #if DEBUG_VALIDATE | 
| -    const SkOpAngle* first = this; | 
| -    const SkOpAngle* next = this; | 
| -    int wind = 0; | 
| -    int opp = 0; | 
| -    int lastXor = -1; | 
| -    int lastOppXor = -1; | 
| -    do { | 
| -        if (next->unorderable()) { | 
| -            return; | 
| -        } | 
| -        const SkOpSpan* minSpan = next->start()->starter(next->end()); | 
| -        if (minSpan->windValue() == SK_MinS32) { | 
| -            return; | 
| -        } | 
| -        bool op = next->segment()->operand(); | 
| -        bool isXor = next->segment()->isXor(); | 
| -        bool oppXor = next->segment()->oppXor(); | 
| -        SkASSERT(!DEBUG_LIMIT_WIND_SUM || between(0, minSpan->windValue(), DEBUG_LIMIT_WIND_SUM)); | 
| -        SkASSERT(!DEBUG_LIMIT_WIND_SUM | 
| -                || between(-DEBUG_LIMIT_WIND_SUM, minSpan->oppValue(), DEBUG_LIMIT_WIND_SUM)); | 
| -        bool useXor = op ? oppXor : isXor; | 
| -        SkASSERT(lastXor == -1 || lastXor == (int) useXor); | 
| -        lastXor = (int) useXor; | 
| -        wind += next->sign() * (op ? minSpan->oppValue() : minSpan->windValue()); | 
| -        if (useXor) { | 
| -            wind &= 1; | 
| -        } | 
| -        useXor = op ? isXor : oppXor; | 
| -        SkASSERT(lastOppXor == -1 || lastOppXor == (int) useXor); | 
| -        lastOppXor = (int) useXor; | 
| -        opp += next->sign() * (op ? minSpan->windValue() : minSpan->oppValue()); | 
| -        if (useXor) { | 
| -            opp &= 1; | 
| -        } | 
| -        next = next->fNext; | 
| -    } while (next && next != first); | 
| -    SkASSERT(wind == 0); | 
| -    SkASSERT(opp == 0 || !FLAGS_runFail); | 
| -#endif | 
| -} | 
| - | 
| void SkOpAngle::debugValidateNext() const { | 
| -#if !FORCE_RELEASE | 
| const SkOpAngle* first = this; | 
| const SkOpAngle* next = first; | 
| SkTDArray<const SkOpAngle*>(angles); | 
| @@ -337,137 +145,422 @@ | 
| return; | 
| } | 
| } while (true); | 
| -#endif | 
| -} | 
| +} | 
| + | 
| +void SkOpAngle::debugValidateLoop() const { | 
| +    const SkOpAngle* first = this; | 
| +    const SkOpAngle* next = first; | 
| +    SK_ALWAYSBREAK(first->next() != first); | 
| +    int signSum = 0; | 
| +    int oppSum = 0; | 
| +    bool firstOperand = fSegment->operand(); | 
| +    bool unorderable = false; | 
| +    do { | 
| +        unorderable |= next->fUnorderable; | 
| +        const SkOpSegment* segment = next->fSegment; | 
| +        bool operandsMatch = firstOperand == segment->operand(); | 
| +        signSum += operandsMatch ? segment->spanSign(next) : segment->oppSign(next); | 
| +        oppSum += operandsMatch ? segment->oppSign(next) : segment->spanSign(next); | 
| +        const SkOpSpan& span = segment->span(SkMin32(next->fStart, next->fEnd)); | 
| +        if (segment->_xor()) { | 
| +//            SK_ALWAYSBREAK(span.fWindValue == 1); | 
| +//            SK_ALWAYSBREAK(span.fWindSum == SK_MinS32 || span.fWindSum == 1); | 
| +        } | 
| +        if (segment->oppXor()) { | 
| +            SK_ALWAYSBREAK(span.fOppValue == 0 || abs(span.fOppValue) == 1); | 
| +//            SK_ALWAYSBREAK(span.fOppSum == SK_MinS32 || span.fOppSum == 0 || abs(span.fOppSum) == 1); | 
| +        } | 
| +        next = next->next(); | 
| +        if (!next) { | 
| +            return; | 
| +        } | 
| +    } while (next != first); | 
| +    if (unorderable) { | 
| +        return; | 
| +    } | 
| +    SK_ALWAYSBREAK(!signSum || fSegment->_xor()); | 
| +    SK_ALWAYSBREAK(!oppSum || fSegment->oppXor()); | 
| +    int lastWinding; | 
| +    int lastOppWinding; | 
| +    int winding; | 
| +    int oppWinding; | 
| +    do { | 
| +        const SkOpSegment* segment = next->fSegment; | 
| +        const SkOpSpan& span = segment->span(SkMin32(next->fStart, next->fEnd)); | 
| +        winding = span.fWindSum; | 
| +        if (winding != SK_MinS32) { | 
| +//            SK_ALWAYSBREAK(winding != 0); | 
| +            SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(winding)); | 
| +            lastWinding = winding; | 
| +            int diffWinding = segment->spanSign(next); | 
| +            if (!segment->_xor()) { | 
| +                SK_ALWAYSBREAK(diffWinding != 0); | 
| +                bool sameSign = (winding > 0) == (diffWinding > 0); | 
| +                winding -= sameSign ? diffWinding : -diffWinding; | 
| +                SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(winding)); | 
| +                SK_ALWAYSBREAK(abs(winding) <= abs(lastWinding)); | 
| +                if (!sameSign) { | 
| +                    SkTSwap(winding, lastWinding); | 
| +                } | 
| +            } | 
| +            lastOppWinding = oppWinding = span.fOppSum; | 
| +            if (oppWinding != SK_MinS32 && !segment->oppXor()) { | 
| +                int oppDiffWinding = segment->oppSign(next); | 
| +//                SK_ALWAYSBREAK(abs(oppDiffWinding) <= abs(diffWinding) || segment->_xor()); | 
| +                if (oppDiffWinding) { | 
| +                    bool oppSameSign = (oppWinding > 0) == (oppDiffWinding > 0); | 
| +                    oppWinding -= oppSameSign ? oppDiffWinding : -oppDiffWinding; | 
| +                    SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(oppWinding)); | 
| +                    SK_ALWAYSBREAK(abs(oppWinding) <= abs(lastOppWinding)); | 
| +                    if (!oppSameSign) { | 
| +                        SkTSwap(oppWinding, lastOppWinding); | 
| +                    } | 
| +                } | 
| +            } | 
| +            firstOperand = segment->operand(); | 
| +            break; | 
| +        } | 
| +        SK_ALWAYSBREAK(span.fOppSum == SK_MinS32); | 
| +        next = next->next(); | 
| +    } while (next != first); | 
| +    if (winding == SK_MinS32) { | 
| +        return; | 
| +    } | 
| +    SK_ALWAYSBREAK(oppWinding == SK_MinS32 || SkPathOpsDebug::ValidWind(oppWinding)); | 
| +    first = next; | 
| +    next = next->next(); | 
| +    do { | 
| +        const SkOpSegment* segment = next->fSegment; | 
| +        lastWinding = winding; | 
| +        lastOppWinding = oppWinding; | 
| +        bool operandsMatch = firstOperand == segment->operand(); | 
| +        if (operandsMatch) { | 
| +            if (!segment->_xor()) { | 
| +                winding -= segment->spanSign(next); | 
| +                SK_ALWAYSBREAK(winding != lastWinding); | 
| +                SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(winding)); | 
| +            } | 
| +            if (!segment->oppXor()) { | 
| +                int oppDiffWinding = segment->oppSign(next); | 
| +                if (oppWinding != SK_MinS32) { | 
| +                    oppWinding -= oppDiffWinding; | 
| +                    SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(oppWinding)); | 
| +                } else { | 
| +                    SK_ALWAYSBREAK(oppDiffWinding == 0); | 
| +                } | 
| +            } | 
| +        } else { | 
| +            if (!segment->oppXor()) { | 
| +                winding -= segment->oppSign(next); | 
| +                SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(winding)); | 
| +            } | 
| +            if (!segment->_xor()) { | 
| +                oppWinding -= segment->spanSign(next); | 
| +                SK_ALWAYSBREAK(oppWinding != lastOppWinding); | 
| +                SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(oppWinding)); | 
| +            } | 
| +        } | 
| +        bool useInner = SkOpSegment::UseInnerWinding(lastWinding, winding); | 
| +        int sumWinding = useInner ? winding : lastWinding; | 
| +        bool oppUseInner = SkOpSegment::UseInnerWinding(lastOppWinding, oppWinding); | 
| +        int oppSumWinding = oppUseInner ? oppWinding : lastOppWinding; | 
| +        if (!operandsMatch) { | 
| +            SkTSwap(useInner, oppUseInner); | 
| +            SkTSwap(sumWinding, oppSumWinding); | 
| +        } | 
| +        const SkOpSpan& span = segment->span(SkMin32(next->fStart, next->fEnd)); | 
| +        if (winding == -lastWinding) { | 
| +            if (span.fWindSum != SK_MinS32) { | 
| +                SkDebugf("%s useInner=%d spanSign=%d lastWinding=%d winding=%d windSum=%d\n", | 
| +                        __FUNCTION__, | 
| +                        useInner, segment->spanSign(next), lastWinding, winding, span.fWindSum); | 
| +            } | 
| +        } | 
| +        if (oppWinding != SK_MinS32) { | 
| +            if (span.fOppSum != SK_MinS32) { | 
| +                SK_ALWAYSBREAK(span.fOppSum == oppSumWinding || segment->oppXor() || segment->_xor()); | 
| +            } | 
| +        } else { | 
| +            SK_ALWAYSBREAK(!firstOperand); | 
| +            SK_ALWAYSBREAK(!segment->operand()); | 
| +            SK_ALWAYSBREAK(!span.fOppValue); | 
| +        } | 
| +        next = next->next(); | 
| +    } while (next != first); | 
| +} | 
| +#endif | 
| + | 
| +#if DEBUG_SWAP_TOP | 
| +bool SkOpSegment::controlsContainedByEnds(int tStart, int tEnd) const { | 
| +    if (fVerb != SkPath::kCubic_Verb) { | 
| +        return false; | 
| +    } | 
| +    SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); | 
| +    return dst.controlsContainedByEnds(); | 
| +} | 
| +#endif | 
| + | 
| +#if DEBUG_CONCIDENT | 
| +// SK_ALWAYSBREAK if pair has not already been added | 
| +void SkOpSegment::debugAddTPair(double t, const SkOpSegment& other, double otherT) const { | 
| +    for (int i = 0; i < fTs.count(); ++i) { | 
| +        if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) { | 
| +            return; | 
| +        } | 
| +    } | 
| +    SK_ALWAYSBREAK(0); | 
| +} | 
| +#endif | 
| + | 
| +#if DEBUG_ANGLE | 
| +void SkOpSegment::debugCheckPointsEqualish(int tStart, int tEnd) const { | 
| +    const SkPoint& basePt = fTs[tStart].fPt; | 
| +    while (++tStart < tEnd) { | 
| +       const SkPoint& cmpPt = fTs[tStart].fPt; | 
| +       SK_ALWAYSBREAK(SkDPoint::ApproximatelyEqual(basePt, cmpPt)); | 
| +    } | 
| +} | 
| +#endif | 
| + | 
| +#if DEBUG_SWAP_TOP | 
| +int SkOpSegment::debugInflections(int tStart, int tEnd) const { | 
| +    if (fVerb != SkPath::kCubic_Verb) { | 
| +        return false; | 
| +    } | 
| +    SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); | 
| +    double inflections[2]; | 
| +    return dst.findInflections(inflections); | 
| +} | 
| +#endif | 
| + | 
| +const SkOpAngle* SkOpSegment::debugLastAngle() const { | 
| +    const SkOpAngle* result = NULL; | 
| +    for (int index = 0; index < count(); ++index) { | 
| +        const SkOpSpan& span = this->span(index); | 
| +        if (span.fToAngle) { | 
| +            SkASSERT(!result); | 
| +            result = span.fToAngle; | 
| +        } | 
| +    } | 
| +    SkASSERT(result); | 
| +    return result; | 
| +} | 
| + | 
| +void SkOpSegment::debugReset() { | 
| +    fTs.reset(); | 
| +    fAngles.reset(); | 
| +} | 
| + | 
| +#if DEBUG_CONCIDENT | 
| +void SkOpSegment::debugShowTs(const char* prefix) const { | 
| +    SkDebugf("%s %s id=%d", __FUNCTION__, prefix, fID); | 
| +    int lastWind = -1; | 
| +    int lastOpp = -1; | 
| +    double lastT = -1; | 
| +    int i; | 
| +    for (i = 0; i < fTs.count(); ++i) { | 
| +        bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue | 
| +                || lastOpp != fTs[i].fOppValue; | 
| +        if (change && lastWind >= 0) { | 
| +            SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]", | 
| +                    lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp); | 
| +        } | 
| +        if (change) { | 
| +            SkDebugf(" [o=%d", fTs[i].fOther->fID); | 
| +            lastWind = fTs[i].fWindValue; | 
| +            lastOpp = fTs[i].fOppValue; | 
| +            lastT = fTs[i].fT; | 
| +        } else { | 
| +            SkDebugf(",%d", fTs[i].fOther->fID); | 
| +        } | 
| +    } | 
| +    if (i <= 0) { | 
| +        return; | 
| +    } | 
| +    SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]", | 
| +            lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp); | 
| +    if (fOperand) { | 
| +        SkDebugf(" operand"); | 
| +    } | 
| +    if (done()) { | 
| +        SkDebugf(" done"); | 
| +    } | 
| +    SkDebugf("\n"); | 
| +} | 
| +#endif | 
| + | 
| +#if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY | 
| +void SkOpSegment::debugShowActiveSpans() const { | 
| +    debugValidate(); | 
| +    if (done()) { | 
| +        return; | 
| +    } | 
| +#if DEBUG_ACTIVE_SPANS_SHORT_FORM | 
| +    int lastId = -1; | 
| +    double lastT = -1; | 
| +#endif | 
| +    for (int i = 0; i < fTs.count(); ++i) { | 
| +        if (fTs[i].fDone) { | 
| +            continue; | 
| +        } | 
| +        SK_ALWAYSBREAK(i < fTs.count() - 1); | 
| +#if DEBUG_ACTIVE_SPANS_SHORT_FORM | 
| +        if (lastId == fID && lastT == fTs[i].fT) { | 
| +            continue; | 
| +        } | 
| +        lastId = fID; | 
| +        lastT = fTs[i].fT; | 
| +#endif | 
| +        SkDebugf("%s id=%d", __FUNCTION__, fID); | 
| +        SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | 
| +        for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | 
| +            SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | 
| +        } | 
| +        const SkOpSpan* span = &fTs[i]; | 
| +        SkDebugf(") t=%1.9g (%1.9g,%1.9g)", span->fT, xAtT(span), yAtT(span)); | 
| +        int iEnd = i + 1; | 
| +        while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) { | 
| +            ++iEnd; | 
| +        } | 
| +        SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT); | 
| +        const SkOpSegment* other = fTs[i].fOther; | 
| +        SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=", | 
| +                other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex); | 
| +        if (fTs[i].fWindSum == SK_MinS32) { | 
| +            SkDebugf("?"); | 
| +        } else { | 
| +            SkDebugf("%d", fTs[i].fWindSum); | 
| +        } | 
| +        SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue); | 
| +    } | 
| +} | 
| +#endif | 
| + | 
| +#if DEBUG_MARK_DONE || DEBUG_UNSORTABLE | 
| +void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding) { | 
| +    const SkPoint& pt = xyAtT(&span); | 
| +    SkDebugf("%s id=%d", fun, fID); | 
| +    SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | 
| +    for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | 
| +        SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | 
| +    } | 
| +    SK_ALWAYSBREAK(&span == &span.fOther->fTs[span.fOtherIndex].fOther-> | 
| +            fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]); | 
| +    SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d windSum=", | 
| +            span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, | 
| +            (&span)[1].fT, winding); | 
| +    if (span.fWindSum == SK_MinS32) { | 
| +        SkDebugf("?"); | 
| +    } else { | 
| +        SkDebugf("%d", span.fWindSum); | 
| +    } | 
| +    SkDebugf(" windValue=%d\n", span.fWindValue); | 
| +} | 
| + | 
| +void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding, | 
| +                                      int oppWinding) { | 
| +    const SkPoint& pt = xyAtT(&span); | 
| +    SkDebugf("%s id=%d", fun, fID); | 
| +    SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | 
| +    for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | 
| +        SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | 
| +    } | 
| +    SK_ALWAYSBREAK(&span == &span.fOther->fTs[span.fOtherIndex].fOther-> | 
| +            fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]); | 
| +    SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d newOppSum=%d oppSum=", | 
| +            span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, | 
| +            (&span)[1].fT, winding, oppWinding); | 
| +    if (span.fOppSum == SK_MinS32) { | 
| +        SkDebugf("?"); | 
| +    } else { | 
| +        SkDebugf("%d", span.fOppSum); | 
| +    } | 
| +    SkDebugf(" windSum="); | 
| +    if (span.fWindSum == SK_MinS32) { | 
| +        SkDebugf("?"); | 
| +    } else { | 
| +        SkDebugf("%d", span.fWindSum); | 
| +    } | 
| +    SkDebugf(" windValue=%d oppValue=%d\n", span.fWindValue, span.fOppValue); | 
| +} | 
| +#endif | 
| + | 
| +#if DEBUG_SHOW_WINDING | 
| +int SkOpSegment::debugShowWindingValues(int slotCount, int ofInterest) const { | 
| +    if (!(1 << fID & ofInterest)) { | 
| +        return 0; | 
| +    } | 
| +    int sum = 0; | 
| +    SkTArray<char, true> slots(slotCount * 2); | 
| +    memset(slots.begin(), ' ', slotCount * 2); | 
| +    for (int i = 0; i < fTs.count(); ++i) { | 
| +   //     if (!(1 << fTs[i].fOther->fID & ofInterest)) { | 
| +   //         continue; | 
| +   //     } | 
| +        sum += fTs[i].fWindValue; | 
| +        slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue); | 
| +        sum += fTs[i].fOppValue; | 
| +        slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue); | 
| +    } | 
| +    SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount, | 
| +            slots.begin() + slotCount); | 
| +    return sum; | 
| +} | 
| +#endif | 
|  | 
| void SkOpSegment::debugValidate() const { | 
| #if DEBUG_VALIDATE | 
| -    const SkOpSpanBase* span = &fHead; | 
| -    double lastT = -1; | 
| -    const SkOpSpanBase* prev = NULL; | 
| -    int count = 0; | 
| +    int count = fTs.count(); | 
| +    SK_ALWAYSBREAK(count >= 2); | 
| +    SK_ALWAYSBREAK(fTs[0].fT == 0); | 
| +    SK_ALWAYSBREAK(fTs[count - 1].fT == 1); | 
| int done = 0; | 
| -    do { | 
| -        if (!span->final()) { | 
| -            ++count; | 
| -            done += span->upCast()->done() ? 1 : 0; | 
| -        } | 
| -        SkASSERT(span->segment() == this); | 
| -        SkASSERT(!prev || prev->upCast()->next() == span); | 
| -        SkASSERT(!prev || prev == span->prev()); | 
| -        prev = span; | 
| -        double t = span->ptT()->fT; | 
| -        SkASSERT(lastT < t); | 
| -        lastT = t; | 
| -        span->debugValidate(); | 
| -    } while (!span->final() && (span = span->upCast()->next())); | 
| -    SkASSERT(count == fCount); | 
| -    SkASSERT(done == fDoneCount); | 
| -    SkASSERT(span->final()); | 
| -    span->debugValidate(); | 
| -#endif | 
| -} | 
| - | 
| -bool SkOpSpanBase::debugCoinEndLoopCheck() const { | 
| -    int loop = 0; | 
| -    const SkOpSpanBase* next = this; | 
| -    SkOpSpanBase* nextCoin; | 
| -    do { | 
| -        nextCoin = next->fCoinEnd; | 
| -        SkASSERT(nextCoin == this || nextCoin->fCoinEnd != nextCoin); | 
| -        for (int check = 1; check < loop - 1; ++check) { | 
| -            const SkOpSpanBase* checkCoin = this->fCoinEnd; | 
| -            const SkOpSpanBase* innerCoin = checkCoin; | 
| -            for (int inner = check + 1; inner < loop; ++inner) { | 
| -                innerCoin = innerCoin->fCoinEnd; | 
| -                if (checkCoin == innerCoin) { | 
| -                    SkDebugf("*** bad coincident end loop ***\n"); | 
| -                    return false; | 
| -                } | 
| -            } | 
| -        } | 
| -        ++loop; | 
| -    } while ((next = nextCoin) && next != this); | 
| -    return true; | 
| -} | 
| - | 
| -void SkOpSpanBase::debugValidate() const { | 
| -#if DEBUG_VALIDATE | 
| -    const SkOpPtT* ptT = &fPtT; | 
| -    SkASSERT(ptT->span() == this); | 
| -    do { | 
| -//        SkASSERT(SkDPoint::RoughlyEqual(fPtT.fPt, ptT->fPt)); | 
| -        ptT->debugValidate(); | 
| -        ptT = ptT->next(); | 
| -    } while (ptT != &fPtT); | 
| -    SkASSERT(this->debugCoinEndLoopCheck()); | 
| -    if (!this->final()) { | 
| -        SkASSERT(this->upCast()->debugCoinLoopCheck()); | 
| -    } | 
| -    if (fFromAngle) { | 
| -        fFromAngle->debugValidate(); | 
| -    } | 
| -    if (!this->final() && this->upCast()->toAngle()) { | 
| -        this->upCast()->toAngle()->debugValidate(); | 
| -    } | 
| -#endif | 
| -} | 
| - | 
| -bool SkOpSpan::debugCoinLoopCheck() const { | 
| -    int loop = 0; | 
| -    const SkOpSpan* next = this; | 
| -    SkOpSpan* nextCoin; | 
| -    do { | 
| -        nextCoin = next->fCoincident; | 
| -        SkASSERT(nextCoin == this || nextCoin->fCoincident != nextCoin); | 
| -        for (int check = 1; check < loop - 1; ++check) { | 
| -            const SkOpSpan* checkCoin = this->fCoincident; | 
| -            const SkOpSpan* innerCoin = checkCoin; | 
| -            for (int inner = check + 1; inner < loop; ++inner) { | 
| -                innerCoin = innerCoin->fCoincident; | 
| -                if (checkCoin == innerCoin) { | 
| -                    SkDebugf("*** bad coincident loop ***\n"); | 
| -                    return false; | 
| -                } | 
| -            } | 
| -        } | 
| -        ++loop; | 
| -    } while ((next = nextCoin) && next != this); | 
| -    return true; | 
| -} | 
| - | 
| -#include "SkOpContour.h" | 
| - | 
| -int SkOpPtT::debugLoopLimit(bool report) const { | 
| -    int loop = 0; | 
| -    const SkOpPtT* next = this; | 
| -    do { | 
| -        for (int check = 1; check < loop - 1; ++check) { | 
| -            const SkOpPtT* checkPtT = this->fNext; | 
| -            const SkOpPtT* innerPtT = checkPtT; | 
| -            for (int inner = check + 1; inner < loop; ++inner) { | 
| -                innerPtT = innerPtT->fNext; | 
| -                if (checkPtT == innerPtT) { | 
| -                    if (report) { | 
| -                        SkDebugf("*** bad ptT loop ***\n"); | 
| -                    } | 
| -                    return loop; | 
| -                } | 
| -            } | 
| -        } | 
| -        ++loop; | 
| -    } while ((next = next->fNext) && next != this); | 
| -    return 0; | 
| -} | 
| - | 
| -void SkOpPtT::debugValidate() const { | 
| -#if DEBUG_VALIDATE | 
| -    if (contour()->globalState()->phase() == SkOpGlobalState::kIntersecting) { | 
| -        return; | 
| -    } | 
| -    SkASSERT(fNext); | 
| -    SkASSERT(fNext != this); | 
| -    SkASSERT(fNext->fNext); | 
| -    SkASSERT(debugLoopLimit(false) == 0); | 
| -#endif | 
| -} | 
| +    double t = -1; | 
| +    const SkOpSpan* last = NULL; | 
| +    bool tinyTFound = false; | 
| +    bool hasLoop = false; | 
| +    for (int i = 0; i < count; ++i) { | 
| +        const SkOpSpan& span = fTs[i]; | 
| +        SK_ALWAYSBREAK(t <= span.fT); | 
| +        t = span.fT; | 
| +        int otherIndex = span.fOtherIndex; | 
| +        const SkOpSegment* other = span.fOther; | 
| +        SK_ALWAYSBREAK(other != this || fVerb == SkPath::kCubic_Verb); | 
| +        const SkOpSpan& otherSpan = other->fTs[otherIndex]; | 
| +        SK_ALWAYSBREAK(otherSpan.fPt == span.fPt); | 
| +        SK_ALWAYSBREAK(otherSpan.fOtherT == t); | 
| +        SK_ALWAYSBREAK(&fTs[i] == &otherSpan.fOther->fTs[otherSpan.fOtherIndex]); | 
| +        done += span.fDone; | 
| +        if (last) { | 
| +            SK_ALWAYSBREAK(last->fT != span.fT || last->fOther != span.fOther); | 
| +            bool tsEqual = last->fT == span.fT; | 
| +            bool tsPreciselyEqual = precisely_equal(last->fT, span.fT); | 
| +            SK_ALWAYSBREAK(!tsEqual || tsPreciselyEqual); | 
| +            bool pointsEqual = last->fPt == span.fPt; | 
| +            bool pointsNearlyEqual = AlmostEqualUlps(last->fPt, span.fPt); | 
| +#if 0  // bufferOverflow test triggers this | 
| +            SK_ALWAYSBREAK(!tsPreciselyEqual || pointsNearlyEqual); | 
| +#endif | 
| +//            SK_ALWAYSBREAK(!last->fTiny || !tsPreciselyEqual || span.fTiny || tinyTFound); | 
| +            SK_ALWAYSBREAK(last->fTiny || tsPreciselyEqual || !pointsEqual || hasLoop); | 
| +            SK_ALWAYSBREAK(!last->fTiny || pointsEqual); | 
| +            SK_ALWAYSBREAK(!last->fTiny || last->fDone); | 
| +            SK_ALWAYSBREAK(!last->fSmall || pointsNearlyEqual); | 
| +            SK_ALWAYSBREAK(!last->fSmall || last->fDone); | 
| +//            SK_ALWAYSBREAK(!last->fSmall || last->fTiny); | 
| +//            SK_ALWAYSBREAK(last->fTiny || !pointsEqual || last->fDone == span.fDone); | 
| +            if (last->fTiny) { | 
| +                tinyTFound |= !tsPreciselyEqual; | 
| +            } else { | 
| +                tinyTFound = false; | 
| +            } | 
| +        } | 
| +        last = &span; | 
| +        hasLoop |= last->fLoop; | 
| +    } | 
| +    SK_ALWAYSBREAK(done == fDoneSpans); | 
| +//    if (fAngles.count() ) { | 
| +//        fAngles.begin()->debugValidateLoop(); | 
| +//    } | 
| +#endif | 
| +} | 
|  |