gfx/skia/trunk/src/pathops/SkOpSegment.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/pathops/SkOpSegment.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3328 @@
     1.4 +/*
     1.5 + * Copyright 2012 Google Inc.
     1.6 + *
     1.7 + * Use of this source code is governed by a BSD-style license that can be
     1.8 + * found in the LICENSE file.
     1.9 + */
    1.10 +#include "SkIntersections.h"
    1.11 +#include "SkOpSegment.h"
    1.12 +#include "SkPathWriter.h"
    1.13 +#include "SkTSort.h"
    1.14 +
    1.15 +#define F (false)      // discard the edge
    1.16 +#define T (true)       // keep the edge
    1.17 +
    1.18 +static const bool gUnaryActiveEdge[2][2] = {
    1.19 +//  from=0  from=1
    1.20 +//  to=0,1  to=0,1
    1.21 +    {F, T}, {T, F},
    1.22 +};
    1.23 +
    1.24 +static const bool gActiveEdge[kXOR_PathOp + 1][2][2][2][2] = {
    1.25 +//                 miFrom=0                              miFrom=1
    1.26 +//         miTo=0            miTo=1              miTo=0             miTo=1
    1.27 +//    suFrom=0    1     suFrom=0     1      suFrom=0    1      suFrom=0    1
    1.28 +//   suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1
    1.29 +    {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}},  // mi - su
    1.30 +    {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}},  // mi & su
    1.31 +    {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}},  // mi | su
    1.32 +    {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}},  // mi ^ su
    1.33 +};
    1.34 +
    1.35 +#undef F
    1.36 +#undef T
    1.37 +
    1.38 +enum {
    1.39 +    kOutsideTrackedTCount = 16,  // FIXME: determine what this should be
    1.40 +    kMissingSpanCount = 4,  // FIXME: determine what this should be
    1.41 +};
    1.42 +
    1.43 +// note that this follows the same logic flow as build angles
    1.44 +bool SkOpSegment::activeAngle(int index, int* done, SkTArray<SkOpAngle, true>* angles) {
    1.45 +    if (activeAngleInner(index, done, angles)) {
    1.46 +        return true;
    1.47 +    }
    1.48 +    double referenceT = fTs[index].fT;
    1.49 +    int lesser = index;
    1.50 +    while (--lesser >= 0
    1.51 +            && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].fTiny)) {
    1.52 +        if (activeAngleOther(lesser, done, angles)) {
    1.53 +            return true;
    1.54 +        }
    1.55 +    }
    1.56 +    do {
    1.57 +        if (activeAngleOther(index, done, angles)) {
    1.58 +            return true;
    1.59 +        }
    1.60 +        if (++index == fTs.count()) {
    1.61 +            break;
    1.62 +        }
    1.63 +        if (fTs[index - 1].fTiny) {
    1.64 +            referenceT = fTs[index].fT;
    1.65 +            continue;
    1.66 +        }
    1.67 +    } while (precisely_negative(fTs[index].fT - referenceT));
    1.68 +    return false;
    1.69 +}
    1.70 +
    1.71 +bool SkOpSegment::activeAngleOther(int index, int* done, SkTArray<SkOpAngle, true>* angles) {
    1.72 +    SkOpSpan* span = &fTs[index];
    1.73 +    SkOpSegment* other = span->fOther;
    1.74 +    int oIndex = span->fOtherIndex;
    1.75 +    return other->activeAngleInner(oIndex, done, angles);
    1.76 +}
    1.77 +
    1.78 +bool SkOpSegment::activeAngleInner(int index, int* done, SkTArray<SkOpAngle, true>* angles) {
    1.79 +    int next = nextExactSpan(index, 1);
    1.80 +    if (next > 0) {
    1.81 +        SkOpSpan& upSpan = fTs[index];
    1.82 +        if (upSpan.fWindValue || upSpan.fOppValue) {
    1.83 +            addAngle(angles, index, next);
    1.84 +            if (upSpan.fDone || upSpan.fUnsortableEnd) {
    1.85 +                (*done)++;
    1.86 +            } else if (upSpan.fWindSum != SK_MinS32) {
    1.87 +                return true;
    1.88 +            }
    1.89 +        } else if (!upSpan.fDone) {
    1.90 +            upSpan.fDone = true;
    1.91 +            fDoneSpans++;
    1.92 +        }
    1.93 +    }
    1.94 +    int prev = nextExactSpan(index, -1);
    1.95 +    // edge leading into junction
    1.96 +    if (prev >= 0) {
    1.97 +        SkOpSpan& downSpan = fTs[prev];
    1.98 +        if (downSpan.fWindValue || downSpan.fOppValue) {
    1.99 +            addAngle(angles, index, prev);
   1.100 +            if (downSpan.fDone) {
   1.101 +                (*done)++;
   1.102 +             } else if (downSpan.fWindSum != SK_MinS32) {
   1.103 +                return true;
   1.104 +            }
   1.105 +        } else if (!downSpan.fDone) {
   1.106 +            downSpan.fDone = true;
   1.107 +            fDoneSpans++;
   1.108 +        }
   1.109 +    }
   1.110 +    return false;
   1.111 +}
   1.112 +
   1.113 +SkPoint SkOpSegment::activeLeftTop(bool onlySortable, int* firstT) const {
   1.114 +    SkASSERT(!done());
   1.115 +    SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
   1.116 +    int count = fTs.count();
   1.117 +    // see if either end is not done since we want smaller Y of the pair
   1.118 +    bool lastDone = true;
   1.119 +    bool lastUnsortable = false;
   1.120 +    double lastT = -1;
   1.121 +    for (int index = 0; index < count; ++index) {
   1.122 +        const SkOpSpan& span = fTs[index];
   1.123 +        if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
   1.124 +            goto next;
   1.125 +        }
   1.126 +        if (span.fDone && lastDone) {
   1.127 +            goto next;
   1.128 +        }
   1.129 +        if (approximately_negative(span.fT - lastT)) {
   1.130 +            goto next;
   1.131 +        }
   1.132 +        {
   1.133 +            const SkPoint& xy = xyAtT(&span);
   1.134 +            if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
   1.135 +                topPt = xy;
   1.136 +                if (firstT) {
   1.137 +                    *firstT = index;
   1.138 +                }
   1.139 +            }
   1.140 +            if (fVerb != SkPath::kLine_Verb && !lastDone) {
   1.141 +                SkPoint curveTop = (*CurveTop[SkPathOpsVerbToPoints(fVerb)])(fPts, lastT, span.fT);
   1.142 +                if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
   1.143 +                        && topPt.fX > curveTop.fX)) {
   1.144 +                    topPt = curveTop;
   1.145 +                    if (firstT) {
   1.146 +                        *firstT = index;
   1.147 +                    }
   1.148 +                }
   1.149 +            }
   1.150 +            lastT = span.fT;
   1.151 +        }
   1.152 +next:
   1.153 +        lastDone = span.fDone;
   1.154 +        lastUnsortable = span.fUnsortableEnd;
   1.155 +    }
   1.156 +    return topPt;
   1.157 +}
   1.158 +
   1.159 +bool SkOpSegment::activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op) {
   1.160 +    int sumMiWinding = updateWinding(endIndex, index);
   1.161 +    int sumSuWinding = updateOppWinding(endIndex, index);
   1.162 +    if (fOperand) {
   1.163 +        SkTSwap<int>(sumMiWinding, sumSuWinding);
   1.164 +    }
   1.165 +    int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
   1.166 +    return activeOp(xorMiMask, xorSuMask, index, endIndex, op, &sumMiWinding, &sumSuWinding,
   1.167 +            &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
   1.168 +}
   1.169 +
   1.170 +bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op,
   1.171 +        int* sumMiWinding, int* sumSuWinding,
   1.172 +        int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) {
   1.173 +    setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
   1.174 +            maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
   1.175 +    bool miFrom;
   1.176 +    bool miTo;
   1.177 +    bool suFrom;
   1.178 +    bool suTo;
   1.179 +    if (operand()) {
   1.180 +        miFrom = (*oppMaxWinding & xorMiMask) != 0;
   1.181 +        miTo = (*oppSumWinding & xorMiMask) != 0;
   1.182 +        suFrom = (*maxWinding & xorSuMask) != 0;
   1.183 +        suTo = (*sumWinding & xorSuMask) != 0;
   1.184 +    } else {
   1.185 +        miFrom = (*maxWinding & xorMiMask) != 0;
   1.186 +        miTo = (*sumWinding & xorMiMask) != 0;
   1.187 +        suFrom = (*oppMaxWinding & xorSuMask) != 0;
   1.188 +        suTo = (*oppSumWinding & xorSuMask) != 0;
   1.189 +    }
   1.190 +    bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
   1.191 +#if DEBUG_ACTIVE_OP
   1.192 +    SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__,
   1.193 +            SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
   1.194 +#endif
   1.195 +    return result;
   1.196 +}
   1.197 +
   1.198 +bool SkOpSegment::activeWinding(int index, int endIndex) {
   1.199 +    int sumWinding = updateWinding(endIndex, index);
   1.200 +    int maxWinding;
   1.201 +    return activeWinding(index, endIndex, &maxWinding, &sumWinding);
   1.202 +}
   1.203 +
   1.204 +bool SkOpSegment::activeWinding(int index, int endIndex, int* maxWinding, int* sumWinding) {
   1.205 +    setUpWinding(index, endIndex, maxWinding, sumWinding);
   1.206 +    bool from = *maxWinding != 0;
   1.207 +    bool to = *sumWinding  != 0;
   1.208 +    bool result = gUnaryActiveEdge[from][to];
   1.209 +    return result;
   1.210 +}
   1.211 +
   1.212 +void SkOpSegment::addAngle(SkTArray<SkOpAngle, true>* anglesPtr, int start, int end) const {
   1.213 +    SkASSERT(start != end);
   1.214 +    SkOpAngle& angle = anglesPtr->push_back();
   1.215 +    angle.set(this, start, end);
   1.216 +}
   1.217 +
   1.218 +void SkOpSegment::addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt,
   1.219 +        SkOpSegment* other) {
   1.220 +    int tIndex = -1;
   1.221 +    int tCount = fTs.count();
   1.222 +    int oIndex = -1;
   1.223 +    int oCount = other->fTs.count();
   1.224 +    do {
   1.225 +        ++tIndex;
   1.226 +    } while (startPt != fTs[tIndex].fPt && tIndex < tCount);
   1.227 +    int tIndexStart = tIndex;
   1.228 +    do {
   1.229 +        ++oIndex;
   1.230 +    } while (endPt != other->fTs[oIndex].fPt && oIndex < oCount);
   1.231 +    int oIndexStart = oIndex;
   1.232 +    const SkPoint* nextPt;
   1.233 +    do {
   1.234 +        nextPt = &fTs[++tIndex].fPt;
   1.235 +        SkASSERT(fTs[tIndex].fT < 1 || startPt != *nextPt);
   1.236 +    } while (startPt == *nextPt);
   1.237 +    double nextT = fTs[tIndex].fT;
   1.238 +    const SkPoint* oNextPt;
   1.239 +    do {
   1.240 +        oNextPt = &other->fTs[++oIndex].fPt;
   1.241 +        SkASSERT(other->fTs[oIndex].fT < 1 || endPt != *oNextPt);
   1.242 +    } while (endPt == *oNextPt);
   1.243 +    double oNextT = other->fTs[oIndex].fT;
   1.244 +    // at this point, spans before and after are at:
   1.245 +    //  fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
   1.246 +    // if tIndexStart == 0, no prior span
   1.247 +    // if nextT == 1, no following span
   1.248 +
   1.249 +    // advance the span with zero winding
   1.250 +    // if the following span exists (not past the end, non-zero winding)
   1.251 +    // connect the two edges
   1.252 +    if (!fTs[tIndexStart].fWindValue) {
   1.253 +        if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
   1.254 +#if DEBUG_CONCIDENT
   1.255 +            SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
   1.256 +                    __FUNCTION__, fID, other->fID, tIndexStart - 1,
   1.257 +                    fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
   1.258 +                    xyAtT(tIndexStart).fY);
   1.259 +#endif
   1.260 +            addTPair(fTs[tIndexStart].fT, other, other->fTs[oIndex].fT, false,
   1.261 +                    fTs[tIndexStart].fPt);
   1.262 +        }
   1.263 +        if (nextT < 1 && fTs[tIndex].fWindValue) {
   1.264 +#if DEBUG_CONCIDENT
   1.265 +            SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
   1.266 +                    __FUNCTION__, fID, other->fID, tIndex,
   1.267 +                    fTs[tIndex].fT, xyAtT(tIndex).fX,
   1.268 +                    xyAtT(tIndex).fY);
   1.269 +#endif
   1.270 +            addTPair(fTs[tIndex].fT, other, other->fTs[oIndexStart].fT, false, fTs[tIndex].fPt);
   1.271 +        }
   1.272 +    } else {
   1.273 +        SkASSERT(!other->fTs[oIndexStart].fWindValue);
   1.274 +        if (oIndexStart > 0 && other->fTs[oIndexStart - 1].fWindValue) {
   1.275 +#if DEBUG_CONCIDENT
   1.276 +            SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
   1.277 +                    __FUNCTION__, fID, other->fID, oIndexStart - 1,
   1.278 +                    other->fTs[oIndexStart].fT, other->xyAtT(oIndexStart).fX,
   1.279 +                    other->xyAtT(oIndexStart).fY);
   1.280 +            other->debugAddTPair(other->fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
   1.281 +#endif
   1.282 +        }
   1.283 +        if (oNextT < 1 && other->fTs[oIndex].fWindValue) {
   1.284 +#if DEBUG_CONCIDENT
   1.285 +            SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
   1.286 +                    __FUNCTION__, fID, other->fID, oIndex,
   1.287 +                    other->fTs[oIndex].fT, other->xyAtT(oIndex).fX,
   1.288 +                    other->xyAtT(oIndex).fY);
   1.289 +            other->debugAddTPair(other->fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
   1.290 +#endif
   1.291 +        }
   1.292 +    }
   1.293 +}
   1.294 +
   1.295 +void SkOpSegment::addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt,
   1.296 +        SkOpSegment* other) {
   1.297 +    // walk this to startPt
   1.298 +    // walk other to startPt
   1.299 +    // if either is > 0, add a pointer to the other, copying adjacent winding
   1.300 +    int tIndex = -1;
   1.301 +    int oIndex = -1;
   1.302 +    do {
   1.303 +        ++tIndex;
   1.304 +    } while (startPt != fTs[tIndex].fPt);
   1.305 +    do {
   1.306 +        ++oIndex;
   1.307 +    } while (startPt != other->fTs[oIndex].fPt);
   1.308 +    if (tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) {
   1.309 +        addTPair(fTs[tIndex].fT, other, other->fTs[oIndex].fT, false, startPt);
   1.310 +    }
   1.311 +    SkPoint nextPt = startPt;
   1.312 +    do {
   1.313 +        const SkPoint* workPt;
   1.314 +        do {
   1.315 +            workPt = &fTs[++tIndex].fPt;
   1.316 +        } while (nextPt == *workPt);
   1.317 +        do {
   1.318 +            workPt = &other->fTs[++oIndex].fPt;
   1.319 +        } while (nextPt == *workPt);
   1.320 +        nextPt = *workPt;
   1.321 +        double tStart = fTs[tIndex].fT;
   1.322 +        double oStart = other->fTs[oIndex].fT;
   1.323 +        if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) {
   1.324 +            break;
   1.325 +        }
   1.326 +        addTPair(tStart, other, oStart, false, nextPt);
   1.327 +    } while (endPt != nextPt);
   1.328 +}
   1.329 +
   1.330 +void SkOpSegment::addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
   1.331 +    init(pts, SkPath::kCubic_Verb, operand, evenOdd);
   1.332 +    fBounds.setCubicBounds(pts);
   1.333 +}
   1.334 +
   1.335 +void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active) const {
   1.336 +    SkPoint edge[4];
   1.337 +    const SkPoint* ePtr;
   1.338 +    int lastT = fTs.count() - 1;
   1.339 +    if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
   1.340 +        ePtr = fPts;
   1.341 +    } else {
   1.342 +    // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
   1.343 +        subDivide(start, end, edge);
   1.344 +        ePtr = edge;
   1.345 +    }
   1.346 +    if (active) {
   1.347 +        bool reverse = ePtr == fPts && start != 0;
   1.348 +        if (reverse) {
   1.349 +            path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]);
   1.350 +            switch (fVerb) {
   1.351 +                case SkPath::kLine_Verb:
   1.352 +                    path->deferredLine(ePtr[0]);
   1.353 +                    break;
   1.354 +                case SkPath::kQuad_Verb:
   1.355 +                    path->quadTo(ePtr[1], ePtr[0]);
   1.356 +                    break;
   1.357 +                case SkPath::kCubic_Verb:
   1.358 +                    path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
   1.359 +                    break;
   1.360 +                default:
   1.361 +                    SkASSERT(0);
   1.362 +            }
   1.363 +   //         return ePtr[0];
   1.364 +       } else {
   1.365 +            path->deferredMoveLine(ePtr[0]);
   1.366 +            switch (fVerb) {
   1.367 +                case SkPath::kLine_Verb:
   1.368 +                    path->deferredLine(ePtr[1]);
   1.369 +                    break;
   1.370 +                case SkPath::kQuad_Verb:
   1.371 +                    path->quadTo(ePtr[1], ePtr[2]);
   1.372 +                    break;
   1.373 +                case SkPath::kCubic_Verb:
   1.374 +                    path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
   1.375 +                    break;
   1.376 +                default:
   1.377 +                    SkASSERT(0);
   1.378 +            }
   1.379 +        }
   1.380 +    }
   1.381 +  //  return ePtr[SkPathOpsVerbToPoints(fVerb)];
   1.382 +}
   1.383 +
   1.384 +void SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
   1.385 +    init(pts, SkPath::kLine_Verb, operand, evenOdd);
   1.386 +    fBounds.set(pts, 2);
   1.387 +}
   1.388 +
   1.389 +// add 2 to edge or out of range values to get T extremes
   1.390 +void SkOpSegment::addOtherT(int index, double otherT, int otherIndex) {
   1.391 +    SkOpSpan& span = fTs[index];
   1.392 +    if (precisely_zero(otherT)) {
   1.393 +        otherT = 0;
   1.394 +    } else if (precisely_equal(otherT, 1)) {
   1.395 +        otherT = 1;
   1.396 +    }
   1.397 +    span.fOtherT = otherT;
   1.398 +    span.fOtherIndex = otherIndex;
   1.399 +}
   1.400 +
   1.401 +void SkOpSegment::addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
   1.402 +    init(pts, SkPath::kQuad_Verb, operand, evenOdd);
   1.403 +    fBounds.setQuadBounds(pts);
   1.404 +}
   1.405 +
   1.406 +    // Defer all coincident edge processing until
   1.407 +    // after normal intersections have been computed
   1.408 +
   1.409 +// no need to be tricky; insert in normal T order
   1.410 +// resolve overlapping ts when considering coincidence later
   1.411 +
   1.412 +    // add non-coincident intersection. Resulting edges are sorted in T.
   1.413 +int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) {
   1.414 +    if (precisely_zero(newT)) {
   1.415 +        newT = 0;
   1.416 +    } else if (precisely_equal(newT, 1)) {
   1.417 +        newT = 1;
   1.418 +    }
   1.419 +    // FIXME: in the pathological case where there is a ton of intercepts,
   1.420 +    //  binary search?
   1.421 +    int insertedAt = -1;
   1.422 +    size_t tCount = fTs.count();
   1.423 +    const SkPoint& firstPt = fPts[0];
   1.424 +    const SkPoint& lastPt = fPts[SkPathOpsVerbToPoints(fVerb)];
   1.425 +    for (size_t index = 0; index < tCount; ++index) {
   1.426 +        // OPTIMIZATION: if there are three or more identical Ts, then
   1.427 +        // the fourth and following could be further insertion-sorted so
   1.428 +        // that all the edges are clockwise or counterclockwise.
   1.429 +        // This could later limit segment tests to the two adjacent
   1.430 +        // neighbors, although it doesn't help with determining which
   1.431 +        // circular direction to go in.
   1.432 +        const SkOpSpan& span = fTs[index];
   1.433 +        if (newT < span.fT) {
   1.434 +            insertedAt = index;
   1.435 +            break;
   1.436 +        }
   1.437 +        if (newT == span.fT) {
   1.438 +            if (pt == span.fPt) {
   1.439 +                insertedAt = index;
   1.440 +                break;
   1.441 +            }
   1.442 +            if ((pt == firstPt && newT == 0) || (span.fPt == lastPt && newT == 1)) {
   1.443 +                insertedAt = index;
   1.444 +                break;
   1.445 +            }
   1.446 +        }
   1.447 +    }
   1.448 +    SkOpSpan* span;
   1.449 +    if (insertedAt >= 0) {
   1.450 +        span = fTs.insert(insertedAt);
   1.451 +    } else {
   1.452 +        insertedAt = tCount;
   1.453 +        span = fTs.append();
   1.454 +    }
   1.455 +    span->fT = newT;
   1.456 +    span->fOther = other;
   1.457 +    span->fPt = pt;
   1.458 +#if 0
   1.459 +    // cubics, for instance, may not be exact enough to satisfy this check (e.g., cubicOp69d)
   1.460 +    SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX)
   1.461 +            && approximately_equal(xyAtT(newT).fY, pt.fY));
   1.462 +#endif
   1.463 +    span->fWindSum = SK_MinS32;
   1.464 +    span->fOppSum = SK_MinS32;
   1.465 +    span->fWindValue = 1;
   1.466 +    span->fOppValue = 0;
   1.467 +    span->fSmall = false;
   1.468 +    span->fTiny = false;
   1.469 +    span->fLoop = false;
   1.470 +    if ((span->fDone = newT == 1)) {
   1.471 +        ++fDoneSpans;
   1.472 +    }
   1.473 +    span->fUnsortableStart = false;
   1.474 +    span->fUnsortableEnd = false;
   1.475 +    int less = -1;
   1.476 +    while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt, span->fPt)) {
   1.477 +        if (span[less].fDone) {
   1.478 +            break;
   1.479 +        }
   1.480 +        double tInterval = newT - span[less].fT;
   1.481 +        if (precisely_negative(tInterval)) {
   1.482 +            break;
   1.483 +        }
   1.484 +        if (fVerb == SkPath::kCubic_Verb) {
   1.485 +            double tMid = newT - tInterval / 2;
   1.486 +            SkDPoint midPt = dcubic_xy_at_t(fPts, tMid);
   1.487 +            if (!midPt.approximatelyEqual(xyAtT(span))) {
   1.488 +                break;
   1.489 +            }
   1.490 +        }
   1.491 +        span[less].fSmall = true;
   1.492 +        bool tiny = span[less].fPt == span->fPt;
   1.493 +        span[less].fTiny = tiny;
   1.494 +        span[less].fDone = true;
   1.495 +        if (approximately_negative(newT - span[less].fT) && tiny) {
   1.496 +            if (approximately_greater_than_one(newT)) {
   1.497 +                SkASSERT(&span[less] - fTs.begin() < fTs.count());
   1.498 +                span[less].fUnsortableStart = true;
   1.499 +                if (&span[less - 1] - fTs.begin() >= 0) {
   1.500 +                    span[less - 1].fUnsortableEnd = true;
   1.501 +                }
   1.502 +            }
   1.503 +            if (approximately_less_than_zero(span[less].fT)) {
   1.504 +                SkASSERT(&span[less + 1] - fTs.begin() < fTs.count());
   1.505 +                SkASSERT(&span[less] - fTs.begin() >= 0);
   1.506 +                span[less + 1].fUnsortableStart = true;
   1.507 +                span[less].fUnsortableEnd = true;
   1.508 +            }
   1.509 +        }
   1.510 +        ++fDoneSpans;
   1.511 +        --less;
   1.512 +    }
   1.513 +    int more = 1;
   1.514 +    while (fTs.end() - &span[more - 1] > 1 && AlmostEqualUlps(span[more].fPt, span->fPt)) {
   1.515 +        if (span[more - 1].fDone) {
   1.516 +            break;
   1.517 +        }
   1.518 +        double tEndInterval = span[more].fT - newT;
   1.519 +        if (precisely_negative(tEndInterval)) {
   1.520 +            if ((span->fTiny = span[more].fTiny)) {
   1.521 +                span->fDone = true;
   1.522 +                ++fDoneSpans;
   1.523 +            }
   1.524 +            break;
   1.525 +        }
   1.526 +        if (fVerb == SkPath::kCubic_Verb) {
   1.527 +            double tMid = newT - tEndInterval / 2;
   1.528 +            SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid);
   1.529 +            if (!midEndPt.approximatelyEqual(xyAtT(span))) {
   1.530 +                break;
   1.531 +            }
   1.532 +        }
   1.533 +        span[more - 1].fSmall = true;
   1.534 +        bool tiny = span[more].fPt == span->fPt;
   1.535 +        span[more - 1].fTiny = tiny;
   1.536 +        span[more - 1].fDone = true;
   1.537 +        if (approximately_negative(span[more].fT - newT) && tiny) {
   1.538 +            if (approximately_greater_than_one(span[more].fT)) {
   1.539 +                span[more + 1].fUnsortableStart = true;
   1.540 +                span[more].fUnsortableEnd = true;
   1.541 +            }
   1.542 +            if (approximately_less_than_zero(newT)) {
   1.543 +                span[more].fUnsortableStart = true;
   1.544 +                span[more - 1].fUnsortableEnd = true;
   1.545 +            }
   1.546 +        }
   1.547 +        ++fDoneSpans;
   1.548 +        ++more;
   1.549 +    }
   1.550 +    return insertedAt;
   1.551 +}
   1.552 +
   1.553 +// set spans from start to end to decrement by one
   1.554 +// note this walks other backwards
   1.555 +// FIXME: there's probably an edge case that can be constructed where
   1.556 +// two span in one segment are separated by float epsilon on one span but
   1.557 +// not the other, if one segment is very small. For this
   1.558 +// case the counts asserted below may or may not be enough to separate the
   1.559 +// spans. Even if the counts work out, what if the spans aren't correctly
   1.560 +// sorted? It feels better in such a case to match the span's other span
   1.561 +// pointer since both coincident segments must contain the same spans.
   1.562 +// FIXME? It seems that decrementing by one will fail for complex paths that
   1.563 +// have three or more coincident edges. Shouldn't this subtract the difference
   1.564 +// between the winding values?
   1.565 +/*                                      |-->                           |-->
   1.566 +this     0>>>>1>>>>2>>>>3>>>4      0>>>>1>>>>2>>>>3>>>4      0>>>>1>>>>2>>>>3>>>4
   1.567 +other         2<<<<1<<<<0               2<<<<1<<<<0               2<<<<1<<<<0
   1.568 +              ^         ^                 <--|                           <--|
   1.569 +           startPt    endPt        test/oTest first pos      test/oTest final pos
   1.570 +*/
   1.571 +void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other) {
   1.572 +    bool binary = fOperand != other->fOperand;
   1.573 +    int index = 0;
   1.574 +    while (startPt != fTs[index].fPt) {
   1.575 +        SkASSERT(index < fTs.count());
   1.576 +        ++index;
   1.577 +    }
   1.578 +    while (index > 0 && fTs[index].fT == fTs[index - 1].fT) {
   1.579 +        --index;
   1.580 +    }
   1.581 +    int oIndex = other->fTs.count();
   1.582 +    while (startPt != other->fTs[--oIndex].fPt) {  // look for startPt match
   1.583 +        SkASSERT(oIndex > 0);
   1.584 +    }
   1.585 +    double oStartT = other->fTs[oIndex].fT;
   1.586 +    // look for first point beyond match
   1.587 +    while (startPt == other->fTs[--oIndex].fPt || oStartT == other->fTs[oIndex].fT) {
   1.588 +        SkASSERT(oIndex > 0);
   1.589 +    }
   1.590 +    SkOpSpan* test = &fTs[index];
   1.591 +    SkOpSpan* oTest = &other->fTs[oIndex];
   1.592 +    SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
   1.593 +    SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
   1.594 +    do {
   1.595 +        SkASSERT(test->fT < 1);
   1.596 +        SkASSERT(oTest->fT < 1);
   1.597 +        bool decrement = test->fWindValue && oTest->fWindValue;
   1.598 +        bool track = test->fWindValue || oTest->fWindValue;
   1.599 +        bool bigger = test->fWindValue >= oTest->fWindValue;
   1.600 +        const SkPoint& testPt = test->fPt;
   1.601 +        double testT = test->fT;
   1.602 +        const SkPoint& oTestPt = oTest->fPt;
   1.603 +        double oTestT = oTest->fT;
   1.604 +        do {
   1.605 +            if (decrement) {
   1.606 +                if (binary && bigger) {
   1.607 +                    test->fOppValue--;
   1.608 +                } else {
   1.609 +                    decrementSpan(test);
   1.610 +                }
   1.611 +            } else if (track) {
   1.612 +                TrackOutsidePair(&outsidePts, testPt, oTestPt);
   1.613 +            }
   1.614 +            SkASSERT(index < fTs.count() - 1);
   1.615 +            test = &fTs[++index];
   1.616 +        } while (testPt == test->fPt || testT == test->fT);
   1.617 +        SkDEBUGCODE(int originalWindValue = oTest->fWindValue);
   1.618 +        do {
   1.619 +            SkASSERT(oTest->fT < 1);
   1.620 +            SkASSERT(originalWindValue == oTest->fWindValue);
   1.621 +            if (decrement) {
   1.622 +                if (binary && !bigger) {
   1.623 +                    oTest->fOppValue--;
   1.624 +                } else {
   1.625 +                    other->decrementSpan(oTest);
   1.626 +                }
   1.627 +            } else if (track) {
   1.628 +                TrackOutsidePair(&oOutsidePts, oTestPt, testPt);
   1.629 +            }
   1.630 +            if (!oIndex) {
   1.631 +                break;
   1.632 +            }
   1.633 +            oTest = &other->fTs[--oIndex];
   1.634 +        } while (oTestPt == oTest->fPt || oTestT == oTest->fT);
   1.635 +    } while (endPt != test->fPt && test->fT < 1);
   1.636 +    // FIXME: determine if canceled edges need outside ts added
   1.637 +    int outCount = outsidePts.count();
   1.638 +    if (!done() && outCount) {
   1.639 +        addCancelOutsides(outsidePts[0], outsidePts[1], other);
   1.640 +        if (outCount > 2) {
   1.641 +            addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1], other);
   1.642 +        }
   1.643 +    }
   1.644 +    if (!other->done() && oOutsidePts.count()) {
   1.645 +        other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this);
   1.646 +    }
   1.647 +}
   1.648 +
   1.649 +int SkOpSegment::addSelfT(SkOpSegment* other, const SkPoint& pt, double newT) {
   1.650 +    // if the tail nearly intersects itself but not quite, the caller records this separately
   1.651 +    int result = addT(other, pt, newT);
   1.652 +    SkOpSpan* span = &fTs[result];
   1.653 +    span->fLoop = true;
   1.654 +    return result;
   1.655 +}
   1.656 +
   1.657 +void SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* indexPtr,
   1.658 +        SkTArray<SkPoint, true>* outsideTs) {
   1.659 +    int index = *indexPtr;
   1.660 +    int oWindValue = oTest.fWindValue;
   1.661 +    int oOppValue = oTest.fOppValue;
   1.662 +    if (binary) {
   1.663 +        SkTSwap<int>(oWindValue, oOppValue);
   1.664 +    }
   1.665 +    SkOpSpan* const test = &fTs[index];
   1.666 +    SkOpSpan* end = test;
   1.667 +    const SkPoint& oStartPt = oTest.fPt;
   1.668 +    do {
   1.669 +        if (bumpSpan(end, oWindValue, oOppValue)) {
   1.670 +            TrackOutside(outsideTs, oStartPt);
   1.671 +        }
   1.672 +        end = &fTs[++index];
   1.673 +    } while ((end->fPt == test->fPt || end->fT == test->fT) && end->fT < 1);
   1.674 +    *indexPtr = index;
   1.675 +}
   1.676 +
   1.677 +// because of the order in which coincidences are resolved, this and other
   1.678 +// may not have the same intermediate points. Compute the corresponding
   1.679 +// intermediate T values (using this as the master, other as the follower)
   1.680 +// and walk other conditionally -- hoping that it catches up in the end
   1.681 +void SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr,
   1.682 +        SkTArray<SkPoint, true>* oOutsidePts) {
   1.683 +    int oIndex = *oIndexPtr;
   1.684 +    SkOpSpan* const oTest = &fTs[oIndex];
   1.685 +    SkOpSpan* oEnd = oTest;
   1.686 +    const SkPoint& startPt = test.fPt;
   1.687 +    const SkPoint& oStartPt = oTest->fPt;
   1.688 +    double oStartT = oTest->fT;
   1.689 +    if (oStartPt == oEnd->fPt || oStartT == oEnd->fT) {
   1.690 +        TrackOutside(oOutsidePts, startPt);
   1.691 +    }
   1.692 +    while (oStartPt == oEnd->fPt || oStartT == oEnd->fT) {
   1.693 +        zeroSpan(oEnd);
   1.694 +        oEnd = &fTs[++oIndex];
   1.695 +    }
   1.696 +    *oIndexPtr = oIndex;
   1.697 +}
   1.698 +
   1.699 +// FIXME: need to test this case:
   1.700 +// contourA has two segments that are coincident
   1.701 +// contourB has two segments that are coincident in the same place
   1.702 +// each ends up with +2/0 pairs for winding count
   1.703 +// since logic below doesn't transfer count (only increments/decrements) can this be
   1.704 +// resolved to +4/0 ?
   1.705 +
   1.706 +// set spans from start to end to increment the greater by one and decrement
   1.707 +// the lesser
   1.708 +void SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, double endT,
   1.709 +        SkOpSegment* other) {
   1.710 +    bool binary = fOperand != other->fOperand;
   1.711 +    int index = 0;
   1.712 +    while (startPt != fTs[index].fPt) {
   1.713 +        SkASSERT(index < fTs.count());
   1.714 +        ++index;
   1.715 +    }
   1.716 +    double startT = fTs[index].fT;
   1.717 +    while (index > 0 && fTs[index - 1].fT == startT) {
   1.718 +        --index;
   1.719 +    }
   1.720 +    int oIndex = 0;
   1.721 +    while (startPt != other->fTs[oIndex].fPt) {
   1.722 +        SkASSERT(oIndex < other->fTs.count());
   1.723 +        ++oIndex;
   1.724 +    }
   1.725 +    double oStartT = other->fTs[oIndex].fT;
   1.726 +    while (oIndex > 0 && other->fTs[oIndex - 1].fT == oStartT) {
   1.727 +        --oIndex;
   1.728 +    }
   1.729 +    SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
   1.730 +    SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
   1.731 +    SkOpSpan* test = &fTs[index];
   1.732 +    const SkPoint* testPt = &test->fPt;
   1.733 +    double testT = test->fT;
   1.734 +    SkOpSpan* oTest = &other->fTs[oIndex];
   1.735 +    const SkPoint* oTestPt = &oTest->fPt;
   1.736 +    SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
   1.737 +    do {
   1.738 +        SkASSERT(test->fT < 1);
   1.739 +        SkASSERT(oTest->fT < 1);
   1.740 +#if 0
   1.741 +        if (test->fDone || oTest->fDone) {
   1.742 +#else  // consolidate the winding count even if done
   1.743 +        if ((test->fWindValue == 0 && test->fOppValue == 0)
   1.744 +                || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) {
   1.745 +#endif
   1.746 +            SkDEBUGCODE(int firstWind = test->fWindValue);
   1.747 +            SkDEBUGCODE(int firstOpp = test->fOppValue);
   1.748 +            do {
   1.749 +                SkASSERT(firstWind == fTs[index].fWindValue);
   1.750 +                SkASSERT(firstOpp == fTs[index].fOppValue);
   1.751 +                ++index;
   1.752 +                SkASSERT(index < fTs.count());
   1.753 +            } while (*testPt == fTs[index].fPt);
   1.754 +            SkDEBUGCODE(firstWind = oTest->fWindValue);
   1.755 +            SkDEBUGCODE(firstOpp = oTest->fOppValue);
   1.756 +            do {
   1.757 +                SkASSERT(firstWind == other->fTs[oIndex].fWindValue);
   1.758 +                SkASSERT(firstOpp == other->fTs[oIndex].fOppValue);
   1.759 +                ++oIndex;
   1.760 +                SkASSERT(oIndex < other->fTs.count());
   1.761 +            } while (*oTestPt == other->fTs[oIndex].fPt);
   1.762 +        } else {
   1.763 +            if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
   1.764 +                bumpCoincidentThis(*oTest, binary, &index, &outsidePts);
   1.765 +                other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts);
   1.766 +            } else {
   1.767 +                other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts);
   1.768 +                bumpCoincidentOther(*oTest, &index, &outsidePts);
   1.769 +            }
   1.770 +        }
   1.771 +        test = &fTs[index];
   1.772 +        testPt = &test->fPt;
   1.773 +        testT = test->fT;
   1.774 +        if (endPt == *testPt || endT == testT) {
   1.775 +            break;
   1.776 +        }
   1.777 +        oTest = &other->fTs[oIndex];
   1.778 +        oTestPt = &oTest->fPt;
   1.779 +        SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
   1.780 +    } while (endPt != *oTestPt);
   1.781 +    if (endPt != *testPt && endT != testT) {  // in rare cases, one may have ended before the other
   1.782 +        int lastWind = test[-1].fWindValue;
   1.783 +        int lastOpp = test[-1].fOppValue;
   1.784 +        bool zero = lastWind == 0 && lastOpp == 0;
   1.785 +        do {
   1.786 +            if (test->fWindValue || test->fOppValue) {
   1.787 +                test->fWindValue = lastWind;
   1.788 +                test->fOppValue = lastOpp;
   1.789 +                if (zero) {
   1.790 +                    test->fDone = true;
   1.791 +                    ++fDoneSpans;
   1.792 +                }
   1.793 +            }
   1.794 +            test = &fTs[++index];
   1.795 +            testPt = &test->fPt;
   1.796 +        } while (endPt != *testPt);
   1.797 +   }
   1.798 +    int outCount = outsidePts.count();
   1.799 +    if (!done() && outCount) {
   1.800 +        addCoinOutsides(outsidePts[0], endPt, other);
   1.801 +    }
   1.802 +    if (!other->done() && oOutsidePts.count()) {
   1.803 +        other->addCoinOutsides(oOutsidePts[0], endPt, this);
   1.804 +    }
   1.805 +}
   1.806 +
   1.807 +// FIXME: this doesn't prevent the same span from being added twice
   1.808 +// fix in caller, SkASSERT here?
   1.809 +void SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
   1.810 +                           const SkPoint& pt) {
   1.811 +    int tCount = fTs.count();
   1.812 +    for (int tIndex = 0; tIndex < tCount; ++tIndex) {
   1.813 +        const SkOpSpan& span = fTs[tIndex];
   1.814 +        if (!approximately_negative(span.fT - t)) {
   1.815 +            break;
   1.816 +        }
   1.817 +        if (approximately_negative(span.fT - t) && span.fOther == other
   1.818 +                && approximately_equal(span.fOtherT, otherT)) {
   1.819 +#if DEBUG_ADD_T_PAIR
   1.820 +            SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
   1.821 +                    __FUNCTION__, fID, t, other->fID, otherT);
   1.822 +#endif
   1.823 +            return;
   1.824 +        }
   1.825 +    }
   1.826 +#if DEBUG_ADD_T_PAIR
   1.827 +    SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
   1.828 +            __FUNCTION__, fID, t, other->fID, otherT);
   1.829 +#endif
   1.830 +    int insertedAt = addT(other, pt, t);
   1.831 +    int otherInsertedAt = other->addT(this, pt, otherT);
   1.832 +    addOtherT(insertedAt, otherT, otherInsertedAt);
   1.833 +    other->addOtherT(otherInsertedAt, t, insertedAt);
   1.834 +    matchWindingValue(insertedAt, t, borrowWind);
   1.835 +    other->matchWindingValue(otherInsertedAt, otherT, borrowWind);
   1.836 +}
   1.837 +
   1.838 +void SkOpSegment::addTwoAngles(int start, int end, SkTArray<SkOpAngle, true>* angles) const {
   1.839 +    // add edge leading into junction
   1.840 +    int min = SkMin32(end, start);
   1.841 +    if (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0) {
   1.842 +        addAngle(angles, end, start);
   1.843 +    }
   1.844 +    // add edge leading away from junction
   1.845 +    int step = SkSign32(end - start);
   1.846 +    int tIndex = nextExactSpan(end, step);
   1.847 +    min = SkMin32(end, tIndex);
   1.848 +    if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0)) {
   1.849 +        addAngle(angles, end, tIndex);
   1.850 +    }
   1.851 +}
   1.852 +
   1.853 +bool SkOpSegment::betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const {
   1.854 +    const SkPoint midPt = ptAtT(midT);
   1.855 +    SkPathOpsBounds bounds;
   1.856 +    bounds.set(pt1.fX, pt1.fY, pt2.fX, pt2.fY);
   1.857 +    bounds.sort();
   1.858 +    return bounds.almostContains(midPt);
   1.859 +}
   1.860 +
   1.861 +bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const {
   1.862 +    if (lesser > greater) {
   1.863 +        SkTSwap<int>(lesser, greater);
   1.864 +    }
   1.865 +    return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
   1.866 +}
   1.867 +
   1.868 +// note that this follows the same logic flow as active angle
   1.869 +bool SkOpSegment::buildAngles(int index, SkTArray<SkOpAngle, true>* angles, bool allowOpp) const {
   1.870 +    double referenceT = fTs[index].fT;
   1.871 +    const SkPoint& referencePt = fTs[index].fPt;
   1.872 +    int lesser = index;
   1.873 +    while (--lesser >= 0 && (allowOpp || fTs[lesser].fOther->fOperand == fOperand)
   1.874 +            && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].fTiny)) {
   1.875 +        buildAnglesInner(lesser, angles);
   1.876 +    }
   1.877 +    do {
   1.878 +        buildAnglesInner(index, angles);
   1.879 +        if (++index == fTs.count()) {
   1.880 +            break;
   1.881 +        }
   1.882 +        if (!allowOpp && fTs[index].fOther->fOperand != fOperand) {
   1.883 +            break;
   1.884 +        }
   1.885 +        if (fTs[index - 1].fTiny) {
   1.886 +            referenceT = fTs[index].fT;
   1.887 +            continue;
   1.888 +        }
   1.889 +        if (!precisely_negative(fTs[index].fT - referenceT) && fTs[index].fPt == referencePt) {
   1.890 +            // FIXME
   1.891 +            // testQuad8 generates the wrong output unless false is returned here. Other tests will
   1.892 +            // take this path although they aren't required to. This means that many go much slower
   1.893 +            // because of this sort fail.
   1.894 + //           SkDebugf("!!!\n");
   1.895 +            return false;
   1.896 +        }
   1.897 +    } while (precisely_negative(fTs[index].fT - referenceT));
   1.898 +    return true;
   1.899 +}
   1.900 +
   1.901 +void SkOpSegment::buildAnglesInner(int index, SkTArray<SkOpAngle, true>* angles) const {
   1.902 +    const SkOpSpan* span = &fTs[index];
   1.903 +    SkOpSegment* other = span->fOther;
   1.904 +// if there is only one live crossing, and no coincidence, continue
   1.905 +// in the same direction
   1.906 +// if there is coincidence, the only choice may be to reverse direction
   1.907 +    // find edge on either side of intersection
   1.908 +    int oIndex = span->fOtherIndex;
   1.909 +    // if done == -1, prior span has already been processed
   1.910 +    int step = 1;
   1.911 +    int next = other->nextExactSpan(oIndex, step);
   1.912 +   if (next < 0) {
   1.913 +        step = -step;
   1.914 +        next = other->nextExactSpan(oIndex, step);
   1.915 +    }
   1.916 +    // add candidate into and away from junction
   1.917 +    other->addTwoAngles(next, oIndex, angles);
   1.918 +}
   1.919 +
   1.920 +int SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType,
   1.921 +        SkTArray<SkOpAngle, true>* angles, SkTArray<SkOpAngle*, true>* sorted) {
   1.922 +    addTwoAngles(startIndex, endIndex, angles);
   1.923 +    if (!buildAngles(endIndex, angles, includeType == SkOpAngle::kBinaryOpp)) {
   1.924 +        return SK_NaN32;
   1.925 +    }
   1.926 +    int angleCount = angles->count();
   1.927 +    // abort early before sorting if an unsortable (not an unorderable) angle is found
   1.928 +    if (includeType != SkOpAngle::kUnaryXor) {
   1.929 +        int firstIndex = -1;
   1.930 +        while (++firstIndex < angleCount) {
   1.931 +            const SkOpAngle& angle = (*angles)[firstIndex];
   1.932 +            if (angle.segment()->windSum(&angle) != SK_MinS32) {
   1.933 +                break;
   1.934 +            }
   1.935 +        }
   1.936 +        if (firstIndex == angleCount) {
   1.937 +            return SK_MinS32;
   1.938 +        }
   1.939 +    }
   1.940 +    bool sortable = SortAngles2(*angles, sorted);
   1.941 +#if DEBUG_SORT_RAW
   1.942 +    if (sorted->count() > 0) {
   1.943 +        (*sorted)[0]->segment()->debugShowSort(__FUNCTION__, *sorted, 0, 0, 0, sortable);
   1.944 +    }
   1.945 +#endif
   1.946 +    if (!sortable) {
   1.947 +        return SK_NaN32;
   1.948 +    }
   1.949 +    if (includeType == SkOpAngle::kUnaryXor) {
   1.950 +        return SK_MinS32;
   1.951 +    }
   1.952 +    // if all angles have a computed winding,
   1.953 +    //  or if no adjacent angles are orderable,
   1.954 +    //  or if adjacent orderable angles have no computed winding,
   1.955 +    //  there's nothing to do
   1.956 +    // if two orderable angles are adjacent, and one has winding computed, transfer to the other
   1.957 +    const SkOpAngle* baseAngle = NULL;
   1.958 +    int last = angleCount;
   1.959 +    int finalInitialOrderable = -1;
   1.960 +    bool tryReverse = false;
   1.961 +    // look for counterclockwise transfers
   1.962 +    do {
   1.963 +        int index = 0;
   1.964 +        do {
   1.965 +            SkOpAngle* testAngle = (*sorted)[index];
   1.966 +            int testWinding = testAngle->segment()->windSum(testAngle);
   1.967 +            if (SK_MinS32 != testWinding && !testAngle->unorderable()) {
   1.968 +                baseAngle = testAngle;
   1.969 +                continue;
   1.970 +            }
   1.971 +            if (testAngle->unorderable()) {
   1.972 +                baseAngle = NULL;
   1.973 +                tryReverse = true;
   1.974 +                continue;
   1.975 +            }
   1.976 +            if (baseAngle) {
   1.977 +                ComputeOneSum(baseAngle, testAngle, includeType);
   1.978 +                baseAngle = SK_MinS32 != testAngle->segment()->windSum(testAngle) ? testAngle
   1.979 +                        : NULL;
   1.980 +                tryReverse |= !baseAngle;
   1.981 +                continue;
   1.982 +            }
   1.983 +            if (finalInitialOrderable + 1 == index) {
   1.984 +                finalInitialOrderable = index;
   1.985 +            }
   1.986 +        } while (++index != last);
   1.987 +        if (finalInitialOrderable < 0) {
   1.988 +            break;
   1.989 +        }
   1.990 +        last = finalInitialOrderable + 1;
   1.991 +        finalInitialOrderable = -2;  // make this always negative the second time through
   1.992 +    } while (baseAngle);
   1.993 +    if (tryReverse) {
   1.994 +        baseAngle = NULL;
   1.995 +        last = 0;
   1.996 +        finalInitialOrderable = angleCount;
   1.997 +        do {
   1.998 +            int index = angleCount;
   1.999 +            while (--index >= last) {
  1.1000 +                SkOpAngle* testAngle = (*sorted)[index];
  1.1001 +                int testWinding = testAngle->segment()->windSum(testAngle);
  1.1002 +                if (SK_MinS32 != testWinding) {
  1.1003 +                    baseAngle = testAngle;
  1.1004 +                    continue;
  1.1005 +                }
  1.1006 +                if (testAngle->unorderable()) {
  1.1007 +                    baseAngle = NULL;
  1.1008 +                    continue;
  1.1009 +                }
  1.1010 +                if (baseAngle) {
  1.1011 +                    ComputeOneSumReverse(baseAngle, testAngle, includeType);
  1.1012 +                    baseAngle = SK_MinS32 != testAngle->segment()->windSum(testAngle) ? testAngle
  1.1013 +                            : NULL;
  1.1014 +                    continue;
  1.1015 +                }
  1.1016 +                if (finalInitialOrderable - 1 == index) {
  1.1017 +                    finalInitialOrderable = index;
  1.1018 +                }
  1.1019 +            }
  1.1020 +            if (finalInitialOrderable >= angleCount) {
  1.1021 +                break;
  1.1022 +            }
  1.1023 +            last = finalInitialOrderable;
  1.1024 +            finalInitialOrderable = angleCount + 1;  // make this inactive 2nd time through
  1.1025 +        } while (baseAngle);
  1.1026 +    }
  1.1027 +    int minIndex = SkMin32(startIndex, endIndex);
  1.1028 +    return windSum(minIndex);
  1.1029 +}
  1.1030 +
  1.1031 +void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
  1.1032 +        SkOpAngle::IncludeType includeType) {
  1.1033 +    const SkOpSegment* baseSegment = baseAngle->segment();
  1.1034 +    int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
  1.1035 +    int sumSuWinding;
  1.1036 +    bool binary = includeType >= SkOpAngle::kBinarySingle;
  1.1037 +    if (binary) {
  1.1038 +        sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
  1.1039 +        if (baseSegment->operand()) {
  1.1040 +            SkTSwap<int>(sumMiWinding, sumSuWinding);
  1.1041 +        }
  1.1042 +    }
  1.1043 +    SkOpSegment* nextSegment = nextAngle->segment();
  1.1044 +    int maxWinding, sumWinding;
  1.1045 +    SkOpSpan* last;
  1.1046 +    if (binary) {
  1.1047 +        int oppMaxWinding, oppSumWinding;
  1.1048 +        nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
  1.1049 +                &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
  1.1050 +        last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
  1.1051 +                nextAngle);
  1.1052 +    } else {
  1.1053 +        nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
  1.1054 +                &maxWinding, &sumWinding);
  1.1055 +        last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
  1.1056 +    }
  1.1057 +    nextAngle->setLastMarked(last);
  1.1058 +}
  1.1059 +
  1.1060 +void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
  1.1061 +        SkOpAngle::IncludeType includeType) {
  1.1062 +    const SkOpSegment* baseSegment = baseAngle->segment();
  1.1063 +    int sumMiWinding = baseSegment->updateWinding(baseAngle);
  1.1064 +    int sumSuWinding;
  1.1065 +    bool binary = includeType >= SkOpAngle::kBinarySingle;
  1.1066 +    if (binary) {
  1.1067 +        sumSuWinding = baseSegment->updateOppWinding(baseAngle);
  1.1068 +        if (baseSegment->operand()) {
  1.1069 +            SkTSwap<int>(sumMiWinding, sumSuWinding);
  1.1070 +        }
  1.1071 +    }
  1.1072 +    SkOpSegment* nextSegment = nextAngle->segment();
  1.1073 +    int maxWinding, sumWinding;
  1.1074 +    SkOpSpan* last;
  1.1075 +    if (binary) {
  1.1076 +        int oppMaxWinding, oppSumWinding;
  1.1077 +        nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
  1.1078 +                &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
  1.1079 +        last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
  1.1080 +                nextAngle);
  1.1081 +    } else {
  1.1082 +        nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
  1.1083 +                &maxWinding, &sumWinding);
  1.1084 +        last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
  1.1085 +    }
  1.1086 +    nextAngle->setLastMarked(last);
  1.1087 +}
  1.1088 +
  1.1089 +int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT,
  1.1090 +                              bool* hitSomething, double mid, bool opp, bool current) const {
  1.1091 +    SkScalar bottom = fBounds.fBottom;
  1.1092 +    int bestTIndex = -1;
  1.1093 +    if (bottom <= *bestY) {
  1.1094 +        return bestTIndex;
  1.1095 +    }
  1.1096 +    SkScalar top = fBounds.fTop;
  1.1097 +    if (top >= basePt.fY) {
  1.1098 +        return bestTIndex;
  1.1099 +    }
  1.1100 +    if (fBounds.fLeft > basePt.fX) {
  1.1101 +        return bestTIndex;
  1.1102 +    }
  1.1103 +    if (fBounds.fRight < basePt.fX) {
  1.1104 +        return bestTIndex;
  1.1105 +    }
  1.1106 +    if (fBounds.fLeft == fBounds.fRight) {
  1.1107 +        // if vertical, and directly above test point, wait for another one
  1.1108 +        return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
  1.1109 +    }
  1.1110 +    // intersect ray starting at basePt with edge
  1.1111 +    SkIntersections intersections;
  1.1112 +    // OPTIMIZE: use specialty function that intersects ray with curve,
  1.1113 +    // returning t values only for curve (we don't care about t on ray)
  1.1114 +    intersections.allowNear(false);
  1.1115 +    int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)])
  1.1116 +            (fPts, top, bottom, basePt.fX, false);
  1.1117 +    if (pts == 0 || (current && pts == 1)) {
  1.1118 +        return bestTIndex;
  1.1119 +    }
  1.1120 +    if (current) {
  1.1121 +        SkASSERT(pts > 1);
  1.1122 +        int closestIdx = 0;
  1.1123 +        double closest = fabs(intersections[0][0] - mid);
  1.1124 +        for (int idx = 1; idx < pts; ++idx) {
  1.1125 +            double test = fabs(intersections[0][idx] - mid);
  1.1126 +            if (closest > test) {
  1.1127 +                closestIdx = idx;
  1.1128 +                closest = test;
  1.1129 +            }
  1.1130 +        }
  1.1131 +        intersections.quickRemoveOne(closestIdx, --pts);
  1.1132 +    }
  1.1133 +    double bestT = -1;
  1.1134 +    for (int index = 0; index < pts; ++index) {
  1.1135 +        double foundT = intersections[0][index];
  1.1136 +        if (approximately_less_than_zero(foundT)
  1.1137 +                    || approximately_greater_than_one(foundT)) {
  1.1138 +            continue;
  1.1139 +        }
  1.1140 +        SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fY;
  1.1141 +        if (approximately_negative(testY - *bestY)
  1.1142 +                || approximately_negative(basePt.fY - testY)) {
  1.1143 +            continue;
  1.1144 +        }
  1.1145 +        if (pts > 1 && fVerb == SkPath::kLine_Verb) {
  1.1146 +            return SK_MinS32;  // if the intersection is edge on, wait for another one
  1.1147 +        }
  1.1148 +        if (fVerb > SkPath::kLine_Verb) {
  1.1149 +            SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fX;
  1.1150 +            if (approximately_zero(dx)) {
  1.1151 +                return SK_MinS32;  // hit vertical, wait for another one
  1.1152 +            }
  1.1153 +        }
  1.1154 +        *bestY = testY;
  1.1155 +        bestT = foundT;
  1.1156 +    }
  1.1157 +    if (bestT < 0) {
  1.1158 +        return bestTIndex;
  1.1159 +    }
  1.1160 +    SkASSERT(bestT >= 0);
  1.1161 +    SkASSERT(bestT <= 1);
  1.1162 +    int start;
  1.1163 +    int end = 0;
  1.1164 +    do {
  1.1165 +        start = end;
  1.1166 +        end = nextSpan(start, 1);
  1.1167 +    } while (fTs[end].fT < bestT);
  1.1168 +    // FIXME: see next candidate for a better pattern to find the next start/end pair
  1.1169 +    while (start + 1 < end && fTs[start].fDone) {
  1.1170 +        ++start;
  1.1171 +    }
  1.1172 +    if (!isCanceled(start)) {
  1.1173 +        *hitT = bestT;
  1.1174 +        bestTIndex = start;
  1.1175 +        *hitSomething = true;
  1.1176 +    }
  1.1177 +    return bestTIndex;
  1.1178 +}
  1.1179 +
  1.1180 +bool SkOpSegment::decrementSpan(SkOpSpan* span) {
  1.1181 +    SkASSERT(span->fWindValue > 0);
  1.1182 +    if (--(span->fWindValue) == 0) {
  1.1183 +        if (!span->fOppValue && !span->fDone) {
  1.1184 +            span->fDone = true;
  1.1185 +            ++fDoneSpans;
  1.1186 +            return true;
  1.1187 +        }
  1.1188 +    }
  1.1189 +    return false;
  1.1190 +}
  1.1191 +
  1.1192 +bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) {
  1.1193 +    SkASSERT(!span->fDone || span->fTiny || span->fSmall);
  1.1194 +    span->fWindValue += windDelta;
  1.1195 +    SkASSERT(span->fWindValue >= 0);
  1.1196 +    span->fOppValue += oppDelta;
  1.1197 +    SkASSERT(span->fOppValue >= 0);
  1.1198 +    if (fXor) {
  1.1199 +        span->fWindValue &= 1;
  1.1200 +    }
  1.1201 +    if (fOppXor) {
  1.1202 +        span->fOppValue &= 1;
  1.1203 +    }
  1.1204 +    if (!span->fWindValue && !span->fOppValue) {
  1.1205 +        span->fDone = true;
  1.1206 +        ++fDoneSpans;
  1.1207 +        return true;
  1.1208 +    }
  1.1209 +    return false;
  1.1210 +}
  1.1211 +
  1.1212 +// look to see if the curve end intersects an intermediary that intersects the other
  1.1213 +void SkOpSegment::checkEnds() {
  1.1214 +    debugValidate();
  1.1215 +    SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
  1.1216 +    int count = fTs.count();
  1.1217 +    for (int index = 0; index < count; ++index) {
  1.1218 +        const SkOpSpan& span = fTs[index];
  1.1219 +        double otherT = span.fOtherT;
  1.1220 +        if (otherT != 0 && otherT != 1) { // only check ends
  1.1221 +            continue;
  1.1222 +        }
  1.1223 +        const SkOpSegment* other = span.fOther;
  1.1224 +        // peek start/last describe the range of spans that match the other t of this span
  1.1225 +        int peekStart = span.fOtherIndex;
  1.1226 +        while (--peekStart >= 0 && other->fTs[peekStart].fT == otherT)
  1.1227 +            ;
  1.1228 +        int otherCount = other->fTs.count();
  1.1229 +        int peekLast = span.fOtherIndex;
  1.1230 +        while (++peekLast < otherCount && other->fTs[peekLast].fT == otherT)
  1.1231 +            ;
  1.1232 +        if (++peekStart == --peekLast) { // if there isn't a range, there's nothing to do
  1.1233 +            continue;
  1.1234 +        }
  1.1235 +        // t start/last describe the range of spans that match the t of this span
  1.1236 +        double t = span.fT;
  1.1237 +        double tBottom = -1;
  1.1238 +        int tStart = -1;
  1.1239 +        int tLast = count;
  1.1240 +        bool lastSmall = false;
  1.1241 +        double afterT = t;
  1.1242 +        for (int inner = 0; inner < count; ++inner) {
  1.1243 +            double innerT = fTs[inner].fT;
  1.1244 +            if (innerT <= t && innerT > tBottom) {
  1.1245 +                if (innerT < t || !lastSmall) {
  1.1246 +                    tStart = inner - 1;
  1.1247 +                }
  1.1248 +                tBottom = innerT;
  1.1249 +            }
  1.1250 +            if (innerT > afterT) {
  1.1251 +                if (t == afterT && lastSmall) {
  1.1252 +                    afterT = innerT;
  1.1253 +                } else {
  1.1254 +                    tLast = inner;
  1.1255 +                    break;
  1.1256 +                }
  1.1257 +            }
  1.1258 +            lastSmall = innerT <= t ? fTs[inner].fSmall : false;
  1.1259 +        }
  1.1260 +        for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) {
  1.1261 +            if (peekIndex == span.fOtherIndex) {  // skip the other span pointed to by this span
  1.1262 +                continue;
  1.1263 +            }
  1.1264 +            const SkOpSpan& peekSpan = other->fTs[peekIndex];
  1.1265 +            SkOpSegment* match = peekSpan.fOther;
  1.1266 +            if (match->done()) {
  1.1267 +                continue;  // if the edge has already been eaten (likely coincidence), ignore it
  1.1268 +            }
  1.1269 +            const double matchT = peekSpan.fOtherT;
  1.1270 +            // see if any of the spans match the other spans
  1.1271 +            for (int tIndex = tStart + 1; tIndex < tLast; ++tIndex) {
  1.1272 +                const SkOpSpan& tSpan = fTs[tIndex];
  1.1273 +                if (tSpan.fOther == match) {
  1.1274 +                    if (tSpan.fOtherT == matchT) {
  1.1275 +                        goto nextPeekIndex;
  1.1276 +                    }
  1.1277 +                    double midT = (tSpan.fOtherT + matchT) / 2;
  1.1278 +                    if (match->betweenPoints(midT, tSpan.fPt, peekSpan.fPt)) {
  1.1279 +                        goto nextPeekIndex;
  1.1280 +                    }
  1.1281 +                }
  1.1282 +            }
  1.1283 +            if (missingSpans.count() > 0) {
  1.1284 +                const MissingSpan& lastMissing = missingSpans.back();
  1.1285 +                if (lastMissing.fT == t
  1.1286 +                        && lastMissing.fOther == match
  1.1287 +                        && lastMissing.fOtherT == matchT) {
  1.1288 +                    SkASSERT(lastMissing.fPt == peekSpan.fPt);
  1.1289 +                    continue;
  1.1290 +                }
  1.1291 +            }
  1.1292 +#if DEBUG_CHECK_ENDS
  1.1293 +            SkDebugf("%s id=%d missing t=%1.9g other=%d otherT=%1.9g pt=(%1.9g,%1.9g)\n",
  1.1294 +                    __FUNCTION__, fID, t, match->fID, matchT, peekSpan.fPt.fX, peekSpan.fPt.fY);
  1.1295 +#endif
  1.1296 +            // this segment is missing a entry that the other contains
  1.1297 +            // remember so we can add the missing one and recompute the indices
  1.1298 +            {
  1.1299 +                MissingSpan& missing = missingSpans.push_back();
  1.1300 +                SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
  1.1301 +                missing.fT = t;
  1.1302 +                missing.fOther = match;
  1.1303 +                missing.fOtherT = matchT;
  1.1304 +                missing.fPt = peekSpan.fPt;
  1.1305 +            }
  1.1306 +            break;
  1.1307 +nextPeekIndex:
  1.1308 +            ;
  1.1309 +        }
  1.1310 +    }
  1.1311 +    if (missingSpans.count() == 0) {
  1.1312 +        debugValidate();
  1.1313 +        return;
  1.1314 +    }
  1.1315 +    debugValidate();
  1.1316 +    int missingCount = missingSpans.count();
  1.1317 +    for (int index = 0; index < missingCount; ++index)  {
  1.1318 +        MissingSpan& missing = missingSpans[index];
  1.1319 +        addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt);
  1.1320 +    }
  1.1321 +    fixOtherTIndex();
  1.1322 +    // OPTIMIZATION: this may fix indices more than once. Build an array of unique segments to
  1.1323 +    // avoid this
  1.1324 +    for (int index = 0; index < missingCount; ++index)  {
  1.1325 +        missingSpans[index].fOther->fixOtherTIndex();
  1.1326 +    }
  1.1327 +    debugValidate();
  1.1328 +}
  1.1329 +
  1.1330 +bool SkOpSegment::checkSmall(int index) const {
  1.1331 +    if (fTs[index].fSmall) {
  1.1332 +        return true;
  1.1333 +    }
  1.1334 +    double tBase = fTs[index].fT;
  1.1335 +    while (index > 0 && precisely_negative(tBase - fTs[--index].fT))
  1.1336 +        ;
  1.1337 +    return fTs[index].fSmall;
  1.1338 +}
  1.1339 +
  1.1340 +// if pair of spans on either side of tiny have the same end point and mid point, mark
  1.1341 +// them as parallel
  1.1342 +// OPTIMIZATION : mark the segment to note that some span is tiny
  1.1343 +void SkOpSegment::checkTiny() {
  1.1344 +    SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
  1.1345 +    SkOpSpan* thisSpan = fTs.begin() - 1;
  1.1346 +    const SkOpSpan* endSpan = fTs.end() - 1;  // last can't be tiny
  1.1347 +    while (++thisSpan < endSpan) {
  1.1348 +        if (!thisSpan->fTiny) {
  1.1349 +            continue;
  1.1350 +        }
  1.1351 +        SkOpSpan* nextSpan = thisSpan + 1;
  1.1352 +        double thisT = thisSpan->fT;
  1.1353 +        double nextT = nextSpan->fT;
  1.1354 +        if (thisT == nextT) {
  1.1355 +            continue;
  1.1356 +        }
  1.1357 +        SkASSERT(thisT < nextT);
  1.1358 +        SkASSERT(thisSpan->fPt == nextSpan->fPt);
  1.1359 +        SkOpSegment* thisOther = thisSpan->fOther;
  1.1360 +        SkOpSegment* nextOther = nextSpan->fOther;
  1.1361 +        int oIndex = thisSpan->fOtherIndex;
  1.1362 +        for (int oStep = -1; oStep <= 1; oStep += 2) {
  1.1363 +            int oEnd = thisOther->nextExactSpan(oIndex, oStep);
  1.1364 +            if (oEnd < 0) {
  1.1365 +                continue;
  1.1366 +            }
  1.1367 +            const SkOpSpan& oSpan = thisOther->span(oEnd);
  1.1368 +            int nIndex = nextSpan->fOtherIndex;
  1.1369 +            for (int nStep = -1; nStep <= 1; nStep += 2) {
  1.1370 +                int nEnd = nextOther->nextExactSpan(nIndex, nStep);
  1.1371 +                if (nEnd < 0) {
  1.1372 +                    continue;
  1.1373 +                }
  1.1374 +                const SkOpSpan& nSpan = nextOther->span(nEnd);
  1.1375 +                if (oSpan.fPt != nSpan.fPt) {
  1.1376 +                    continue;
  1.1377 +                }
  1.1378 +                double oMidT = (thisSpan->fOtherT + oSpan.fT) / 2;
  1.1379 +                const SkPoint& oPt = thisOther->ptAtT(oMidT);
  1.1380 +                double nMidT = (nextSpan->fOtherT + nSpan.fT) / 2;
  1.1381 +                const SkPoint& nPt = nextOther->ptAtT(nMidT);
  1.1382 +                if (!AlmostEqualUlps(oPt, nPt)) {
  1.1383 +                    continue;
  1.1384 +                }
  1.1385 +#if DEBUG_CHECK_TINY
  1.1386 +                SkDebugf("%s [%d] add coincidence [%d] [%d]\n", __FUNCTION__, fID,
  1.1387 +                    thisOther->fID, nextOther->fID);
  1.1388 +#endif
  1.1389 +                // this segment is missing a entry that the other contains
  1.1390 +                // remember so we can add the missing one and recompute the indices
  1.1391 +                MissingSpan& missing = missingSpans.push_back();
  1.1392 +                SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
  1.1393 +                missing.fSegment = thisOther;
  1.1394 +                missing.fT = thisSpan->fOtherT;
  1.1395 +                missing.fOther = nextOther;
  1.1396 +                missing.fOtherT = nextSpan->fOtherT;
  1.1397 +                missing.fPt = thisSpan->fPt;
  1.1398 +            }
  1.1399 +        }
  1.1400 +    }
  1.1401 +    int missingCount = missingSpans.count();
  1.1402 +    if (!missingCount) {
  1.1403 +        return;
  1.1404 +    }
  1.1405 +    for (int index = 0; index < missingCount; ++index)  {
  1.1406 +        MissingSpan& missing = missingSpans[index];
  1.1407 +        missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt);
  1.1408 +    }
  1.1409 +    for (int index = 0; index < missingCount; ++index)  {
  1.1410 +        MissingSpan& missing = missingSpans[index];
  1.1411 +        missing.fSegment->fixOtherTIndex();
  1.1412 +        missing.fOther->fixOtherTIndex();
  1.1413 +    }
  1.1414 +}
  1.1415 +
  1.1416 +bool SkOpSegment::findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int oStart,
  1.1417 +        int oEnd, int step, SkPoint* startPt, SkPoint* endPt, double* endT) const {
  1.1418 +    SkASSERT(span->fT == 0 || span->fT == 1);
  1.1419 +    SkASSERT(span->fOtherT == 0 || span->fOtherT == 1);
  1.1420 +    const SkOpSpan* otherSpan = &other->span(oEnd);
  1.1421 +    double refT = otherSpan->fT;
  1.1422 +    const SkPoint& refPt = otherSpan->fPt;
  1.1423 +    const SkOpSpan* lastSpan = &other->span(step > 0 ? other->count() - 1 : 0);
  1.1424 +    do {
  1.1425 +        const SkOpSegment* match = span->fOther;
  1.1426 +        if (match == otherSpan->fOther) {
  1.1427 +            // find start of respective spans and see if both have winding
  1.1428 +            int startIndex, endIndex;
  1.1429 +            if (span->fOtherT == 1) {
  1.1430 +                endIndex = span->fOtherIndex;
  1.1431 +                startIndex = match->nextExactSpan(endIndex, -1);
  1.1432 +            } else {
  1.1433 +                startIndex = span->fOtherIndex;
  1.1434 +                endIndex = match->nextExactSpan(startIndex, 1);
  1.1435 +            }
  1.1436 +            const SkOpSpan& startSpan = match->span(startIndex);
  1.1437 +            if (startSpan.fWindValue != 0) {
  1.1438 +                // draw ray from endSpan.fPt perpendicular to end tangent and measure distance
  1.1439 +                // to other segment.
  1.1440 +                const SkOpSpan& endSpan = match->span(endIndex);
  1.1441 +                SkDLine ray;
  1.1442 +                SkVector dxdy;
  1.1443 +                if (span->fOtherT == 1) {
  1.1444 +                    ray.fPts[0].set(startSpan.fPt);
  1.1445 +                    dxdy = match->dxdy(startIndex);
  1.1446 +                } else {
  1.1447 +                    ray.fPts[0].set(endSpan.fPt);
  1.1448 +                    dxdy = match->dxdy(endIndex);
  1.1449 +                }
  1.1450 +                ray.fPts[1].fX = ray.fPts[0].fX + dxdy.fY;
  1.1451 +                ray.fPts[1].fY = ray.fPts[0].fY - dxdy.fX;
  1.1452 +                SkIntersections i;
  1.1453 +                int roots = (i.*CurveRay[SkPathOpsVerbToPoints(other->verb())])(other->pts(), ray);
  1.1454 +                for (int index = 0; index < roots; ++index) {
  1.1455 +                    if (ray.fPts[0].approximatelyEqual(i.pt(index))) {
  1.1456 +                        double matchMidT = (match->span(startIndex).fT
  1.1457 +                                + match->span(endIndex).fT) / 2;
  1.1458 +                        SkPoint matchMidPt = match->ptAtT(matchMidT);
  1.1459 +                        double otherMidT = (i[0][index] + other->span(oStart).fT) / 2;
  1.1460 +                        SkPoint otherMidPt = other->ptAtT(otherMidT);
  1.1461 +                        if (SkDPoint::ApproximatelyEqual(matchMidPt, otherMidPt)) {
  1.1462 +                            *startPt = startSpan.fPt;
  1.1463 +                            *endPt = endSpan.fPt;
  1.1464 +                            *endT = endSpan.fT;
  1.1465 +                            return true;
  1.1466 +                        }
  1.1467 +                    }
  1.1468 +                }
  1.1469 +            }
  1.1470 +            return false;
  1.1471 +        }
  1.1472 +        if (otherSpan == lastSpan) {
  1.1473 +            break;
  1.1474 +        }
  1.1475 +        otherSpan += step;
  1.1476 +    } while (otherSpan->fT == refT || otherSpan->fPt == refPt);
  1.1477 +    return false;
  1.1478 +}
  1.1479 +
  1.1480 +/*
  1.1481 + The M and S variable name parts stand for the operators.
  1.1482 +   Mi stands for Minuend (see wiki subtraction, analogous to difference)
  1.1483 +   Su stands for Subtrahend
  1.1484 + The Opp variable name part designates that the value is for the Opposite operator.
  1.1485 + Opposite values result from combining coincident spans.
  1.1486 + */
  1.1487 +SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
  1.1488 +                                     bool* unsortable, SkPathOp op, const int xorMiMask,
  1.1489 +                                     const int xorSuMask) {
  1.1490 +    const int startIndex = *nextStart;
  1.1491 +    const int endIndex = *nextEnd;
  1.1492 +    SkASSERT(startIndex != endIndex);
  1.1493 +    SkDEBUGCODE(const int count = fTs.count());
  1.1494 +    SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
  1.1495 +    const int step = SkSign32(endIndex - startIndex);
  1.1496 +    const int end = nextExactSpan(startIndex, step);
  1.1497 +    SkASSERT(end >= 0);
  1.1498 +    SkOpSpan* endSpan = &fTs[end];
  1.1499 +    SkOpSegment* other;
  1.1500 +    if (isSimple(end)) {
  1.1501 +    // mark the smaller of startIndex, endIndex done, and all adjacent
  1.1502 +    // spans with the same T value (but not 'other' spans)
  1.1503 +#if DEBUG_WINDING
  1.1504 +        SkDebugf("%s simple\n", __FUNCTION__);
  1.1505 +#endif
  1.1506 +        int min = SkMin32(startIndex, endIndex);
  1.1507 +        if (fTs[min].fDone) {
  1.1508 +            return NULL;
  1.1509 +        }
  1.1510 +        markDoneBinary(min);
  1.1511 +        other = endSpan->fOther;
  1.1512 +        *nextStart = endSpan->fOtherIndex;
  1.1513 +        double startT = other->fTs[*nextStart].fT;
  1.1514 +        *nextEnd = *nextStart;
  1.1515 +        do {
  1.1516 +            *nextEnd += step;
  1.1517 +        } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
  1.1518 +        SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
  1.1519 +        if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
  1.1520 +            *unsortable = true;
  1.1521 +            return NULL;
  1.1522 +        }
  1.1523 +        return other;
  1.1524 +    }
  1.1525 +    // more than one viable candidate -- measure angles to find best
  1.1526 +    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
  1.1527 +    SkASSERT(startIndex - endIndex != 0);
  1.1528 +    SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
  1.1529 +    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
  1.1530 +    int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp, &angles, &sorted);
  1.1531 +    bool sortable = calcWinding != SK_NaN32;
  1.1532 +    if (sortable && sorted.count() == 0) {
  1.1533 +        // if no edge has a computed winding sum, we can go no further
  1.1534 +        *unsortable = true;
  1.1535 +        return NULL;
  1.1536 +    }
  1.1537 +    int angleCount = angles.count();
  1.1538 +    int firstIndex = findStartingEdge(sorted, startIndex, end);
  1.1539 +    SkASSERT(!sortable || firstIndex >= 0);
  1.1540 +#if DEBUG_SORT
  1.1541 +    debugShowSort(__FUNCTION__, sorted, firstIndex, sortable);
  1.1542 +#endif
  1.1543 +    if (!sortable) {
  1.1544 +        *unsortable = true;
  1.1545 +        return NULL;
  1.1546 +    }
  1.1547 +    SkASSERT(sorted[firstIndex]->segment() == this);
  1.1548 +#if DEBUG_WINDING
  1.1549 +    SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
  1.1550 +            sorted[firstIndex]->sign());
  1.1551 +#endif
  1.1552 +    int sumMiWinding = updateWinding(endIndex, startIndex);
  1.1553 +    int sumSuWinding = updateOppWinding(endIndex, startIndex);
  1.1554 +    if (operand()) {
  1.1555 +        SkTSwap<int>(sumMiWinding, sumSuWinding);
  1.1556 +    }
  1.1557 +    int nextIndex = firstIndex + 1;
  1.1558 +    int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
  1.1559 +    const SkOpAngle* foundAngle = NULL;
  1.1560 +    bool foundDone = false;
  1.1561 +    // iterate through the angle, and compute everyone's winding
  1.1562 +    SkOpSegment* nextSegment;
  1.1563 +    int activeCount = 0;
  1.1564 +    do {
  1.1565 +        SkASSERT(nextIndex != firstIndex);
  1.1566 +        if (nextIndex == angleCount) {
  1.1567 +            nextIndex = 0;
  1.1568 +        }
  1.1569 +        const SkOpAngle* nextAngle = sorted[nextIndex];
  1.1570 +        nextSegment = nextAngle->segment();
  1.1571 +        int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
  1.1572 +        bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
  1.1573 +                nextAngle->end(), op, &sumMiWinding, &sumSuWinding,
  1.1574 +                &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
  1.1575 +        if (activeAngle) {
  1.1576 +            ++activeCount;
  1.1577 +            if (!foundAngle || (foundDone && activeCount & 1)) {
  1.1578 +                if (nextSegment->isTiny(nextAngle)) {
  1.1579 +                    *unsortable = true;
  1.1580 +                    return NULL;
  1.1581 +                }
  1.1582 +                foundAngle = nextAngle;
  1.1583 +                foundDone = nextSegment->done(nextAngle);
  1.1584 +            }
  1.1585 +        }
  1.1586 +        if (nextSegment->done()) {
  1.1587 +            continue;
  1.1588 +        }
  1.1589 +        if (nextSegment->isTiny(nextAngle)) {
  1.1590 +            continue;
  1.1591 +        }
  1.1592 +        if (!activeAngle) {
  1.1593 +            nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextAngle->end());
  1.1594 +        }
  1.1595 +        SkOpSpan* last = nextAngle->lastMarked();
  1.1596 +        if (last) {
  1.1597 +            *chase->append() = last;
  1.1598 +#if DEBUG_WINDING
  1.1599 +            SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
  1.1600 +                    last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
  1.1601 +                    last->fSmall);
  1.1602 +#endif
  1.1603 +        }
  1.1604 +    } while (++nextIndex != lastIndex);
  1.1605 +    markDoneBinary(SkMin32(startIndex, endIndex));
  1.1606 +    if (!foundAngle) {
  1.1607 +        return NULL;
  1.1608 +    }
  1.1609 +    *nextStart = foundAngle->start();
  1.1610 +    *nextEnd = foundAngle->end();
  1.1611 +    nextSegment = foundAngle->segment();
  1.1612 +#if DEBUG_WINDING
  1.1613 +    SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
  1.1614 +            __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
  1.1615 + #endif
  1.1616 +    return nextSegment;
  1.1617 +}
  1.1618 +
  1.1619 +SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart,
  1.1620 +                                          int* nextEnd, bool* unsortable) {
  1.1621 +    const int startIndex = *nextStart;
  1.1622 +    const int endIndex = *nextEnd;
  1.1623 +    SkASSERT(startIndex != endIndex);
  1.1624 +    SkDEBUGCODE(const int count = fTs.count());
  1.1625 +    SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
  1.1626 +    const int step = SkSign32(endIndex - startIndex);
  1.1627 +    const int end = nextExactSpan(startIndex, step);
  1.1628 +    SkASSERT(end >= 0);
  1.1629 +    SkOpSpan* endSpan = &fTs[end];
  1.1630 +    SkOpSegment* other;
  1.1631 +    if (isSimple(end)) {
  1.1632 +    // mark the smaller of startIndex, endIndex done, and all adjacent
  1.1633 +    // spans with the same T value (but not 'other' spans)
  1.1634 +#if DEBUG_WINDING
  1.1635 +        SkDebugf("%s simple\n", __FUNCTION__);
  1.1636 +#endif
  1.1637 +        int min = SkMin32(startIndex, endIndex);
  1.1638 +        if (fTs[min].fDone) {
  1.1639 +            return NULL;
  1.1640 +        }
  1.1641 +        markDoneUnary(min);
  1.1642 +        other = endSpan->fOther;
  1.1643 +        *nextStart = endSpan->fOtherIndex;
  1.1644 +        double startT = other->fTs[*nextStart].fT;
  1.1645 +        *nextEnd = *nextStart;
  1.1646 +        do {
  1.1647 +            *nextEnd += step;
  1.1648 +        } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
  1.1649 +        SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
  1.1650 +        if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
  1.1651 +            *unsortable = true;
  1.1652 +            return NULL;
  1.1653 +        }
  1.1654 +        return other;
  1.1655 +    }
  1.1656 +    // more than one viable candidate -- measure angles to find best
  1.1657 +    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
  1.1658 +    SkASSERT(startIndex - endIndex != 0);
  1.1659 +    SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
  1.1660 +    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
  1.1661 +    int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryWinding, &angles, &sorted);
  1.1662 +    bool sortable = calcWinding != SK_NaN32;
  1.1663 +    int angleCount = angles.count();
  1.1664 +    int firstIndex = findStartingEdge(sorted, startIndex, end);
  1.1665 +    SkASSERT(!sortable || firstIndex >= 0);
  1.1666 +#if DEBUG_SORT
  1.1667 +    debugShowSort(__FUNCTION__, sorted, firstIndex, sortable);
  1.1668 +#endif
  1.1669 +    if (!sortable) {
  1.1670 +        *unsortable = true;
  1.1671 +        return NULL;
  1.1672 +    }
  1.1673 +    SkASSERT(sorted[firstIndex]->segment() == this);
  1.1674 +#if DEBUG_WINDING
  1.1675 +    SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
  1.1676 +            sorted[firstIndex]->sign());
  1.1677 +#endif
  1.1678 +    int sumWinding = updateWinding(endIndex, startIndex);
  1.1679 +    int nextIndex = firstIndex + 1;
  1.1680 +    int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
  1.1681 +    const SkOpAngle* foundAngle = NULL;
  1.1682 +    bool foundDone = false;
  1.1683 +    // iterate through the angle, and compute everyone's winding
  1.1684 +    SkOpSegment* nextSegment;
  1.1685 +    int activeCount = 0;
  1.1686 +    do {
  1.1687 +        SkASSERT(nextIndex != firstIndex);
  1.1688 +        if (nextIndex == angleCount) {
  1.1689 +            nextIndex = 0;
  1.1690 +        }
  1.1691 +        const SkOpAngle* nextAngle = sorted[nextIndex];
  1.1692 +        nextSegment = nextAngle->segment();
  1.1693 +        int maxWinding;
  1.1694 +        bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
  1.1695 +                &maxWinding, &sumWinding);
  1.1696 +        if (activeAngle) {
  1.1697 +            ++activeCount;
  1.1698 +            if (!foundAngle || (foundDone && activeCount & 1)) {
  1.1699 +                if (nextSegment->isTiny(nextAngle)) {
  1.1700 +                    *unsortable = true;
  1.1701 +                    return NULL;
  1.1702 +                }
  1.1703 +                foundAngle = nextAngle;
  1.1704 +                foundDone = nextSegment->done(nextAngle);
  1.1705 +            }
  1.1706 +        }
  1.1707 +        if (nextSegment->done()) {
  1.1708 +            continue;
  1.1709 +        }
  1.1710 +        if (nextSegment->isTiny(nextAngle)) {
  1.1711 +            continue;
  1.1712 +        }
  1.1713 +        if (!activeAngle) {
  1.1714 +            nextSegment->markAndChaseDoneUnary(nextAngle->start(), nextAngle->end());
  1.1715 +        }
  1.1716 +        SkOpSpan* last = nextAngle->lastMarked();
  1.1717 +        if (last) {
  1.1718 +            *chase->append() = last;
  1.1719 +#if DEBUG_WINDING
  1.1720 +            SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
  1.1721 +                    last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
  1.1722 +                    last->fSmall);
  1.1723 +#endif
  1.1724 +        }
  1.1725 +    } while (++nextIndex != lastIndex);
  1.1726 +    markDoneUnary(SkMin32(startIndex, endIndex));
  1.1727 +    if (!foundAngle) {
  1.1728 +        return NULL;
  1.1729 +    }
  1.1730 +    *nextStart = foundAngle->start();
  1.1731 +    *nextEnd = foundAngle->end();
  1.1732 +    nextSegment = foundAngle->segment();
  1.1733 +#if DEBUG_WINDING
  1.1734 +    SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
  1.1735 +            __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
  1.1736 + #endif
  1.1737 +    return nextSegment;
  1.1738 +}
  1.1739 +
  1.1740 +SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsortable) {
  1.1741 +    const int startIndex = *nextStart;
  1.1742 +    const int endIndex = *nextEnd;
  1.1743 +    SkASSERT(startIndex != endIndex);
  1.1744 +    SkDEBUGCODE(int count = fTs.count());
  1.1745 +    SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
  1.1746 +    int step = SkSign32(endIndex - startIndex);
  1.1747 +    int end = nextExactSpan(startIndex, step);
  1.1748 +    SkASSERT(end >= 0);
  1.1749 +    SkOpSpan* endSpan = &fTs[end];
  1.1750 +    SkOpSegment* other;
  1.1751 +    if (isSimple(end)) {
  1.1752 +#if DEBUG_WINDING
  1.1753 +        SkDebugf("%s simple\n", __FUNCTION__);
  1.1754 +#endif
  1.1755 +        int min = SkMin32(startIndex, endIndex);
  1.1756 +        if (fTs[min].fDone) {
  1.1757 +            return NULL;
  1.1758 +        }
  1.1759 +        markDone(min, 1);
  1.1760 +        other = endSpan->fOther;
  1.1761 +        *nextStart = endSpan->fOtherIndex;
  1.1762 +        double startT = other->fTs[*nextStart].fT;
  1.1763 +        // FIXME: I don't know why the logic here is difference from the winding case
  1.1764 +        SkDEBUGCODE(bool firstLoop = true;)
  1.1765 +        if ((approximately_less_than_zero(startT) && step < 0)
  1.1766 +                || (approximately_greater_than_one(startT) && step > 0)) {
  1.1767 +            step = -step;
  1.1768 +            SkDEBUGCODE(firstLoop = false;)
  1.1769 +        }
  1.1770 +        do {
  1.1771 +            *nextEnd = *nextStart;
  1.1772 +            do {
  1.1773 +                *nextEnd += step;
  1.1774 +            } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
  1.1775 +            if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) {
  1.1776 +                break;
  1.1777 +            }
  1.1778 +            SkASSERT(firstLoop);
  1.1779 +            SkDEBUGCODE(firstLoop = false;)
  1.1780 +            step = -step;
  1.1781 +        } while (true);
  1.1782 +        SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
  1.1783 +        return other;
  1.1784 +    }
  1.1785 +    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
  1.1786 +    SkASSERT(startIndex - endIndex != 0);
  1.1787 +    SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
  1.1788 +    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
  1.1789 +    int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryXor, &angles, &sorted);
  1.1790 +    bool sortable = calcWinding != SK_NaN32;
  1.1791 +    int angleCount = angles.count();
  1.1792 +    int firstIndex = findStartingEdge(sorted, startIndex, end);
  1.1793 +    SkASSERT(!sortable || firstIndex >= 0);
  1.1794 +#if DEBUG_SORT
  1.1795 +    debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0, sortable);
  1.1796 +#endif
  1.1797 +    if (!sortable) {
  1.1798 +        *unsortable = true;
  1.1799 +        return NULL;
  1.1800 +    }
  1.1801 +    SkASSERT(sorted[firstIndex]->segment() == this);
  1.1802 +#if DEBUG_WINDING
  1.1803 +    SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
  1.1804 +            sorted[firstIndex]->sign());
  1.1805 +#endif
  1.1806 +    int nextIndex = firstIndex + 1;
  1.1807 +    int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
  1.1808 +    const SkOpAngle* foundAngle = NULL;
  1.1809 +    bool foundDone = false;
  1.1810 +    SkOpSegment* nextSegment;
  1.1811 +    int activeCount = 0;
  1.1812 +    do {
  1.1813 +        SkASSERT(nextIndex != firstIndex);
  1.1814 +        if (nextIndex == angleCount) {
  1.1815 +            nextIndex = 0;
  1.1816 +        }
  1.1817 +        const SkOpAngle* nextAngle = sorted[nextIndex];
  1.1818 +        nextSegment = nextAngle->segment();
  1.1819 +        ++activeCount;
  1.1820 +        if (!foundAngle || (foundDone && activeCount & 1)) {
  1.1821 +            if (nextSegment->isTiny(nextAngle)) {
  1.1822 +                *unsortable = true;
  1.1823 +                return NULL;
  1.1824 +            }
  1.1825 +            foundAngle = nextAngle;
  1.1826 +            foundDone = nextSegment->done(nextAngle);
  1.1827 +        }
  1.1828 +        if (nextSegment->done()) {
  1.1829 +            continue;
  1.1830 +        }
  1.1831 +    } while (++nextIndex != lastIndex);
  1.1832 +    markDone(SkMin32(startIndex, endIndex), 1);
  1.1833 +    if (!foundAngle) {
  1.1834 +        return NULL;
  1.1835 +    }
  1.1836 +    *nextStart = foundAngle->start();
  1.1837 +    *nextEnd = foundAngle->end();
  1.1838 +    nextSegment = foundAngle->segment();
  1.1839 +#if DEBUG_WINDING
  1.1840 +    SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
  1.1841 +            __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
  1.1842 + #endif
  1.1843 +    return nextSegment;
  1.1844 +}
  1.1845 +
  1.1846 +int SkOpSegment::findStartingEdge(const SkTArray<SkOpAngle*, true>& sorted, int start, int end) {
  1.1847 +    int angleCount = sorted.count();
  1.1848 +    int firstIndex = -1;
  1.1849 +    for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
  1.1850 +        const SkOpAngle* angle = sorted[angleIndex];
  1.1851 +        if (angle->segment() == this && angle->start() == end &&
  1.1852 +                angle->end() == start) {
  1.1853 +            firstIndex = angleIndex;
  1.1854 +            break;
  1.1855 +        }
  1.1856 +    }
  1.1857 +    return firstIndex;
  1.1858 +}
  1.1859 +
  1.1860 +int SkOpSegment::findT(double t, const SkOpSegment* match) const {
  1.1861 +    int count = this->count();
  1.1862 +    for (int index = 0; index < count; ++index) {
  1.1863 +        const SkOpSpan& span = fTs[index];
  1.1864 +        if (span.fT == t && span.fOther == match) {
  1.1865 +            return index;
  1.1866 +        }
  1.1867 +    }
  1.1868 +    SkASSERT(0);
  1.1869 +    return -1;
  1.1870 +}
  1.1871 +
  1.1872 +// FIXME: either:
  1.1873 +// a) mark spans with either end unsortable as done, or
  1.1874 +// b) rewrite findTop / findTopSegment / findTopContour to iterate further
  1.1875 +//    when encountering an unsortable span
  1.1876 +
  1.1877 +// OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
  1.1878 +// and use more concise logic like the old edge walker code?
  1.1879 +// FIXME: this needs to deal with coincident edges
  1.1880 +SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable,
  1.1881 +                                  bool onlySortable) {
  1.1882 +    // iterate through T intersections and return topmost
  1.1883 +    // topmost tangent from y-min to first pt is closer to horizontal
  1.1884 +    SkASSERT(!done());
  1.1885 +    int firstT = -1;
  1.1886 +    /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT);
  1.1887 +    if (firstT < 0) {
  1.1888 +        *unsortable = true;
  1.1889 +        firstT = 0;
  1.1890 +        while (fTs[firstT].fDone) {
  1.1891 +            SkASSERT(firstT < fTs.count());
  1.1892 +            ++firstT;
  1.1893 +        }
  1.1894 +        *tIndexPtr = firstT;
  1.1895 +        *endIndexPtr = nextExactSpan(firstT, 1);
  1.1896 +        return this;
  1.1897 +    }
  1.1898 +    // sort the edges to find the leftmost
  1.1899 +    int step = 1;
  1.1900 +    int end = nextSpan(firstT, step);
  1.1901 +    if (end == -1) {
  1.1902 +        step = -1;
  1.1903 +        end = nextSpan(firstT, step);
  1.1904 +        SkASSERT(end != -1);
  1.1905 +    }
  1.1906 +    // if the topmost T is not on end, or is three-way or more, find left
  1.1907 +    // look for left-ness from tLeft to firstT (matching y of other)
  1.1908 +    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
  1.1909 +    SkASSERT(firstT - end != 0);
  1.1910 +    addTwoAngles(end, firstT, &angles);
  1.1911 +    if (!buildAngles(firstT, &angles, true) && onlySortable) {
  1.1912 +//        *unsortable = true;
  1.1913 +//        return NULL;
  1.1914 +    }
  1.1915 +    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
  1.1916 +    bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMayBeUnordered_SortAngleKind);
  1.1917 +    if (onlySortable && !sortable) {
  1.1918 +        *unsortable = true;
  1.1919 +        return NULL;
  1.1920 +    }
  1.1921 +    int first = SK_MaxS32;
  1.1922 +    SkScalar top = SK_ScalarMax;
  1.1923 +    int count = sorted.count();
  1.1924 +    for (int index = 0; index < count; ++index) {
  1.1925 +        const SkOpAngle* angle = sorted[index];
  1.1926 +        if (onlySortable && angle->unorderable()) {
  1.1927 +            continue;
  1.1928 +        }
  1.1929 +        SkOpSegment* next = angle->segment();
  1.1930 +        SkPathOpsBounds bounds;
  1.1931 +        next->subDivideBounds(angle->end(), angle->start(), &bounds);
  1.1932 +        if (approximately_greater(top, bounds.fTop)) {
  1.1933 +            top = bounds.fTop;
  1.1934 +            first = index;
  1.1935 +        }
  1.1936 +    }
  1.1937 +    SkASSERT(first < SK_MaxS32);
  1.1938 +#if DEBUG_SORT  // || DEBUG_SWAP_TOP
  1.1939 +    sorted[first]->segment()->debugShowSort(__FUNCTION__, sorted, first, 0, 0, sortable);
  1.1940 +#endif
  1.1941 +    // skip edges that have already been processed
  1.1942 +    firstT = first - 1;
  1.1943 +    SkOpSegment* leftSegment;
  1.1944 +    do {
  1.1945 +        if (++firstT == count) {
  1.1946 +            firstT = 0;
  1.1947 +        }
  1.1948 +        const SkOpAngle* angle = sorted[firstT];
  1.1949 +        SkASSERT(!onlySortable || !angle->unsortable());
  1.1950 +        leftSegment = angle->segment();
  1.1951 +        *tIndexPtr = angle->end();
  1.1952 +        *endIndexPtr = angle->start();
  1.1953 +    } while (leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone);
  1.1954 +    if (leftSegment->verb() >= SkPath::kQuad_Verb) {
  1.1955 +        const int tIndex = *tIndexPtr;
  1.1956 +        const int endIndex = *endIndexPtr;
  1.1957 +        if (!leftSegment->clockwise(tIndex, endIndex)) {
  1.1958 +            bool swap = !leftSegment->monotonicInY(tIndex, endIndex)
  1.1959 +                    && !leftSegment->serpentine(tIndex, endIndex);
  1.1960 +    #if DEBUG_SWAP_TOP
  1.1961 +            SkDebugf("%s swap=%d serpentine=%d containedByEnds=%d monotonic=%d\n", __FUNCTION__,
  1.1962 +                    swap,
  1.1963 +                    leftSegment->serpentine(tIndex, endIndex),
  1.1964 +                    leftSegment->controlsContainedByEnds(tIndex, endIndex),
  1.1965 +                    leftSegment->monotonicInY(tIndex, endIndex));
  1.1966 +    #endif
  1.1967 +            if (swap) {
  1.1968 +    // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first
  1.1969 +    // sorted but merely the first not already processed (i.e., not done)
  1.1970 +                SkTSwap(*tIndexPtr, *endIndexPtr);
  1.1971 +            }
  1.1972 +        }
  1.1973 +    }
  1.1974 +    SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny);
  1.1975 +    return leftSegment;
  1.1976 +}
  1.1977 +
  1.1978 +// FIXME: not crazy about this
  1.1979 +// when the intersections are performed, the other index is into an
  1.1980 +// incomplete array. As the array grows, the indices become incorrect
  1.1981 +// while the following fixes the indices up again, it isn't smart about
  1.1982 +// skipping segments whose indices are already correct
  1.1983 +// assuming we leave the code that wrote the index in the first place
  1.1984 +// FIXME: if called after remove, this needs to correct tiny
  1.1985 +void SkOpSegment::fixOtherTIndex() {
  1.1986 +    int iCount = fTs.count();
  1.1987 +    for (int i = 0; i < iCount; ++i) {
  1.1988 +        SkOpSpan& iSpan = fTs[i];
  1.1989 +        double oT = iSpan.fOtherT;
  1.1990 +        SkOpSegment* other = iSpan.fOther;
  1.1991 +        int oCount = other->fTs.count();
  1.1992 +        SkDEBUGCODE(iSpan.fOtherIndex = -1);
  1.1993 +        for (int o = 0; o < oCount; ++o) {
  1.1994 +            SkOpSpan& oSpan = other->fTs[o];
  1.1995 +            if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan.fT) {
  1.1996 +                iSpan.fOtherIndex = o;
  1.1997 +                oSpan.fOtherIndex = i;
  1.1998 +                break;
  1.1999 +            }
  1.2000 +        }
  1.2001 +        SkASSERT(iSpan.fOtherIndex >= 0);
  1.2002 +    }
  1.2003 +}
  1.2004 +
  1.2005 +void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
  1.2006 +    fDoneSpans = 0;
  1.2007 +    fOperand = operand;
  1.2008 +    fXor = evenOdd;
  1.2009 +    fPts = pts;
  1.2010 +    fVerb = verb;
  1.2011 +}
  1.2012 +
  1.2013 +void SkOpSegment::initWinding(int start, int end) {
  1.2014 +    int local = spanSign(start, end);
  1.2015 +    int oppLocal = oppSign(start, end);
  1.2016 +    (void) markAndChaseWinding(start, end, local, oppLocal);
  1.2017 +    // OPTIMIZATION: the reverse mark and chase could skip the first marking
  1.2018 +    (void) markAndChaseWinding(end, start, local, oppLocal);
  1.2019 +}
  1.2020 +
  1.2021 +/*
  1.2022 +when we start with a vertical intersect, we try to use the dx to determine if the edge is to
  1.2023 +the left or the right of vertical. This determines if we need to add the span's
  1.2024 +sign or not. However, this isn't enough.
  1.2025 +If the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed.
  1.2026 +If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
  1.2027 +from has the same x direction as this span, the winding should change. If the dx is opposite, then
  1.2028 +the same winding is shared by both.
  1.2029 +*/
  1.2030 +void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkScalar hitDx,
  1.2031 +                              int oppWind, SkScalar hitOppDx) {
  1.2032 +    SkASSERT(hitDx || !winding);
  1.2033 +    SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
  1.2034 +    SkASSERT(dx);
  1.2035 +    int windVal = windValue(SkMin32(start, end));
  1.2036 +#if DEBUG_WINDING_AT_T
  1.2037 +    SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
  1.2038 +            hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
  1.2039 +#endif
  1.2040 +    if (!winding) {
  1.2041 +        winding = dx < 0 ? windVal : -windVal;
  1.2042 +    } else if (winding * dx < 0) {
  1.2043 +        int sideWind = winding + (dx < 0 ? windVal : -windVal);
  1.2044 +        if (abs(winding) < abs(sideWind)) {
  1.2045 +            winding = sideWind;
  1.2046 +        }
  1.2047 +    }
  1.2048 +#if DEBUG_WINDING_AT_T
  1.2049 +    SkDebugf(" winding=%d\n", winding);
  1.2050 +#endif
  1.2051 +    SkDEBUGCODE(int oppLocal = oppSign(start, end));
  1.2052 +    SkASSERT(hitOppDx || !oppWind || !oppLocal);
  1.2053 +    int oppWindVal = oppValue(SkMin32(start, end));
  1.2054 +    if (!oppWind) {
  1.2055 +        oppWind = dx < 0 ? oppWindVal : -oppWindVal;
  1.2056 +    } else if (hitOppDx * dx >= 0) {
  1.2057 +        int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
  1.2058 +        if (abs(oppWind) < abs(oppSideWind)) {
  1.2059 +            oppWind = oppSideWind;
  1.2060 +        }
  1.2061 +    }
  1.2062 +    (void) markAndChaseWinding(start, end, winding, oppWind);
  1.2063 +    // OPTIMIZATION: the reverse mark and chase could skip the first marking
  1.2064 +    (void) markAndChaseWinding(end, start, winding, oppWind);
  1.2065 +}
  1.2066 +
  1.2067 +// OPTIMIZE: successive calls could start were the last leaves off
  1.2068 +// or calls could specialize to walk forwards or backwards
  1.2069 +bool SkOpSegment::isMissing(double startT, const SkPoint& pt) const {
  1.2070 +    size_t tCount = fTs.count();
  1.2071 +    for (size_t index = 0; index < tCount; ++index) {
  1.2072 +        const SkOpSpan& span = fTs[index];
  1.2073 +        if (approximately_zero(startT - span.fT) && pt == span.fPt) {
  1.2074 +            return false;
  1.2075 +        }
  1.2076 +    }
  1.2077 +    return true;
  1.2078 +}
  1.2079 +
  1.2080 +bool SkOpSegment::isSimple(int end) const {
  1.2081 +    int count = fTs.count();
  1.2082 +    if (count == 2) {
  1.2083 +        return true;
  1.2084 +    }
  1.2085 +    double t = fTs[end].fT;
  1.2086 +    if (approximately_less_than_zero(t)) {
  1.2087 +        return !approximately_less_than_zero(fTs[1].fT);
  1.2088 +    }
  1.2089 +    if (approximately_greater_than_one(t)) {
  1.2090 +        return !approximately_greater_than_one(fTs[count - 2].fT);
  1.2091 +    }
  1.2092 +    return false;
  1.2093 +}
  1.2094 +
  1.2095 +bool SkOpSegment::isTiny(const SkOpAngle* angle) const {
  1.2096 +    int start = angle->start();
  1.2097 +    int end = angle->end();
  1.2098 +    const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
  1.2099 +    return mSpan.fTiny;
  1.2100 +}
  1.2101 +
  1.2102 +bool SkOpSegment::isTiny(int index) const {
  1.2103 +    return fTs[index].fTiny;
  1.2104 +}
  1.2105 +
  1.2106 +// look pair of active edges going away from coincident edge
  1.2107 +// one of them should be the continuation of other
  1.2108 +// if both are active, look to see if they both the connect to another coincident pair
  1.2109 +// if one at least one is a line, then make the pair coincident
  1.2110 +// if neither is a line, test for coincidence
  1.2111 +bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, int step,
  1.2112 +        bool cancel) {
  1.2113 +    int otherTIndex = other->findT(otherT, this);
  1.2114 +    int next = other->nextExactSpan(otherTIndex, step);
  1.2115 +    int otherMin = SkTMin(otherTIndex, next);
  1.2116 +    int otherWind = other->span(otherMin).fWindValue;
  1.2117 +    if (otherWind == 0) {
  1.2118 +        return false;
  1.2119 +    }
  1.2120 +    SkASSERT(next >= 0);
  1.2121 +    int tIndex = 0;
  1.2122 +    do {
  1.2123 +        SkOpSpan* test = &fTs[tIndex];
  1.2124 +        SkASSERT(test->fT == 0);
  1.2125 +        if (test->fOther == other || test->fOtherT != 1) {
  1.2126 +            continue;
  1.2127 +        }
  1.2128 +        SkPoint startPt, endPt;
  1.2129 +        double endT;
  1.2130 +        if (findCoincidentMatch(test, other, otherTIndex, next, step, &startPt, &endPt, &endT)) {
  1.2131 +            SkOpSegment* match = test->fOther;
  1.2132 +            if (cancel) {
  1.2133 +                match->addTCancel(startPt, endPt, other);
  1.2134 +            } else {
  1.2135 +                match->addTCoincident(startPt, endPt, endT, other);
  1.2136 +            }
  1.2137 +            return true;
  1.2138 +        }
  1.2139 +    } while (fTs[++tIndex].fT == 0);
  1.2140 +    return false;
  1.2141 +}
  1.2142 +
  1.2143 +// this span is excluded by the winding rule -- chase the ends
  1.2144 +// as long as they are unambiguous to mark connections as done
  1.2145 +// and give them the same winding value
  1.2146 +
  1.2147 +SkOpSpan* SkOpSegment::markAndChaseDoneBinary(int index, int endIndex) {
  1.2148 +    int step = SkSign32(endIndex - index);
  1.2149 +    int min = SkMin32(index, endIndex);
  1.2150 +    markDoneBinary(min);
  1.2151 +    SkOpSpan* last;
  1.2152 +    SkOpSegment* other = this;
  1.2153 +    while ((other = other->nextChase(&index, step, &min, &last))) {
  1.2154 +        if (other->done()) {
  1.2155 +            return NULL;
  1.2156 +        }
  1.2157 +        other->markDoneBinary(min);
  1.2158 +    }
  1.2159 +    return last;
  1.2160 +}
  1.2161 +
  1.2162 +SkOpSpan* SkOpSegment::markAndChaseDoneUnary(int index, int endIndex) {
  1.2163 +    int step = SkSign32(endIndex - index);
  1.2164 +    int min = SkMin32(index, endIndex);
  1.2165 +    markDoneUnary(min);
  1.2166 +    SkOpSpan* last;
  1.2167 +    SkOpSegment* other = this;
  1.2168 +    while ((other = other->nextChase(&index, step, &min, &last))) {
  1.2169 +        if (other->done()) {
  1.2170 +            return NULL;
  1.2171 +        }
  1.2172 +        other->markDoneUnary(min);
  1.2173 +    }
  1.2174 +    return last;
  1.2175 +}
  1.2176 +
  1.2177 +SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, const int winding) {
  1.2178 +    int index = angle->start();
  1.2179 +    int endIndex = angle->end();
  1.2180 +    int step = SkSign32(endIndex - index);
  1.2181 +    int min = SkMin32(index, endIndex);
  1.2182 +    markWinding(min, winding);
  1.2183 +    SkOpSpan* last;
  1.2184 +    SkOpSegment* other = this;
  1.2185 +    while ((other = other->nextChase(&index, step, &min, &last))) {
  1.2186 +        if (other->fTs[min].fWindSum != SK_MinS32) {
  1.2187 +            SkASSERT(other->fTs[min].fWindSum == winding);
  1.2188 +            return NULL;
  1.2189 +        }
  1.2190 +        other->markWinding(min, winding);
  1.2191 +    }
  1.2192 +    return last;
  1.2193 +}
  1.2194 +
  1.2195 +SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
  1.2196 +    int min = SkMin32(index, endIndex);
  1.2197 +    int step = SkSign32(endIndex - index);
  1.2198 +    markWinding(min, winding, oppWinding);
  1.2199 +    SkOpSpan* last;
  1.2200 +    SkOpSegment* other = this;
  1.2201 +    while ((other = other->nextChase(&index, step, &min, &last))) {
  1.2202 +        if (other->fTs[min].fWindSum != SK_MinS32) {
  1.2203 +            SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
  1.2204 +            return NULL;
  1.2205 +        }
  1.2206 +        other->markWinding(min, winding, oppWinding);
  1.2207 +    }
  1.2208 +    return last;
  1.2209 +}
  1.2210 +
  1.2211 +SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding) {
  1.2212 +    int start = angle->start();
  1.2213 +    int end = angle->end();
  1.2214 +    return markAndChaseWinding(start, end, winding, oppWinding);
  1.2215 +}
  1.2216 +
  1.2217 +SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
  1.2218 +    SkASSERT(angle->segment() == this);
  1.2219 +    if (UseInnerWinding(maxWinding, sumWinding)) {
  1.2220 +        maxWinding = sumWinding;
  1.2221 +    }
  1.2222 +    SkOpSpan* last = markAndChaseWinding(angle, maxWinding);
  1.2223 +#if DEBUG_WINDING
  1.2224 +    if (last) {
  1.2225 +        SkDebugf("%s last id=%d windSum=", __FUNCTION__,
  1.2226 +                last->fOther->fTs[last->fOtherIndex].fOther->debugID());
  1.2227 +        SkPathOpsDebug::WindingPrintf(last->fWindSum);
  1.2228 +        SkDebugf(" small=%d\n", last->fSmall);
  1.2229 +    }
  1.2230 +#endif
  1.2231 +    return last;
  1.2232 +}
  1.2233 +
  1.2234 +SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
  1.2235 +                                 int oppSumWinding, const SkOpAngle* angle) {
  1.2236 +    SkASSERT(angle->segment() == this);
  1.2237 +    if (UseInnerWinding(maxWinding, sumWinding)) {
  1.2238 +        maxWinding = sumWinding;
  1.2239 +    }
  1.2240 +    if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
  1.2241 +        oppMaxWinding = oppSumWinding;
  1.2242 +    }
  1.2243 +    SkOpSpan* last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
  1.2244 +#if DEBUG_WINDING
  1.2245 +    if (last) {
  1.2246 +        SkDebugf("%s last id=%d windSum=", __FUNCTION__,
  1.2247 +                last->fOther->fTs[last->fOtherIndex].fOther->debugID());
  1.2248 +        SkPathOpsDebug::WindingPrintf(last->fWindSum);
  1.2249 +        SkDebugf(" small=%d\n", last->fSmall);
  1.2250 +    }
  1.2251 +#endif
  1.2252 +    return last;
  1.2253 +}
  1.2254 +
  1.2255 +// FIXME: this should also mark spans with equal (x,y)
  1.2256 +// This may be called when the segment is already marked done. While this
  1.2257 +// wastes time, it shouldn't do any more than spin through the T spans.
  1.2258 +// OPTIMIZATION: abort on first done found (assuming that this code is
  1.2259 +// always called to mark segments done).
  1.2260 +void SkOpSegment::markDone(int index, int winding) {
  1.2261 +  //  SkASSERT(!done());
  1.2262 +    SkASSERT(winding);
  1.2263 +    double referenceT = fTs[index].fT;
  1.2264 +    int lesser = index;
  1.2265 +    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
  1.2266 +        markOneDone(__FUNCTION__, lesser, winding);
  1.2267 +    }
  1.2268 +    do {
  1.2269 +        markOneDone(__FUNCTION__, index, winding);
  1.2270 +    } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
  1.2271 +}
  1.2272 +
  1.2273 +void SkOpSegment::markDoneBinary(int index) {
  1.2274 +    double referenceT = fTs[index].fT;
  1.2275 +    int lesser = index;
  1.2276 +    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
  1.2277 +        markOneDoneBinary(__FUNCTION__, lesser);
  1.2278 +    }
  1.2279 +    do {
  1.2280 +        markOneDoneBinary(__FUNCTION__, index);
  1.2281 +    } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
  1.2282 +}
  1.2283 +
  1.2284 +void SkOpSegment::markDoneUnary(int index) {
  1.2285 +    double referenceT = fTs[index].fT;
  1.2286 +    int lesser = index;
  1.2287 +    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
  1.2288 +        markOneDoneUnary(__FUNCTION__, lesser);
  1.2289 +    }
  1.2290 +    do {
  1.2291 +        markOneDoneUnary(__FUNCTION__, index);
  1.2292 +    } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
  1.2293 +}
  1.2294 +
  1.2295 +void SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) {
  1.2296 +    SkOpSpan* span = markOneWinding(funName, tIndex, winding);
  1.2297 +    if (!span) {
  1.2298 +        return;
  1.2299 +    }
  1.2300 +    span->fDone = true;
  1.2301 +    fDoneSpans++;
  1.2302 +}
  1.2303 +
  1.2304 +void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) {
  1.2305 +    SkOpSpan* span = verifyOneWinding(funName, tIndex);
  1.2306 +    if (!span) {
  1.2307 +        return;
  1.2308 +    }
  1.2309 +    span->fDone = true;
  1.2310 +    fDoneSpans++;
  1.2311 +}
  1.2312 +
  1.2313 +void SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) {
  1.2314 +    SkOpSpan* span = verifyOneWindingU(funName, tIndex);
  1.2315 +    if (!span) {
  1.2316 +        return;
  1.2317 +    }
  1.2318 +    span->fDone = true;
  1.2319 +    fDoneSpans++;
  1.2320 +}
  1.2321 +
  1.2322 +SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding) {
  1.2323 +    SkOpSpan& span = fTs[tIndex];
  1.2324 +    if (span.fDone) {
  1.2325 +        return NULL;
  1.2326 +    }
  1.2327 +#if DEBUG_MARK_DONE
  1.2328 +    debugShowNewWinding(funName, span, winding);
  1.2329 +#endif
  1.2330 +    SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
  1.2331 +    SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum);
  1.2332 +    span.fWindSum = winding;
  1.2333 +    return &span;
  1.2334 +}
  1.2335 +
  1.2336 +SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding,
  1.2337 +                                      int oppWinding) {
  1.2338 +    SkOpSpan& span = fTs[tIndex];
  1.2339 +    if (span.fDone && !span.fSmall) {
  1.2340 +        return NULL;
  1.2341 +    }
  1.2342 +#if DEBUG_MARK_DONE
  1.2343 +    debugShowNewWinding(funName, span, winding, oppWinding);
  1.2344 +#endif
  1.2345 +    SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
  1.2346 +    SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum);
  1.2347 +    span.fWindSum = winding;
  1.2348 +    SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
  1.2349 +    SkASSERT(abs(oppWinding) <= SkPathOpsDebug::gMaxWindSum);
  1.2350 +    span.fOppSum = oppWinding;
  1.2351 +    return &span;
  1.2352 +}
  1.2353 +
  1.2354 +// from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
  1.2355 +bool SkOpSegment::clockwise(int tStart, int tEnd) const {
  1.2356 +    SkASSERT(fVerb != SkPath::kLine_Verb);
  1.2357 +    SkPoint edge[4];
  1.2358 +    subDivide(tStart, tEnd, edge);
  1.2359 +    int points = SkPathOpsVerbToPoints(fVerb);
  1.2360 +    double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY);
  1.2361 +    if (fVerb == SkPath::kCubic_Verb) {
  1.2362 +        SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY);
  1.2363 +        if (edge[1].fY < lesser && edge[2].fY < lesser) {
  1.2364 +            SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1].fY} }};
  1.2365 +            SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3].fY} }};
  1.2366 +            if (SkIntersections::Test(tangent1, tangent2)) {
  1.2367 +                SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT);
  1.2368 +                sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY);
  1.2369 +                sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY);
  1.2370 +                return sum <= 0;
  1.2371 +            }
  1.2372 +        }
  1.2373 +    }
  1.2374 +    for (int idx = 0; idx < points; ++idx){
  1.2375 +        sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
  1.2376 +    }
  1.2377 +    return sum <= 0;
  1.2378 +}
  1.2379 +
  1.2380 +bool SkOpSegment::monotonicInY(int tStart, int tEnd) const {
  1.2381 +    if (fVerb == SkPath::kLine_Verb) {
  1.2382 +        return false;
  1.2383 +    }
  1.2384 +    if (fVerb == SkPath::kQuad_Verb) {
  1.2385 +        SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
  1.2386 +        return dst.monotonicInY();
  1.2387 +    }
  1.2388 +    SkASSERT(fVerb == SkPath::kCubic_Verb);
  1.2389 +    SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
  1.2390 +    return dst.monotonicInY();
  1.2391 +}
  1.2392 +
  1.2393 +bool SkOpSegment::serpentine(int tStart, int tEnd) const {
  1.2394 +    if (fVerb != SkPath::kCubic_Verb) {
  1.2395 +        return false;
  1.2396 +    }
  1.2397 +    SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
  1.2398 +    return dst.serpentine();
  1.2399 +}
  1.2400 +
  1.2401 +SkOpSpan* SkOpSegment::verifyOneWinding(const char* funName, int tIndex) {
  1.2402 +    SkOpSpan& span = fTs[tIndex];
  1.2403 +    if (span.fDone) {
  1.2404 +        return NULL;
  1.2405 +    }
  1.2406 +#if DEBUG_MARK_DONE
  1.2407 +    debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
  1.2408 +#endif
  1.2409 +// If the prior angle in the sort is unorderable, the winding sum may not be computable.
  1.2410 +// To enable the assert, the 'prior is unorderable' state could be
  1.2411 +// piped down to this test, but not sure it's worth it.
  1.2412 +// (Once the sort order is stored in the span, this test may be feasible.)
  1.2413 +//    SkASSERT(span.fWindSum != SK_MinS32);
  1.2414 +//    SkASSERT(span.fOppSum != SK_MinS32);
  1.2415 +    return &span;
  1.2416 +}
  1.2417 +
  1.2418 +SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) {
  1.2419 +    SkOpSpan& span = fTs[tIndex];
  1.2420 +    if (span.fDone) {
  1.2421 +        return NULL;
  1.2422 +    }
  1.2423 +#if DEBUG_MARK_DONE
  1.2424 +    debugShowNewWinding(funName, span, span.fWindSum);
  1.2425 +#endif
  1.2426 +// If the prior angle in the sort is unorderable, the winding sum may not be computable.
  1.2427 +// To enable the assert, the 'prior is unorderable' state could be
  1.2428 +// piped down to this test, but not sure it's worth it.
  1.2429 +// (Once the sort order is stored in the span, this test may be feasible.)
  1.2430 +//    SkASSERT(span.fWindSum != SK_MinS32);
  1.2431 +    return &span;
  1.2432 +}
  1.2433 +
  1.2434 +// note that just because a span has one end that is unsortable, that's
  1.2435 +// not enough to mark it done. The other end may be sortable, allowing the
  1.2436 +// span to be added.
  1.2437 +// FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
  1.2438 +void SkOpSegment::markUnsortable(int start, int end) {
  1.2439 +    SkOpSpan* span = &fTs[start];
  1.2440 +    if (start < end) {
  1.2441 +#if DEBUG_UNSORTABLE
  1.2442 +        debugShowNewWinding(__FUNCTION__, *span, 0);
  1.2443 +#endif
  1.2444 +        span->fUnsortableStart = true;
  1.2445 +    } else {
  1.2446 +        --span;
  1.2447 +#if DEBUG_UNSORTABLE
  1.2448 +        debugShowNewWinding(__FUNCTION__, *span, 0);
  1.2449 +#endif
  1.2450 +        span->fUnsortableEnd = true;
  1.2451 +    }
  1.2452 +    if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
  1.2453 +        return;
  1.2454 +    }
  1.2455 +    span->fDone = true;
  1.2456 +    fDoneSpans++;
  1.2457 +}
  1.2458 +
  1.2459 +void SkOpSegment::markWinding(int index, int winding) {
  1.2460 +//    SkASSERT(!done());
  1.2461 +    SkASSERT(winding);
  1.2462 +    double referenceT = fTs[index].fT;
  1.2463 +    int lesser = index;
  1.2464 +    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
  1.2465 +        markOneWinding(__FUNCTION__, lesser, winding);
  1.2466 +    }
  1.2467 +    do {
  1.2468 +        markOneWinding(__FUNCTION__, index, winding);
  1.2469 +   } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
  1.2470 +}
  1.2471 +
  1.2472 +void SkOpSegment::markWinding(int index, int winding, int oppWinding) {
  1.2473 +//    SkASSERT(!done());
  1.2474 +    SkASSERT(winding || oppWinding);
  1.2475 +    double referenceT = fTs[index].fT;
  1.2476 +    int lesser = index;
  1.2477 +    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
  1.2478 +        markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
  1.2479 +    }
  1.2480 +    do {
  1.2481 +        markOneWinding(__FUNCTION__, index, winding, oppWinding);
  1.2482 +   } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
  1.2483 +}
  1.2484 +
  1.2485 +void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) {
  1.2486 +    int nextDoorWind = SK_MaxS32;
  1.2487 +    int nextOppWind = SK_MaxS32;
  1.2488 +    if (tIndex > 0) {
  1.2489 +        const SkOpSpan& below = fTs[tIndex - 1];
  1.2490 +        if (approximately_negative(t - below.fT)) {
  1.2491 +            nextDoorWind = below.fWindValue;
  1.2492 +            nextOppWind = below.fOppValue;
  1.2493 +        }
  1.2494 +    }
  1.2495 +    if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
  1.2496 +        const SkOpSpan& above = fTs[tIndex + 1];
  1.2497 +        if (approximately_negative(above.fT - t)) {
  1.2498 +            nextDoorWind = above.fWindValue;
  1.2499 +            nextOppWind = above.fOppValue;
  1.2500 +        }
  1.2501 +    }
  1.2502 +    if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
  1.2503 +        const SkOpSpan& below = fTs[tIndex - 1];
  1.2504 +        nextDoorWind = below.fWindValue;
  1.2505 +        nextOppWind = below.fOppValue;
  1.2506 +    }
  1.2507 +    if (nextDoorWind != SK_MaxS32) {
  1.2508 +        SkOpSpan& newSpan = fTs[tIndex];
  1.2509 +        newSpan.fWindValue = nextDoorWind;
  1.2510 +        newSpan.fOppValue = nextOppWind;
  1.2511 +        if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
  1.2512 +            newSpan.fDone = true;
  1.2513 +            ++fDoneSpans;
  1.2514 +        }
  1.2515 +    }
  1.2516 +}
  1.2517 +
  1.2518 +// return span if when chasing, two or more radiating spans are not done
  1.2519 +// OPTIMIZATION: ? multiple spans is detected when there is only one valid
  1.2520 +// candidate and the remaining spans have windValue == 0 (canceled by
  1.2521 +// coincidence). The coincident edges could either be removed altogether,
  1.2522 +// or this code could be more complicated in detecting this case. Worth it?
  1.2523 +bool SkOpSegment::multipleSpans(int end) const {
  1.2524 +    return end > 0 && end < fTs.count() - 1;
  1.2525 +}
  1.2526 +
  1.2527 +bool SkOpSegment::nextCandidate(int* start, int* end) const {
  1.2528 +    while (fTs[*end].fDone) {
  1.2529 +        if (fTs[*end].fT == 1) {
  1.2530 +            return false;
  1.2531 +        }
  1.2532 +        ++(*end);
  1.2533 +    }
  1.2534 +    *start = *end;
  1.2535 +    *end = nextExactSpan(*start, 1);
  1.2536 +    return true;
  1.2537 +}
  1.2538 +
  1.2539 +SkOpSegment* SkOpSegment::nextChase(int* index, const int step, int* min, SkOpSpan** last) {
  1.2540 +    int end = nextExactSpan(*index, step);
  1.2541 +    SkASSERT(end >= 0);
  1.2542 +    if (fTs[end].fSmall) {
  1.2543 +        *last = NULL;
  1.2544 +        return NULL;
  1.2545 +    }
  1.2546 +    if (multipleSpans(end)) {
  1.2547 +        *last = &fTs[end];
  1.2548 +        return NULL;
  1.2549 +    }
  1.2550 +    const SkOpSpan& endSpan = fTs[end];
  1.2551 +    SkOpSegment* other = endSpan.fOther;
  1.2552 +    *index = endSpan.fOtherIndex;
  1.2553 +    SkASSERT(*index >= 0);
  1.2554 +    int otherEnd = other->nextExactSpan(*index, step);
  1.2555 +    SkASSERT(otherEnd >= 0);
  1.2556 +    *min = SkMin32(*index, otherEnd);
  1.2557 +    if (other->fTs[*min].fSmall) {
  1.2558 +        *last = NULL;
  1.2559 +        return NULL;
  1.2560 +    }
  1.2561 +    return other;
  1.2562 +}
  1.2563 +
  1.2564 +// This has callers for two different situations: one establishes the end
  1.2565 +// of the current span, and one establishes the beginning of the next span
  1.2566 +// (thus the name). When this is looking for the end of the current span,
  1.2567 +// coincidence is found when the beginning Ts contain -step and the end
  1.2568 +// contains step. When it is looking for the beginning of the next, the
  1.2569 +// first Ts found can be ignored and the last Ts should contain -step.
  1.2570 +// OPTIMIZATION: probably should split into two functions
  1.2571 +int SkOpSegment::nextSpan(int from, int step) const {
  1.2572 +    const SkOpSpan& fromSpan = fTs[from];
  1.2573 +    int count = fTs.count();
  1.2574 +    int to = from;
  1.2575 +    while (step > 0 ? ++to < count : --to >= 0) {
  1.2576 +        const SkOpSpan& span = fTs[to];
  1.2577 +        if (approximately_zero(span.fT - fromSpan.fT)) {
  1.2578 +            continue;
  1.2579 +        }
  1.2580 +        return to;
  1.2581 +    }
  1.2582 +    return -1;
  1.2583 +}
  1.2584 +
  1.2585 +// FIXME
  1.2586 +// this returns at any difference in T, vs. a preset minimum. It may be
  1.2587 +// that all callers to nextSpan should use this instead.
  1.2588 +int SkOpSegment::nextExactSpan(int from, int step) const {
  1.2589 +    int to = from;
  1.2590 +    if (step < 0) {
  1.2591 +        const SkOpSpan& fromSpan = fTs[from];
  1.2592 +        while (--to >= 0) {
  1.2593 +            const SkOpSpan& span = fTs[to];
  1.2594 +            if (precisely_negative(fromSpan.fT - span.fT) || span.fTiny) {
  1.2595 +                continue;
  1.2596 +            }
  1.2597 +            return to;
  1.2598 +        }
  1.2599 +    } else {
  1.2600 +        while (fTs[from].fTiny) {
  1.2601 +            from++;
  1.2602 +        }
  1.2603 +        const SkOpSpan& fromSpan = fTs[from];
  1.2604 +        int count = fTs.count();
  1.2605 +        while (++to < count) {
  1.2606 +            const SkOpSpan& span = fTs[to];
  1.2607 +            if (precisely_negative(span.fT - fromSpan.fT)) {
  1.2608 +                continue;
  1.2609 +            }
  1.2610 +            return to;
  1.2611 +        }
  1.2612 +    }
  1.2613 +    return -1;
  1.2614 +}
  1.2615 +
  1.2616 +void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
  1.2617 +        int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) {
  1.2618 +    int deltaSum = spanSign(index, endIndex);
  1.2619 +    int oppDeltaSum = oppSign(index, endIndex);
  1.2620 +    if (operand()) {
  1.2621 +        *maxWinding = *sumSuWinding;
  1.2622 +        *sumWinding = *sumSuWinding -= deltaSum;
  1.2623 +        *oppMaxWinding = *sumMiWinding;
  1.2624 +        *oppSumWinding = *sumMiWinding -= oppDeltaSum;
  1.2625 +    } else {
  1.2626 +        *maxWinding = *sumMiWinding;
  1.2627 +        *sumWinding = *sumMiWinding -= deltaSum;
  1.2628 +        *oppMaxWinding = *sumSuWinding;
  1.2629 +        *oppSumWinding = *sumSuWinding -= oppDeltaSum;
  1.2630 +    }
  1.2631 +    SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum);
  1.2632 +    SkASSERT(abs(*oppSumWinding) <= SkPathOpsDebug::gMaxWindSum);
  1.2633 +}
  1.2634 +
  1.2635 +void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding,
  1.2636 +        int* maxWinding, int* sumWinding) {
  1.2637 +    int deltaSum = spanSign(index, endIndex);
  1.2638 +    *maxWinding = *sumMiWinding;
  1.2639 +    *sumWinding = *sumMiWinding -= deltaSum;
  1.2640 +    SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum);
  1.2641 +}
  1.2642 +
  1.2643 +// This marks all spans unsortable so that this info is available for early
  1.2644 +// exclusion in find top and others. This could be optimized to only mark
  1.2645 +// adjacent spans that unsortable. However, this makes it difficult to later
  1.2646 +// determine starting points for edge detection in find top and the like.
  1.2647 +bool SkOpSegment::SortAngles(const SkTArray<SkOpAngle, true>& angles,
  1.2648 +                             SkTArray<SkOpAngle*, true>* angleList,
  1.2649 +                             SortAngleKind orderKind) {
  1.2650 +    bool sortable = true;
  1.2651 +    int angleCount = angles.count();
  1.2652 +    int angleIndex;
  1.2653 +    for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
  1.2654 +        const SkOpAngle& angle = angles[angleIndex];
  1.2655 +        angleList->push_back(const_cast<SkOpAngle*>(&angle));
  1.2656 +#if DEBUG_ANGLE
  1.2657 +        (*(angleList->end() - 1))->setID(angleIndex);
  1.2658 +#endif
  1.2659 +        sortable &= !(angle.unsortable() || (orderKind == kMustBeOrdered_SortAngleKind
  1.2660 +                    && angle.unorderable()));
  1.2661 +    }
  1.2662 +    if (sortable) {
  1.2663 +        SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1);
  1.2664 +        for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
  1.2665 +            if (angles[angleIndex].unsortable() || (orderKind == kMustBeOrdered_SortAngleKind
  1.2666 +                        && angles[angleIndex].unorderable())) {
  1.2667 +                sortable = false;
  1.2668 +                break;
  1.2669 +            }
  1.2670 +        }
  1.2671 +    }
  1.2672 +    if (!sortable) {
  1.2673 +        for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
  1.2674 +            const SkOpAngle& angle = angles[angleIndex];
  1.2675 +            angle.segment()->markUnsortable(angle.start(), angle.end());
  1.2676 +        }
  1.2677 +    }
  1.2678 +    return sortable;
  1.2679 +}
  1.2680 +
  1.2681 +// set segments to unsortable if angle is unsortable, but do not set all angles
  1.2682 +// note that for a simple 4 way crossing, two of the edges may be orderable even though
  1.2683 +// two edges are too short to be orderable.
  1.2684 +// perhaps some classes of unsortable angles should make all shared angles unsortable, but
  1.2685 +// simple lines that have tiny crossings are always sortable on the large ends
  1.2686 +// OPTIMIZATION: check earlier when angles are added to input if any are unsortable
  1.2687 +// may make sense then to mark all segments in angle sweep as unsortableStart/unsortableEnd
  1.2688 +// solely for the purpose of short-circuiting future angle building around this center
  1.2689 +bool SkOpSegment::SortAngles2(const SkTArray<SkOpAngle, true>& angles,
  1.2690 +                              SkTArray<SkOpAngle*, true>* angleList) {
  1.2691 +    int angleCount = angles.count();
  1.2692 +    int angleIndex;
  1.2693 +    for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
  1.2694 +        const SkOpAngle& angle = angles[angleIndex];
  1.2695 +        if (angle.unsortable()) {
  1.2696 +            return false;
  1.2697 +        }
  1.2698 +        angleList->push_back(const_cast<SkOpAngle*>(&angle));
  1.2699 +#if DEBUG_ANGLE
  1.2700 +        (*(angleList->end() - 1))->setID(angleIndex);
  1.2701 +#endif
  1.2702 +    }
  1.2703 +    SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1);
  1.2704 +    // at this point angles are sorted but individually may not be orderable
  1.2705 +    // this means that only adjcent orderable segments may transfer winding
  1.2706 +    return true;
  1.2707 +}
  1.2708 +
  1.2709 +// return true if midpoints were computed
  1.2710 +bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const {
  1.2711 +    SkASSERT(start != end);
  1.2712 +    edge[0] = fTs[start].fPt;
  1.2713 +    int points = SkPathOpsVerbToPoints(fVerb);
  1.2714 +    edge[points] = fTs[end].fPt;
  1.2715 +    if (fVerb == SkPath::kLine_Verb) {
  1.2716 +        return false;
  1.2717 +    }
  1.2718 +    double startT = fTs[start].fT;
  1.2719 +    double endT = fTs[end].fT;
  1.2720 +    if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
  1.2721 +        // don't compute midpoints if we already have them
  1.2722 +        if (fVerb == SkPath::kQuad_Verb) {
  1.2723 +            edge[1] = fPts[1];
  1.2724 +            return false;
  1.2725 +        }
  1.2726 +        SkASSERT(fVerb == SkPath::kCubic_Verb);
  1.2727 +        if (start < end) {
  1.2728 +            edge[1] = fPts[1];
  1.2729 +            edge[2] = fPts[2];
  1.2730 +            return false;
  1.2731 +        }
  1.2732 +        edge[1] = fPts[2];
  1.2733 +        edge[2] = fPts[1];
  1.2734 +        return false;
  1.2735 +    }
  1.2736 +    const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[points].fY }};
  1.2737 +    if (fVerb == SkPath::kQuad_Verb) {
  1.2738 +        edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
  1.2739 +    } else {
  1.2740 +        SkASSERT(fVerb == SkPath::kCubic_Verb);
  1.2741 +        SkDPoint ctrl[2];
  1.2742 +        SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
  1.2743 +        edge[1] = ctrl[0].asSkPoint();
  1.2744 +        edge[2] = ctrl[1].asSkPoint();
  1.2745 +    }
  1.2746 +    return true;
  1.2747 +}
  1.2748 +
  1.2749 +// return true if midpoints were computed
  1.2750 +bool SkOpSegment::subDivide(int start, int end, SkDCubic* result) const {
  1.2751 +    SkASSERT(start != end);
  1.2752 +    (*result)[0].set(fTs[start].fPt);
  1.2753 +    int points = SkPathOpsVerbToPoints(fVerb);
  1.2754 +    (*result)[points].set(fTs[end].fPt);
  1.2755 +    if (fVerb == SkPath::kLine_Verb) {
  1.2756 +        return false;
  1.2757 +    }
  1.2758 +    double startT = fTs[start].fT;
  1.2759 +    double endT = fTs[end].fT;
  1.2760 +    if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
  1.2761 +        // don't compute midpoints if we already have them
  1.2762 +        if (fVerb == SkPath::kQuad_Verb) {
  1.2763 +            (*result)[1].set(fPts[1]);
  1.2764 +            return false;
  1.2765 +        }
  1.2766 +        SkASSERT(fVerb == SkPath::kCubic_Verb);
  1.2767 +        if (start < end) {
  1.2768 +            (*result)[1].set(fPts[1]);
  1.2769 +            (*result)[2].set(fPts[2]);
  1.2770 +            return false;
  1.2771 +        }
  1.2772 +        (*result)[1].set(fPts[2]);
  1.2773 +        (*result)[2].set(fPts[1]);
  1.2774 +        return false;
  1.2775 +    }
  1.2776 +    if (fVerb == SkPath::kQuad_Verb) {
  1.2777 +        (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], startT, endT);
  1.2778 +    } else {
  1.2779 +        SkASSERT(fVerb == SkPath::kCubic_Verb);
  1.2780 +        SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*result)[1]);
  1.2781 +    }
  1.2782 +    return true;
  1.2783 +}
  1.2784 +
  1.2785 +void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const {
  1.2786 +    SkPoint edge[4];
  1.2787 +    subDivide(start, end, edge);
  1.2788 +    (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge);
  1.2789 +}
  1.2790 +
  1.2791 +void SkOpSegment::TrackOutsidePair(SkTArray<SkPoint, true>* outsidePts, const SkPoint& endPt,
  1.2792 +        const SkPoint& startPt) {
  1.2793 +    int outCount = outsidePts->count();
  1.2794 +    if (outCount == 0 || endPt != (*outsidePts)[outCount - 2]) {
  1.2795 +        outsidePts->push_back(endPt);
  1.2796 +        outsidePts->push_back(startPt);
  1.2797 +    }
  1.2798 +}
  1.2799 +
  1.2800 +void SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoint& startPt) {
  1.2801 +    int outCount = outsidePts->count();
  1.2802 +    if (outCount == 0 || startPt != (*outsidePts)[outCount - 1]) {
  1.2803 +        outsidePts->push_back(startPt);
  1.2804 +    }
  1.2805 +}
  1.2806 +
  1.2807 +void SkOpSegment::undoneSpan(int* start, int* end) {
  1.2808 +    size_t tCount = fTs.count();
  1.2809 +    size_t index;
  1.2810 +    for (index = 0; index < tCount; ++index) {
  1.2811 +        if (!fTs[index].fDone) {
  1.2812 +            break;
  1.2813 +        }
  1.2814 +    }
  1.2815 +    SkASSERT(index < tCount - 1);
  1.2816 +    *start = index;
  1.2817 +    double startT = fTs[index].fT;
  1.2818 +    while (approximately_negative(fTs[++index].fT - startT))
  1.2819 +        SkASSERT(index < tCount);
  1.2820 +    SkASSERT(index < tCount);
  1.2821 +    *end = index;
  1.2822 +}
  1.2823 +
  1.2824 +int SkOpSegment::updateOppWinding(int index, int endIndex) const {
  1.2825 +    int lesser = SkMin32(index, endIndex);
  1.2826 +    int oppWinding = oppSum(lesser);
  1.2827 +    int oppSpanWinding = oppSign(index, endIndex);
  1.2828 +    if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
  1.2829 +            && oppWinding != SK_MaxS32) {
  1.2830 +        oppWinding -= oppSpanWinding;
  1.2831 +    }
  1.2832 +    return oppWinding;
  1.2833 +}
  1.2834 +
  1.2835 +int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
  1.2836 +    int startIndex = angle->start();
  1.2837 +    int endIndex = angle->end();
  1.2838 +    return updateOppWinding(endIndex, startIndex);
  1.2839 +}
  1.2840 +
  1.2841 +int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
  1.2842 +    int startIndex = angle->start();
  1.2843 +    int endIndex = angle->end();
  1.2844 +    return updateOppWinding(startIndex, endIndex);
  1.2845 +}
  1.2846 +
  1.2847 +int SkOpSegment::updateWinding(int index, int endIndex) const {
  1.2848 +    int lesser = SkMin32(index, endIndex);
  1.2849 +    int winding = windSum(lesser);
  1.2850 +    int spanWinding = spanSign(index, endIndex);
  1.2851 +    if (winding && UseInnerWinding(winding - spanWinding, winding)
  1.2852 +            && winding != SK_MaxS32) {
  1.2853 +        winding -= spanWinding;
  1.2854 +    }
  1.2855 +    return winding;
  1.2856 +}
  1.2857 +
  1.2858 +int SkOpSegment::updateWinding(const SkOpAngle* angle) const {
  1.2859 +    int startIndex = angle->start();
  1.2860 +    int endIndex = angle->end();
  1.2861 +    return updateWinding(endIndex, startIndex);
  1.2862 +}
  1.2863 +
  1.2864 +int SkOpSegment::updateWindingReverse(int index, int endIndex) const {
  1.2865 +    int lesser = SkMin32(index, endIndex);
  1.2866 +    int winding = windSum(lesser);
  1.2867 +    int spanWinding = spanSign(endIndex, index);
  1.2868 +    if (winding && UseInnerWindingReverse(winding - spanWinding, winding)
  1.2869 +            && winding != SK_MaxS32) {
  1.2870 +        winding -= spanWinding;
  1.2871 +    }
  1.2872 +    return winding;
  1.2873 +}
  1.2874 +
  1.2875 +int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const {
  1.2876 +    int startIndex = angle->start();
  1.2877 +    int endIndex = angle->end();
  1.2878 +    return updateWindingReverse(endIndex, startIndex);
  1.2879 +}
  1.2880 +
  1.2881 +// OPTIMIZATION: does the following also work, and is it any faster?
  1.2882 +// return outerWinding * innerWinding > 0
  1.2883 +//      || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
  1.2884 +bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
  1.2885 +    SkASSERT(outerWinding != SK_MaxS32);
  1.2886 +    SkASSERT(innerWinding != SK_MaxS32);
  1.2887 +    int absOut = abs(outerWinding);
  1.2888 +    int absIn = abs(innerWinding);
  1.2889 +    bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
  1.2890 +    return result;
  1.2891 +}
  1.2892 +
  1.2893 +bool SkOpSegment::UseInnerWindingReverse(int outerWinding, int innerWinding) {
  1.2894 +    SkASSERT(outerWinding != SK_MaxS32);
  1.2895 +    SkASSERT(innerWinding != SK_MaxS32);
  1.2896 +    int absOut = abs(outerWinding);
  1.2897 +    int absIn = abs(innerWinding);
  1.2898 +    bool result = absOut == absIn ? true : absOut < absIn;
  1.2899 +    return result;
  1.2900 +}
  1.2901 +
  1.2902 +int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const {
  1.2903 +    if (approximately_zero(tHit - t(tIndex))) {  // if we hit the end of a span, disregard
  1.2904 +        return SK_MinS32;
  1.2905 +    }
  1.2906 +    int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
  1.2907 +    SkASSERT(winding != SK_MinS32);
  1.2908 +    int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
  1.2909 +#if DEBUG_WINDING_AT_T
  1.2910 +    SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
  1.2911 +#endif
  1.2912 +    // see if a + change in T results in a +/- change in X (compute x'(T))
  1.2913 +    *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
  1.2914 +    if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
  1.2915 +        *dx = fPts[2].fX - fPts[1].fX - *dx;
  1.2916 +    }
  1.2917 +    if (*dx == 0) {
  1.2918 +#if DEBUG_WINDING_AT_T
  1.2919 +        SkDebugf(" dx=0 winding=SK_MinS32\n");
  1.2920 +#endif
  1.2921 +        return SK_MinS32;
  1.2922 +    }
  1.2923 +    if (windVal < 0) {  // reverse sign if opp contour traveled in reverse
  1.2924 +            *dx = -*dx;
  1.2925 +    }
  1.2926 +    if (winding * *dx > 0) {  // if same signs, result is negative
  1.2927 +        winding += *dx > 0 ? -windVal : windVal;
  1.2928 +    }
  1.2929 +#if DEBUG_WINDING_AT_T
  1.2930 +    SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding);
  1.2931 +#endif
  1.2932 +    return winding;
  1.2933 +}
  1.2934 +
  1.2935 +int SkOpSegment::windSum(const SkOpAngle* angle) const {
  1.2936 +    int start = angle->start();
  1.2937 +    int end = angle->end();
  1.2938 +    int index = SkMin32(start, end);
  1.2939 +    return windSum(index);
  1.2940 +}
  1.2941 +
  1.2942 +void SkOpSegment::zeroSpan(SkOpSpan* span) {
  1.2943 +    SkASSERT(span->fWindValue > 0 || span->fOppValue != 0);
  1.2944 +    span->fWindValue = 0;
  1.2945 +    span->fOppValue = 0;
  1.2946 +    if (span->fTiny || span->fSmall) {
  1.2947 +        return;
  1.2948 +    }
  1.2949 +    SkASSERT(!span->fDone);
  1.2950 +    span->fDone = true;
  1.2951 +    ++fDoneSpans;
  1.2952 +}
  1.2953 +
  1.2954 +#if DEBUG_SWAP_TOP
  1.2955 +bool SkOpSegment::controlsContainedByEnds(int tStart, int tEnd) const {
  1.2956 +    if (fVerb != SkPath::kCubic_Verb) {
  1.2957 +        return false;
  1.2958 +    }
  1.2959 +    SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
  1.2960 +    return dst.controlsContainedByEnds();
  1.2961 +}
  1.2962 +#endif
  1.2963 +
  1.2964 +#if DEBUG_CONCIDENT
  1.2965 +// SkASSERT if pair has not already been added
  1.2966 +void SkOpSegment::debugAddTPair(double t, const SkOpSegment& other, double otherT) const {
  1.2967 +    for (int i = 0; i < fTs.count(); ++i) {
  1.2968 +        if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
  1.2969 +            return;
  1.2970 +        }
  1.2971 +    }
  1.2972 +    SkASSERT(0);
  1.2973 +}
  1.2974 +#endif
  1.2975 +
  1.2976 +#if DEBUG_CONCIDENT
  1.2977 +void SkOpSegment::debugShowTs(const char* prefix) const {
  1.2978 +    SkDebugf("%s %s id=%d", __FUNCTION__, prefix, fID);
  1.2979 +    int lastWind = -1;
  1.2980 +    int lastOpp = -1;
  1.2981 +    double lastT = -1;
  1.2982 +    int i;
  1.2983 +    for (i = 0; i < fTs.count(); ++i) {
  1.2984 +        bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
  1.2985 +                || lastOpp != fTs[i].fOppValue;
  1.2986 +        if (change && lastWind >= 0) {
  1.2987 +            SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
  1.2988 +                    lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
  1.2989 +        }
  1.2990 +        if (change) {
  1.2991 +            SkDebugf(" [o=%d", fTs[i].fOther->fID);
  1.2992 +            lastWind = fTs[i].fWindValue;
  1.2993 +            lastOpp = fTs[i].fOppValue;
  1.2994 +            lastT = fTs[i].fT;
  1.2995 +        } else {
  1.2996 +            SkDebugf(",%d", fTs[i].fOther->fID);
  1.2997 +        }
  1.2998 +    }
  1.2999 +    if (i <= 0) {
  1.3000 +        return;
  1.3001 +    }
  1.3002 +    SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
  1.3003 +            lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
  1.3004 +    if (fOperand) {
  1.3005 +        SkDebugf(" operand");
  1.3006 +    }
  1.3007 +    if (done()) {
  1.3008 +        SkDebugf(" done");
  1.3009 +    }
  1.3010 +    SkDebugf("\n");
  1.3011 +}
  1.3012 +#endif
  1.3013 +
  1.3014 +#if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
  1.3015 +void SkOpSegment::debugShowActiveSpans() const {
  1.3016 +    debugValidate();
  1.3017 +    if (done()) {
  1.3018 +        return;
  1.3019 +    }
  1.3020 +#if DEBUG_ACTIVE_SPANS_SHORT_FORM
  1.3021 +    int lastId = -1;
  1.3022 +    double lastT = -1;
  1.3023 +#endif
  1.3024 +    for (int i = 0; i < fTs.count(); ++i) {
  1.3025 +        if (fTs[i].fDone) {
  1.3026 +            continue;
  1.3027 +        }
  1.3028 +        SkASSERT(i < fTs.count() - 1);
  1.3029 +#if DEBUG_ACTIVE_SPANS_SHORT_FORM
  1.3030 +        if (lastId == fID && lastT == fTs[i].fT) {
  1.3031 +            continue;
  1.3032 +        }
  1.3033 +        lastId = fID;
  1.3034 +        lastT = fTs[i].fT;
  1.3035 +#endif
  1.3036 +        SkDebugf("%s id=%d", __FUNCTION__, fID);
  1.3037 +        SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
  1.3038 +        for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
  1.3039 +            SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
  1.3040 +        }
  1.3041 +        const SkOpSpan* span = &fTs[i];
  1.3042 +        SkDebugf(") t=%1.9g (%1.9g,%1.9g)", span->fT, xAtT(span), yAtT(span));
  1.3043 +        int iEnd = i + 1;
  1.3044 +        while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) {
  1.3045 +            ++iEnd;
  1.3046 +        }
  1.3047 +        SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT);
  1.3048 +        const SkOpSegment* other = fTs[i].fOther;
  1.3049 +        SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
  1.3050 +                other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
  1.3051 +        if (fTs[i].fWindSum == SK_MinS32) {
  1.3052 +            SkDebugf("?");
  1.3053 +        } else {
  1.3054 +            SkDebugf("%d", fTs[i].fWindSum);
  1.3055 +        }
  1.3056 +        SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
  1.3057 +    }
  1.3058 +}
  1.3059 +#endif
  1.3060 +
  1.3061 +
  1.3062 +#if DEBUG_MARK_DONE || DEBUG_UNSORTABLE
  1.3063 +void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding) {
  1.3064 +    const SkPoint& pt = xyAtT(&span);
  1.3065 +    SkDebugf("%s id=%d", fun, fID);
  1.3066 +    SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
  1.3067 +    for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
  1.3068 +        SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
  1.3069 +    }
  1.3070 +    SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
  1.3071 +            fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
  1.3072 +    SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d windSum=",
  1.3073 +            span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
  1.3074 +            (&span)[1].fT, winding);
  1.3075 +    if (span.fWindSum == SK_MinS32) {
  1.3076 +        SkDebugf("?");
  1.3077 +    } else {
  1.3078 +        SkDebugf("%d", span.fWindSum);
  1.3079 +    }
  1.3080 +    SkDebugf(" windValue=%d\n", span.fWindValue);
  1.3081 +}
  1.3082 +
  1.3083 +void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding,
  1.3084 +                                      int oppWinding) {
  1.3085 +    const SkPoint& pt = xyAtT(&span);
  1.3086 +    SkDebugf("%s id=%d", fun, fID);
  1.3087 +    SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
  1.3088 +    for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
  1.3089 +        SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
  1.3090 +    }
  1.3091 +    SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
  1.3092 +            fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
  1.3093 +    SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d newOppSum=%d oppSum=",
  1.3094 +            span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
  1.3095 +            (&span)[1].fT, winding, oppWinding);
  1.3096 +    if (span.fOppSum == SK_MinS32) {
  1.3097 +        SkDebugf("?");
  1.3098 +    } else {
  1.3099 +        SkDebugf("%d", span.fOppSum);
  1.3100 +    }
  1.3101 +    SkDebugf(" windSum=");
  1.3102 +    if (span.fWindSum == SK_MinS32) {
  1.3103 +        SkDebugf("?");
  1.3104 +    } else {
  1.3105 +        SkDebugf("%d", span.fWindSum);
  1.3106 +    }
  1.3107 +    SkDebugf(" windValue=%d\n", span.fWindValue);
  1.3108 +}
  1.3109 +#endif
  1.3110 +
  1.3111 +#if DEBUG_SORT || DEBUG_SWAP_TOP
  1.3112 +void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles,
  1.3113 +                                int first, const int contourWinding,
  1.3114 +                                const int oppContourWinding, bool sortable) const {
  1.3115 +    if (--SkPathOpsDebug::gSortCount < 0) {
  1.3116 +        return;
  1.3117 +    }
  1.3118 +    if (!sortable) {
  1.3119 +        if (angles.count() == 0) {
  1.3120 +            return;
  1.3121 +        }
  1.3122 +        if (first < 0) {
  1.3123 +            first = 0;
  1.3124 +        }
  1.3125 +    }
  1.3126 +    SkASSERT(angles[first]->segment() == this);
  1.3127 +    SkASSERT(!sortable || angles.count() > 1);
  1.3128 +    int lastSum = contourWinding;
  1.3129 +    int oppLastSum = oppContourWinding;
  1.3130 +    const SkOpAngle* firstAngle = angles[first];
  1.3131 +    int windSum = lastSum - spanSign(firstAngle);
  1.3132 +    int oppoSign = oppSign(firstAngle);
  1.3133 +    int oppWindSum = oppLastSum - oppoSign;
  1.3134 +    #define WIND_AS_STRING(x) char x##Str[12]; \
  1.3135 +            if (!SkPathOpsDebug::ValidWind(x)) strcpy(x##Str, "?"); \
  1.3136 +            else SK_SNPRINTF(x##Str, sizeof(x##Str), "%d", x)
  1.3137 +    WIND_AS_STRING(contourWinding);
  1.3138 +    WIND_AS_STRING(oppContourWinding);
  1.3139 +    SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FUNCTION__,
  1.3140 +            contourWindingStr, oppContourWindingStr, spanSign(angles[first]));
  1.3141 +    int index = first;
  1.3142 +    bool firstTime = true;
  1.3143 +    do {
  1.3144 +        const SkOpAngle& angle = *angles[index];
  1.3145 +        const SkOpSegment& segment = *angle.segment();
  1.3146 +        int start = angle.start();
  1.3147 +        int end = angle.end();
  1.3148 +        const SkOpSpan& sSpan = segment.fTs[start];
  1.3149 +        const SkOpSpan& eSpan = segment.fTs[end];
  1.3150 +        const SkOpSpan& mSpan = segment.fTs[SkMin32(start, end)];
  1.3151 +        bool opp = segment.fOperand ^ fOperand;
  1.3152 +        if (!firstTime) {
  1.3153 +            oppoSign = segment.oppSign(&angle);
  1.3154 +            if (opp) {
  1.3155 +                oppLastSum = oppWindSum;
  1.3156 +                oppWindSum -= segment.spanSign(&angle);
  1.3157 +                if (oppoSign) {
  1.3158 +                    lastSum = windSum;
  1.3159 +                    windSum -= oppoSign;
  1.3160 +                }
  1.3161 +            } else {
  1.3162 +                lastSum = windSum;
  1.3163 +                windSum -= segment.spanSign(&angle);
  1.3164 +                if (oppoSign) {
  1.3165 +                    oppLastSum = oppWindSum;
  1.3166 +                    oppWindSum -= oppoSign;
  1.3167 +                }
  1.3168 +            }
  1.3169 +        }
  1.3170 +        SkDebugf("%s [%d] %s", __FUNCTION__, index,
  1.3171 +                angle.unsortable() ? "*** UNSORTABLE *** " : "");
  1.3172 +    #if DEBUG_SORT_COMPACT
  1.3173 +        SkDebugf("id=%d %s start=%d (%1.9g,%1.9g) end=%d (%1.9g,%1.9g)",
  1.3174 +                segment.fID, kLVerbStr[SkPathOpsVerbToPoints(segment.fVerb)],
  1.3175 +                start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
  1.3176 +                segment.xAtT(&eSpan), segment.yAtT(&eSpan));
  1.3177 +    #else
  1.3178 +        switch (segment.fVerb) {
  1.3179 +            case SkPath::kLine_Verb:
  1.3180 +                SkDebugf(LINE_DEBUG_STR, LINE_DEBUG_DATA(segment.fPts));
  1.3181 +                break;
  1.3182 +            case SkPath::kQuad_Verb:
  1.3183 +                SkDebugf(QUAD_DEBUG_STR, QUAD_DEBUG_DATA(segment.fPts));
  1.3184 +                break;
  1.3185 +            case SkPath::kCubic_Verb:
  1.3186 +                SkDebugf(CUBIC_DEBUG_STR, CUBIC_DEBUG_DATA(segment.fPts));
  1.3187 +                break;
  1.3188 +            default:
  1.3189 +                SkASSERT(0);
  1.3190 +        }
  1.3191 +        SkDebugf(" tStart=%1.9g tEnd=%1.9g", sSpan.fT, eSpan.fT);
  1.3192 +    #endif
  1.3193 +        SkDebugf(" sign=%d windValue=%d windSum=", angle.sign(), mSpan.fWindValue);
  1.3194 +        SkPathOpsDebug::WindingPrintf(mSpan.fWindSum);
  1.3195 +        int last, wind;
  1.3196 +        if (opp) {
  1.3197 +            last = oppLastSum;
  1.3198 +            wind = oppWindSum;
  1.3199 +        } else {
  1.3200 +            last = lastSum;
  1.3201 +            wind = windSum;
  1.3202 +        }
  1.3203 +        bool useInner = SkPathOpsDebug::ValidWind(last) && SkPathOpsDebug::ValidWind(wind)
  1.3204 +                && UseInnerWinding(last, wind);
  1.3205 +        WIND_AS_STRING(last);
  1.3206 +        WIND_AS_STRING(wind);
  1.3207 +        WIND_AS_STRING(lastSum);
  1.3208 +        WIND_AS_STRING(oppLastSum);
  1.3209 +        WIND_AS_STRING(windSum);
  1.3210 +        WIND_AS_STRING(oppWindSum);
  1.3211 +        #undef WIND_AS_STRING
  1.3212 +        if (!oppoSign) {
  1.3213 +            SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr : lastStr);
  1.3214 +        } else {
  1.3215 +            SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : oppLastSumStr,
  1.3216 +                    opp ? windSumStr : oppWindSumStr);
  1.3217 +        }
  1.3218 +        SkDebugf(" done=%d unord=%d small=%d tiny=%d opp=%d\n",
  1.3219 +                mSpan.fDone, angle.unorderable(), mSpan.fSmall, mSpan.fTiny, opp);
  1.3220 +        ++index;
  1.3221 +        if (index == angles.count()) {
  1.3222 +            index = 0;
  1.3223 +        }
  1.3224 +        if (firstTime) {
  1.3225 +            firstTime = false;
  1.3226 +        }
  1.3227 +    } while (index != first);
  1.3228 +}
  1.3229 +
  1.3230 +void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles,
  1.3231 +                                int first, bool sortable) {
  1.3232 +    if (!sortable) {
  1.3233 +        if (angles.count() == 0) {
  1.3234 +            return;
  1.3235 +        }
  1.3236 +        if (first < 0) {
  1.3237 +            first = 0;
  1.3238 +        }
  1.3239 +    }
  1.3240 +    const SkOpAngle* firstAngle = angles[first];
  1.3241 +    const SkOpSegment* segment = firstAngle->segment();
  1.3242 +    int winding = segment->updateWinding(firstAngle);
  1.3243 +    int oppWinding = segment->updateOppWinding(firstAngle);
  1.3244 +    debugShowSort(fun, angles, first, winding, oppWinding, sortable);
  1.3245 +}
  1.3246 +
  1.3247 +#endif
  1.3248 +
  1.3249 +#if DEBUG_SHOW_WINDING
  1.3250 +int SkOpSegment::debugShowWindingValues(int slotCount, int ofInterest) const {
  1.3251 +    if (!(1 << fID & ofInterest)) {
  1.3252 +        return 0;
  1.3253 +    }
  1.3254 +    int sum = 0;
  1.3255 +    SkTArray<char, true> slots(slotCount * 2);
  1.3256 +    memset(slots.begin(), ' ', slotCount * 2);
  1.3257 +    for (int i = 0; i < fTs.count(); ++i) {
  1.3258 +   //     if (!(1 << fTs[i].fOther->fID & ofInterest)) {
  1.3259 +   //         continue;
  1.3260 +   //     }
  1.3261 +        sum += fTs[i].fWindValue;
  1.3262 +        slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
  1.3263 +        sum += fTs[i].fOppValue;
  1.3264 +        slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
  1.3265 +    }
  1.3266 +    SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
  1.3267 +            slots.begin() + slotCount);
  1.3268 +    return sum;
  1.3269 +}
  1.3270 +#endif
  1.3271 +
  1.3272 +void SkOpSegment::debugValidate() const {
  1.3273 +#if DEBUG_VALIDATE
  1.3274 +    int count = fTs.count();
  1.3275 +    SkASSERT(count >= 2);
  1.3276 +    SkASSERT(fTs[0].fT == 0);
  1.3277 +    SkASSERT(fTs[count - 1].fT == 1);
  1.3278 +    int done = 0;
  1.3279 +    double t = -1;
  1.3280 +    for (int i = 0; i < count; ++i) {
  1.3281 +        const SkOpSpan& span = fTs[i];
  1.3282 +        SkASSERT(t <= span.fT);
  1.3283 +        t = span.fT;
  1.3284 +        int otherIndex = span.fOtherIndex;
  1.3285 +        const SkOpSegment* other = span.fOther;
  1.3286 +        const SkOpSpan& otherSpan = other->fTs[otherIndex];
  1.3287 +        SkASSERT(otherSpan.fPt == span.fPt);
  1.3288 +        SkASSERT(otherSpan.fOtherT == t);
  1.3289 +        SkASSERT(&fTs[i] == &otherSpan.fOther->fTs[otherSpan.fOtherIndex]);
  1.3290 +        done += span.fDone;
  1.3291 +    }
  1.3292 +    SkASSERT(done == fDoneSpans);
  1.3293 +#endif
  1.3294 +}
  1.3295 +
  1.3296 +#ifdef SK_DEBUG
  1.3297 +void SkOpSegment::dumpPts() const {
  1.3298 +    int last = SkPathOpsVerbToPoints(fVerb);
  1.3299 +    SkDebugf("{{");
  1.3300 +    int index = 0;
  1.3301 +    do {
  1.3302 +        SkDPoint::dump(fPts[index]);
  1.3303 +        SkDebugf(", ");
  1.3304 +    } while (++index < last);
  1.3305 +    SkDPoint::dump(fPts[index]);
  1.3306 +    SkDebugf("}}\n");
  1.3307 +}
  1.3308 +
  1.3309 +void SkOpSegment::dumpDPts() const {
  1.3310 +    int count = SkPathOpsVerbToPoints(fVerb);
  1.3311 +    SkDebugf("{{");
  1.3312 +    int index = 0;
  1.3313 +    do {
  1.3314 +        SkDPoint dPt = {fPts[index].fX, fPts[index].fY};
  1.3315 +        dPt.dump();
  1.3316 +        if (index != count) {
  1.3317 +            SkDebugf(", ");
  1.3318 +        }
  1.3319 +    } while (++index <= count);
  1.3320 +    SkDebugf("}}\n");
  1.3321 +}
  1.3322 +
  1.3323 +void SkOpSegment::dumpSpans() const {
  1.3324 +    int count = this->count();
  1.3325 +    for (int index = 0; index < count; ++index) {
  1.3326 +        const SkOpSpan& span = this->span(index);
  1.3327 +        SkDebugf("[%d] ", index);
  1.3328 +        span.dump();
  1.3329 +    }
  1.3330 +}
  1.3331 +#endif

mercurial