SkOpSegment.cpp revision 4431e7757cfcb8cfa99535eed0e9f156dabf95c2
1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#include "SkIntersections.h"
8#include "SkOpSegment.h"
9#include "SkPathWriter.h"
10#include "SkTSort.h"
11
12#define F (false)      // discard the edge
13#define T (true)       // keep the edge
14
15static const bool gUnaryActiveEdge[2][2] = {
16//  from=0  from=1
17//  to=0,1  to=0,1
18    {F, T}, {T, F},
19};
20
21static const bool gActiveEdge[kXOR_PathOp + 1][2][2][2][2] = {
22//                 miFrom=0                              miFrom=1
23//         miTo=0             miTo=1             miTo=0             miTo=1
24//     suFrom=0    1      suFrom=0    1      suFrom=0    1      suFrom=0    1
25//   suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1
26    {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}},  // mi - su
27    {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}},  // mi & su
28    {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}},  // mi | su
29    {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}},  // mi ^ su
30};
31
32#undef F
33#undef T
34
35enum {
36    kOutsideTrackedTCount = 16,  // FIXME: determine what this should be
37    kMissingSpanCount = 4,  // FIXME: determine what this should be
38};
39
40const SkOpAngle* SkOpSegment::activeAngle(int index, int* start, int* end, bool* done,
41        bool* sortable) const {
42    if (const SkOpAngle* result = activeAngleInner(index, start, end, done, sortable)) {
43        return result;
44    }
45    double referenceT = fTs[index].fT;
46    int lesser = index;
47    while (--lesser >= 0
48            && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].fTiny)) {
49        if (const SkOpAngle* result = activeAngleOther(lesser, start, end, done, sortable)) {
50            return result;
51        }
52    }
53    do {
54        if (const SkOpAngle* result = activeAngleOther(index, start, end, done, sortable)) {
55            return result;
56        }
57        if (++index == fTs.count()) {
58            break;
59        }
60        if (fTs[index - 1].fTiny) {
61            referenceT = fTs[index].fT;
62            continue;
63        }
64    } while (precisely_negative(fTs[index].fT - referenceT));
65    return NULL;
66}
67
68const SkOpAngle* SkOpSegment::activeAngleInner(int index, int* start, int* end, bool* done,
69        bool* sortable) const {
70    int next = nextExactSpan(index, 1);
71    if (next > 0) {
72        const SkOpSpan& upSpan = fTs[index];
73        if (upSpan.fUnsortableStart) {
74            *sortable = false;
75            return NULL;
76        }
77        if (upSpan.fWindValue || upSpan.fOppValue) {
78            if (*end < 0) {
79                *start = index;
80                *end = next;
81            }
82            if (!upSpan.fDone && !upSpan.fUnsortableEnd) {
83                if (upSpan.fWindSum != SK_MinS32) {
84                    return spanToAngle(index, next);
85                }
86                *done = false;
87            }
88        } else {
89            SkASSERT(upSpan.fDone);
90        }
91    }
92    int prev = nextExactSpan(index, -1);
93    // edge leading into junction
94    if (prev >= 0) {
95        const SkOpSpan& downSpan = fTs[prev];
96        if (downSpan.fUnsortableEnd) {
97            *sortable = false;
98            return NULL;
99        }
100        if (downSpan.fWindValue || downSpan.fOppValue) {
101            if (*end < 0) {
102                *start = index;
103                *end = prev;
104            }
105            if (!downSpan.fDone) {
106                if (downSpan.fWindSum != SK_MinS32) {
107                    return spanToAngle(index, prev);
108                }
109                *done = false;
110            }
111        } else {
112            SkASSERT(downSpan.fDone);
113        }
114    }
115    return NULL;
116}
117
118const SkOpAngle* SkOpSegment::activeAngleOther(int index, int* start, int* end, bool* done,
119        bool* sortable) const {
120    const SkOpSpan* span = &fTs[index];
121    SkOpSegment* other = span->fOther;
122    int oIndex = span->fOtherIndex;
123    return other->activeAngleInner(oIndex, start, end, done, sortable);
124}
125
126SkPoint SkOpSegment::activeLeftTop(bool onlySortable, int* firstT) const {
127    SkASSERT(!done());
128    SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
129    int count = fTs.count();
130    // see if either end is not done since we want smaller Y of the pair
131    bool lastDone = true;
132    bool lastUnsortable = false;
133    double lastT = -1;
134    for (int index = 0; index < count; ++index) {
135        const SkOpSpan& span = fTs[index];
136        if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
137            goto next;
138        }
139        if (span.fDone && lastDone) {
140            goto next;
141        }
142        if (approximately_negative(span.fT - lastT)) {
143            goto next;
144        }
145        {
146            const SkPoint& xy = xyAtT(&span);
147            if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
148                topPt = xy;
149                if (firstT) {
150                    *firstT = index;
151                }
152            }
153            if (fVerb != SkPath::kLine_Verb && !lastDone) {
154                SkPoint curveTop = (*CurveTop[SkPathOpsVerbToPoints(fVerb)])(fPts, lastT, span.fT);
155                if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
156                        && topPt.fX > curveTop.fX)) {
157                    topPt = curveTop;
158                    if (firstT) {
159                        *firstT = index;
160                    }
161                }
162            }
163            lastT = span.fT;
164        }
165next:
166        lastDone = span.fDone;
167        lastUnsortable = span.fUnsortableEnd;
168    }
169    return topPt;
170}
171
172bool SkOpSegment::activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op) {
173    int sumMiWinding = updateWinding(endIndex, index);
174    int sumSuWinding = updateOppWinding(endIndex, index);
175    if (fOperand) {
176        SkTSwap<int>(sumMiWinding, sumSuWinding);
177    }
178    return activeOp(xorMiMask, xorSuMask, index, endIndex, op, &sumMiWinding, &sumSuWinding);
179}
180
181bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op,
182        int* sumMiWinding, int* sumSuWinding) {
183    int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
184    setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
185            &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
186    bool miFrom;
187    bool miTo;
188    bool suFrom;
189    bool suTo;
190    if (operand()) {
191        miFrom = (oppMaxWinding & xorMiMask) != 0;
192        miTo = (oppSumWinding & xorMiMask) != 0;
193        suFrom = (maxWinding & xorSuMask) != 0;
194        suTo = (sumWinding & xorSuMask) != 0;
195    } else {
196        miFrom = (maxWinding & xorMiMask) != 0;
197        miTo = (sumWinding & xorMiMask) != 0;
198        suFrom = (oppMaxWinding & xorSuMask) != 0;
199        suTo = (oppSumWinding & xorSuMask) != 0;
200    }
201    bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
202#if DEBUG_ACTIVE_OP
203    SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__,
204            SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
205#endif
206    return result;
207}
208
209bool SkOpSegment::activeWinding(int index, int endIndex) {
210    int sumWinding = updateWinding(endIndex, index);
211    return activeWinding(index, endIndex, &sumWinding);
212}
213
214bool SkOpSegment::activeWinding(int index, int endIndex, int* sumWinding) {
215    int maxWinding;
216    setUpWinding(index, endIndex, &maxWinding, sumWinding);
217    bool from = maxWinding != 0;
218    bool to = *sumWinding  != 0;
219    bool result = gUnaryActiveEdge[from][to];
220    return result;
221}
222
223void SkOpSegment::addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt,
224        SkOpSegment* other) {
225    int tIndex = -1;
226    int tCount = fTs.count();
227    int oIndex = -1;
228    int oCount = other->fTs.count();
229    do {
230        ++tIndex;
231    } while (startPt != fTs[tIndex].fPt && tIndex < tCount);
232    int tIndexStart = tIndex;
233    do {
234        ++oIndex;
235    } while (endPt != other->fTs[oIndex].fPt && oIndex < oCount);
236    int oIndexStart = oIndex;
237    const SkPoint* nextPt;
238    do {
239        nextPt = &fTs[++tIndex].fPt;
240        SkASSERT(fTs[tIndex].fT < 1 || startPt != *nextPt);
241    } while (startPt == *nextPt);
242    double nextT = fTs[tIndex].fT;
243    const SkPoint* oNextPt;
244    do {
245        oNextPt = &other->fTs[++oIndex].fPt;
246        SkASSERT(other->fTs[oIndex].fT < 1 || endPt != *oNextPt);
247    } while (endPt == *oNextPt);
248    double oNextT = other->fTs[oIndex].fT;
249    // at this point, spans before and after are at:
250    //  fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
251    // if tIndexStart == 0, no prior span
252    // if nextT == 1, no following span
253
254    // advance the span with zero winding
255    // if the following span exists (not past the end, non-zero winding)
256    // connect the two edges
257    if (!fTs[tIndexStart].fWindValue) {
258        if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
259#if DEBUG_CONCIDENT
260            SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
261                    __FUNCTION__, fID, other->fID, tIndexStart - 1,
262                    fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
263                    xyAtT(tIndexStart).fY);
264#endif
265            addTPair(fTs[tIndexStart].fT, other, other->fTs[oIndex].fT, false,
266                    fTs[tIndexStart].fPt);
267        }
268        if (nextT < 1 && fTs[tIndex].fWindValue) {
269#if DEBUG_CONCIDENT
270            SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
271                    __FUNCTION__, fID, other->fID, tIndex,
272                    fTs[tIndex].fT, xyAtT(tIndex).fX,
273                    xyAtT(tIndex).fY);
274#endif
275            addTPair(fTs[tIndex].fT, other, other->fTs[oIndexStart].fT, false, fTs[tIndex].fPt);
276        }
277    } else {
278        SkASSERT(!other->fTs[oIndexStart].fWindValue);
279        if (oIndexStart > 0 && other->fTs[oIndexStart - 1].fWindValue) {
280#if DEBUG_CONCIDENT
281            SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
282                    __FUNCTION__, fID, other->fID, oIndexStart - 1,
283                    other->fTs[oIndexStart].fT, other->xyAtT(oIndexStart).fX,
284                    other->xyAtT(oIndexStart).fY);
285            other->debugAddTPair(other->fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
286#endif
287        }
288        if (oNextT < 1 && other->fTs[oIndex].fWindValue) {
289#if DEBUG_CONCIDENT
290            SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
291                    __FUNCTION__, fID, other->fID, oIndex,
292                    other->fTs[oIndex].fT, other->xyAtT(oIndex).fX,
293                    other->xyAtT(oIndex).fY);
294            other->debugAddTPair(other->fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
295#endif
296        }
297    }
298}
299
300void SkOpSegment::addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt,
301        SkOpSegment* other) {
302    // walk this to startPt
303    // walk other to startPt
304    // if either is > 0, add a pointer to the other, copying adjacent winding
305    int tIndex = -1;
306    int oIndex = -1;
307    do {
308        ++tIndex;
309    } while (startPt != fTs[tIndex].fPt);
310    int ttIndex = tIndex;
311    bool checkOtherTMatch = false;
312    do {
313        const SkOpSpan& span = fTs[ttIndex];
314        if (startPt != span.fPt) {
315            break;
316        }
317        if (span.fOther == other && span.fPt == startPt) {
318            checkOtherTMatch = true;
319            break;
320        }
321    } while (++ttIndex < count());
322    do {
323        ++oIndex;
324    } while (startPt != other->fTs[oIndex].fPt);
325    bool skipAdd = false;
326    if (checkOtherTMatch) {
327        int ooIndex = oIndex;
328        do {
329            const SkOpSpan& oSpan = other->fTs[ooIndex];
330            if (startPt != oSpan.fPt) {
331                break;
332            }
333            if (oSpan.fT == fTs[ttIndex].fOtherT) {
334                skipAdd = true;
335                break;
336            }
337        } while (++ooIndex < other->count());
338    }
339    if ((tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) && !skipAdd) {
340        addTPair(fTs[tIndex].fT, other, other->fTs[oIndex].fT, false, startPt);
341    }
342    SkPoint nextPt = startPt;
343    do {
344        const SkPoint* workPt;
345        do {
346            workPt = &fTs[++tIndex].fPt;
347        } while (nextPt == *workPt);
348        do {
349            workPt = &other->fTs[++oIndex].fPt;
350        } while (nextPt == *workPt);
351        nextPt = *workPt;
352        double tStart = fTs[tIndex].fT;
353        double oStart = other->fTs[oIndex].fT;
354        if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) {
355            break;
356        }
357        addTPair(tStart, other, oStart, false, nextPt);
358    } while (endPt != nextPt);
359}
360
361void SkOpSegment::addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
362    init(pts, SkPath::kCubic_Verb, operand, evenOdd);
363    fBounds.setCubicBounds(pts);
364}
365
366void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active) const {
367    SkPoint edge[4];
368    const SkPoint* ePtr;
369    int lastT = fTs.count() - 1;
370    if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
371        ePtr = fPts;
372    } else {
373    // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
374        subDivide(start, end, edge);
375        ePtr = edge;
376    }
377    if (active) {
378        bool reverse = ePtr == fPts && start != 0;
379        if (reverse) {
380            path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]);
381            switch (fVerb) {
382                case SkPath::kLine_Verb:
383                    path->deferredLine(ePtr[0]);
384                    break;
385                case SkPath::kQuad_Verb:
386                    path->quadTo(ePtr[1], ePtr[0]);
387                    break;
388                case SkPath::kCubic_Verb:
389                    path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
390                    break;
391                default:
392                    SkASSERT(0);
393            }
394   //         return ePtr[0];
395       } else {
396            path->deferredMoveLine(ePtr[0]);
397            switch (fVerb) {
398                case SkPath::kLine_Verb:
399                    path->deferredLine(ePtr[1]);
400                    break;
401                case SkPath::kQuad_Verb:
402                    path->quadTo(ePtr[1], ePtr[2]);
403                    break;
404                case SkPath::kCubic_Verb:
405                    path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
406                    break;
407                default:
408                    SkASSERT(0);
409            }
410        }
411    }
412  //  return ePtr[SkPathOpsVerbToPoints(fVerb)];
413}
414
415void SkOpSegment::addEndSpan(int endIndex) {
416    int spanCount = fTs.count();
417    int angleIndex = fAngles.count();
418    int startIndex = endIndex - 1;
419    while (fTs[startIndex].fT == 1 || fTs[startIndex].fTiny) {
420        ++startIndex;
421        SkASSERT(startIndex < spanCount - 1);
422        ++endIndex;
423    }
424    fAngles.push_back().set(this, spanCount - 1, startIndex);
425#if DEBUG_ANGLE
426    fAngles.back().setID(angleIndex);
427    debugCheckPointsEqualish(endIndex, spanCount);
428#endif
429    setFromAngleIndex(endIndex, angleIndex);
430}
431
432void SkOpSegment::setFromAngleIndex(int endIndex, int angleIndex) {
433    int spanCount = fTs.count();
434    do {
435        fTs[endIndex].fFromAngleIndex = angleIndex;
436    } while (++endIndex < spanCount);
437}
438
439void SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
440    init(pts, SkPath::kLine_Verb, operand, evenOdd);
441    fBounds.set(pts, 2);
442}
443
444// add 2 to edge or out of range values to get T extremes
445void SkOpSegment::addOtherT(int index, double otherT, int otherIndex) {
446    SkOpSpan& span = fTs[index];
447    if (precisely_zero(otherT)) {
448        otherT = 0;
449    } else if (precisely_equal(otherT, 1)) {
450        otherT = 1;
451    }
452    span.fOtherT = otherT;
453    span.fOtherIndex = otherIndex;
454}
455
456void SkOpSegment::addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
457    init(pts, SkPath::kQuad_Verb, operand, evenOdd);
458    fBounds.setQuadBounds(pts);
459}
460
461int SkOpSegment::addSingletonAngleDown(int endIndex, SkOpSegment** otherPtr) {
462    int startIndex = findEndSpan(endIndex);
463    SkASSERT(startIndex > 0);
464    int spanIndex = endIndex - 1;
465    fSingletonAngles.push_back().set(this, spanIndex, startIndex - 1);
466    setFromAngleIndex(startIndex, fAngles.count() + fSingletonAngles.count() - 1);
467    SkOpSegment* other;
468    do {
469        other = fTs[spanIndex].fOther;
470        if (other->fTs[0].fWindValue) {
471            break;
472        }
473        --spanIndex;
474        SkASSERT(fTs[spanIndex].fT == 1);
475    } while (true);
476    int oEndIndex = other->findStartSpan(0);
477    SkASSERT(oEndIndex > 0);
478    int otherIndex = other->fSingletonAngles.count();
479    other->fSingletonAngles.push_back().set(other, 0, oEndIndex);
480    other->setToAngleIndex(oEndIndex, other->fAngles.count() + otherIndex);
481    *otherPtr = other;
482    return otherIndex;
483}
484
485int SkOpSegment::addSingletonAngleUp(int start, SkOpSegment** otherPtr) {
486    int endIndex = findStartSpan(start);
487    SkASSERT(endIndex > 0);
488    int thisIndex = fSingletonAngles.count();
489    fSingletonAngles.push_back().set(this, start, endIndex);
490    setToAngleIndex(endIndex, fAngles.count() + thisIndex);
491    int spanIndex = start;
492    SkOpSegment* other;
493    int oCount, oStartIndex;
494    do {
495        other = fTs[spanIndex].fOther;
496        oCount = other->count();
497        oStartIndex = other->findEndSpan(oCount);
498        SkASSERT(oStartIndex > 0);
499        if (other->fTs[oStartIndex - 1].fWindValue) {
500            break;
501        }
502        ++spanIndex;
503        SkASSERT(fTs[spanIndex].fT == 0);
504    } while (true);
505    int otherIndex = other->fSingletonAngles.count();
506    other->fSingletonAngles.push_back().set(other, oCount - 1, oStartIndex - 1);
507    other->setFromAngleIndex(oStartIndex, other->fAngles.count() + otherIndex);
508    *otherPtr = other;
509    return otherIndex;
510}
511
512SkOpAngle* SkOpSegment::addSingletonAngles(int start, int step) {
513    int thisIndex = fSingletonAngles.count();
514    SkOpSegment* other;
515    int otherIndex;
516    if (step > 0) {
517        otherIndex = addSingletonAngleUp(start, &other);
518    } else {
519        otherIndex = addSingletonAngleDown(start + 1, &other);
520    }
521    fSingletonAngles[thisIndex].insert(&other->fSingletonAngles[otherIndex]);
522#if DEBUG_ANGLE
523    fSingletonAngles[thisIndex].setID(fAngles.count() + thisIndex);
524    other->fSingletonAngles[otherIndex].setID(other->fAngles.count() + otherIndex);
525#endif
526    return &fSingletonAngles[thisIndex];
527}
528
529void SkOpSegment::addStartSpan(int endIndex) {
530    int angleIndex = fAngles.count();
531    int index = 0;
532    fAngles.push_back().set(this, index, endIndex);
533#if DEBUG_ANGLE
534    fAngles.back().setID(angleIndex);
535    debugCheckPointsEqualish(index, endIndex);
536#endif
537    setToAngleIndex(endIndex, angleIndex);
538}
539
540void SkOpSegment::setToAngleIndex(int endIndex, int angleIndex) {
541    int index = 0;
542    do {
543        fTs[index].fToAngleIndex = angleIndex;
544    } while (++index < endIndex);
545}
546
547    // Defer all coincident edge processing until
548    // after normal intersections have been computed
549
550// no need to be tricky; insert in normal T order
551// resolve overlapping ts when considering coincidence later
552
553    // add non-coincident intersection. Resulting edges are sorted in T.
554int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) {
555    SkASSERT(this != other || fVerb == SkPath::kCubic_Verb);
556 #if 0  // this needs an even rougher association to be useful
557    SkASSERT(SkDPoint::RoughlyEqual(ptAtT(newT), pt));
558 #endif
559    if (precisely_zero(newT)) {
560        newT = 0;
561    } else if (precisely_equal(newT, 1)) {
562        newT = 1;
563    }
564    // FIXME: in the pathological case where there is a ton of intercepts,
565    //  binary search?
566    int insertedAt = -1;
567    int tCount = fTs.count();
568    const SkPoint& firstPt = fPts[0];
569    const SkPoint& lastPt = fPts[SkPathOpsVerbToPoints(fVerb)];
570    for (int index = 0; index < tCount; ++index) {
571        // OPTIMIZATION: if there are three or more identical Ts, then
572        // the fourth and following could be further insertion-sorted so
573        // that all the edges are clockwise or counterclockwise.
574        // This could later limit segment tests to the two adjacent
575        // neighbors, although it doesn't help with determining which
576        // circular direction to go in.
577        const SkOpSpan& span = fTs[index];
578        if (newT < span.fT) {
579            insertedAt = index;
580            break;
581        }
582        if (newT == span.fT) {
583            if (pt == span.fPt) {
584                insertedAt = index;
585                break;
586            }
587            if ((pt == firstPt && newT == 0) || (span.fPt == lastPt && newT == 1)) {
588                insertedAt = index;
589                break;
590            }
591        }
592    }
593    SkOpSpan* span;
594    if (insertedAt >= 0) {
595        span = fTs.insert(insertedAt);
596    } else {
597        insertedAt = tCount;
598        span = fTs.append();
599    }
600    span->fT = newT;
601    span->fOther = other;
602    span->fPt = pt;
603#if 0
604    // cubics, for instance, may not be exact enough to satisfy this check (e.g., cubicOp69d)
605    SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX)
606            && approximately_equal(xyAtT(newT).fY, pt.fY));
607#endif
608    span->fFromAngleIndex = -1;
609    span->fToAngleIndex = -1;
610    span->fWindSum = SK_MinS32;
611    span->fOppSum = SK_MinS32;
612    span->fWindValue = 1;
613    span->fOppValue = 0;
614    span->fChased = false;
615    if ((span->fDone = newT == 1)) {
616        ++fDoneSpans;
617    }
618    span->fLoop = false;
619    span->fSmall = false;
620    span->fTiny = false;
621    span->fUnsortableStart = false;
622    span->fUnsortableEnd = false;
623    int less = -1;
624// find range of spans with nearly the same point as this one
625    while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt, pt)) {
626        if (fVerb == SkPath::kCubic_Verb) {
627            double tInterval = newT - span[less].fT;
628            double tMid = newT - tInterval / 2;
629            SkDPoint midPt = dcubic_xy_at_t(fPts, tMid);
630            if (!midPt.approximatelyEqual(xyAtT(span))) {
631                break;
632            }
633        }
634        --less;
635    }
636    int more = 1;
637    while (fTs.end() - &span[more - 1] > 1 && AlmostEqualUlps(span[more].fPt, pt)) {
638        if (fVerb == SkPath::kCubic_Verb) {
639            double tEndInterval = span[more].fT - newT;
640            double tMid = newT - tEndInterval / 2;
641            SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid);
642            if (!midEndPt.approximatelyEqual(xyAtT(span))) {
643                break;
644            }
645        }
646        ++more;
647    }
648    ++less;
649    --more;
650    while (more - 1 > less && span[more].fPt == span[more - 1].fPt
651            && span[more].fT == span[more - 1].fT) {
652        --more;
653    }
654    if (less == more) {
655        return insertedAt;
656    }
657    if (precisely_negative(span[more].fT - span[less].fT)) {
658        return insertedAt;
659    }
660// if the total range of t values is big enough, mark all tiny
661    bool tiny = span[less].fPt == span[more].fPt;
662    int index = less;
663    do {
664        fSmall = span[index].fSmall = true;
665        fTiny |= span[index].fTiny = tiny;
666        if (!span[index].fDone) {
667            span[index].fDone = true;
668            ++fDoneSpans;
669        }
670    } while (++index < more);
671    return insertedAt;
672}
673
674// set spans from start to end to decrement by one
675// note this walks other backwards
676// FIXME: there's probably an edge case that can be constructed where
677// two span in one segment are separated by float epsilon on one span but
678// not the other, if one segment is very small. For this
679// case the counts asserted below may or may not be enough to separate the
680// spans. Even if the counts work out, what if the spans aren't correctly
681// sorted? It feels better in such a case to match the span's other span
682// pointer since both coincident segments must contain the same spans.
683// FIXME? It seems that decrementing by one will fail for complex paths that
684// have three or more coincident edges. Shouldn't this subtract the difference
685// between the winding values?
686/*                                      |-->                           |-->
687this     0>>>>1>>>>2>>>>3>>>4      0>>>>1>>>>2>>>>3>>>4      0>>>>1>>>>2>>>>3>>>4
688other         2<<<<1<<<<0               2<<<<1<<<<0               2<<<<1<<<<0
689              ^         ^                 <--|                           <--|
690           startPt    endPt        test/oTest first pos      test/oTest final pos
691*/
692void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other) {
693    bool binary = fOperand != other->fOperand;
694    int index = 0;
695    while (startPt != fTs[index].fPt) {
696        SkASSERT(index < fTs.count());
697        ++index;
698    }
699    while (index > 0 && precisely_equal(fTs[index].fT, fTs[index - 1].fT)) {
700        --index;
701    }
702    int oIndex = other->fTs.count();
703    while (startPt != other->fTs[--oIndex].fPt) {  // look for startPt match
704        SkASSERT(oIndex > 0);
705    }
706    double oStartT = other->fTs[oIndex].fT;
707    // look for first point beyond match
708    while (startPt == other->fTs[--oIndex].fPt || precisely_equal(oStartT, other->fTs[oIndex].fT)) {
709        SkASSERT(oIndex > 0);
710    }
711    SkOpSpan* test = &fTs[index];
712    SkOpSpan* oTest = &other->fTs[oIndex];
713    SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
714    SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
715    do {
716        SkASSERT(test->fT < 1);
717        SkASSERT(oTest->fT < 1);
718        bool decrement = test->fWindValue && oTest->fWindValue;
719        bool track = test->fWindValue || oTest->fWindValue;
720        bool bigger = test->fWindValue >= oTest->fWindValue;
721        const SkPoint& testPt = test->fPt;
722        double testT = test->fT;
723        const SkPoint& oTestPt = oTest->fPt;
724        double oTestT = oTest->fT;
725        do {
726            if (decrement) {
727                if (binary && bigger) {
728                    test->fOppValue--;
729                } else {
730                    decrementSpan(test);
731                }
732            } else if (track) {
733                TrackOutsidePair(&outsidePts, testPt, oTestPt);
734            }
735            SkASSERT(index < fTs.count() - 1);
736            test = &fTs[++index];
737        } while (testPt == test->fPt || precisely_equal(testT, test->fT));
738        SkDEBUGCODE(int originalWindValue = oTest->fWindValue);
739        do {
740            SkASSERT(oTest->fT < 1);
741            SkASSERT(originalWindValue == oTest->fWindValue);
742            if (decrement) {
743                if (binary && !bigger) {
744                    oTest->fOppValue--;
745                } else {
746                    other->decrementSpan(oTest);
747                }
748            } else if (track) {
749                TrackOutsidePair(&oOutsidePts, oTestPt, testPt);
750            }
751            if (!oIndex) {
752                break;
753            }
754            oTest = &other->fTs[--oIndex];
755        } while (oTestPt == oTest->fPt || precisely_equal(oTestT, oTest->fT));
756    } while (endPt != test->fPt && test->fT < 1);
757    // FIXME: determine if canceled edges need outside ts added
758    int outCount = outsidePts.count();
759    if (!done() && outCount) {
760        addCancelOutsides(outsidePts[0], outsidePts[1], other);
761        if (outCount > 2) {
762            addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1], other);
763        }
764    }
765    if (!other->done() && oOutsidePts.count()) {
766        other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this);
767    }
768}
769
770int SkOpSegment::addSelfT(const SkPoint& pt, double newT) {
771    // if the tail nearly intersects itself but not quite, the caller records this separately
772    int result = addT(this, pt, newT);
773    SkOpSpan* span = &fTs[result];
774    fLoop = span->fLoop = true;
775    return result;
776}
777
778void SkOpSegment::addSimpleAngle(int index) {
779    if (index == 0) {
780        SkASSERT(!fTs[index].fTiny && fTs[index + 1].fT > 0);
781        addStartSpan(1);
782    } else {
783        SkASSERT(!fTs[index - 1].fTiny && fTs[index - 1].fT < 1);
784        addEndSpan(index);
785    }
786    SkOpSpan& span = fTs[index];
787    SkOpSegment* other = span.fOther;
788    SkOpSpan& oSpan = other->fTs[span.fOtherIndex];
789    SkOpAngle* angle, * oAngle;
790    if (index == 0) {
791        SkASSERT(span.fOtherIndex - 1 >= 0);
792        SkASSERT(span.fOtherT == 1);
793        SkDEBUGCODE(SkOpSpan& oPrior = other->fTs[span.fOtherIndex - 1]);
794        SkASSERT(!oPrior.fTiny && oPrior.fT < 1);
795        other->addEndSpan(span.fOtherIndex);
796        angle = &this->angle(span.fToAngleIndex);
797        oAngle = &other->angle(oSpan.fFromAngleIndex);
798    } else {
799        SkASSERT(span.fOtherIndex + 1 < other->count());
800        SkASSERT(span.fOtherT == 0);
801        SkASSERT(!oSpan.fTiny && (other->fTs[span.fOtherIndex + 1].fT > 0
802                || (other->fTs[span.fOtherIndex + 1].fFromAngleIndex < 0
803                && other->fTs[span.fOtherIndex + 1].fToAngleIndex < 0)));
804        int oIndex = 1;
805        do {
806            const SkOpSpan& osSpan = other->span(oIndex);
807            if (osSpan.fFromAngleIndex >= 0 || osSpan.fT > 0) {
808                break;
809            }
810            ++oIndex;
811            SkASSERT(oIndex < other->count());
812        } while (true);
813        other->addStartSpan(oIndex);
814        angle = &this->angle(span.fFromAngleIndex);
815        oAngle = &other->angle(oSpan.fToAngleIndex);
816    }
817    angle->insert(oAngle);
818}
819
820bool SkOpSegment::alignSpan(int index, double thisT, const SkPoint& thisPt) {
821    bool aligned = false;
822    SkOpSpan* span = &fTs[index];
823    SkOpSegment* other = span->fOther;
824    int oIndex = span->fOtherIndex;
825    SkOpSpan* oSpan = &other->fTs[oIndex];
826    if (span->fT != thisT) {
827        span->fT = thisT;
828        oSpan->fOtherT = thisT;
829        aligned = true;
830    }
831    if (span->fPt != thisPt) {
832        span->fPt = thisPt;
833        oSpan->fPt = thisPt;
834        aligned = true;
835    }
836    double oT = oSpan->fT;
837    if (oT == 0 || oT == 1) {
838        return aligned;
839    }
840    int oStart = other->nextSpan(oIndex, -1) + 1;
841    int oEnd = other->nextSpan(oIndex, 1);
842    oSpan = &other->fTs[oStart];
843    oT = oSpan->fT;
844    bool oAligned = false;
845    if (oSpan->fPt != thisPt) {
846        oAligned |= other->alignSpan(oStart, oT, thisPt);
847    }
848    int otherIndex = oStart;
849    while (++otherIndex < oEnd) {
850        SkOpSpan* oNextSpan = &other->fTs[otherIndex];
851        if (oNextSpan->fT != oT || oNextSpan->fPt != thisPt) {
852            oAligned |= other->alignSpan(otherIndex, oT, thisPt);
853        }
854    }
855    if (oAligned) {
856        other->alignSpanState(oStart, oEnd);
857    }
858    return aligned;
859}
860
861void SkOpSegment::alignSpanState(int start, int end) {
862    SkOpSpan* lastSpan = &fTs[--end];
863    bool allSmall = lastSpan->fSmall;
864    bool allTiny = lastSpan->fTiny;
865    bool allDone = lastSpan->fDone;
866    SkDEBUGCODE(int winding = lastSpan->fWindValue);
867    SkDEBUGCODE(int oppWinding = lastSpan->fOppValue);
868    int index = start;
869    while (index < end) {
870        SkOpSpan* span = &fTs[index];
871        span->fSmall = allSmall;
872        span->fTiny = allTiny;
873        if (span->fDone != allDone) {
874            span->fDone = allDone;
875            fDoneSpans += allDone ? 1 : -1;
876        }
877        SkASSERT(span->fWindValue == winding);
878        SkASSERT(span->fOppValue == oppWinding);
879        ++index;
880    }
881}
882
883void SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* indexPtr,
884        SkTArray<SkPoint, true>* outsideTs) {
885    int index = *indexPtr;
886    int oWindValue = oTest.fWindValue;
887    int oOppValue = oTest.fOppValue;
888    if (binary) {
889        SkTSwap<int>(oWindValue, oOppValue);
890    }
891    SkOpSpan* const test = &fTs[index];
892    SkOpSpan* end = test;
893    const SkPoint& oStartPt = oTest.fPt;
894    do {
895        if (bumpSpan(end, oWindValue, oOppValue)) {
896            TrackOutside(outsideTs, oStartPt);
897        }
898        end = &fTs[++index];
899    } while ((end->fPt == test->fPt || precisely_equal(end->fT, test->fT)) && end->fT < 1);
900    *indexPtr = index;
901}
902
903// because of the order in which coincidences are resolved, this and other
904// may not have the same intermediate points. Compute the corresponding
905// intermediate T values (using this as the master, other as the follower)
906// and walk other conditionally -- hoping that it catches up in the end
907void SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr,
908        SkTArray<SkPoint, true>* oOutsidePts) {
909    int oIndex = *oIndexPtr;
910    SkOpSpan* const oTest = &fTs[oIndex];
911    SkOpSpan* oEnd = oTest;
912    const SkPoint& oStartPt = oTest->fPt;
913    double oStartT = oTest->fT;
914#if 0  // FIXME : figure out what disabling this breaks
915    const SkPoint& startPt = test.fPt;
916    // this is always true since oEnd == oTest && oStartPt == oTest->fPt -- find proper condition
917    if (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) {
918        TrackOutside(oOutsidePts, startPt);
919    }
920#endif
921    while (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) {
922        zeroSpan(oEnd);
923        oEnd = &fTs[++oIndex];
924    }
925    *oIndexPtr = oIndex;
926}
927
928// FIXME: need to test this case:
929// contourA has two segments that are coincident
930// contourB has two segments that are coincident in the same place
931// each ends up with +2/0 pairs for winding count
932// since logic below doesn't transfer count (only increments/decrements) can this be
933// resolved to +4/0 ?
934
935// set spans from start to end to increment the greater by one and decrement
936// the lesser
937void SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, double endT,
938        SkOpSegment* other) {
939    bool binary = fOperand != other->fOperand;
940    int index = 0;
941    while (startPt != fTs[index].fPt) {
942        SkASSERT(index < fTs.count());
943        ++index;
944    }
945    double startT = fTs[index].fT;
946    while (index > 0 && precisely_equal(fTs[index - 1].fT, startT)) {
947        --index;
948    }
949    int oIndex = 0;
950    while (startPt != other->fTs[oIndex].fPt) {
951        SkASSERT(oIndex < other->fTs.count());
952        ++oIndex;
953    }
954    double oStartT = other->fTs[oIndex].fT;
955    while (oIndex > 0 && precisely_equal(other->fTs[oIndex - 1].fT, oStartT)) {
956        --oIndex;
957    }
958    SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
959    SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
960    SkOpSpan* test = &fTs[index];
961    const SkPoint* testPt = &test->fPt;
962    double testT = test->fT;
963    SkOpSpan* oTest = &other->fTs[oIndex];
964    const SkPoint* oTestPt = &oTest->fPt;
965    SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
966    do {
967        SkASSERT(test->fT < 1);
968        SkASSERT(oTest->fT < 1);
969
970        // consolidate the winding count even if done
971        if ((test->fWindValue == 0 && test->fOppValue == 0)
972                || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) {
973            SkDEBUGCODE(int firstWind = test->fWindValue);
974            SkDEBUGCODE(int firstOpp = test->fOppValue);
975            do {
976                SkASSERT(firstWind == fTs[index].fWindValue);
977                SkASSERT(firstOpp == fTs[index].fOppValue);
978                ++index;
979                SkASSERT(index < fTs.count());
980            } while (*testPt == fTs[index].fPt);
981            SkDEBUGCODE(firstWind = oTest->fWindValue);
982            SkDEBUGCODE(firstOpp = oTest->fOppValue);
983            do {
984                SkASSERT(firstWind == other->fTs[oIndex].fWindValue);
985                SkASSERT(firstOpp == other->fTs[oIndex].fOppValue);
986                ++oIndex;
987                SkASSERT(oIndex < other->fTs.count());
988            } while (*oTestPt == other->fTs[oIndex].fPt);
989        } else {
990            if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
991                bumpCoincidentThis(*oTest, binary, &index, &outsidePts);
992                other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts);
993            } else {
994                other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts);
995                bumpCoincidentOther(*oTest, &index, &outsidePts);
996            }
997        }
998        test = &fTs[index];
999        testPt = &test->fPt;
1000        testT = test->fT;
1001        oTest = &other->fTs[oIndex];
1002        oTestPt = &oTest->fPt;
1003        if (endPt == *testPt || precisely_equal(endT, testT)) {
1004            break;
1005        }
1006//        SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
1007    } while (endPt != *oTestPt);
1008    // in rare cases, one may have ended before the other
1009    if (endPt != *testPt && !precisely_equal(endT, testT)) {
1010        int lastWind = test[-1].fWindValue;
1011        int lastOpp = test[-1].fOppValue;
1012        bool zero = lastWind == 0 && lastOpp == 0;
1013        do {
1014            if (test->fWindValue || test->fOppValue) {
1015                test->fWindValue = lastWind;
1016                test->fOppValue = lastOpp;
1017                if (zero) {
1018                    test->fDone = true;
1019                    ++fDoneSpans;
1020                }
1021            }
1022            test = &fTs[++index];
1023            testPt = &test->fPt;
1024        } while (endPt != *testPt);
1025    }
1026    if (endPt != *oTestPt) {
1027        // look ahead to see if zeroing more spans will allows us to catch up
1028        int oPeekIndex = oIndex;
1029        bool success = true;
1030        SkOpSpan* oPeek;
1031        do {
1032            oPeek = &other->fTs[oPeekIndex];
1033            if (oPeek->fT == 1) {
1034                success = false;
1035                break;
1036            }
1037            ++oPeekIndex;
1038        } while (endPt != oPeek->fPt);
1039        if (success) {
1040            // make sure the matching point completes the coincidence span
1041            success = false;
1042            do {
1043                if (oPeek->fOther == this) {
1044                    success = true;
1045                    break;
1046                }
1047                oPeek = &other->fTs[++oPeekIndex];
1048            } while (endPt == oPeek->fPt);
1049        }
1050        if (success) {
1051            do {
1052                if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
1053                    other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts);
1054                } else {
1055                    other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts);
1056                }
1057                oTest = &other->fTs[oIndex];
1058                oTestPt = &oTest->fPt;
1059            } while (endPt != *oTestPt);
1060        }
1061    }
1062    int outCount = outsidePts.count();
1063    if (!done() && outCount) {
1064        addCoinOutsides(outsidePts[0], endPt, other);
1065    }
1066    if (!other->done() && oOutsidePts.count()) {
1067        other->addCoinOutsides(oOutsidePts[0], endPt, this);
1068    }
1069}
1070
1071// FIXME: this doesn't prevent the same span from being added twice
1072// fix in caller, SkASSERT here?
1073const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
1074                           const SkPoint& pt) {
1075    int tCount = fTs.count();
1076    for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1077        const SkOpSpan& span = fTs[tIndex];
1078        if (!approximately_negative(span.fT - t)) {
1079            break;
1080        }
1081        if (approximately_negative(span.fT - t) && span.fOther == other
1082                && approximately_equal(span.fOtherT, otherT)) {
1083#if DEBUG_ADD_T_PAIR
1084            SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1085                    __FUNCTION__, fID, t, other->fID, otherT);
1086#endif
1087            return NULL;
1088        }
1089    }
1090#if DEBUG_ADD_T_PAIR
1091    SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1092            __FUNCTION__, fID, t, other->fID, otherT);
1093#endif
1094    int insertedAt = addT(other, pt, t);
1095    int otherInsertedAt = other->addT(this, pt, otherT);
1096    addOtherT(insertedAt, otherT, otherInsertedAt);
1097    other->addOtherT(otherInsertedAt, t, insertedAt);
1098    matchWindingValue(insertedAt, t, borrowWind);
1099    other->matchWindingValue(otherInsertedAt, otherT, borrowWind);
1100    return &span(insertedAt);
1101}
1102
1103const SkOpAngle& SkOpSegment::angle(int index) const {
1104    SkASSERT(index >= 0);
1105    int count = fAngles.count();
1106    if (index < count) {
1107        return fAngles[index];
1108    }
1109    index -= count;
1110    count = fSingletonAngles.count();
1111    SkASSERT(index < count);
1112    return fSingletonAngles[index];
1113}
1114
1115bool SkOpSegment::betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const {
1116    const SkPoint midPt = ptAtT(midT);
1117    SkPathOpsBounds bounds;
1118    bounds.set(pt1.fX, pt1.fY, pt2.fX, pt2.fY);
1119    bounds.sort();
1120    return bounds.almostContains(midPt);
1121}
1122
1123bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const {
1124    if (lesser > greater) {
1125        SkTSwap<int>(lesser, greater);
1126    }
1127    return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
1128}
1129
1130// in extreme cases (like the buffer overflow test) return false to abort
1131// for now, if one t value represents two different points, then the values are too extreme
1132// to generate meaningful results
1133bool SkOpSegment::calcAngles() {
1134    int spanCount = fTs.count();
1135    if (spanCount <= 2) {
1136        return spanCount == 2;
1137    }
1138    int index = 1;
1139    const SkOpSpan* firstSpan = &fTs[index];
1140    int activePrior = checkSetAngle(0);
1141    const SkOpSpan* span = &fTs[0];
1142    if (firstSpan->fT == 0 || span->fTiny || span->fOtherT != 1 || span->fOther->multipleEnds()) {
1143        index = findStartSpan(0);  // curve start intersects
1144        if (index < 0) {
1145            return false;
1146        }
1147        if (activePrior >= 0) {
1148            addStartSpan(index);
1149        }
1150    }
1151    bool addEnd;
1152    int endIndex = spanCount - 1;
1153    span = &fTs[endIndex - 1];
1154    if ((addEnd = span->fT == 1 || span->fTiny)) {  // if curve end intersects
1155        endIndex = findEndSpan(endIndex);
1156        if (endIndex < 0) {
1157            return false;
1158        }
1159    } else {
1160        addEnd = fTs[endIndex].fOtherT != 0 || fTs[endIndex].fOther->multipleStarts();
1161    }
1162    SkASSERT(endIndex >= index);
1163    int prior = 0;
1164    while (index < endIndex) {
1165        const SkOpSpan& fromSpan = fTs[index];  // for each intermediate intersection
1166        const SkOpSpan* lastSpan;
1167        span = &fromSpan;
1168        int start = index;
1169        do {
1170            lastSpan = span;
1171            span = &fTs[++index];
1172            SkASSERT(index < spanCount);
1173            if (!precisely_negative(span->fT - lastSpan->fT) && !lastSpan->fTiny) {
1174                break;
1175            }
1176            if (!SkDPoint::ApproximatelyEqual(lastSpan->fPt, span->fPt)) {
1177                return false;
1178            }
1179        } while (true);
1180        int angleIndex = fAngles.count();
1181        int priorAngleIndex;
1182        if (activePrior >= 0) {
1183            int pActive = firstActive(prior);
1184            SkASSERT(pActive < start);
1185            fAngles.push_back().set(this, start, pActive);
1186            priorAngleIndex = angleIndex++;
1187    #if DEBUG_ANGLE
1188            fAngles.back().setID(priorAngleIndex);
1189    #endif
1190        }
1191        int active = checkSetAngle(start);
1192        if (active >= 0) {
1193            SkASSERT(active < index);
1194            fAngles.push_back().set(this, active, index);
1195    #if DEBUG_ANGLE
1196            fAngles.back().setID(angleIndex);
1197    #endif
1198        }
1199    #if DEBUG_ANGLE
1200        debugCheckPointsEqualish(start, index);
1201    #endif
1202        prior = start;
1203        do {
1204            const SkOpSpan* startSpan = &fTs[start - 1];
1205            if (!startSpan->fSmall || startSpan->fFromAngleIndex >= 0
1206                    || startSpan->fToAngleIndex >= 0) {
1207                break;
1208            }
1209            --start;
1210        } while (start > 0);
1211        do {
1212            if (activePrior >= 0) {
1213                SkASSERT(fTs[start].fFromAngleIndex == -1);
1214                fTs[start].fFromAngleIndex = priorAngleIndex;
1215            }
1216            if (active >= 0) {
1217                SkASSERT(fTs[start].fToAngleIndex == -1);
1218                fTs[start].fToAngleIndex = angleIndex;
1219            }
1220        } while (++start < index);
1221        activePrior = active;
1222    }
1223    if (addEnd && activePrior >= 0) {
1224        addEndSpan(endIndex);
1225    }
1226    return true;
1227}
1228
1229int SkOpSegment::checkSetAngle(int tIndex) const {
1230    const SkOpSpan* span = &fTs[tIndex];
1231    while (span->fTiny /* || span->fSmall */) {
1232        span = &fTs[++tIndex];
1233    }
1234    return isCanceled(tIndex) ? -1 : tIndex;
1235}
1236
1237// at this point, the span is already ordered, or unorderable, or unsortable
1238int SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType) {
1239    SkASSERT(includeType != SkOpAngle::kUnaryXor);
1240    SkOpAngle* firstAngle = spanToAngle(endIndex, startIndex);
1241    if (NULL == firstAngle) {
1242        return SK_NaN32;
1243    }
1244    // if all angles have a computed winding,
1245    //  or if no adjacent angles are orderable,
1246    //  or if adjacent orderable angles have no computed winding,
1247    //  there's nothing to do
1248    // if two orderable angles are adjacent, and one has winding computed, transfer to the other
1249    SkOpAngle* baseAngle = NULL;
1250    bool tryReverse = false;
1251    // look for counterclockwise transfers
1252    SkOpAngle* angle = firstAngle;
1253    do {
1254        int testWinding = angle->segment()->windSum(angle);
1255        if (SK_MinS32 != testWinding && !angle->unorderable()) {
1256            baseAngle = angle;
1257            continue;
1258        }
1259        if (angle->unorderable()) {
1260            baseAngle = NULL;
1261            tryReverse = true;
1262            continue;
1263        }
1264        if (baseAngle) {
1265            ComputeOneSum(baseAngle, angle, includeType);
1266            baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle : NULL;
1267            tryReverse |= !baseAngle;
1268        }
1269    } while ((angle = angle->next()) != firstAngle);
1270    if (baseAngle && SK_MinS32 == firstAngle->segment()->windSum(angle)) {
1271        firstAngle = baseAngle;
1272        tryReverse = true;
1273    }
1274    if (tryReverse) {
1275        baseAngle = NULL;
1276        angle = firstAngle;
1277        do {
1278            int testWinding = angle->segment()->windSum(angle);
1279            if (SK_MinS32 != testWinding) {
1280                baseAngle = angle;
1281                continue;
1282            }
1283            if (angle->unorderable()) {
1284                baseAngle = NULL;
1285                continue;
1286            }
1287            if (baseAngle) {
1288                ComputeOneSumReverse(baseAngle, angle, includeType);
1289                baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle : NULL;
1290            }
1291        } while ((angle = angle->previous()) != firstAngle);
1292    }
1293    int minIndex = SkMin32(startIndex, endIndex);
1294    return windSum(minIndex);
1295}
1296
1297void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
1298        SkOpAngle::IncludeType includeType) {
1299    const SkOpSegment* baseSegment = baseAngle->segment();
1300    int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
1301    int sumSuWinding;
1302    bool binary = includeType >= SkOpAngle::kBinarySingle;
1303    if (binary) {
1304        sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
1305        if (baseSegment->operand()) {
1306            SkTSwap<int>(sumMiWinding, sumSuWinding);
1307        }
1308    }
1309    SkOpSegment* nextSegment = nextAngle->segment();
1310    int maxWinding, sumWinding;
1311    SkOpSpan* last;
1312    if (binary) {
1313        int oppMaxWinding, oppSumWinding;
1314        nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
1315                &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1316        last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
1317                nextAngle);
1318    } else {
1319        nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
1320                &maxWinding, &sumWinding);
1321        last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
1322    }
1323    nextAngle->setLastMarked(last);
1324}
1325
1326void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
1327        SkOpAngle::IncludeType includeType) {
1328    const SkOpSegment* baseSegment = baseAngle->segment();
1329    int sumMiWinding = baseSegment->updateWinding(baseAngle);
1330    int sumSuWinding;
1331    bool binary = includeType >= SkOpAngle::kBinarySingle;
1332    if (binary) {
1333        sumSuWinding = baseSegment->updateOppWinding(baseAngle);
1334        if (baseSegment->operand()) {
1335            SkTSwap<int>(sumMiWinding, sumSuWinding);
1336        }
1337    }
1338    SkOpSegment* nextSegment = nextAngle->segment();
1339    int maxWinding, sumWinding;
1340    SkOpSpan* last;
1341    if (binary) {
1342        int oppMaxWinding, oppSumWinding;
1343        nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
1344                &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1345        last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
1346                nextAngle);
1347    } else {
1348        nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
1349                &maxWinding, &sumWinding);
1350        last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
1351    }
1352    nextAngle->setLastMarked(last);
1353}
1354
1355void SkOpSegment::constructLine(SkPoint shortLine[2]) {
1356    addLine(shortLine, false, false);
1357    addT(NULL, shortLine[0], 0);
1358    addT(NULL, shortLine[1], 1);
1359    addStartSpan(1);
1360    addEndSpan(1);
1361    SkOpAngle& angle = fAngles.push_back();
1362    angle.set(this, 0, 1);
1363}
1364
1365int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT,
1366                              bool* hitSomething, double mid, bool opp, bool current) const {
1367    SkScalar bottom = fBounds.fBottom;
1368    int bestTIndex = -1;
1369    if (bottom <= *bestY) {
1370        return bestTIndex;
1371    }
1372    SkScalar top = fBounds.fTop;
1373    if (top >= basePt.fY) {
1374        return bestTIndex;
1375    }
1376    if (fBounds.fLeft > basePt.fX) {
1377        return bestTIndex;
1378    }
1379    if (fBounds.fRight < basePt.fX) {
1380        return bestTIndex;
1381    }
1382    if (fBounds.fLeft == fBounds.fRight) {
1383        // if vertical, and directly above test point, wait for another one
1384        return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
1385    }
1386    // intersect ray starting at basePt with edge
1387    SkIntersections intersections;
1388    // OPTIMIZE: use specialty function that intersects ray with curve,
1389    // returning t values only for curve (we don't care about t on ray)
1390    intersections.allowNear(false);
1391    int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)])
1392            (fPts, top, bottom, basePt.fX, false);
1393    if (pts == 0 || (current && pts == 1)) {
1394        return bestTIndex;
1395    }
1396    if (current) {
1397        SkASSERT(pts > 1);
1398        int closestIdx = 0;
1399        double closest = fabs(intersections[0][0] - mid);
1400        for (int idx = 1; idx < pts; ++idx) {
1401            double test = fabs(intersections[0][idx] - mid);
1402            if (closest > test) {
1403                closestIdx = idx;
1404                closest = test;
1405            }
1406        }
1407        intersections.quickRemoveOne(closestIdx, --pts);
1408    }
1409    double bestT = -1;
1410    for (int index = 0; index < pts; ++index) {
1411        double foundT = intersections[0][index];
1412        if (approximately_less_than_zero(foundT)
1413                    || approximately_greater_than_one(foundT)) {
1414            continue;
1415        }
1416        SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fY;
1417        if (approximately_negative(testY - *bestY)
1418                || approximately_negative(basePt.fY - testY)) {
1419            continue;
1420        }
1421        if (pts > 1 && fVerb == SkPath::kLine_Verb) {
1422            return SK_MinS32;  // if the intersection is edge on, wait for another one
1423        }
1424        if (fVerb > SkPath::kLine_Verb) {
1425            SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fX;
1426            if (approximately_zero(dx)) {
1427                return SK_MinS32;  // hit vertical, wait for another one
1428            }
1429        }
1430        *bestY = testY;
1431        bestT = foundT;
1432    }
1433    if (bestT < 0) {
1434        return bestTIndex;
1435    }
1436    SkASSERT(bestT >= 0);
1437    SkASSERT(bestT <= 1);
1438    int start;
1439    int end = 0;
1440    do {
1441        start = end;
1442        end = nextSpan(start, 1);
1443    } while (fTs[end].fT < bestT);
1444    // FIXME: see next candidate for a better pattern to find the next start/end pair
1445    while (start + 1 < end && fTs[start].fDone) {
1446        ++start;
1447    }
1448    if (!isCanceled(start)) {
1449        *hitT = bestT;
1450        bestTIndex = start;
1451        *hitSomething = true;
1452    }
1453    return bestTIndex;
1454}
1455
1456bool SkOpSegment::decrementSpan(SkOpSpan* span) {
1457    SkASSERT(span->fWindValue > 0);
1458    if (--(span->fWindValue) == 0) {
1459        if (!span->fOppValue && !span->fDone) {
1460            span->fDone = true;
1461            ++fDoneSpans;
1462            return true;
1463        }
1464    }
1465    return false;
1466}
1467
1468bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) {
1469    SkASSERT(!span->fDone || span->fTiny || span->fSmall);
1470    span->fWindValue += windDelta;
1471    SkASSERT(span->fWindValue >= 0);
1472    span->fOppValue += oppDelta;
1473    SkASSERT(span->fOppValue >= 0);
1474    if (fXor) {
1475        span->fWindValue &= 1;
1476    }
1477    if (fOppXor) {
1478        span->fOppValue &= 1;
1479    }
1480    if (!span->fWindValue && !span->fOppValue) {
1481        span->fDone = true;
1482        ++fDoneSpans;
1483        return true;
1484    }
1485    return false;
1486}
1487
1488const SkOpSpan& SkOpSegment::firstSpan(const SkOpSpan& thisSpan) const {
1489    const SkOpSpan* firstSpan = &thisSpan; // rewind to the start
1490    const SkOpSpan* beginSpan = fTs.begin();
1491    const SkPoint& testPt = thisSpan.fPt;
1492    while (firstSpan > beginSpan && firstSpan[-1].fPt == testPt) {
1493        --firstSpan;
1494    }
1495    return *firstSpan;
1496}
1497
1498const SkOpSpan& SkOpSegment::lastSpan(const SkOpSpan& thisSpan) const {
1499    const SkOpSpan* endSpan = fTs.end() - 1;  // last can't be small
1500    const SkOpSpan* lastSpan = &thisSpan;  // find the end
1501    const SkPoint& testPt = thisSpan.fPt;
1502    while (lastSpan < endSpan && lastSpan[1].fPt == testPt) {
1503        ++lastSpan;
1504    }
1505    return *lastSpan;
1506}
1507
1508// with a loop, the comparison is move involved
1509// scan backwards and forwards to count all matching points
1510// (verify that there are twp scans marked as loops)
1511// compare that against 2 matching scans for loop plus other results
1512bool SkOpSegment::calcLoopSpanCount(const SkOpSpan& thisSpan, int* smallCounts) {
1513    const SkOpSpan& firstSpan = this->firstSpan(thisSpan); // rewind to the start
1514    const SkOpSpan& lastSpan = this->lastSpan(thisSpan);  // find the end
1515    double firstLoopT = -1, lastLoopT = -1;
1516    const SkOpSpan* testSpan = &firstSpan - 1;
1517    while (++testSpan <= &lastSpan) {
1518        if (testSpan->fLoop) {
1519            firstLoopT = testSpan->fT;
1520            break;
1521        }
1522    }
1523    testSpan = &lastSpan + 1;
1524    while (--testSpan >= &firstSpan) {
1525        if (testSpan->fLoop) {
1526            lastLoopT = testSpan->fT;
1527            break;
1528        }
1529    }
1530    SkASSERT((firstLoopT == -1) == (lastLoopT == -1));
1531    if (firstLoopT == -1) {
1532        return false;
1533    }
1534    SkASSERT(firstLoopT < lastLoopT);
1535    testSpan = &firstSpan - 1;
1536    smallCounts[0] = smallCounts[1] = 0;
1537    while (++testSpan <= &lastSpan) {
1538        SkASSERT(approximately_equal(testSpan->fT, firstLoopT) +
1539                approximately_equal(testSpan->fT, lastLoopT) == 1);
1540        smallCounts[approximately_equal(testSpan->fT, lastLoopT)]++;
1541    }
1542    return true;
1543}
1544
1545// see if spans with two or more intersections have the same number on the other end
1546void SkOpSegment::checkDuplicates() {
1547    debugValidate();
1548    SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
1549    int index;
1550    int endIndex = 0;
1551    bool endFound;
1552    do {
1553        index = endIndex;
1554        endIndex = nextExactSpan(index, 1);
1555        if ((endFound = endIndex < 0)) {
1556            endIndex = count();
1557        }
1558        int dupCount = endIndex - index;
1559        if (dupCount < 2) {
1560            continue;
1561        }
1562        do {
1563            const SkOpSpan* thisSpan = &fTs[index];
1564            SkOpSegment* other = thisSpan->fOther;
1565            int oIndex = thisSpan->fOtherIndex;
1566            int oStart = other->nextExactSpan(oIndex, -1) + 1;
1567            int oEnd = other->nextExactSpan(oIndex, 1);
1568            if (oEnd < 0) {
1569                oEnd = other->count();
1570            }
1571            int oCount = oEnd - oStart;
1572            // force the other to match its t and this pt if not on an end point
1573            if (oCount != dupCount) {
1574                MissingSpan& missing = missingSpans.push_back();
1575                missing.fOther = NULL;
1576                SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
1577                missing.fPt = thisSpan->fPt;
1578                const SkOpSpan& oSpan = other->span(oIndex);
1579                if (oCount > dupCount) {
1580                    missing.fSegment = this;
1581                    missing.fT = thisSpan->fT;
1582                    other->checkLinks(&oSpan, &missingSpans);
1583                } else {
1584                    missing.fSegment = other;
1585                    missing.fT = oSpan.fT;
1586                    checkLinks(thisSpan, &missingSpans);
1587                }
1588                if (!missingSpans.back().fOther) {
1589                    missingSpans.pop_back();
1590                }
1591            }
1592        } while (++index < endIndex);
1593    } while (!endFound);
1594    int missingCount = missingSpans.count();
1595    if (missingCount == 0) {
1596        return;
1597    }
1598    SkSTArray<kMissingSpanCount, MissingSpan, true> missingCoincidence;
1599    for (index = 0; index < missingCount; ++index)  {
1600        MissingSpan& missing = missingSpans[index];
1601        SkOpSegment* missingOther = missing.fOther;
1602        if (missing.fSegment == missing.fOther) {
1603            continue;
1604        }
1605        const SkOpSpan* added = missing.fSegment->addTPair(missing.fT, missingOther,
1606                missing.fOtherT, false, missing.fPt);
1607        if (added && added->fSmall) {
1608            missing.fSegment->checkSmallCoincidence(*added, &missingCoincidence);
1609        }
1610    }
1611    for (index = 0; index < missingCount; ++index)  {
1612        MissingSpan& missing = missingSpans[index];
1613        missing.fSegment->fixOtherTIndex();
1614        missing.fOther->fixOtherTIndex();
1615    }
1616    for (index = 0; index < missingCoincidence.count(); ++index) {
1617        MissingSpan& missing = missingCoincidence[index];
1618        missing.fSegment->fixOtherTIndex();
1619    }
1620    debugValidate();
1621}
1622
1623// look to see if the curve end intersects an intermediary that intersects the other
1624void SkOpSegment::checkEnds() {
1625    debugValidate();
1626    SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
1627    int count = fTs.count();
1628    for (int index = 0; index < count; ++index) {
1629        const SkOpSpan& span = fTs[index];
1630        double otherT = span.fOtherT;
1631        if (otherT != 0 && otherT != 1) { // only check ends
1632            continue;
1633        }
1634        const SkOpSegment* other = span.fOther;
1635        // peek start/last describe the range of spans that match the other t of this span
1636        int peekStart = span.fOtherIndex;
1637        while (--peekStart >= 0 && other->fTs[peekStart].fT == otherT)
1638            ;
1639        int otherCount = other->fTs.count();
1640        int peekLast = span.fOtherIndex;
1641        while (++peekLast < otherCount && other->fTs[peekLast].fT == otherT)
1642            ;
1643        if (++peekStart == --peekLast) { // if there isn't a range, there's nothing to do
1644            continue;
1645        }
1646        // t start/last describe the range of spans that match the t of this span
1647        double t = span.fT;
1648        double tBottom = -1;
1649        int tStart = -1;
1650        int tLast = count;
1651        bool lastSmall = false;
1652        double afterT = t;
1653        for (int inner = 0; inner < count; ++inner) {
1654            double innerT = fTs[inner].fT;
1655            if (innerT <= t && innerT > tBottom) {
1656                if (innerT < t || !lastSmall) {
1657                    tStart = inner - 1;
1658                }
1659                tBottom = innerT;
1660            }
1661            if (innerT > afterT) {
1662                if (t == afterT && lastSmall) {
1663                    afterT = innerT;
1664                } else {
1665                    tLast = inner;
1666                    break;
1667                }
1668            }
1669            lastSmall = innerT <= t ? fTs[inner].fSmall : false;
1670        }
1671        for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) {
1672            if (peekIndex == span.fOtherIndex) {  // skip the other span pointed to by this span
1673                continue;
1674            }
1675            const SkOpSpan& peekSpan = other->fTs[peekIndex];
1676            SkOpSegment* match = peekSpan.fOther;
1677            if (match->done()) {
1678                continue;  // if the edge has already been eaten (likely coincidence), ignore it
1679            }
1680            const double matchT = peekSpan.fOtherT;
1681            // see if any of the spans match the other spans
1682            for (int tIndex = tStart + 1; tIndex < tLast; ++tIndex) {
1683                const SkOpSpan& tSpan = fTs[tIndex];
1684                if (tSpan.fOther == match) {
1685                    if (tSpan.fOtherT == matchT) {
1686                        goto nextPeekIndex;
1687                    }
1688                    double midT = (tSpan.fOtherT + matchT) / 2;
1689                    if (match->betweenPoints(midT, tSpan.fPt, peekSpan.fPt)) {
1690                        goto nextPeekIndex;
1691                    }
1692                }
1693            }
1694            if (missingSpans.count() > 0) {
1695                const MissingSpan& lastMissing = missingSpans.back();
1696                if (lastMissing.fT == t
1697                        && lastMissing.fOther == match
1698                        && lastMissing.fOtherT == matchT) {
1699                    SkASSERT(lastMissing.fPt == peekSpan.fPt);
1700                    continue;
1701                }
1702            }
1703#if DEBUG_CHECK_ENDS
1704            SkDebugf("%s id=%d missing t=%1.9g other=%d otherT=%1.9g pt=(%1.9g,%1.9g)\n",
1705                    __FUNCTION__, fID, t, match->fID, matchT, peekSpan.fPt.fX, peekSpan.fPt.fY);
1706#endif
1707            // this segment is missing a entry that the other contains
1708            // remember so we can add the missing one and recompute the indices
1709            {
1710                MissingSpan& missing = missingSpans.push_back();
1711                SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
1712                missing.fT = t;
1713                missing.fOther = match;
1714                missing.fOtherT = matchT;
1715                missing.fPt = peekSpan.fPt;
1716            }
1717            break;
1718nextPeekIndex:
1719            ;
1720        }
1721    }
1722    if (missingSpans.count() == 0) {
1723        debugValidate();
1724        return;
1725    }
1726    debugValidate();
1727    int missingCount = missingSpans.count();
1728    for (int index = 0; index < missingCount; ++index)  {
1729        MissingSpan& missing = missingSpans[index];
1730        if (this != missing.fOther) {
1731            addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt);
1732        }
1733    }
1734    fixOtherTIndex();
1735    // OPTIMIZATION: this may fix indices more than once. Build an array of unique segments to
1736    // avoid this
1737    for (int index = 0; index < missingCount; ++index)  {
1738        missingSpans[index].fOther->fixOtherTIndex();
1739    }
1740    debugValidate();
1741}
1742
1743void SkOpSegment::checkLinks(const SkOpSpan* base,
1744        SkTArray<MissingSpan, true>* missingSpans) const {
1745    const SkOpSpan* first = fTs.begin();
1746    const SkOpSpan* last = fTs.end() - 1;
1747    SkASSERT(base >= first && last >= base);
1748    const SkOpSegment* other = base->fOther;
1749    const SkOpSpan* oFirst = other->fTs.begin();
1750    const SkOpSpan* oLast = other->fTs.end() - 1;
1751    const SkOpSpan* oSpan = &other->fTs[base->fOtherIndex];
1752    const SkOpSpan* test = base;
1753    const SkOpSpan* missing = NULL;
1754    while (test > first && (--test)->fPt == base->fPt) {
1755        CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans);
1756    }
1757    test = base;
1758    while (test < last && (++test)->fPt == base->fPt) {
1759        CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans);
1760    }
1761}
1762
1763// see if spans with two or more intersections all agree on common t and point values
1764void SkOpSegment::checkMultiples() {
1765    debugValidate();
1766    int index;
1767    int end = 0;
1768    while (fTs[++end].fT == 0)
1769        ;
1770    while (fTs[end].fT < 1) {
1771        int start = index = end;
1772        end = nextExactSpan(index, 1);
1773        if (end <= index) {
1774            return;  // buffer overflow example triggers this
1775        }
1776        if (index + 1 == end) {
1777            continue;
1778        }
1779        // force the duplicates to agree on t and pt if not on the end
1780        double thisT = fTs[index].fT;
1781        const SkPoint& thisPt = fTs[index].fPt;
1782        bool aligned = false;
1783        while (++index < end) {
1784            aligned |= alignSpan(index, thisT, thisPt);
1785        }
1786        if (aligned) {
1787            alignSpanState(start, end);
1788        }
1789    }
1790    debugValidate();
1791}
1792
1793void SkOpSegment::CheckOneLink(const SkOpSpan* test, const SkOpSpan* oSpan,
1794        const SkOpSpan* oFirst, const SkOpSpan* oLast, const SkOpSpan** missingPtr,
1795        SkTArray<MissingSpan, true>* missingSpans) {
1796    SkASSERT(oSpan->fPt == test->fPt);
1797    const SkOpSpan* oTest = oSpan;
1798    while (oTest > oFirst && (--oTest)->fPt == test->fPt) {
1799        if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) {
1800            return;
1801        }
1802    }
1803    oTest = oSpan;
1804    while (oTest < oLast && (++oTest)->fPt == test->fPt) {
1805        if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) {
1806            return;
1807        }
1808    }
1809    if (*missingPtr) {
1810        missingSpans->push_back();
1811    }
1812    MissingSpan& lastMissing = missingSpans->back();
1813    if (*missingPtr) {
1814        lastMissing = missingSpans->end()[-2];
1815    }
1816    *missingPtr = test;
1817    lastMissing.fOther = test->fOther;
1818    lastMissing.fOtherT = test->fOtherT;
1819}
1820
1821bool SkOpSegment::checkSmall(int index) const {
1822    if (fTs[index].fSmall) {
1823        return true;
1824    }
1825    double tBase = fTs[index].fT;
1826    while (index > 0 && precisely_negative(tBase - fTs[--index].fT))
1827        ;
1828    return fTs[index].fSmall;
1829}
1830
1831// a pair of curves may turn into coincident lines -- small may be a hint that that happened
1832// if a cubic contains a loop, the counts must be adjusted
1833void SkOpSegment::checkSmall() {
1834    SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
1835    const SkOpSpan* beginSpan = fTs.begin();
1836    const SkOpSpan* thisSpan = beginSpan - 1;
1837    const SkOpSpan* endSpan = fTs.end() - 1;  // last can't be small
1838    while (++thisSpan < endSpan) {
1839        if (!thisSpan->fSmall) {
1840            continue;
1841        }
1842        if (!thisSpan->fWindValue) {
1843            continue;
1844        }
1845        const SkOpSpan& firstSpan = this->firstSpan(*thisSpan);
1846        const SkOpSpan& lastSpan = this->lastSpan(*thisSpan);
1847        ptrdiff_t smallCount = &lastSpan - &firstSpan + 1;
1848        SkASSERT(1 <= smallCount && smallCount < count());
1849        if (smallCount <= 1) {
1850            SkASSERT(1 == smallCount);
1851            checkSmallCoincidence(firstSpan, NULL);
1852            continue;
1853        }
1854        // at this point, check for missing computed intersections
1855        const SkPoint& testPt = firstSpan.fPt;
1856        thisSpan = &firstSpan - 1;
1857        SkOpSegment* other = NULL;
1858        while (++thisSpan <= &lastSpan) {
1859            other = thisSpan->fOther;
1860            if (other != this) {
1861                break;
1862            }
1863        }
1864        SkASSERT(other != this);
1865        int oIndex = thisSpan->fOtherIndex;
1866        const SkOpSpan& oSpan = other->span(oIndex);
1867        const SkOpSpan& oFirstSpan = other->firstSpan(oSpan);
1868        const SkOpSpan& oLastSpan = other->lastSpan(oSpan);
1869        ptrdiff_t oCount = &oLastSpan - &oFirstSpan + 1;
1870        if (fLoop) {
1871            int smallCounts[2];
1872            SkASSERT(!other->fLoop);  // FIXME: we need more complicated logic for pair of loops
1873            if (calcLoopSpanCount(*thisSpan, smallCounts)) {
1874                if (smallCounts[0] && oCount != smallCounts[0]) {
1875                    SkASSERT(0);  // FIXME: need a working test case to properly code & debug
1876                }
1877                if (smallCounts[1] && oCount != smallCounts[1]) {
1878                    SkASSERT(0);  // FIXME: need a working test case to properly code & debug
1879                }
1880                goto nextSmallCheck;
1881            }
1882        }
1883        if (other->fLoop) {
1884            int otherCounts[2];
1885            if (other->calcLoopSpanCount(other->span(oIndex), otherCounts)) {
1886                if (otherCounts[0] && otherCounts[0] != smallCount) {
1887                    SkASSERT(0);  // FIXME: need a working test case to properly code & debug
1888                }
1889                if (otherCounts[1] && otherCounts[1] != smallCount) {
1890                    SkASSERT(0);  // FIXME: need a working test case to properly code & debug
1891                }
1892                goto nextSmallCheck;
1893            }
1894        }
1895        if (oCount != smallCount) {  // check if number of pts in this match other
1896            MissingSpan& missing = missingSpans.push_back();
1897            missing.fOther = NULL;
1898            SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
1899            missing.fPt = testPt;
1900            const SkOpSpan& oSpan = other->span(oIndex);
1901            if (oCount > smallCount) {
1902                missing.fSegment = this;
1903                missing.fT = thisSpan->fT;
1904                other->checkLinks(&oSpan, &missingSpans);
1905            } else {
1906                missing.fSegment = other;
1907                missing.fT = oSpan.fT;
1908                checkLinks(thisSpan, &missingSpans);
1909            }
1910            if (!missingSpans.back().fOther || missing.fSegment->done()) {
1911                missingSpans.pop_back();
1912            }
1913        }
1914nextSmallCheck:
1915        thisSpan = &lastSpan;
1916    }
1917    int missingCount = missingSpans.count();
1918    for (int index = 0; index < missingCount; ++index)  {
1919        MissingSpan& missing = missingSpans[index];
1920        SkOpSegment* missingOther = missing.fOther;
1921        // note that add t pair may edit span arrays, so prior pointers to spans are no longer valid
1922        if (!missing.fSegment->addTPair(missing.fT, missingOther, missing.fOtherT, false,
1923                missing.fPt)) {
1924            continue;
1925        }
1926        int otherTIndex = missingOther->findT(missing.fOtherT, missing.fSegment);
1927        const SkOpSpan& otherSpan = missingOther->span(otherTIndex);
1928        if (otherSpan.fSmall) {
1929            const SkOpSpan* nextSpan = &otherSpan;
1930            do {
1931                ++nextSpan;
1932            } while (nextSpan->fSmall);
1933            missing.fSegment->addTCoincident(missing.fPt, nextSpan->fPt, nextSpan->fT,
1934                    missingOther);
1935        } else if (otherSpan.fT > 0) {
1936            const SkOpSpan* priorSpan = &otherSpan;
1937            do {
1938                --priorSpan;
1939            } while (priorSpan->fT == otherSpan.fT);
1940            if (priorSpan->fSmall) {
1941                missing.fSegment->addTCancel(missing.fPt, priorSpan->fPt, missingOther);
1942            }
1943        }
1944    }
1945    // OPTIMIZATION: this may fix indices more than once. Build an array of unique segments to
1946    // avoid this
1947    for (int index = 0; index < missingCount; ++index)  {
1948        MissingSpan& missing = missingSpans[index];
1949        missing.fSegment->fixOtherTIndex();
1950        missing.fOther->fixOtherTIndex();
1951    }
1952    debugValidate();
1953}
1954
1955void SkOpSegment::checkSmallCoincidence(const SkOpSpan& span,
1956        SkTArray<MissingSpan, true>* checkMultiple) {
1957    SkASSERT(span.fSmall);
1958    SkASSERT(span.fWindValue);
1959    SkASSERT(&span < fTs.end() - 1);
1960    const SkOpSpan* next = &span + 1;
1961    SkASSERT(!next->fSmall || checkMultiple);
1962    if (checkMultiple) {
1963        while (next->fSmall) {
1964            ++next;
1965            SkASSERT(next < fTs.end());
1966        }
1967    }
1968    SkOpSegment* other = span.fOther;
1969    while (other != next->fOther) {
1970        if (!checkMultiple) {
1971            return;
1972        }
1973        const SkOpSpan* test = next + 1;
1974        if (test == fTs.end()) {
1975            return;
1976        }
1977        if (test->fPt != next->fPt || !precisely_equal(test->fT, next->fT)) {
1978            return;
1979        }
1980        next = test;
1981    }
1982    SkASSERT(span.fT < next->fT);
1983    int oStartIndex = other->findExactT(span.fOtherT, this);
1984    int oEndIndex = other->findExactT(next->fOtherT, this);
1985    // FIXME: be overly conservative by limiting this to the caller that allows multiple smalls
1986    if (!checkMultiple || fVerb != SkPath::kLine_Verb || other->fVerb != SkPath::kLine_Verb) {
1987        SkPoint mid = ptAtT((span.fT + next->fT) / 2);
1988        const SkOpSpan& oSpanStart = other->fTs[oStartIndex];
1989        const SkOpSpan& oSpanEnd = other->fTs[oEndIndex];
1990        SkPoint oMid = other->ptAtT((oSpanStart.fT + oSpanEnd.fT) / 2);
1991        if (!SkDPoint::ApproximatelyEqual(mid, oMid)) {
1992            return;
1993        }
1994    }
1995    // FIXME: again, be overly conservative to avoid breaking existing tests
1996    const SkOpSpan& oSpan = oStartIndex < oEndIndex ? other->fTs[oStartIndex]
1997            : other->fTs[oEndIndex];
1998    if (checkMultiple && !oSpan.fSmall) {
1999        return;
2000    }
2001    SkASSERT(oSpan.fSmall);
2002    if (oStartIndex < oEndIndex) {
2003        addTCoincident(span.fPt, next->fPt, next->fT, other);
2004    } else {
2005        addTCancel(span.fPt, next->fPt, other);
2006    }
2007    if (!checkMultiple) {
2008        return;
2009    }
2010    // check to see if either segment is coincident with a third segment -- if it is, and if
2011    // the opposite segment is not already coincident with the third, make it so
2012    // OPTIMIZE: to make this check easier, add coincident and cancel could set a coincident bit
2013    if (span.fWindValue != 1 || span.fOppValue != 0) {
2014//        start here;
2015        // iterate through the spans, looking for the third coincident case
2016        // if we find one, we need to return state to the caller so that the indices can be fixed
2017        // this also suggests that all of this function is fragile since it relies on a valid index
2018    }
2019    // probably should make this a common function rather than copy/paste code
2020    if (oSpan.fWindValue != 1 || oSpan.fOppValue != 0) {
2021        const SkOpSpan* oTest = &oSpan;
2022        while (--oTest >= other->fTs.begin()) {
2023            if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT)) {
2024                break;
2025            }
2026            SkOpSegment* testOther = oTest->fOther;
2027            SkASSERT(testOther != this);
2028            // look in both directions to see if there is a coincident span
2029            const SkOpSpan* tTest = testOther->fTs.begin();
2030            for (int testIndex = 0; testIndex < testOther->count(); ++testIndex) {
2031                if (tTest->fPt != span.fPt) {
2032                    ++tTest;
2033                    continue;
2034                }
2035                if (testOther->verb() != SkPath::kLine_Verb
2036                        || other->verb() != SkPath::kLine_Verb) {
2037                    SkPoint mid = ptAtT((span.fT + next->fT) / 2);
2038                    SkPoint oMid = other->ptAtT((oTest->fOtherT + tTest->fT) / 2);
2039                    if (!SkDPoint::ApproximatelyEqual(mid, oMid)) {
2040                        continue;
2041                    }
2042                }
2043#if DEBUG_CONCIDENT
2044                SkDebugf("%s coincident found=%d %1.9g %1.9g\n", __FUNCTION__, testOther->fID,
2045                        oTest->fOtherT, tTest->fT);
2046#endif
2047                if (tTest->fT < oTest->fOtherT) {
2048                    addTCoincident(span.fPt, next->fPt, next->fT, testOther);
2049                } else {
2050                    addTCancel(span.fPt, next->fPt, testOther);
2051                }
2052                MissingSpan missing;
2053                missing.fSegment = testOther;
2054                checkMultiple->push_back(missing);
2055                break;
2056            }
2057        }
2058        oTest = &oSpan;
2059        while (++oTest < other->fTs.end()) {
2060            if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT)) {
2061                break;
2062            }
2063
2064        }
2065    }
2066}
2067
2068// if pair of spans on either side of tiny have the same end point and mid point, mark
2069// them as parallel
2070void SkOpSegment::checkTiny() {
2071    SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
2072    SkOpSpan* thisSpan = fTs.begin() - 1;
2073    const SkOpSpan* endSpan = fTs.end() - 1;  // last can't be tiny
2074    while (++thisSpan < endSpan) {
2075        if (!thisSpan->fTiny) {
2076            continue;
2077        }
2078        SkOpSpan* nextSpan = thisSpan + 1;
2079        double thisT = thisSpan->fT;
2080        double nextT = nextSpan->fT;
2081        if (thisT == nextT) {
2082            continue;
2083        }
2084        SkASSERT(thisT < nextT);
2085        SkASSERT(thisSpan->fPt == nextSpan->fPt);
2086        SkOpSegment* thisOther = thisSpan->fOther;
2087        SkOpSegment* nextOther = nextSpan->fOther;
2088        int oIndex = thisSpan->fOtherIndex;
2089        for (int oStep = -1; oStep <= 1; oStep += 2) {
2090            int oEnd = thisOther->nextExactSpan(oIndex, oStep);
2091            if (oEnd < 0) {
2092                continue;
2093            }
2094            const SkOpSpan& oSpan = thisOther->span(oEnd);
2095            int nIndex = nextSpan->fOtherIndex;
2096            for (int nStep = -1; nStep <= 1; nStep += 2) {
2097                int nEnd = nextOther->nextExactSpan(nIndex, nStep);
2098                if (nEnd < 0) {
2099                    continue;
2100                }
2101                const SkOpSpan& nSpan = nextOther->span(nEnd);
2102                if (oSpan.fPt != nSpan.fPt) {
2103                    continue;
2104                }
2105                double oMidT = (thisSpan->fOtherT + oSpan.fT) / 2;
2106                const SkPoint& oPt = thisOther->ptAtT(oMidT);
2107                double nMidT = (nextSpan->fOtherT + nSpan.fT) / 2;
2108                const SkPoint& nPt = nextOther->ptAtT(nMidT);
2109                if (!AlmostEqualUlps(oPt, nPt)) {
2110                    continue;
2111                }
2112#if DEBUG_CHECK_TINY
2113                SkDebugf("%s [%d] add coincidence [%d] [%d]\n", __FUNCTION__, fID,
2114                    thisOther->fID, nextOther->fID);
2115#endif
2116                // this segment is missing a entry that the other contains
2117                // remember so we can add the missing one and recompute the indices
2118                MissingSpan& missing = missingSpans.push_back();
2119                SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
2120                missing.fSegment = thisOther;
2121                missing.fT = thisSpan->fOtherT;
2122                missing.fOther = nextOther;
2123                missing.fOtherT = nextSpan->fOtherT;
2124                missing.fPt = thisSpan->fPt;
2125            }
2126        }
2127    }
2128    int missingCount = missingSpans.count();
2129    if (!missingCount) {
2130        return;
2131    }
2132    for (int index = 0; index < missingCount; ++index)  {
2133        MissingSpan& missing = missingSpans[index];
2134        if (missing.fSegment != missing.fOther) {
2135            missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOtherT, false,
2136                    missing.fPt);
2137        }
2138    }
2139    // OPTIMIZE: consolidate to avoid multiple calls to fix index
2140    for (int index = 0; index < missingCount; ++index)  {
2141        MissingSpan& missing = missingSpans[index];
2142        missing.fSegment->fixOtherTIndex();
2143        missing.fOther->fixOtherTIndex();
2144    }
2145}
2146
2147bool SkOpSegment::findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int oStart,
2148        int oEnd, int step, SkPoint* startPt, SkPoint* endPt, double* endT) const {
2149    SkASSERT(span->fT == 0 || span->fT == 1);
2150    SkASSERT(span->fOtherT == 0 || span->fOtherT == 1);
2151    const SkOpSpan* otherSpan = &other->span(oEnd);
2152    double refT = otherSpan->fT;
2153    const SkPoint& refPt = otherSpan->fPt;
2154    const SkOpSpan* lastSpan = &other->span(step > 0 ? other->count() - 1 : 0);
2155    do {
2156        const SkOpSegment* match = span->fOther;
2157        if (match == otherSpan->fOther) {
2158            // find start of respective spans and see if both have winding
2159            int startIndex, endIndex;
2160            if (span->fOtherT == 1) {
2161                endIndex = span->fOtherIndex;
2162                startIndex = match->nextExactSpan(endIndex, -1);
2163            } else {
2164                startIndex = span->fOtherIndex;
2165                endIndex = match->nextExactSpan(startIndex, 1);
2166            }
2167            const SkOpSpan& startSpan = match->span(startIndex);
2168            if (startSpan.fWindValue != 0) {
2169                // draw ray from endSpan.fPt perpendicular to end tangent and measure distance
2170                // to other segment.
2171                const SkOpSpan& endSpan = match->span(endIndex);
2172                SkDLine ray;
2173                SkVector dxdy;
2174                if (span->fOtherT == 1) {
2175                    ray.fPts[0].set(startSpan.fPt);
2176                    dxdy = match->dxdy(startIndex);
2177                } else {
2178                    ray.fPts[0].set(endSpan.fPt);
2179                    dxdy = match->dxdy(endIndex);
2180                }
2181                ray.fPts[1].fX = ray.fPts[0].fX + dxdy.fY;
2182                ray.fPts[1].fY = ray.fPts[0].fY - dxdy.fX;
2183                SkIntersections i;
2184                int roots = (i.*CurveRay[SkPathOpsVerbToPoints(other->verb())])(other->pts(), ray);
2185                for (int index = 0; index < roots; ++index) {
2186                    if (ray.fPts[0].approximatelyEqual(i.pt(index))) {
2187                        double matchMidT = (match->span(startIndex).fT
2188                                + match->span(endIndex).fT) / 2;
2189                        SkPoint matchMidPt = match->ptAtT(matchMidT);
2190                        double otherMidT = (i[0][index] + other->span(oStart).fT) / 2;
2191                        SkPoint otherMidPt = other->ptAtT(otherMidT);
2192                        if (SkDPoint::ApproximatelyEqual(matchMidPt, otherMidPt)) {
2193                            *startPt = startSpan.fPt;
2194                            *endPt = endSpan.fPt;
2195                            *endT = endSpan.fT;
2196                            return true;
2197                        }
2198                    }
2199                }
2200            }
2201            return false;
2202        }
2203        if (otherSpan == lastSpan) {
2204            break;
2205        }
2206        otherSpan += step;
2207    } while (otherSpan->fT == refT || otherSpan->fPt == refPt);
2208    return false;
2209}
2210
2211int SkOpSegment::findEndSpan(int endIndex) const {
2212    const SkOpSpan* span = &fTs[--endIndex];
2213    const SkPoint& lastPt = span->fPt;
2214    double endT = span->fT;
2215    do {
2216        span = &fTs[--endIndex];
2217    } while (SkDPoint::ApproximatelyEqual(span->fPt, lastPt) && (span->fT == endT || span->fTiny));
2218    return endIndex + 1;
2219}
2220
2221/*
2222 The M and S variable name parts stand for the operators.
2223   Mi stands for Minuend (see wiki subtraction, analogous to difference)
2224   Su stands for Subtrahend
2225 The Opp variable name part designates that the value is for the Opposite operator.
2226 Opposite values result from combining coincident spans.
2227 */
2228SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
2229                                     bool* unsortable, SkPathOp op, const int xorMiMask,
2230                                     const int xorSuMask) {
2231    const int startIndex = *nextStart;
2232    const int endIndex = *nextEnd;
2233    SkASSERT(startIndex != endIndex);
2234    SkDEBUGCODE(const int count = fTs.count());
2235    SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2236    const int step = SkSign32(endIndex - startIndex);
2237    const int end = nextExactSpan(startIndex, step);
2238    SkASSERT(end >= 0);
2239    SkOpSpan* endSpan = &fTs[end];
2240    SkOpSegment* other;
2241    if (isSimple(end)) {
2242    // mark the smaller of startIndex, endIndex done, and all adjacent
2243    // spans with the same T value (but not 'other' spans)
2244#if DEBUG_WINDING
2245        SkDebugf("%s simple\n", __FUNCTION__);
2246#endif
2247        int min = SkMin32(startIndex, endIndex);
2248        if (fTs[min].fDone) {
2249            return NULL;
2250        }
2251        markDoneBinary(min);
2252        other = endSpan->fOther;
2253        *nextStart = endSpan->fOtherIndex;
2254        double startT = other->fTs[*nextStart].fT;
2255        *nextEnd = *nextStart;
2256        do {
2257            *nextEnd += step;
2258        } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
2259        SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
2260        if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
2261            *unsortable = true;
2262            return NULL;
2263        }
2264        return other;
2265    }
2266    SkASSERT(startIndex - endIndex != 0);
2267    SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2268    // more than one viable candidate -- measure angles to find best
2269
2270    int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp);
2271    bool sortable = calcWinding != SK_NaN32;
2272    if (!sortable) {
2273        *unsortable = true;
2274        return NULL;
2275    }
2276    SkOpAngle* angle = spanToAngle(end, startIndex);
2277    if (angle->unorderable()) {
2278        *unsortable = true;
2279        return NULL;
2280    }
2281#if DEBUG_SORT
2282    SkDebugf("%s\n", __FUNCTION__);
2283    angle->debugLoop();
2284#endif
2285    int sumMiWinding = updateWinding(endIndex, startIndex);
2286    int sumSuWinding = updateOppWinding(endIndex, startIndex);
2287    if (operand()) {
2288        SkTSwap<int>(sumMiWinding, sumSuWinding);
2289    }
2290    SkOpAngle* nextAngle = angle->next();
2291    const SkOpAngle* foundAngle = NULL;
2292    bool foundDone = false;
2293    // iterate through the angle, and compute everyone's winding
2294    SkOpSegment* nextSegment;
2295    int activeCount = 0;
2296    do {
2297        nextSegment = nextAngle->segment();
2298        bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2299                nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
2300        if (activeAngle) {
2301            ++activeCount;
2302            if (!foundAngle || (foundDone && activeCount & 1)) {
2303                if (nextSegment->isTiny(nextAngle)) {
2304                    *unsortable = true;
2305                    return NULL;
2306                }
2307                foundAngle = nextAngle;
2308                foundDone = nextSegment->done(nextAngle);
2309            }
2310        }
2311        if (nextSegment->done()) {
2312            continue;
2313        }
2314        if (nextSegment->isTiny(nextAngle)) {
2315            continue;
2316        }
2317        if (!activeAngle) {
2318            nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextAngle->end());
2319        }
2320        SkOpSpan* last = nextAngle->lastMarked();
2321        if (last) {
2322            SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
2323            *chase->append() = last;
2324#if DEBUG_WINDING
2325            SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
2326                    last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
2327                    last->fSmall);
2328#endif
2329        }
2330    } while ((nextAngle = nextAngle->next()) != angle);
2331#if DEBUG_ANGLE
2332    if (foundAngle) {
2333        foundAngle->debugSameAs(foundAngle);
2334    }
2335#endif
2336
2337    markDoneBinary(SkMin32(startIndex, endIndex));
2338    if (!foundAngle) {
2339        return NULL;
2340    }
2341    *nextStart = foundAngle->start();
2342    *nextEnd = foundAngle->end();
2343    nextSegment = foundAngle->segment();
2344#if DEBUG_WINDING
2345    SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2346            __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
2347 #endif
2348    return nextSegment;
2349}
2350
2351SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart,
2352                                          int* nextEnd, bool* unsortable) {
2353    const int startIndex = *nextStart;
2354    const int endIndex = *nextEnd;
2355    SkASSERT(startIndex != endIndex);
2356    SkDEBUGCODE(const int count = fTs.count());
2357    SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2358    const int step = SkSign32(endIndex - startIndex);
2359    const int end = nextExactSpan(startIndex, step);
2360    SkASSERT(end >= 0);
2361    SkOpSpan* endSpan = &fTs[end];
2362    SkOpSegment* other;
2363    if (isSimple(end)) {
2364    // mark the smaller of startIndex, endIndex done, and all adjacent
2365    // spans with the same T value (but not 'other' spans)
2366#if DEBUG_WINDING
2367        SkDebugf("%s simple\n", __FUNCTION__);
2368#endif
2369        int min = SkMin32(startIndex, endIndex);
2370        if (fTs[min].fDone) {
2371            return NULL;
2372        }
2373        markDoneUnary(min);
2374        other = endSpan->fOther;
2375        *nextStart = endSpan->fOtherIndex;
2376        double startT = other->fTs[*nextStart].fT;
2377        *nextEnd = *nextStart;
2378        do {
2379            *nextEnd += step;
2380        } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
2381        SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
2382        if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
2383            *unsortable = true;
2384            return NULL;
2385        }
2386        return other;
2387    }
2388    SkASSERT(startIndex - endIndex != 0);
2389    SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2390    // more than one viable candidate -- measure angles to find best
2391
2392    int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryWinding);
2393    bool sortable = calcWinding != SK_NaN32;
2394    if (!sortable) {
2395        *unsortable = true;
2396        return NULL;
2397    }
2398    SkOpAngle* angle = spanToAngle(end, startIndex);
2399#if DEBUG_SORT
2400    SkDebugf("%s\n", __FUNCTION__);
2401    angle->debugLoop();
2402#endif
2403    int sumWinding = updateWinding(endIndex, startIndex);
2404    SkOpAngle* nextAngle = angle->next();
2405    const SkOpAngle* foundAngle = NULL;
2406    bool foundDone = false;
2407    SkOpSegment* nextSegment;
2408    int activeCount = 0;
2409    do {
2410        nextSegment = nextAngle->segment();
2411        bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
2412                &sumWinding);
2413        if (activeAngle) {
2414            ++activeCount;
2415            if (!foundAngle || (foundDone && activeCount & 1)) {
2416                if (nextSegment->isTiny(nextAngle)) {
2417                    *unsortable = true;
2418                    return NULL;
2419                }
2420                foundAngle = nextAngle;
2421                foundDone = nextSegment->done(nextAngle);
2422            }
2423        }
2424        if (nextSegment->done()) {
2425            continue;
2426        }
2427        if (nextSegment->isTiny(nextAngle)) {
2428            continue;
2429        }
2430        if (!activeAngle) {
2431            nextSegment->markAndChaseDoneUnary(nextAngle->start(), nextAngle->end());
2432        }
2433        SkOpSpan* last = nextAngle->lastMarked();
2434        if (last) {
2435            SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
2436            // assert here that span isn't already in array
2437            *chase->append() = last;
2438#if DEBUG_WINDING
2439            SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
2440                    last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
2441                    last->fSmall);
2442#endif
2443        }
2444    } while ((nextAngle = nextAngle->next()) != angle);
2445    markDoneUnary(SkMin32(startIndex, endIndex));
2446    if (!foundAngle) {
2447        return NULL;
2448    }
2449    *nextStart = foundAngle->start();
2450    *nextEnd = foundAngle->end();
2451    nextSegment = foundAngle->segment();
2452#if DEBUG_WINDING
2453    SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2454            __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
2455 #endif
2456    return nextSegment;
2457}
2458
2459SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsortable) {
2460    const int startIndex = *nextStart;
2461    const int endIndex = *nextEnd;
2462    SkASSERT(startIndex != endIndex);
2463    SkDEBUGCODE(int count = fTs.count());
2464    SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2465    int step = SkSign32(endIndex - startIndex);
2466    int end = nextExactSpan(startIndex, step);
2467    SkASSERT(end >= 0);
2468    SkOpSpan* endSpan = &fTs[end];
2469    SkOpSegment* other;
2470// Detect cases where all the ends canceled out (e.g.,
2471// there is no angle) and therefore there's only one valid connection
2472    if (isSimple(end) || !spanToAngle(end, startIndex)) {
2473#if DEBUG_WINDING
2474        SkDebugf("%s simple\n", __FUNCTION__);
2475#endif
2476        int min = SkMin32(startIndex, endIndex);
2477        if (fTs[min].fDone) {
2478            return NULL;
2479        }
2480        markDone(min, 1);
2481        other = endSpan->fOther;
2482        *nextStart = endSpan->fOtherIndex;
2483        double startT = other->fTs[*nextStart].fT;
2484        // FIXME: I don't know why the logic here is difference from the winding case
2485        SkDEBUGCODE(bool firstLoop = true;)
2486        if ((approximately_less_than_zero(startT) && step < 0)
2487                || (approximately_greater_than_one(startT) && step > 0)) {
2488            step = -step;
2489            SkDEBUGCODE(firstLoop = false;)
2490        }
2491        do {
2492            *nextEnd = *nextStart;
2493            do {
2494                *nextEnd += step;
2495            } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
2496            if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) {
2497                break;
2498            }
2499            SkASSERT(firstLoop);
2500            SkDEBUGCODE(firstLoop = false;)
2501            step = -step;
2502        } while (true);
2503        SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
2504        return other;
2505    }
2506    SkASSERT(startIndex - endIndex != 0);
2507    SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2508    // parallel block above with presorted version
2509    SkOpAngle* angle = spanToAngle(end, startIndex);
2510    SkASSERT(angle);
2511#if DEBUG_SORT
2512    SkDebugf("%s\n", __FUNCTION__);
2513    angle->debugLoop();
2514#endif
2515    SkOpAngle* nextAngle = angle->next();
2516    const SkOpAngle* foundAngle = NULL;
2517    bool foundDone = false;
2518    SkOpSegment* nextSegment;
2519    int activeCount = 0;
2520    do {
2521        nextSegment = nextAngle->segment();
2522        ++activeCount;
2523        if (!foundAngle || (foundDone && activeCount & 1)) {
2524            if (nextSegment->isTiny(nextAngle)) {
2525                *unsortable = true;
2526                return NULL;
2527            }
2528            foundAngle = nextAngle;
2529            if (!(foundDone = nextSegment->done(nextAngle))) {
2530                break;
2531            }
2532        }
2533        nextAngle = nextAngle->next();
2534    } while (nextAngle != angle);
2535    markDone(SkMin32(startIndex, endIndex), 1);
2536    if (!foundAngle) {
2537        return NULL;
2538    }
2539    *nextStart = foundAngle->start();
2540    *nextEnd = foundAngle->end();
2541    nextSegment = foundAngle->segment();
2542#if DEBUG_WINDING
2543    SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2544            __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
2545 #endif
2546    return nextSegment;
2547}
2548
2549int SkOpSegment::findStartSpan(int startIndex) const {
2550    int index = startIndex;
2551    const SkOpSpan* span = &fTs[index];
2552    const SkPoint& firstPt = span->fPt;
2553    double firstT = span->fT;
2554    do {
2555        if (index > 0) {
2556            if (span->fT != firstT) {
2557                break;
2558            }
2559            if (!SkDPoint::ApproximatelyEqual(firstPt, fTs[index].fPt)) {
2560                return -1;
2561            }
2562        }
2563        ++index;
2564        if (span->fTiny) {
2565            if (!SkDPoint::ApproximatelyEqual(firstPt, fTs[index].fPt)) {
2566                return -1;
2567            }
2568            firstT = fTs[index++].fT;
2569        }
2570        span = &fTs[index];
2571    } while (true);
2572    return index;
2573}
2574
2575int SkOpSegment::findExactT(double t, const SkOpSegment* match) const {
2576    int count = this->count();
2577    for (int index = 0; index < count; ++index) {
2578        const SkOpSpan& span = fTs[index];
2579        if (span.fT == t && span.fOther == match) {
2580            return index;
2581        }
2582    }
2583    SkASSERT(0);
2584    return -1;
2585}
2586
2587int SkOpSegment::findT(double t, const SkOpSegment* match) const {
2588    int count = this->count();
2589    for (int index = 0; index < count; ++index) {
2590        const SkOpSpan& span = fTs[index];
2591        if (approximately_equal_orderable(span.fT, t) && span.fOther == match) {
2592            return index;
2593        }
2594    }
2595    SkASSERT(0);
2596    return -1;
2597}
2598
2599SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable) {
2600    // iterate through T intersections and return topmost
2601    // topmost tangent from y-min to first pt is closer to horizontal
2602    SkASSERT(!done());
2603    int firstT = -1;
2604    /* SkPoint topPt = */ activeLeftTop(true, &firstT);
2605    if (firstT < 0) {
2606        *unsortable = true;
2607        firstT = 0;
2608        while (fTs[firstT].fDone) {
2609            SkASSERT(firstT < fTs.count());
2610            ++firstT;
2611        }
2612        *tIndexPtr = firstT;
2613        *endIndexPtr = nextExactSpan(firstT, 1);
2614        return this;
2615    }
2616    // sort the edges to find the leftmost
2617    int step = 1;
2618    int end;
2619    if (span(firstT).fDone || (end = nextSpan(firstT, step)) == -1) {
2620        step = -1;
2621        end = nextSpan(firstT, step);
2622        SkASSERT(end != -1);
2623    }
2624    // if the topmost T is not on end, or is three-way or more, find left
2625    // look for left-ness from tLeft to firstT (matching y of other)
2626    SkASSERT(firstT - end != 0);
2627    SkOpAngle* markAngle = spanToAngle(firstT, end);
2628    if (!markAngle) {
2629        markAngle = addSingletonAngles(firstT, step);
2630    }
2631    markAngle->markStops();
2632    const SkOpAngle* baseAngle = markAngle->findFirst();
2633    if (!baseAngle) {
2634        return NULL;  // nothing to do
2635    }
2636    SkScalar top = SK_ScalarMax;
2637    const SkOpAngle* firstAngle = NULL;
2638    const SkOpAngle* angle = baseAngle;
2639    do {
2640        if (!angle->unorderable()) {
2641            SkOpSegment* next = angle->segment();
2642            SkPathOpsBounds bounds;
2643            next->subDivideBounds(angle->end(), angle->start(), &bounds);
2644            if (approximately_greater(top, bounds.fTop)) {
2645                top = bounds.fTop;
2646                firstAngle = angle;
2647            }
2648        }
2649        angle = angle->next();
2650    } while (angle != baseAngle);
2651    SkASSERT(firstAngle);
2652#if DEBUG_SORT
2653    SkDebugf("%s\n", __FUNCTION__);
2654    firstAngle->debugLoop();
2655#endif
2656    // skip edges that have already been processed
2657    angle = firstAngle;
2658    SkOpSegment* leftSegment;
2659    do {
2660//        SkASSERT(!angle->unsortable());
2661        leftSegment = angle->segment();
2662        *tIndexPtr = angle->end();
2663        *endIndexPtr = angle->start();
2664        angle = angle->next();
2665    } while (leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone);
2666    if (leftSegment->verb() >= SkPath::kQuad_Verb) {
2667        const int tIndex = *tIndexPtr;
2668        const int endIndex = *endIndexPtr;
2669        if (!leftSegment->clockwise(tIndex, endIndex)) {
2670            bool swap = !leftSegment->monotonicInY(tIndex, endIndex)
2671                    && !leftSegment->serpentine(tIndex, endIndex);
2672    #if DEBUG_SWAP_TOP
2673            SkDebugf("%s swap=%d serpentine=%d containedByEnds=%d monotonic=%d\n", __FUNCTION__,
2674                    swap,
2675                    leftSegment->serpentine(tIndex, endIndex),
2676                    leftSegment->controlsContainedByEnds(tIndex, endIndex),
2677                    leftSegment->monotonicInY(tIndex, endIndex));
2678    #endif
2679            if (swap) {
2680    // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first
2681    // sorted but merely the first not already processed (i.e., not done)
2682                SkTSwap(*tIndexPtr, *endIndexPtr);
2683            }
2684        }
2685    }
2686    SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny);
2687    return leftSegment;
2688}
2689
2690int SkOpSegment::firstActive(int tIndex) const {
2691    while (fTs[tIndex].fTiny) {
2692        SkASSERT(!isCanceled(tIndex));
2693        ++tIndex;
2694    }
2695    return tIndex;
2696}
2697
2698// FIXME: not crazy about this
2699// when the intersections are performed, the other index is into an
2700// incomplete array. As the array grows, the indices become incorrect
2701// while the following fixes the indices up again, it isn't smart about
2702// skipping segments whose indices are already correct
2703// assuming we leave the code that wrote the index in the first place
2704// FIXME: if called after remove, this needs to correct tiny
2705void SkOpSegment::fixOtherTIndex() {
2706    int iCount = fTs.count();
2707    for (int i = 0; i < iCount; ++i) {
2708        SkOpSpan& iSpan = fTs[i];
2709        double oT = iSpan.fOtherT;
2710        SkOpSegment* other = iSpan.fOther;
2711        int oCount = other->fTs.count();
2712        SkDEBUGCODE(iSpan.fOtherIndex = -1);
2713        for (int o = 0; o < oCount; ++o) {
2714            SkOpSpan& oSpan = other->fTs[o];
2715            if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan.fT) {
2716                iSpan.fOtherIndex = o;
2717                oSpan.fOtherIndex = i;
2718                break;
2719            }
2720        }
2721        SkASSERT(iSpan.fOtherIndex >= 0);
2722    }
2723}
2724
2725void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
2726    fDoneSpans = 0;
2727    fOperand = operand;
2728    fXor = evenOdd;
2729    fPts = pts;
2730    fVerb = verb;
2731    fLoop = fSmall = fTiny = false;
2732}
2733
2734void SkOpSegment::initWinding(int start, int end, SkOpAngle::IncludeType angleIncludeType) {
2735    int local = spanSign(start, end);
2736    if (angleIncludeType == SkOpAngle::kBinarySingle) {
2737        int oppLocal = oppSign(start, end);
2738        (void) markAndChaseWinding(start, end, local, oppLocal);
2739    // OPTIMIZATION: the reverse mark and chase could skip the first marking
2740        (void) markAndChaseWinding(end, start, local, oppLocal);
2741    } else {
2742        (void) markAndChaseWinding(start, end, local);
2743    // OPTIMIZATION: the reverse mark and chase could skip the first marking
2744        (void) markAndChaseWinding(end, start, local);
2745    }
2746}
2747
2748/*
2749when we start with a vertical intersect, we try to use the dx to determine if the edge is to
2750the left or the right of vertical. This determines if we need to add the span's
2751sign or not. However, this isn't enough.
2752If the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed.
2753If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
2754from has the same x direction as this span, the winding should change. If the dx is opposite, then
2755the same winding is shared by both.
2756*/
2757void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkScalar hitDx,
2758                              int oppWind, SkScalar hitOppDx) {
2759    SkASSERT(hitDx || !winding);
2760    SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
2761    SkASSERT(dx);
2762    int windVal = windValue(SkMin32(start, end));
2763#if DEBUG_WINDING_AT_T
2764    SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
2765            hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
2766#endif
2767    int sideWind = winding + (dx < 0 ? windVal : -windVal);
2768    if (abs(winding) < abs(sideWind)) {
2769        winding = sideWind;
2770    }
2771#if DEBUG_WINDING_AT_T
2772    SkDebugf(" winding=%d\n", winding);
2773#endif
2774    SkDEBUGCODE(int oppLocal = oppSign(start, end));
2775    SkASSERT(hitOppDx || !oppWind || !oppLocal);
2776    int oppWindVal = oppValue(SkMin32(start, end));
2777    if (!oppWind) {
2778        oppWind = dx < 0 ? oppWindVal : -oppWindVal;
2779    } else if (hitOppDx * dx >= 0) {
2780        int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
2781        if (abs(oppWind) < abs(oppSideWind)) {
2782            oppWind = oppSideWind;
2783        }
2784    }
2785    (void) markAndChaseWinding(start, end, winding, oppWind);
2786    // OPTIMIZATION: the reverse mark and chase could skip the first marking
2787    (void) markAndChaseWinding(end, start, winding, oppWind);
2788}
2789
2790bool SkOpSegment::inLoop(const SkOpAngle* baseAngle, int spanCount, int* indexPtr) const {
2791    if (!baseAngle->inLoop()) {
2792        return false;
2793    }
2794    int index = *indexPtr;
2795    int froIndex = fTs[index].fFromAngleIndex;
2796    int toIndex = fTs[index].fToAngleIndex;
2797    while (++index < spanCount) {
2798        int nextFro = fTs[index].fFromAngleIndex;
2799        int nextTo = fTs[index].fToAngleIndex;
2800        if (froIndex != nextFro || toIndex != nextTo) {
2801            break;
2802        }
2803    }
2804    *indexPtr = index;
2805    return true;
2806}
2807
2808// OPTIMIZE: successive calls could start were the last leaves off
2809// or calls could specialize to walk forwards or backwards
2810bool SkOpSegment::isMissing(double startT, const SkPoint& pt) const {
2811    int tCount = fTs.count();
2812    for (int index = 0; index < tCount; ++index) {
2813        const SkOpSpan& span = fTs[index];
2814        if (approximately_zero(startT - span.fT) && pt == span.fPt) {
2815            return false;
2816        }
2817    }
2818    return true;
2819}
2820
2821bool SkOpSegment::isSimple(int end) const {
2822#if 1
2823    int count = fTs.count();
2824    if (count == 2) {
2825        return true;
2826    }
2827    double t = fTs[end].fT;
2828    if (approximately_less_than_zero(t)) {
2829        return !approximately_less_than_zero(fTs[1].fT);
2830    }
2831    if (approximately_greater_than_one(t)) {
2832        return !approximately_greater_than_one(fTs[count - 2].fT);
2833    }
2834    return false;
2835#else
2836    // OPTIMIZE: code could be rejiggered to use this simpler test. To make this work, a little
2837    // more logic is required to ignore the dangling canceled out spans
2838    const SkOpSpan& span = fTs[end];
2839    return span.fFromAngleIndex < 0 && span.fToAngleIndex < 0;
2840#endif
2841}
2842
2843bool SkOpSegment::isSmall(const SkOpAngle* angle) const {
2844    int start = angle->start();
2845    int end = angle->end();
2846    const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
2847    return mSpan.fSmall;
2848}
2849
2850bool SkOpSegment::isTiny(const SkOpAngle* angle) const {
2851    int start = angle->start();
2852    int end = angle->end();
2853    const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
2854    return mSpan.fTiny;
2855}
2856
2857bool SkOpSegment::isTiny(int index) const {
2858    return fTs[index].fTiny;
2859}
2860
2861// look pair of active edges going away from coincident edge
2862// one of them should be the continuation of other
2863// if both are active, look to see if they both the connect to another coincident pair
2864// if at least one is a line, then make the pair coincident
2865// if neither is a line, test for coincidence
2866bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, int step, bool cancel) {
2867    int otherTIndex = other->findT(otherT, this);
2868    int next = other->nextExactSpan(otherTIndex, step);
2869    int otherMin = SkMin32(otherTIndex, next);
2870    int otherWind = other->span(otherMin).fWindValue;
2871    if (otherWind == 0) {
2872        return false;
2873    }
2874    SkASSERT(next >= 0);
2875    int tIndex = 0;
2876    do {
2877        SkOpSpan* test = &fTs[tIndex];
2878        SkASSERT(test->fT == 0);
2879        if (test->fOther == other || test->fOtherT != 1) {
2880            continue;
2881        }
2882        SkPoint startPt, endPt;
2883        double endT;
2884        if (findCoincidentMatch(test, other, otherTIndex, next, step, &startPt, &endPt, &endT)) {
2885            SkOpSegment* match = test->fOther;
2886            if (cancel) {
2887                match->addTCancel(startPt, endPt, other);
2888            } else {
2889                match->addTCoincident(startPt, endPt, endT, other);
2890            }
2891            return true;
2892        }
2893    } while (fTs[++tIndex].fT == 0);
2894    return false;
2895}
2896
2897// this span is excluded by the winding rule -- chase the ends
2898// as long as they are unambiguous to mark connections as done
2899// and give them the same winding value
2900
2901SkOpSpan* SkOpSegment::markAndChaseDoneBinary(int index, int endIndex) {
2902    int step = SkSign32(endIndex - index);
2903    int min = SkMin32(index, endIndex);
2904    markDoneBinary(min);
2905    SkOpSpan* last;
2906    SkOpSegment* other = this;
2907    while ((other = other->nextChase(&index, step, &min, &last))) {
2908        if (other->done()) {
2909            return NULL;
2910        }
2911        other->markDoneBinary(min);
2912    }
2913    return last;
2914}
2915
2916SkOpSpan* SkOpSegment::markAndChaseDoneUnary(int index, int endIndex) {
2917    int step = SkSign32(endIndex - index);
2918    int min = SkMin32(index, endIndex);
2919    markDoneUnary(min);
2920    SkOpSpan* last;
2921    SkOpSegment* other = this;
2922    while ((other = other->nextChase(&index, step, &min, &last))) {
2923        if (other->done()) {
2924            return NULL;
2925        }
2926        other->markDoneUnary(min);
2927    }
2928    return last;
2929}
2930
2931SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding) {
2932    int index = angle->start();
2933    int endIndex = angle->end();
2934    int step = SkSign32(endIndex - index);
2935    int min = SkMin32(index, endIndex);
2936    markWinding(min, winding);
2937    SkOpSpan* last;
2938    SkOpSegment* other = this;
2939    while ((other = other->nextChase(&index, step, &min, &last))) {
2940        if (other->fTs[min].fWindSum != SK_MinS32) {
2941            SkASSERT(other->fTs[min].fWindSum == winding);
2942            return NULL;
2943        }
2944        other->markWinding(min, winding);
2945    }
2946    return last;
2947}
2948
2949SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding) {
2950    int min = SkMin32(index, endIndex);
2951    int step = SkSign32(endIndex - index);
2952    markWinding(min, winding);
2953    SkOpSpan* last;
2954    SkOpSegment* other = this;
2955    while ((other = other->nextChase(&index, step, &min, &last))) {
2956        if (other->fTs[min].fWindSum != SK_MinS32) {
2957            SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
2958            return NULL;
2959        }
2960        other->markWinding(min, winding);
2961    }
2962    return last;
2963}
2964
2965SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
2966    int min = SkMin32(index, endIndex);
2967    int step = SkSign32(endIndex - index);
2968    markWinding(min, winding, oppWinding);
2969    SkOpSpan* last;
2970    SkOpSegment* other = this;
2971    while ((other = other->nextChase(&index, step, &min, &last))) {
2972        if (other->fTs[min].fWindSum != SK_MinS32) {
2973            SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
2974            return NULL;
2975        }
2976        other->markWinding(min, winding, oppWinding);
2977    }
2978    return last;
2979}
2980
2981SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding) {
2982    int start = angle->start();
2983    int end = angle->end();
2984    return markAndChaseWinding(start, end, winding, oppWinding);
2985}
2986
2987SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
2988    SkASSERT(angle->segment() == this);
2989    if (UseInnerWinding(maxWinding, sumWinding)) {
2990        maxWinding = sumWinding;
2991    }
2992    SkOpSpan* last = markAndChaseWinding(angle, maxWinding);
2993#if DEBUG_WINDING
2994    if (last) {
2995        SkDebugf("%s last id=%d windSum=", __FUNCTION__,
2996                last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2997        SkPathOpsDebug::WindingPrintf(last->fWindSum);
2998        SkDebugf(" small=%d\n", last->fSmall);
2999    }
3000#endif
3001    return last;
3002}
3003
3004SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
3005                                 int oppSumWinding, const SkOpAngle* angle) {
3006    SkASSERT(angle->segment() == this);
3007    if (UseInnerWinding(maxWinding, sumWinding)) {
3008        maxWinding = sumWinding;
3009    }
3010    if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
3011        oppMaxWinding = oppSumWinding;
3012    }
3013    SkOpSpan* last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3014#if DEBUG_WINDING
3015    if (last) {
3016        SkDebugf("%s last id=%d windSum=", __FUNCTION__,
3017                last->fOther->fTs[last->fOtherIndex].fOther->debugID());
3018        SkPathOpsDebug::WindingPrintf(last->fWindSum);
3019        SkDebugf(" small=%d\n", last->fSmall);
3020    }
3021#endif
3022    return last;
3023}
3024
3025// FIXME: this should also mark spans with equal (x,y)
3026// This may be called when the segment is already marked done. While this
3027// wastes time, it shouldn't do any more than spin through the T spans.
3028// OPTIMIZATION: abort on first done found (assuming that this code is
3029// always called to mark segments done).
3030void SkOpSegment::markDone(int index, int winding) {
3031  //  SkASSERT(!done());
3032    SkASSERT(winding);
3033    double referenceT = fTs[index].fT;
3034    int lesser = index;
3035    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3036        markOneDone(__FUNCTION__, lesser, winding);
3037    }
3038    do {
3039        markOneDone(__FUNCTION__, index, winding);
3040    } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3041    debugValidate();
3042}
3043
3044void SkOpSegment::markDoneBinary(int index) {
3045    double referenceT = fTs[index].fT;
3046    int lesser = index;
3047    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3048        markOneDoneBinary(__FUNCTION__, lesser);
3049    }
3050    do {
3051        markOneDoneBinary(__FUNCTION__, index);
3052    } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3053    debugValidate();
3054}
3055
3056void SkOpSegment::markDoneUnary(int index) {
3057    double referenceT = fTs[index].fT;
3058    int lesser = index;
3059    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3060        markOneDoneUnary(__FUNCTION__, lesser);
3061    }
3062    do {
3063        markOneDoneUnary(__FUNCTION__, index);
3064    } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3065    debugValidate();
3066}
3067
3068void SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) {
3069    SkOpSpan* span = markOneWinding(funName, tIndex, winding);
3070    if (!span || span->fDone) {
3071        return;
3072    }
3073    span->fDone = true;
3074    fDoneSpans++;
3075}
3076
3077void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) {
3078    SkOpSpan* span = verifyOneWinding(funName, tIndex);
3079    if (!span) {
3080        return;
3081    }
3082    SkASSERT(!span->fDone);
3083    span->fDone = true;
3084    fDoneSpans++;
3085}
3086
3087void SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) {
3088    SkOpSpan* span = verifyOneWindingU(funName, tIndex);
3089    if (!span) {
3090        return;
3091    }
3092    if (span->fWindSum == SK_MinS32) {
3093        SkDebugf("%s uncomputed\n", __FUNCTION__);
3094    }
3095    SkASSERT(!span->fDone);
3096    span->fDone = true;
3097    fDoneSpans++;
3098}
3099
3100SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding) {
3101    SkOpSpan& span = fTs[tIndex];
3102    if (span.fDone && !span.fSmall) {
3103        return NULL;
3104    }
3105#if DEBUG_MARK_DONE
3106    debugShowNewWinding(funName, span, winding);
3107#endif
3108    SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3109    SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum);
3110    span.fWindSum = winding;
3111    return &span;
3112}
3113
3114SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding,
3115                                      int oppWinding) {
3116    SkOpSpan& span = fTs[tIndex];
3117    if (span.fDone && !span.fSmall) {
3118        return NULL;
3119    }
3120#if DEBUG_MARK_DONE
3121    debugShowNewWinding(funName, span, winding, oppWinding);
3122#endif
3123    SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3124    SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum);
3125    span.fWindSum = winding;
3126    SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3127    SkASSERT(abs(oppWinding) <= SkPathOpsDebug::gMaxWindSum);
3128    span.fOppSum = oppWinding;
3129    debugValidate();
3130    return &span;
3131}
3132
3133// from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
3134bool SkOpSegment::clockwise(int tStart, int tEnd) const {
3135    SkASSERT(fVerb != SkPath::kLine_Verb);
3136    SkPoint edge[4];
3137    subDivide(tStart, tEnd, edge);
3138    int points = SkPathOpsVerbToPoints(fVerb);
3139    double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY);
3140    if (fVerb == SkPath::kCubic_Verb) {
3141        SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY);
3142        if (edge[1].fY < lesser && edge[2].fY < lesser) {
3143            SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1].fY} }};
3144            SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3].fY} }};
3145            if (SkIntersections::Test(tangent1, tangent2)) {
3146                SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT);
3147                sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY);
3148                sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY);
3149                return sum <= 0;
3150            }
3151        }
3152    }
3153    for (int idx = 0; idx < points; ++idx){
3154        sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
3155    }
3156    return sum <= 0;
3157}
3158
3159bool SkOpSegment::monotonicInY(int tStart, int tEnd) const {
3160    if (fVerb == SkPath::kLine_Verb) {
3161        return false;
3162    }
3163    if (fVerb == SkPath::kQuad_Verb) {
3164        SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
3165        return dst.monotonicInY();
3166    }
3167    SkASSERT(fVerb == SkPath::kCubic_Verb);
3168    SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
3169    return dst.monotonicInY();
3170}
3171
3172bool SkOpSegment::serpentine(int tStart, int tEnd) const {
3173    if (fVerb != SkPath::kCubic_Verb) {
3174        return false;
3175    }
3176    SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
3177    return dst.serpentine();
3178}
3179
3180SkOpSpan* SkOpSegment::verifyOneWinding(const char* funName, int tIndex) {
3181    SkOpSpan& span = fTs[tIndex];
3182    if (span.fDone) {
3183        return NULL;
3184    }
3185#if DEBUG_MARK_DONE
3186    debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3187#endif
3188// If the prior angle in the sort is unorderable, the winding sum may not be computable.
3189// To enable the assert, the 'prior is unorderable' state could be
3190// piped down to this test, but not sure it's worth it.
3191// (Once the sort order is stored in the span, this test may be feasible.)
3192//    SkASSERT(span.fWindSum != SK_MinS32);
3193//    SkASSERT(span.fOppSum != SK_MinS32);
3194    return &span;
3195}
3196
3197SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) {
3198    SkOpSpan& span = fTs[tIndex];
3199    if (span.fDone) {
3200        return NULL;
3201    }
3202#if DEBUG_MARK_DONE
3203    debugShowNewWinding(funName, span, span.fWindSum);
3204#endif
3205// If the prior angle in the sort is unorderable, the winding sum may not be computable.
3206// To enable the assert, the 'prior is unorderable' state could be
3207// piped down to this test, but not sure it's worth it.
3208// (Once the sort order is stored in the span, this test may be feasible.)
3209//    SkASSERT(span.fWindSum != SK_MinS32);
3210    return &span;
3211}
3212
3213// note that just because a span has one end that is unsortable, that's
3214// not enough to mark it done. The other end may be sortable, allowing the
3215// span to be added.
3216// FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
3217void SkOpSegment::markUnsortable(int start, int end) {
3218    SkOpSpan* span = &fTs[start];
3219    if (start < end) {
3220#if DEBUG_UNSORTABLE
3221        debugShowNewWinding(__FUNCTION__, *span, 0);
3222#endif
3223        span->fUnsortableStart = true;
3224    } else {
3225        --span;
3226#if DEBUG_UNSORTABLE
3227        debugShowNewWinding(__FUNCTION__, *span, 0);
3228#endif
3229        span->fUnsortableEnd = true;
3230    }
3231    if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
3232        debugValidate();
3233        return;
3234    }
3235    span->fDone = true;
3236    fDoneSpans++;
3237    debugValidate();
3238}
3239
3240void SkOpSegment::markWinding(int index, int winding) {
3241//    SkASSERT(!done());
3242    SkASSERT(winding);
3243    double referenceT = fTs[index].fT;
3244    int lesser = index;
3245    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3246        markOneWinding(__FUNCTION__, lesser, winding);
3247    }
3248    do {
3249        markOneWinding(__FUNCTION__, index, winding);
3250   } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3251    debugValidate();
3252}
3253
3254void SkOpSegment::markWinding(int index, int winding, int oppWinding) {
3255//    SkASSERT(!done());
3256    SkASSERT(winding || oppWinding);
3257    double referenceT = fTs[index].fT;
3258    int lesser = index;
3259    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3260        markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
3261    }
3262    do {
3263        markOneWinding(__FUNCTION__, index, winding, oppWinding);
3264   } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3265    debugValidate();
3266}
3267
3268void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) {
3269    int nextDoorWind = SK_MaxS32;
3270    int nextOppWind = SK_MaxS32;
3271    // prefer exact matches
3272    if (tIndex > 0) {
3273        const SkOpSpan& below = fTs[tIndex - 1];
3274        if (below.fT == t) {
3275            nextDoorWind = below.fWindValue;
3276            nextOppWind = below.fOppValue;
3277        }
3278    }
3279    if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3280        const SkOpSpan& above = fTs[tIndex + 1];
3281        if (above.fT == t) {
3282            nextDoorWind = above.fWindValue;
3283            nextOppWind = above.fOppValue;
3284        }
3285    }
3286    if (nextDoorWind == SK_MaxS32 && tIndex > 0) {
3287        const SkOpSpan& below = fTs[tIndex - 1];
3288        if (approximately_negative(t - below.fT)) {
3289            nextDoorWind = below.fWindValue;
3290            nextOppWind = below.fOppValue;
3291        }
3292    }
3293    if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3294        const SkOpSpan& above = fTs[tIndex + 1];
3295        if (approximately_negative(above.fT - t)) {
3296            nextDoorWind = above.fWindValue;
3297            nextOppWind = above.fOppValue;
3298        }
3299    }
3300    if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3301        const SkOpSpan& below = fTs[tIndex - 1];
3302        nextDoorWind = below.fWindValue;
3303        nextOppWind = below.fOppValue;
3304    }
3305    if (nextDoorWind != SK_MaxS32) {
3306        SkOpSpan& newSpan = fTs[tIndex];
3307        newSpan.fWindValue = nextDoorWind;
3308        newSpan.fOppValue = nextOppWind;
3309        if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
3310            newSpan.fDone = true;
3311            ++fDoneSpans;
3312        }
3313    }
3314}
3315
3316// return span if when chasing, two or more radiating spans are not done
3317// OPTIMIZATION: ? multiple spans is detected when there is only one valid
3318// candidate and the remaining spans have windValue == 0 (canceled by
3319// coincidence). The coincident edges could either be removed altogether,
3320// or this code could be more complicated in detecting this case. Worth it?
3321bool SkOpSegment::multipleSpans(int end) const {
3322    return end > 0 && end < fTs.count() - 1;
3323}
3324
3325bool SkOpSegment::nextCandidate(int* start, int* end) const {
3326    while (fTs[*end].fDone) {
3327        if (fTs[*end].fT == 1) {
3328            return false;
3329        }
3330        ++(*end);
3331    }
3332    *start = *end;
3333    *end = nextExactSpan(*start, 1);
3334    return true;
3335}
3336
3337SkOpSegment* SkOpSegment::nextChase(int* index, const int step, int* min, SkOpSpan** last) {
3338    int end = nextExactSpan(*index, step);
3339    SkASSERT(end >= 0);
3340    if (fTs[end].fSmall) {
3341        *last = NULL;
3342        return NULL;
3343    }
3344    if (multipleSpans(end)) {
3345        *last = &fTs[end];
3346        return NULL;
3347    }
3348    const SkOpSpan& endSpan = fTs[end];
3349    SkOpSegment* other = endSpan.fOther;
3350    *index = endSpan.fOtherIndex;
3351    SkASSERT(*index >= 0);
3352    int otherEnd = other->nextExactSpan(*index, step);
3353    SkASSERT(otherEnd >= 0);
3354    *min = SkMin32(*index, otherEnd);
3355    if (other->fTs[*min].fSmall) {
3356        *last = NULL;
3357        return NULL;
3358    }
3359    return other;
3360}
3361
3362// This has callers for two different situations: one establishes the end
3363// of the current span, and one establishes the beginning of the next span
3364// (thus the name). When this is looking for the end of the current span,
3365// coincidence is found when the beginning Ts contain -step and the end
3366// contains step. When it is looking for the beginning of the next, the
3367// first Ts found can be ignored and the last Ts should contain -step.
3368// OPTIMIZATION: probably should split into two functions
3369int SkOpSegment::nextSpan(int from, int step) const {
3370    const SkOpSpan& fromSpan = fTs[from];
3371    int count = fTs.count();
3372    int to = from;
3373    while (step > 0 ? ++to < count : --to >= 0) {
3374        const SkOpSpan& span = fTs[to];
3375        if (approximately_zero(span.fT - fromSpan.fT)) {
3376            continue;
3377        }
3378        return to;
3379    }
3380    return -1;
3381}
3382
3383// FIXME
3384// this returns at any difference in T, vs. a preset minimum. It may be
3385// that all callers to nextSpan should use this instead.
3386int SkOpSegment::nextExactSpan(int from, int step) const {
3387    int to = from;
3388    if (step < 0) {
3389        const SkOpSpan& fromSpan = fTs[from];
3390        while (--to >= 0) {
3391            const SkOpSpan& span = fTs[to];
3392            if (precisely_negative(fromSpan.fT - span.fT) || span.fTiny) {
3393                continue;
3394            }
3395            return to;
3396        }
3397    } else {
3398        while (fTs[from].fTiny) {
3399            from++;
3400        }
3401        const SkOpSpan& fromSpan = fTs[from];
3402        int count = fTs.count();
3403        while (++to < count) {
3404            const SkOpSpan& span = fTs[to];
3405            if (precisely_negative(span.fT - fromSpan.fT)) {
3406                continue;
3407            }
3408            return to;
3409        }
3410    }
3411    return -1;
3412}
3413
3414void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
3415        int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) {
3416    int deltaSum = spanSign(index, endIndex);
3417    int oppDeltaSum = oppSign(index, endIndex);
3418    if (operand()) {
3419        *maxWinding = *sumSuWinding;
3420        *sumWinding = *sumSuWinding -= deltaSum;
3421        *oppMaxWinding = *sumMiWinding;
3422        *oppSumWinding = *sumMiWinding -= oppDeltaSum;
3423    } else {
3424        *maxWinding = *sumMiWinding;
3425        *sumWinding = *sumMiWinding -= deltaSum;
3426        *oppMaxWinding = *sumSuWinding;
3427        *oppSumWinding = *sumSuWinding -= oppDeltaSum;
3428    }
3429    SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum);
3430    SkASSERT(abs(*oppSumWinding) <= SkPathOpsDebug::gMaxWindSum);
3431}
3432
3433void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding,
3434        int* maxWinding, int* sumWinding) {
3435    int deltaSum = spanSign(index, endIndex);
3436    *maxWinding = *sumMiWinding;
3437    *sumWinding = *sumMiWinding -= deltaSum;
3438    SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum);
3439}
3440
3441void SkOpSegment::sortAngles() {
3442    int spanCount = fTs.count();
3443    if (spanCount <= 2) {
3444        return;
3445    }
3446    int index = 0;
3447    do {
3448        int fromIndex = fTs[index].fFromAngleIndex;
3449        int toIndex = fTs[index].fToAngleIndex;
3450        if (fromIndex < 0 && toIndex < 0) {
3451            index += 1;
3452            continue;
3453        }
3454        SkOpAngle* baseAngle = NULL;
3455        if (fromIndex >= 0) {
3456            baseAngle = &this->angle(fromIndex);
3457            if (inLoop(baseAngle, spanCount, &index)) {
3458                continue;
3459            }
3460        }
3461#if DEBUG_ANGLE
3462        bool wroteAfterHeader = false;
3463#endif
3464        if (toIndex >= 0) {
3465            SkOpAngle* toAngle = &this->angle(toIndex);
3466            if (!baseAngle) {
3467                baseAngle = toAngle;
3468                if (inLoop(baseAngle, spanCount, &index)) {
3469                    continue;
3470                }
3471            } else {
3472                SkDEBUGCODE(int newIndex = index);
3473                SkASSERT(!inLoop(baseAngle, spanCount, &newIndex) && newIndex == index);
3474#if DEBUG_ANGLE
3475                SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT,
3476                        index);
3477                wroteAfterHeader = true;
3478#endif
3479                baseAngle->insert(toAngle);
3480            }
3481        }
3482        int nextFrom, nextTo;
3483        int firstIndex = index;
3484        do {
3485            SkOpSpan& span = fTs[index];
3486            SkOpSegment* other = span.fOther;
3487            SkOpSpan& oSpan = other->fTs[span.fOtherIndex];
3488            int otherAngleIndex = oSpan.fFromAngleIndex;
3489            if (otherAngleIndex >= 0) {
3490#if DEBUG_ANGLE
3491                if (!wroteAfterHeader) {
3492                    SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT,
3493                            index);
3494                    wroteAfterHeader = true;
3495                }
3496#endif
3497                baseAngle->insert(&other->angle(otherAngleIndex));
3498            }
3499            otherAngleIndex = oSpan.fToAngleIndex;
3500            if (otherAngleIndex >= 0) {
3501#if DEBUG_ANGLE
3502                if (!wroteAfterHeader) {
3503                    SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT,
3504                            index);
3505                    wroteAfterHeader = true;
3506                }
3507#endif
3508                baseAngle->insert(&other->angle(otherAngleIndex));
3509            }
3510            if (++index == spanCount) {
3511                break;
3512            }
3513            nextFrom = fTs[index].fFromAngleIndex;
3514            nextTo = fTs[index].fToAngleIndex;
3515        } while (fromIndex == nextFrom && toIndex == nextTo);
3516        if (baseAngle && baseAngle->loopCount() == 1) {
3517            index = firstIndex;
3518            do {
3519                SkOpSpan& span = fTs[index];
3520                span.fFromAngleIndex = span.fToAngleIndex = -1;
3521                if (++index == spanCount) {
3522                    break;
3523                }
3524                nextFrom = fTs[index].fFromAngleIndex;
3525                nextTo = fTs[index].fToAngleIndex;
3526            } while (fromIndex == nextFrom && toIndex == nextTo);
3527            baseAngle = NULL;
3528        }
3529#if DEBUG_SORT
3530        SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
3531#endif
3532    } while (index < spanCount);
3533}
3534
3535// return true if midpoints were computed
3536bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const {
3537    SkASSERT(start != end);
3538    edge[0] = fTs[start].fPt;
3539    int points = SkPathOpsVerbToPoints(fVerb);
3540    edge[points] = fTs[end].fPt;
3541    if (fVerb == SkPath::kLine_Verb) {
3542        return false;
3543    }
3544    double startT = fTs[start].fT;
3545    double endT = fTs[end].fT;
3546    if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
3547        // don't compute midpoints if we already have them
3548        if (fVerb == SkPath::kQuad_Verb) {
3549            edge[1] = fPts[1];
3550            return false;
3551        }
3552        SkASSERT(fVerb == SkPath::kCubic_Verb);
3553        if (start < end) {
3554            edge[1] = fPts[1];
3555            edge[2] = fPts[2];
3556            return false;
3557        }
3558        edge[1] = fPts[2];
3559        edge[2] = fPts[1];
3560        return false;
3561    }
3562    const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[points].fY }};
3563    if (fVerb == SkPath::kQuad_Verb) {
3564        edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
3565    } else {
3566        SkASSERT(fVerb == SkPath::kCubic_Verb);
3567        SkDPoint ctrl[2];
3568        SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
3569        edge[1] = ctrl[0].asSkPoint();
3570        edge[2] = ctrl[1].asSkPoint();
3571    }
3572    return true;
3573}
3574
3575// return true if midpoints were computed
3576bool SkOpSegment::subDivide(int start, int end, SkDCubic* result) const {
3577    SkASSERT(start != end);
3578    (*result)[0].set(fTs[start].fPt);
3579    int points = SkPathOpsVerbToPoints(fVerb);
3580    (*result)[points].set(fTs[end].fPt);
3581    if (fVerb == SkPath::kLine_Verb) {
3582        return false;
3583    }
3584    double startT = fTs[start].fT;
3585    double endT = fTs[end].fT;
3586    if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
3587        // don't compute midpoints if we already have them
3588        if (fVerb == SkPath::kQuad_Verb) {
3589            (*result)[1].set(fPts[1]);
3590            return false;
3591        }
3592        SkASSERT(fVerb == SkPath::kCubic_Verb);
3593        if (start < end) {
3594            (*result)[1].set(fPts[1]);
3595            (*result)[2].set(fPts[2]);
3596            return false;
3597        }
3598        (*result)[1].set(fPts[2]);
3599        (*result)[2].set(fPts[1]);
3600        return false;
3601    }
3602    if (fVerb == SkPath::kQuad_Verb) {
3603        (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], startT, endT);
3604    } else {
3605        SkASSERT(fVerb == SkPath::kCubic_Verb);
3606        SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*result)[1]);
3607    }
3608    return true;
3609}
3610
3611void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const {
3612    SkPoint edge[4];
3613    subDivide(start, end, edge);
3614    (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge);
3615}
3616
3617void SkOpSegment::TrackOutsidePair(SkTArray<SkPoint, true>* outsidePts, const SkPoint& endPt,
3618        const SkPoint& startPt) {
3619    int outCount = outsidePts->count();
3620    if (outCount == 0 || endPt != (*outsidePts)[outCount - 2]) {
3621        outsidePts->push_back(endPt);
3622        outsidePts->push_back(startPt);
3623    }
3624}
3625
3626void SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoint& startPt) {
3627    int outCount = outsidePts->count();
3628    if (outCount == 0 || startPt != (*outsidePts)[outCount - 1]) {
3629        outsidePts->push_back(startPt);
3630    }
3631}
3632
3633void SkOpSegment::undoneSpan(int* start, int* end) {
3634    int tCount = fTs.count();
3635    int index;
3636    for (index = 0; index < tCount; ++index) {
3637        if (!fTs[index].fDone) {
3638            break;
3639        }
3640    }
3641    SkASSERT(index < tCount - 1);
3642    *start = index;
3643    double startT = fTs[index].fT;
3644    while (approximately_negative(fTs[++index].fT - startT))
3645        SkASSERT(index < tCount);
3646    SkASSERT(index < tCount);
3647    *end = index;
3648}
3649
3650int SkOpSegment::updateOppWinding(int index, int endIndex) const {
3651    int lesser = SkMin32(index, endIndex);
3652    int oppWinding = oppSum(lesser);
3653    int oppSpanWinding = oppSign(index, endIndex);
3654    if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
3655            && oppWinding != SK_MaxS32) {
3656        oppWinding -= oppSpanWinding;
3657    }
3658    return oppWinding;
3659}
3660
3661int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
3662    int startIndex = angle->start();
3663    int endIndex = angle->end();
3664    return updateOppWinding(endIndex, startIndex);
3665}
3666
3667int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
3668    int startIndex = angle->start();
3669    int endIndex = angle->end();
3670    return updateOppWinding(startIndex, endIndex);
3671}
3672
3673int SkOpSegment::updateWinding(int index, int endIndex) const {
3674    int lesser = SkMin32(index, endIndex);
3675    int winding = windSum(lesser);
3676    int spanWinding = spanSign(index, endIndex);
3677    if (winding && UseInnerWinding(winding - spanWinding, winding)
3678            && winding != SK_MaxS32) {
3679        winding -= spanWinding;
3680    }
3681    return winding;
3682}
3683
3684int SkOpSegment::updateWinding(const SkOpAngle* angle) const {
3685    int startIndex = angle->start();
3686    int endIndex = angle->end();
3687    return updateWinding(endIndex, startIndex);
3688}
3689
3690int SkOpSegment::updateWindingReverse(int index, int endIndex) const {
3691    int lesser = SkMin32(index, endIndex);
3692    int winding = windSum(lesser);
3693    int spanWinding = spanSign(endIndex, index);
3694    if (winding && UseInnerWindingReverse(winding - spanWinding, winding)
3695            && winding != SK_MaxS32) {
3696        winding -= spanWinding;
3697    }
3698    return winding;
3699}
3700
3701int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const {
3702    int startIndex = angle->start();
3703    int endIndex = angle->end();
3704    return updateWindingReverse(endIndex, startIndex);
3705}
3706
3707// OPTIMIZATION: does the following also work, and is it any faster?
3708// return outerWinding * innerWinding > 0
3709//      || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
3710bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
3711    SkASSERT(outerWinding != SK_MaxS32);
3712    SkASSERT(innerWinding != SK_MaxS32);
3713    int absOut = abs(outerWinding);
3714    int absIn = abs(innerWinding);
3715    bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
3716    return result;
3717}
3718
3719bool SkOpSegment::UseInnerWindingReverse(int outerWinding, int innerWinding) {
3720    SkASSERT(outerWinding != SK_MaxS32);
3721    SkASSERT(innerWinding != SK_MaxS32);
3722    int absOut = abs(outerWinding);
3723    int absIn = abs(innerWinding);
3724    bool result = absOut == absIn ? true : absOut < absIn;
3725    return result;
3726}
3727
3728int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const {
3729    if (approximately_zero(tHit - t(tIndex))) {  // if we hit the end of a span, disregard
3730        return SK_MinS32;
3731    }
3732    int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3733    SkASSERT(winding != SK_MinS32);
3734    int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
3735#if DEBUG_WINDING_AT_T
3736    SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
3737#endif
3738    // see if a + change in T results in a +/- change in X (compute x'(T))
3739    *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
3740    if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
3741        *dx = fPts[2].fX - fPts[1].fX - *dx;
3742    }
3743    if (*dx == 0) {
3744#if DEBUG_WINDING_AT_T
3745        SkDebugf(" dx=0 winding=SK_MinS32\n");
3746#endif
3747        return SK_MinS32;
3748    }
3749    if (windVal < 0) {  // reverse sign if opp contour traveled in reverse
3750            *dx = -*dx;
3751    }
3752    if (winding * *dx > 0) {  // if same signs, result is negative
3753        winding += *dx > 0 ? -windVal : windVal;
3754    }
3755#if DEBUG_WINDING_AT_T
3756    SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding);
3757#endif
3758    return winding;
3759}
3760
3761int SkOpSegment::windSum(const SkOpAngle* angle) const {
3762    int start = angle->start();
3763    int end = angle->end();
3764    int index = SkMin32(start, end);
3765    return windSum(index);
3766}
3767
3768void SkOpSegment::zeroSpan(SkOpSpan* span) {
3769    SkASSERT(span->fWindValue > 0 || span->fOppValue != 0);
3770    span->fWindValue = 0;
3771    span->fOppValue = 0;
3772    if (span->fTiny || span->fSmall) {
3773        return;
3774    }
3775    SkASSERT(!span->fDone);
3776    span->fDone = true;
3777    ++fDoneSpans;
3778}
3779