Simplify.cpp revision 0d3d09e5d2fd17aaed035ae23d59804b56b994ff
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 "Simplify.h"
8
9#undef SkASSERT
10#define SkASSERT(cond) while (!(cond)) { sk_throw(); }
11
12// Terminology:
13// A Path contains one of more Contours
14// A Contour is made up of Segment array
15// A Segment is described by a Verb and a Point array with 2, 3, or 4 points
16// A Verb is one of Line, Quad(ratic), or Cubic
17// A Segment contains a Span array
18// A Span is describes a portion of a Segment using starting and ending T
19// T values range from 0 to 1, where 0 is the first Point in the Segment
20// An Edge is a Segment generated from a Span
21
22// FIXME: remove once debugging is complete
23#ifdef SK_DEBUG
24int gDebugMaxWindSum = SK_MaxS32;
25int gDebugMaxWindValue = SK_MaxS32;
26#endif
27
28#define PIN_ADD_T 0
29#define TRY_ROTATE 1
30
31#define DEBUG_UNUSED 0 // set to expose unused functions
32#define FORCE_RELEASE 1  // set force release to 1 for multiple thread -- no debugging
33
34#if FORCE_RELEASE || defined SK_RELEASE
35
36const bool gRunTestsInOneThread = false;
37
38#define DEBUG_ACTIVE_SPANS 0
39#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0
40#define DEBUG_ADD_INTERSECTING_TS 0
41#define DEBUG_ADD_T_PAIR 0
42#define DEBUG_ANGLE 0
43#define DEBUG_CONCIDENT 0
44#define DEBUG_CROSS 0
45#define DEBUG_MARK_DONE 0
46#define DEBUG_PATH_CONSTRUCTION 0
47#define DEBUG_SHOW_WINDING 0
48#define DEBUG_SORT 0
49#define DEBUG_WIND_BUMP 0
50#define DEBUG_WINDING 0
51
52#else
53
54const bool gRunTestsInOneThread = true;
55
56#define DEBUG_ACTIVE_SPANS 1
57#define DEBUG_ACTIVE_SPANS_SHORT_FORM 1
58#define DEBUG_ADD_INTERSECTING_TS 1
59#define DEBUG_ADD_T_PAIR 1
60#define DEBUG_ANGLE 1
61#define DEBUG_CONCIDENT 1
62#define DEBUG_CROSS 0
63#define DEBUG_MARK_DONE 1
64#define DEBUG_PATH_CONSTRUCTION 1
65#define DEBUG_SHOW_WINDING 0
66#define DEBUG_SORT 1
67#define DEBUG_WIND_BUMP 0
68#define DEBUG_WINDING 1
69
70#endif
71
72#define DEBUG_DUMP (DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | DEBUG_PATH_CONSTRUCTION)
73
74#if DEBUG_DUMP
75static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
76// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
77static int gContourID;
78static int gSegmentID;
79#endif
80
81#ifndef DEBUG_TEST
82#define DEBUG_TEST 0
83#endif
84
85#define MAKE_CONST_LINE(line, pts) \
86    const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}
87#define MAKE_CONST_QUAD(quad, pts) \
88    const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
89            {pts[2].fX, pts[2].fY}}
90#define MAKE_CONST_CUBIC(cubic, pts) \
91    const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
92            {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}}
93
94static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
95        Intersections& intersections) {
96    MAKE_CONST_LINE(aLine, a);
97    MAKE_CONST_LINE(bLine, b);
98    return intersect(aLine, bLine, intersections.fT[0], intersections.fT[1]);
99}
100
101static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
102        Intersections& intersections) {
103    MAKE_CONST_QUAD(aQuad, a);
104    MAKE_CONST_LINE(bLine, b);
105    return intersect(aQuad, bLine, intersections);
106}
107
108static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2],
109        Intersections& intersections) {
110    MAKE_CONST_CUBIC(aCubic, a);
111    MAKE_CONST_LINE(bLine, b);
112    return intersect(aCubic, bLine, intersections.fT[0], intersections.fT[1]);
113}
114
115static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
116        Intersections& intersections) {
117    MAKE_CONST_QUAD(aQuad, a);
118    MAKE_CONST_QUAD(bQuad, b);
119#define TRY_QUARTIC_SOLUTION 1
120#if TRY_QUARTIC_SOLUTION
121    intersect2(aQuad, bQuad, intersections);
122#else
123    intersect(aQuad, bQuad, intersections);
124#endif
125    return intersections.fUsed ? intersections.fUsed : intersections.fCoincidentUsed;
126}
127
128static int CubicIntersect(const SkPoint a[4], const SkPoint b[4],
129        Intersections& intersections) {
130    MAKE_CONST_CUBIC(aCubic, a);
131    MAKE_CONST_CUBIC(bCubic, b);
132    intersect(aCubic, bCubic, intersections);
133    return intersections.fUsed;
134}
135
136static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
137        SkScalar y, bool flipped, Intersections& intersections) {
138    MAKE_CONST_LINE(aLine, a);
139    return horizontalIntersect(aLine, left, right, y, flipped, intersections);
140}
141
142static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
143        SkScalar y, bool flipped, Intersections& intersections) {
144    MAKE_CONST_QUAD(aQuad, a);
145    return horizontalIntersect(aQuad, left, right, y, flipped, intersections);
146}
147
148static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
149        SkScalar y, bool flipped, Intersections& intersections) {
150    MAKE_CONST_CUBIC(aCubic, a);
151    return horizontalIntersect(aCubic, left, right, y, flipped, intersections);
152}
153
154static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom,
155        SkScalar x, bool flipped, Intersections& intersections) {
156    MAKE_CONST_LINE(aLine, a);
157    return verticalIntersect(aLine, top, bottom, x, flipped, intersections);
158}
159
160static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom,
161        SkScalar x, bool flipped, Intersections& intersections) {
162    MAKE_CONST_QUAD(aQuad, a);
163    return verticalIntersect(aQuad, top, bottom, x, flipped, intersections);
164}
165
166static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom,
167        SkScalar x, bool flipped, Intersections& intersections) {
168    MAKE_CONST_CUBIC(aCubic, a);
169    return verticalIntersect(aCubic, top, bottom, x, flipped, intersections);
170}
171
172static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar ,
173        SkScalar , SkScalar , bool , Intersections& ) = {
174    NULL,
175    VLineIntersect,
176    VQuadIntersect,
177    VCubicIntersect
178};
179
180static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
181    MAKE_CONST_LINE(line, a);
182    double x, y;
183    xy_at_t(line, t, x, y);
184    out->fX = SkDoubleToScalar(x);
185    out->fY = SkDoubleToScalar(y);
186}
187
188static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
189    MAKE_CONST_QUAD(quad, a);
190    double x, y;
191    xy_at_t(quad, t, x, y);
192    out->fX = SkDoubleToScalar(x);
193    out->fY = SkDoubleToScalar(y);
194}
195
196static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
197    MAKE_CONST_QUAD(quad, a);
198    xy_at_t(quad, t, out->x, out->y);
199}
200
201static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
202    MAKE_CONST_CUBIC(cubic, a);
203    double x, y;
204    xy_at_t(cubic, t, x, y);
205    out->fX = SkDoubleToScalar(x);
206    out->fY = SkDoubleToScalar(y);
207}
208
209static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
210    NULL,
211    LineXYAtT,
212    QuadXYAtT,
213    CubicXYAtT
214};
215
216static SkScalar LineXAtT(const SkPoint a[2], double t) {
217    MAKE_CONST_LINE(aLine, a);
218    double x;
219    xy_at_t(aLine, t, x, *(double*) 0);
220    return SkDoubleToScalar(x);
221}
222
223static SkScalar QuadXAtT(const SkPoint a[3], double t) {
224    MAKE_CONST_QUAD(quad, a);
225    double x;
226    xy_at_t(quad, t, x, *(double*) 0);
227    return SkDoubleToScalar(x);
228}
229
230static SkScalar CubicXAtT(const SkPoint a[4], double t) {
231    MAKE_CONST_CUBIC(cubic, a);
232    double x;
233    xy_at_t(cubic, t, x, *(double*) 0);
234    return SkDoubleToScalar(x);
235}
236
237static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
238    NULL,
239    LineXAtT,
240    QuadXAtT,
241    CubicXAtT
242};
243
244static SkScalar LineYAtT(const SkPoint a[2], double t) {
245    MAKE_CONST_LINE(aLine, a);
246    double y;
247    xy_at_t(aLine, t, *(double*) 0, y);
248    return SkDoubleToScalar(y);
249}
250
251static SkScalar QuadYAtT(const SkPoint a[3], double t) {
252    MAKE_CONST_QUAD(quad, a);
253    double y;
254    xy_at_t(quad, t, *(double*) 0, y);
255    return SkDoubleToScalar(y);
256}
257
258static SkScalar CubicYAtT(const SkPoint a[4], double t) {
259    MAKE_CONST_CUBIC(cubic, a);
260    double y;
261    xy_at_t(cubic, t, *(double*) 0, y);
262    return SkDoubleToScalar(y);
263}
264
265static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
266    NULL,
267    LineYAtT,
268    QuadYAtT,
269    CubicYAtT
270};
271
272static SkScalar LineDXAtT(const SkPoint a[2], double ) {
273    return a[1].fX - a[0].fX;
274}
275
276static SkScalar QuadDXAtT(const SkPoint a[3], double t) {
277    MAKE_CONST_QUAD(quad, a);
278    double x;
279    dxdy_at_t(quad, t, x, *(double*) 0);
280    return SkDoubleToScalar(x);
281}
282
283static SkScalar CubicDXAtT(const SkPoint a[4], double t) {
284    MAKE_CONST_CUBIC(cubic, a);
285    double x;
286    dxdy_at_t(cubic, t, x, *(double*) 0);
287    return SkDoubleToScalar(x);
288}
289
290static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
291    NULL,
292    LineDXAtT,
293    QuadDXAtT,
294    CubicDXAtT
295};
296
297static void LineSubDivide(const SkPoint a[2], double startT, double endT,
298        SkPoint sub[2]) {
299    MAKE_CONST_LINE(aLine, a);
300    _Line dst;
301    sub_divide(aLine, startT, endT, dst);
302    sub[0].fX = SkDoubleToScalar(dst[0].x);
303    sub[0].fY = SkDoubleToScalar(dst[0].y);
304    sub[1].fX = SkDoubleToScalar(dst[1].x);
305    sub[1].fY = SkDoubleToScalar(dst[1].y);
306}
307
308static void QuadSubDivide(const SkPoint a[3], double startT, double endT,
309        SkPoint sub[3]) {
310    MAKE_CONST_QUAD(aQuad, a);
311    Quadratic dst;
312    sub_divide(aQuad, startT, endT, dst);
313    sub[0].fX = SkDoubleToScalar(dst[0].x);
314    sub[0].fY = SkDoubleToScalar(dst[0].y);
315    sub[1].fX = SkDoubleToScalar(dst[1].x);
316    sub[1].fY = SkDoubleToScalar(dst[1].y);
317    sub[2].fX = SkDoubleToScalar(dst[2].x);
318    sub[2].fY = SkDoubleToScalar(dst[2].y);
319}
320
321static void CubicSubDivide(const SkPoint a[4], double startT, double endT,
322        SkPoint sub[4]) {
323    MAKE_CONST_CUBIC(aCubic, a);
324    Cubic dst;
325    sub_divide(aCubic, startT, endT, dst);
326    sub[0].fX = SkDoubleToScalar(dst[0].x);
327    sub[0].fY = SkDoubleToScalar(dst[0].y);
328    sub[1].fX = SkDoubleToScalar(dst[1].x);
329    sub[1].fY = SkDoubleToScalar(dst[1].y);
330    sub[2].fX = SkDoubleToScalar(dst[2].x);
331    sub[2].fY = SkDoubleToScalar(dst[2].y);
332    sub[3].fX = SkDoubleToScalar(dst[3].x);
333    sub[3].fY = SkDoubleToScalar(dst[3].y);
334}
335
336static void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
337        SkPoint []) = {
338    NULL,
339    LineSubDivide,
340    QuadSubDivide,
341    CubicSubDivide
342};
343
344static void LineSubDivideHD(const SkPoint a[2], double startT, double endT,
345        _Line sub) {
346    MAKE_CONST_LINE(aLine, a);
347    _Line dst;
348    sub_divide(aLine, startT, endT, dst);
349    sub[0] = dst[0];
350    sub[1] = dst[1];
351}
352
353static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT,
354        Quadratic sub) {
355    MAKE_CONST_QUAD(aQuad, a);
356    Quadratic dst;
357    sub_divide(aQuad, startT, endT, dst);
358    sub[0] = dst[0];
359    sub[1] = dst[1];
360    sub[2] = dst[2];
361}
362
363static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT,
364        Cubic sub) {
365    MAKE_CONST_CUBIC(aCubic, a);
366    Cubic dst;
367    sub_divide(aCubic, startT, endT, dst);
368    sub[0] = dst[0];
369    sub[1] = dst[1];
370    sub[2] = dst[2];
371    sub[3] = dst[3];
372}
373
374#if DEBUG_UNUSED
375static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
376        SkRect& bounds) {
377    SkPoint dst[3];
378    QuadSubDivide(a, startT, endT, dst);
379    bounds.fLeft = bounds.fRight = dst[0].fX;
380    bounds.fTop = bounds.fBottom = dst[0].fY;
381    for (int index = 1; index < 3; ++index) {
382        bounds.growToInclude(dst[index].fX, dst[index].fY);
383    }
384}
385
386static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
387        SkRect& bounds) {
388    SkPoint dst[4];
389    CubicSubDivide(a, startT, endT, dst);
390    bounds.fLeft = bounds.fRight = dst[0].fX;
391    bounds.fTop = bounds.fBottom = dst[0].fY;
392    for (int index = 1; index < 4; ++index) {
393        bounds.growToInclude(dst[index].fX, dst[index].fY);
394    }
395}
396#endif
397
398static SkPath::Verb QuadReduceOrder(const SkPoint a[3],
399        SkTDArray<SkPoint>& reducePts) {
400    MAKE_CONST_QUAD(aQuad, a);
401    Quadratic dst;
402    int order = reduceOrder(aQuad, dst);
403    if (order == 2) { // quad became line
404        for (int index = 0; index < order; ++index) {
405            SkPoint* pt = reducePts.append();
406            pt->fX = SkDoubleToScalar(dst[index].x);
407            pt->fY = SkDoubleToScalar(dst[index].y);
408        }
409    }
410    return (SkPath::Verb) (order - 1);
411}
412
413static SkPath::Verb CubicReduceOrder(const SkPoint a[4],
414        SkTDArray<SkPoint>& reducePts) {
415    MAKE_CONST_CUBIC(aCubic, a);
416    Cubic dst;
417    int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed);
418    if (order == 2 || order == 3) { // cubic became line or quad
419        for (int index = 0; index < order; ++index) {
420            SkPoint* pt = reducePts.append();
421            pt->fX = SkDoubleToScalar(dst[index].x);
422            pt->fY = SkDoubleToScalar(dst[index].y);
423        }
424    }
425    return (SkPath::Verb) (order - 1);
426}
427
428static bool QuadIsLinear(const SkPoint a[3]) {
429    MAKE_CONST_QUAD(aQuad, a);
430    return isLinear(aQuad, 0, 2);
431}
432
433static bool CubicIsLinear(const SkPoint a[4]) {
434    MAKE_CONST_CUBIC(aCubic, a);
435    return isLinear(aCubic, 0, 3);
436}
437
438static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
439    MAKE_CONST_LINE(aLine, a);
440    double x[2];
441    xy_at_t(aLine, startT, x[0], *(double*) 0);
442    xy_at_t(aLine, endT, x[1], *(double*) 0);
443    return SkMinScalar((float) x[0], (float) x[1]);
444}
445
446static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
447    MAKE_CONST_QUAD(aQuad, a);
448    return (float) leftMostT(aQuad, startT, endT);
449}
450
451static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
452    MAKE_CONST_CUBIC(aCubic, a);
453    return (float) leftMostT(aCubic, startT, endT);
454}
455
456static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
457    NULL,
458    LineLeftMost,
459    QuadLeftMost,
460    CubicLeftMost
461};
462
463#if 0 // currently unused
464static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
465        Intersections& intersections) {
466    MAKE_CONST_QUAD(aQuad, a);
467    MAKE_CONST_LINE(bLine, b);
468    return intersectRay(aQuad, bLine, intersections);
469}
470#endif
471
472static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine,
473        Intersections& intersections) {
474    MAKE_CONST_QUAD(aQuad, a);
475    return intersectRay(aQuad, bLine, intersections);
476}
477
478class Segment;
479
480struct Span {
481    Segment* fOther;
482    mutable SkPoint fPt; // lazily computed as needed
483    double fT;
484    double fOtherT; // value at fOther[fOtherIndex].fT
485    int fOtherIndex;  // can't be used during intersection
486    int fWindSum; // accumulated from contours surrounding this one.
487    int fOppSum; // for binary operators: the opposite winding sum
488    int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
489    int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
490    bool fDone; // if set, this span to next higher T has been processed
491    bool fUnsortableStart; // set when start is part of an unsortable pair
492    bool fUnsortableEnd; // set when end is part of an unsortable pair
493    bool fTiny; // if set, span may still be considered once for edge following
494};
495
496// sorting angles
497// given angles of {dx dy ddx ddy dddx dddy} sort them
498class Angle {
499public:
500    // FIXME: this is bogus for quads and cubics
501    // if the quads and cubics' line from end pt to ctrl pt are coincident,
502    // there's no obvious way to determine the curve ordering from the
503    // derivatives alone. In particular, if one quadratic's coincident tangent
504    // is longer than the other curve, the final control point can place the
505    // longer curve on either side of the shorter one.
506    // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
507    // may provide some help, but nothing has been figured out yet.
508
509    /*(
510    for quads and cubics, set up a parameterized line (e.g. LineParameters )
511    for points [0] to [1]. See if point [2] is on that line, or on one side
512    or the other. If it both quads' end points are on the same side, choose
513    the shorter tangent. If the tangents are equal, choose the better second
514    tangent angle
515
516    maybe I could set up LineParameters lazily
517    */
518    bool operator<(const Angle& rh) const {
519        double y = dy();
520        double ry = rh.dy();
521        if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
522            return y < 0;
523        }
524        double x = dx();
525        double rx = rh.dx();
526        if (y == 0 && ry == 0 && x * rx < 0) {
527            return x < rx;
528        }
529        double x_ry = x * ry;
530        double rx_y = rx * y;
531        double cmp = x_ry - rx_y;
532        if (!approximately_zero(cmp)) {
533            return cmp < 0;
534        }
535        if (approximately_zero(x_ry) && approximately_zero(rx_y)
536                && !approximately_zero_squared(cmp)) {
537            return cmp < 0;
538        }
539        // at this point, the initial tangent line is coincident
540        if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
541                || !approximately_zero(rh.fSide))) {
542            // FIXME: running demo will trigger this assertion
543            // (don't know if commenting out will trigger further assertion or not)
544            // commenting it out allows demo to run in release, though
545     //       SkASSERT(fSide != rh.fSide);
546            return fSide < rh.fSide;
547        }
548        // see if either curve can be lengthened and try the tangent compare again
549        if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
550                && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
551            Angle longer = *this;
552            Angle rhLonger = rh;
553            if (longer.lengthen() | rhLonger.lengthen()) {
554                return longer < rhLonger;
555            }
556            // what if we extend in the other direction?
557            longer = *this;
558            rhLonger = rh;
559            if (longer.reverseLengthen() | rhLonger.reverseLengthen()) {
560                return longer < rhLonger;
561            }
562        }
563        if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
564                || (rh.fVerb == SkPath::kLine_Verb
565                && approximately_zero(rx) && approximately_zero(ry))) {
566            // See general unsortable comment below. This case can happen when
567            // one line has a non-zero change in t but no change in x and y.
568            fUnsortable = true;
569            rh.fUnsortable = true;
570            return this < &rh; // even with no solution, return a stable sort
571        }
572        SkASSERT(fVerb == SkPath::kQuad_Verb); // worry about cubics later
573        SkASSERT(rh.fVerb == SkPath::kQuad_Verb);
574        // FIXME: until I can think of something better, project a ray from the
575        // end of the shorter tangent to midway between the end points
576        // through both curves and use the resulting angle to sort
577        // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
578        double len = fTangent1.normalSquared();
579        double rlen = rh.fTangent1.normalSquared();
580        _Line ray;
581        Intersections i, ri;
582        int roots, rroots;
583        bool flip = false;
584        do {
585            const Quadratic& q = (len < rlen) ^ flip ? fQ : rh.fQ;
586            double midX = (q[0].x + q[2].x) / 2;
587            double midY = (q[0].y + q[2].y) / 2;
588            ray[0] = q[1];
589            ray[1].x = midX;
590            ray[1].y = midY;
591            SkASSERT(ray[0] != ray[1]);
592            roots = QuadRayIntersect(fPts, ray, i);
593            rroots = QuadRayIntersect(rh.fPts, ray, ri);
594        } while ((roots == 0 || rroots == 0) && (flip ^= true));
595        if (roots == 0 || rroots == 0) {
596            // FIXME: we don't have a solution in this case. The interim solution
597            // is to mark the edges as unsortable, exclude them from this and
598            // future computations, and allow the returned path to be fragmented
599            fUnsortable = true;
600            rh.fUnsortable = true;
601            return this < &rh; // even with no solution, return a stable sort
602        }
603        _Point loc;
604        double best = SK_ScalarInfinity;
605        double dx, dy, dist;
606        int index;
607        for (index = 0; index < roots; ++index) {
608            QuadXYAtT(fPts, i.fT[0][index], &loc);
609            dx = loc.x - ray[0].x;
610            dy = loc.y - ray[0].y;
611            dist = dx * dx + dy * dy;
612            if (best > dist) {
613                best = dist;
614            }
615        }
616        for (index = 0; index < rroots; ++index) {
617            QuadXYAtT(rh.fPts, ri.fT[0][index], &loc);
618            dx = loc.x - ray[0].x;
619            dy = loc.y - ray[0].y;
620            dist = dx * dx + dy * dy;
621            if (best > dist) {
622                return fSide < 0;
623            }
624        }
625        return fSide > 0;
626    }
627
628    double dx() const {
629        return fTangent1.dx();
630    }
631
632    double dy() const {
633        return fTangent1.dy();
634    }
635
636    int end() const {
637        return fEnd;
638    }
639
640    bool isHorizontal() const {
641        return dy() == 0 && fVerb == SkPath::kLine_Verb;
642    }
643
644    bool lengthen() {
645        int newEnd = fEnd;
646        if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
647            fEnd = newEnd;
648            setSpans();
649            return true;
650        }
651        return false;
652    }
653
654    bool reverseLengthen() {
655        if (fReversed) {
656            return false;
657        }
658        int newEnd = fStart;
659        if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
660            fEnd = newEnd;
661            fReversed = true;
662            setSpans();
663            return true;
664        }
665        return false;
666    }
667
668    void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
669            int start, int end, const SkTDArray<Span>& spans) {
670        fSegment = segment;
671        fStart = start;
672        fEnd = end;
673        fPts = orig;
674        fVerb = verb;
675        fSpans = &spans;
676        fReversed = false;
677        fUnsortable = false;
678        setSpans();
679    }
680
681    void setSpans() {
682        double startT = (*fSpans)[fStart].fT;
683        double endT = (*fSpans)[fEnd].fT;
684        switch (fVerb) {
685        case SkPath::kLine_Verb:
686            _Line l;
687            LineSubDivideHD(fPts, startT, endT, l);
688            // OPTIMIZATION: for pure line compares, we never need fTangent1.c
689            fTangent1.lineEndPoints(l);
690            fUnsortable = dx() == 0 && dy() == 0;
691            fSide = 0;
692            break;
693        case SkPath::kQuad_Verb:
694            QuadSubDivideHD(fPts, startT, endT, fQ);
695            fTangent1.quadEndPoints(fQ, 0, 1);
696            fSide = -fTangent1.pointDistance(fQ[2]); // not normalized -- compare sign only
697            break;
698        case SkPath::kCubic_Verb:
699            Cubic c;
700            CubicSubDivideHD(fPts, startT, endT, c);
701            fTangent1.cubicEndPoints(c, 0, 1);
702            fSide = -fTangent1.pointDistance(c[2]); // not normalized -- compare sign only
703            break;
704        default:
705            SkASSERT(0);
706        }
707        if (fUnsortable) {
708            return;
709        }
710        SkASSERT(fStart != fEnd);
711        int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
712        for (int index = fStart; index != fEnd; index += step) {
713            if ((*fSpans)[index].fUnsortableStart) {
714                fUnsortable = true;
715                return;
716            }
717            if (index != fStart && (*fSpans)[index].fUnsortableEnd) {
718                fUnsortable = true;
719                return;
720            }
721        }
722    }
723
724    Segment* segment() const {
725        return const_cast<Segment*>(fSegment);
726    }
727
728    int sign() const {
729        return SkSign32(fStart - fEnd);
730    }
731
732    const SkTDArray<Span>* spans() const {
733        return fSpans;
734    }
735
736    int start() const {
737        return fStart;
738    }
739
740    bool unsortable() const {
741        return fUnsortable;
742    }
743
744#if DEBUG_ANGLE
745    const SkPoint* pts() const {
746        return fPts;
747    }
748
749    SkPath::Verb verb() const {
750        return fVerb;
751    }
752
753    void debugShow(const SkPoint& a) const {
754        SkDebugf("    d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
755    }
756#endif
757
758private:
759    const SkPoint* fPts;
760    Quadratic fQ;
761    SkPath::Verb fVerb;
762    double fSide;
763    LineParameters fTangent1;
764    const SkTDArray<Span>* fSpans;
765    const Segment* fSegment;
766    int fStart;
767    int fEnd;
768    bool fReversed;
769    mutable bool fUnsortable; // this alone is editable by the less than operator
770};
771
772// Bounds, unlike Rect, does not consider a line to be empty.
773struct Bounds : public SkRect {
774    static bool Intersects(const Bounds& a, const Bounds& b) {
775        return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
776                a.fTop <= b.fBottom && b.fTop <= a.fBottom;
777    }
778
779    void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
780        if (left < fLeft) {
781            fLeft = left;
782        }
783        if (top < fTop) {
784            fTop = top;
785        }
786        if (right > fRight) {
787            fRight = right;
788        }
789        if (bottom > fBottom) {
790            fBottom = bottom;
791        }
792    }
793
794    void add(const Bounds& toAdd) {
795        add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
796    }
797
798    bool isEmpty() {
799        return fLeft > fRight || fTop > fBottom
800                || (fLeft == fRight && fTop == fBottom)
801                || isnan(fLeft) || isnan(fRight)
802                || isnan(fTop) || isnan(fBottom);
803    }
804
805    void setCubicBounds(const SkPoint a[4]) {
806        _Rect dRect;
807        MAKE_CONST_CUBIC(cubic, a);
808        dRect.setBounds(cubic);
809        set((float) dRect.left, (float) dRect.top, (float) dRect.right,
810                (float) dRect.bottom);
811    }
812
813    void setQuadBounds(const SkPoint a[3]) {
814        MAKE_CONST_QUAD(quad, a);
815        _Rect dRect;
816        dRect.setBounds(quad);
817        set((float) dRect.left, (float) dRect.top, (float) dRect.right,
818                (float) dRect.bottom);
819    }
820};
821
822// OPTIMIZATION: does the following also work, and is it any faster?
823// return outerWinding * innerWinding > 0
824//      || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
825static bool useInnerWinding(int outerWinding, int innerWinding) {
826  //  SkASSERT(outerWinding != innerWinding);
827    int absOut = abs(outerWinding);
828    int absIn = abs(innerWinding);
829    bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
830    if (outerWinding * innerWinding < 0) {
831#if DEBUG_WINDING
832        SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
833                outerWinding, innerWinding, result ? "true" : "false");
834#endif
835    }
836    return result;
837}
838
839#define F (false)      // discard the edge
840#define T (true)       // keep the edge
841
842static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
843//                 miFrom=0                              miFrom=1
844//         miTo=0            miTo=1              miTo=0             miTo=1
845//    suFrom=0    1     suFrom=0     1      suFrom=0    1      suFrom=0    1
846//   suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1
847    {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
848    {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
849    {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
850    {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su
851};
852
853#undef F
854#undef T
855
856// wrap path to keep track of whether the contour is initialized and non-empty
857class PathWrapper {
858public:
859    PathWrapper(SkPath& path)
860        : fPathPtr(&path)
861    {
862        init();
863    }
864
865    void close() {
866        if (!fHasMove) {
867            return;
868        }
869        bool callClose = isClosed();
870        lineTo();
871        if (fEmpty) {
872            return;
873        }
874        if (callClose) {
875    #if DEBUG_PATH_CONSTRUCTION
876            SkDebugf("path.close();\n");
877    #endif
878            fPathPtr->close();
879        }
880        init();
881    }
882
883    void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
884        lineTo();
885        moveTo();
886#if DEBUG_PATH_CONSTRUCTION
887        SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
888                pt1.fX, pt1.fY, pt2.fX, pt2.fY, pt3.fX, pt3.fY);
889#endif
890        fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, pt3.fX, pt3.fY);
891        fDefer[0] = fDefer[1] = pt3;
892        fEmpty = false;
893    }
894
895    void deferredLine(const SkPoint& pt) {
896        if (pt == fDefer[1]) {
897            return;
898        }
899        if (changedSlopes(pt)) {
900            lineTo();
901            fDefer[0] = fDefer[1];
902        }
903        fDefer[1] = pt;
904    }
905
906    void deferredMove(const SkPoint& pt) {
907        fMoved = true;
908        fHasMove = true;
909        fEmpty = true;
910        fDefer[0] = fDefer[1] = pt;
911    }
912
913    void deferredMoveLine(const SkPoint& pt) {
914        if (!fHasMove) {
915            deferredMove(pt);
916        }
917        deferredLine(pt);
918    }
919
920    bool hasMove() const {
921        return fHasMove;
922    }
923
924    void init() {
925        fEmpty = true;
926        fHasMove = false;
927        fMoved = false;
928    }
929
930    bool isClosed() const {
931        return !fEmpty && fFirstPt == fDefer[1];
932    }
933
934    void lineTo() {
935        if (fDefer[0] == fDefer[1]) {
936            return;
937        }
938        moveTo();
939        fEmpty = false;
940#if DEBUG_PATH_CONSTRUCTION
941        SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
942#endif
943        fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
944        fDefer[0] = fDefer[1];
945    }
946
947    const SkPath* nativePath() const {
948        return fPathPtr;
949    }
950
951    void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
952        lineTo();
953        moveTo();
954#if DEBUG_PATH_CONSTRUCTION
955        SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
956                pt1.fX, pt1.fY, pt2.fX, pt2.fY);
957#endif
958        fPathPtr->quadTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY);
959        fDefer[0] = fDefer[1] = pt2;
960        fEmpty = false;
961    }
962
963protected:
964    bool changedSlopes(const SkPoint& pt) const {
965        if (fDefer[0] == fDefer[1]) {
966            return false;
967        }
968        SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
969        SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
970        SkScalar lineDx = pt.fX - fDefer[1].fX;
971        SkScalar lineDy = pt.fY - fDefer[1].fY;
972        return deferDx * lineDy != deferDy * lineDx;
973    }
974
975    void moveTo() {
976        if (!fMoved) {
977            return;
978        }
979        fFirstPt = fDefer[0];
980#if DEBUG_PATH_CONSTRUCTION
981        SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
982#endif
983        fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
984        fMoved = false;
985    }
986
987private:
988    SkPath* fPathPtr;
989    SkPoint fDefer[2];
990    SkPoint fFirstPt;
991    bool fEmpty;
992    bool fHasMove;
993    bool fMoved;
994};
995
996class Segment {
997public:
998    Segment() {
999#if DEBUG_DUMP
1000        fID = ++gSegmentID;
1001#endif
1002    }
1003
1004    bool operator<(const Segment& rh) const {
1005        return fBounds.fTop < rh.fBounds.fTop;
1006    }
1007
1008    bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
1009        if (activeAngleInner(index, done, angles)) {
1010            return true;
1011        }
1012        double referenceT = fTs[index].fT;
1013        int lesser = index;
1014        while (--lesser >= 0 && approximately_negative(referenceT - fTs[lesser].fT)) {
1015            if (activeAngleOther(lesser, done, angles)) {
1016                return true;
1017            }
1018        }
1019        do {
1020            if (activeAngleOther(index, done, angles)) {
1021                return true;
1022            }
1023        } while (++index < fTs.count() && approximately_negative(fTs[index].fT - referenceT));
1024        return false;
1025    }
1026
1027    bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
1028        Span* span = &fTs[index];
1029        Segment* other = span->fOther;
1030        int oIndex = span->fOtherIndex;
1031        return other->activeAngleInner(oIndex, done, angles);
1032    }
1033
1034    bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
1035        int next = nextExactSpan(index, 1);
1036        if (next > 0) {
1037            Span& upSpan = fTs[index];
1038            if (upSpan.fWindValue || upSpan.fOppValue) {
1039                addAngle(angles, index, next);
1040                if (upSpan.fDone || upSpan.fUnsortableEnd) {
1041                    done++;
1042                } else if (upSpan.fWindSum != SK_MinS32) {
1043                    return true;
1044                }
1045            } else if (!upSpan.fDone) {
1046                upSpan.fDone = true;
1047                fDoneSpans++;
1048            }
1049        }
1050        int prev = nextExactSpan(index, -1);
1051        // edge leading into junction
1052        if (prev >= 0) {
1053            Span& downSpan = fTs[prev];
1054            if (downSpan.fWindValue || downSpan.fOppValue) {
1055                addAngle(angles, index, prev);
1056                if (downSpan.fDone) {
1057                    done++;
1058                 } else if (downSpan.fWindSum != SK_MinS32) {
1059                    return true;
1060                }
1061            } else if (!downSpan.fDone) {
1062                downSpan.fDone = true;
1063                fDoneSpans++;
1064            }
1065        }
1066        return false;
1067    }
1068
1069    void activeLeftTop(SkPoint& result) const {
1070        SkASSERT(!done());
1071        int count = fTs.count();
1072        result.fY = SK_ScalarMax;
1073        bool lastDone = true;
1074        bool lastUnsortable = false;
1075        for (int index = 0; index < count; ++index) {
1076            const Span& span = fTs[index];
1077            if (span.fUnsortableStart | lastUnsortable) {
1078                goto next;
1079            }
1080            if (!span.fDone | !lastDone) {
1081                const SkPoint& xy = xyAtT(index);
1082                if (result.fY < xy.fY) {
1083                    goto next;
1084                }
1085                if (result.fY == xy.fY && result.fX < xy.fX) {
1086                    goto next;
1087                }
1088                result = xy;
1089            }
1090    next:
1091            lastDone = span.fDone;
1092            lastUnsortable = span.fUnsortableEnd;
1093        }
1094        SkASSERT(result.fY < SK_ScalarMax);
1095    }
1096
1097    bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
1098        int sumMiWinding = updateWinding(endIndex, index);
1099        int sumSuWinding = updateOppWinding(endIndex, index);
1100        if (fOperand) {
1101            SkTSwap<int>(sumMiWinding, sumSuWinding);
1102        }
1103        int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1104        return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
1105                maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
1106    }
1107
1108    bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
1109            int& sumMiWinding, int& sumSuWinding,
1110            int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
1111        setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1112                maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
1113        bool miFrom;
1114        bool miTo;
1115        bool suFrom;
1116        bool suTo;
1117        if (operand()) {
1118            miFrom = (oppMaxWinding & xorMiMask) != 0;
1119            miTo = (oppSumWinding & xorMiMask) != 0;
1120            suFrom = (maxWinding & xorSuMask) != 0;
1121            suTo = (sumWinding & xorSuMask) != 0;
1122        } else {
1123            miFrom = (maxWinding & xorMiMask) != 0;
1124            miTo = (sumWinding & xorMiMask) != 0;
1125            suFrom = (oppMaxWinding & xorSuMask) != 0;
1126            suTo = (oppSumWinding & xorSuMask) != 0;
1127        }
1128        bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
1129        SkASSERT(result != -1);
1130        return result;
1131    }
1132
1133    void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
1134        SkASSERT(start != end);
1135        Angle* angle = angles.append();
1136#if DEBUG_ANGLE
1137        if (angles.count() > 1 && !fTs[start].fTiny) {
1138            SkPoint angle0Pt, newPt;
1139            (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
1140                    (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
1141            (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
1142            SkASSERT(approximately_equal(angle0Pt.fX, newPt.fX));
1143            SkASSERT(approximately_equal(angle0Pt.fY, newPt.fY));
1144        }
1145#endif
1146        angle->set(fPts, fVerb, this, start, end, fTs);
1147    }
1148
1149    void addCancelOutsides(double tStart, double oStart, Segment& other,
1150            double oEnd) {
1151        int tIndex = -1;
1152        int tCount = fTs.count();
1153        int oIndex = -1;
1154        int oCount = other.fTs.count();
1155        do {
1156            ++tIndex;
1157        } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
1158        int tIndexStart = tIndex;
1159        do {
1160            ++oIndex;
1161        } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
1162        int oIndexStart = oIndex;
1163        double nextT;
1164        do {
1165            nextT = fTs[++tIndex].fT;
1166        } while (nextT < 1 && approximately_negative(nextT - tStart));
1167        double oNextT;
1168        do {
1169            oNextT = other.fTs[++oIndex].fT;
1170        } while (oNextT < 1 && approximately_negative(oNextT - oStart));
1171        // at this point, spans before and after are at:
1172        //  fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1173        // if tIndexStart == 0, no prior span
1174        // if nextT == 1, no following span
1175
1176        // advance the span with zero winding
1177        // if the following span exists (not past the end, non-zero winding)
1178        // connect the two edges
1179        if (!fTs[tIndexStart].fWindValue) {
1180            if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1181    #if DEBUG_CONCIDENT
1182                SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1183                        __FUNCTION__, fID, other.fID, tIndexStart - 1,
1184                        fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
1185                        xyAtT(tIndexStart).fY);
1186    #endif
1187                addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false);
1188            }
1189            if (nextT < 1 && fTs[tIndex].fWindValue) {
1190    #if DEBUG_CONCIDENT
1191                SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1192                        __FUNCTION__, fID, other.fID, tIndex,
1193                        fTs[tIndex].fT, xyAtT(tIndex).fX,
1194                        xyAtT(tIndex).fY);
1195    #endif
1196                addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false);
1197            }
1198        } else {
1199            SkASSERT(!other.fTs[oIndexStart].fWindValue);
1200            if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1201    #if DEBUG_CONCIDENT
1202                SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1203                        __FUNCTION__, fID, other.fID, oIndexStart - 1,
1204                        other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
1205                        other.xyAtT(oIndexStart).fY);
1206                other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
1207    #endif
1208            }
1209            if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1210    #if DEBUG_CONCIDENT
1211                SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1212                        __FUNCTION__, fID, other.fID, oIndex,
1213                        other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1214                        other.xyAtT(oIndex).fY);
1215                other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1216    #endif
1217            }
1218        }
1219    }
1220
1221    void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1222            double oEnd) {
1223        // walk this to outsideTs[0]
1224        // walk other to outsideTs[1]
1225        // if either is > 0, add a pointer to the other, copying adjacent winding
1226        int tIndex = -1;
1227        int oIndex = -1;
1228        double tStart = outsideTs[0];
1229        double oStart = outsideTs[1];
1230        do {
1231            ++tIndex;
1232        } while (!approximately_negative(tStart - fTs[tIndex].fT));
1233        do {
1234            ++oIndex;
1235        } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
1236        if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
1237            addTPair(tStart, other, oStart, false);
1238        }
1239        tStart = fTs[tIndex].fT;
1240        oStart = other.fTs[oIndex].fT;
1241        do {
1242            double nextT;
1243            do {
1244                nextT = fTs[++tIndex].fT;
1245            } while (approximately_negative(nextT - tStart));
1246            tStart = nextT;
1247            do {
1248                nextT = other.fTs[++oIndex].fT;
1249            } while (approximately_negative(nextT - oStart));
1250            oStart = nextT;
1251            if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
1252                break;
1253            }
1254            addTPair(tStart, other, oStart, false);
1255        } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
1256    }
1257
1258    void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
1259        init(pts, SkPath::kCubic_Verb, operand, evenOdd);
1260        fBounds.setCubicBounds(pts);
1261    }
1262
1263    /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
1264        SkPoint edge[4];
1265        const SkPoint* ePtr;
1266        int lastT = fTs.count() - 1;
1267        if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1268            ePtr = fPts;
1269        } else {
1270        // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
1271            (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
1272            ePtr = edge;
1273        }
1274        if (active) {
1275            bool reverse = ePtr == fPts && start != 0;
1276            if (reverse) {
1277                path.deferredMoveLine(ePtr[fVerb]);
1278                switch (fVerb) {
1279                    case SkPath::kLine_Verb:
1280                        path.deferredLine(ePtr[0]);
1281                        break;
1282                    case SkPath::kQuad_Verb:
1283                        path.quadTo(ePtr[1], ePtr[0]);
1284                        break;
1285                    case SkPath::kCubic_Verb:
1286                        path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1287                        break;
1288                    default:
1289                        SkASSERT(0);
1290                }
1291       //         return ePtr[0];
1292           } else {
1293                path.deferredMoveLine(ePtr[0]);
1294                switch (fVerb) {
1295                    case SkPath::kLine_Verb:
1296                        path.deferredLine(ePtr[1]);
1297                        break;
1298                    case SkPath::kQuad_Verb:
1299                        path.quadTo(ePtr[1], ePtr[2]);
1300                        break;
1301                    case SkPath::kCubic_Verb:
1302                        path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1303                        break;
1304                    default:
1305                        SkASSERT(0);
1306                }
1307            }
1308        }
1309      //  return ePtr[fVerb];
1310    }
1311
1312    void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
1313        init(pts, SkPath::kLine_Verb, operand, evenOdd);
1314        fBounds.set(pts, 2);
1315    }
1316
1317#if 0
1318    const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
1319        const SkPoint& pt = xyAtT(tIndex);
1320        if (active) {
1321            path.deferredMove(pt);
1322        }
1323        return pt;
1324    }
1325#endif
1326
1327    // add 2 to edge or out of range values to get T extremes
1328    void addOtherT(int index, double otherT, int otherIndex) {
1329        Span& span = fTs[index];
1330    #if PIN_ADD_T
1331        if (precisely_less_than_zero(otherT)) {
1332            otherT = 0;
1333        } else if (precisely_greater_than_one(otherT)) {
1334            otherT = 1;
1335        }
1336    #endif
1337        span.fOtherT = otherT;
1338        span.fOtherIndex = otherIndex;
1339    }
1340
1341    void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
1342        init(pts, SkPath::kQuad_Verb, operand, evenOdd);
1343        fBounds.setQuadBounds(pts);
1344    }
1345
1346    // Defer all coincident edge processing until
1347    // after normal intersections have been computed
1348
1349// no need to be tricky; insert in normal T order
1350// resolve overlapping ts when considering coincidence later
1351
1352    // add non-coincident intersection. Resulting edges are sorted in T.
1353    int addT(double newT, Segment* other) {
1354        // FIXME: in the pathological case where there is a ton of intercepts,
1355        //  binary search?
1356        int insertedAt = -1;
1357        size_t tCount = fTs.count();
1358    #if PIN_ADD_T
1359        // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
1360        if (precisely_less_than_zero(newT)) {
1361            newT = 0;
1362        } else if (precisely_greater_than_one(newT)) {
1363            newT = 1;
1364        }
1365    #endif
1366        for (size_t index = 0; index < tCount; ++index) {
1367            // OPTIMIZATION: if there are three or more identical Ts, then
1368            // the fourth and following could be further insertion-sorted so
1369            // that all the edges are clockwise or counterclockwise.
1370            // This could later limit segment tests to the two adjacent
1371            // neighbors, although it doesn't help with determining which
1372            // circular direction to go in.
1373            if (newT < fTs[index].fT) {
1374                insertedAt = index;
1375                break;
1376            }
1377        }
1378        Span* span;
1379        if (insertedAt >= 0) {
1380            span = fTs.insert(insertedAt);
1381        } else {
1382            insertedAt = tCount;
1383            span = fTs.append();
1384        }
1385        span->fT = newT;
1386        span->fOther = other;
1387        span->fPt.fX = SK_ScalarNaN;
1388        span->fWindSum = SK_MinS32;
1389        span->fOppSum = SK_MinS32;
1390        span->fWindValue = 1;
1391        span->fOppValue = 0;
1392        span->fTiny = false;
1393        if ((span->fDone = newT == 1)) {
1394            ++fDoneSpans;
1395        }
1396        span->fUnsortableStart = false;
1397        span->fUnsortableEnd = false;
1398        if (span - fTs.begin() > 0 && !span[-1].fDone
1399                && !precisely_negative(newT - span[-1].fT)
1400 //               && approximately_negative(newT - span[-1].fT)
1401                && xyAtT(&span[-1]) == xyAtT(span)) {
1402            span[-1].fTiny = true;
1403            span[-1].fDone = true;
1404            if (approximately_negative(newT - span[-1].fT)) {
1405                if (approximately_greater_than_one(newT)) {
1406                    span[-1].fUnsortableStart = true;
1407                    span[-2].fUnsortableEnd = true;
1408                }
1409                if (approximately_less_than_zero(span[-1].fT)) {
1410                    span->fUnsortableStart = true;
1411                    span[-1].fUnsortableEnd = true;
1412                }
1413            }
1414            ++fDoneSpans;
1415        }
1416        if (fTs.end() - span > 1 && !span->fDone
1417                && !precisely_negative(span[1].fT - newT)
1418 //               && approximately_negative(span[1].fT - newT)
1419                && xyAtT(&span[1]) == xyAtT(span)) {
1420            span->fTiny = true;
1421            span->fDone = true;
1422            if (approximately_negative(span[1].fT - newT)) {
1423                if (approximately_greater_than_one(span[1].fT)) {
1424                    span->fUnsortableStart = true;
1425                    span[-1].fUnsortableEnd = true;
1426                }
1427                if (approximately_less_than_zero(newT)) {
1428                    span[1].fUnsortableStart = true;
1429                    span->fUnsortableEnd = true;
1430                }
1431            }
1432            ++fDoneSpans;
1433        }
1434        return insertedAt;
1435    }
1436
1437    // set spans from start to end to decrement by one
1438    // note this walks other backwards
1439    // FIMXE: there's probably an edge case that can be constructed where
1440    // two span in one segment are separated by float epsilon on one span but
1441    // not the other, if one segment is very small. For this
1442    // case the counts asserted below may or may not be enough to separate the
1443    // spans. Even if the counts work out, what if the spans aren't correctly
1444    // sorted? It feels better in such a case to match the span's other span
1445    // pointer since both coincident segments must contain the same spans.
1446    void addTCancel(double startT, double endT, Segment& other,
1447            double oStartT, double oEndT) {
1448        SkASSERT(!approximately_negative(endT - startT));
1449        SkASSERT(!approximately_negative(oEndT - oStartT));
1450        bool binary = fOperand != other.fOperand;
1451        int index = 0;
1452        while (!approximately_negative(startT - fTs[index].fT)) {
1453            ++index;
1454        }
1455        int oIndex = other.fTs.count();
1456        while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
1457            ;
1458        double tRatio = (oEndT - oStartT) / (endT - startT);
1459        Span* test = &fTs[index];
1460        Span* oTest = &other.fTs[oIndex];
1461        SkTDArray<double> outsideTs;
1462        SkTDArray<double> oOutsideTs;
1463        do {
1464            bool decrement = test->fWindValue && oTest->fWindValue && !binary;
1465            bool track = test->fWindValue || oTest->fWindValue;
1466            double testT = test->fT;
1467            double oTestT = oTest->fT;
1468            Span* span = test;
1469            do {
1470                if (decrement) {
1471                    decrementSpan(span);
1472                } else if (track && span->fT < 1 && oTestT < 1) {
1473                    TrackOutside(outsideTs, span->fT, oTestT);
1474                }
1475                span = &fTs[++index];
1476            } while (approximately_negative(span->fT - testT));
1477            Span* oSpan = oTest;
1478            double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1479            double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1480            SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
1481            while (approximately_negative(otherTMatchStart - oSpan->fT)
1482                    && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
1483        #ifdef SK_DEBUG
1484                SkASSERT(originalWindValue == oSpan->fWindValue);
1485        #endif
1486                if (decrement) {
1487                    other.decrementSpan(oSpan);
1488                } else if (track && oSpan->fT < 1 && testT < 1) {
1489                    TrackOutside(oOutsideTs, oSpan->fT, testT);
1490                }
1491                if (!oIndex) {
1492                    break;
1493                }
1494                oSpan = &other.fTs[--oIndex];
1495            }
1496            test = span;
1497            oTest = oSpan;
1498        } while (!approximately_negative(endT - test->fT));
1499        SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
1500        // FIXME: determine if canceled edges need outside ts added
1501        if (!done() && outsideTs.count()) {
1502            double tStart = outsideTs[0];
1503            double oStart = outsideTs[1];
1504            addCancelOutsides(tStart, oStart, other, oEndT);
1505            int count = outsideTs.count();
1506            if (count > 2) {
1507                double tStart = outsideTs[count - 2];
1508                double oStart = outsideTs[count - 1];
1509                addCancelOutsides(tStart, oStart, other, oEndT);
1510            }
1511        }
1512        if (!other.done() && oOutsideTs.count()) {
1513            double tStart = oOutsideTs[0];
1514            double oStart = oOutsideTs[1];
1515            other.addCancelOutsides(tStart, oStart, *this, endT);
1516        }
1517    }
1518
1519    int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1520            SkTDArray<double>& outsideTs) {
1521        int oWindValue = oTest->fWindValue;
1522        int oOppValue = oTest->fOppValue;
1523        if (opp) {
1524            SkTSwap<int>(oWindValue, oOppValue);
1525        }
1526        Span* const test = &fTs[index];
1527        Span* end = test;
1528        const double oStartT = oTest->fT;
1529        do {
1530            if (bumpSpan(end, oWindValue, oOppValue)) {
1531                TrackOutside(outsideTs, end->fT, oStartT);
1532            }
1533            end = &fTs[++index];
1534        } while (approximately_negative(end->fT - test->fT));
1535        return index;
1536    }
1537
1538    // because of the order in which coincidences are resolved, this and other
1539    // may not have the same intermediate points. Compute the corresponding
1540    // intermediate T values (using this as the master, other as the follower)
1541    // and walk other conditionally -- hoping that it catches up in the end
1542    int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1543            SkTDArray<double>& oOutsideTs) {
1544        Span* const oTest = &fTs[oIndex];
1545        Span* oEnd = oTest;
1546        const double startT = test->fT;
1547        const double oStartT = oTest->fT;
1548        while (!approximately_negative(oEndT - oEnd->fT)
1549                && approximately_negative(oEnd->fT - oStartT)) {
1550            zeroSpan(oEnd);
1551            TrackOutside(oOutsideTs, oEnd->fT, startT);
1552            oEnd = &fTs[++oIndex];
1553        }
1554        return oIndex;
1555    }
1556
1557    // FIXME: need to test this case:
1558    // contourA has two segments that are coincident
1559    // contourB has two segments that are coincident in the same place
1560    // each ends up with +2/0 pairs for winding count
1561    // since logic below doesn't transfer count (only increments/decrements) can this be
1562    // resolved to +4/0 ?
1563
1564    // set spans from start to end to increment the greater by one and decrement
1565    // the lesser
1566    void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
1567        SkASSERT(!approximately_negative(endT - startT));
1568        SkASSERT(!approximately_negative(oEndT - oStartT));
1569        bool opp = fOperand ^ other.fOperand;
1570        int index = 0;
1571        while (!approximately_negative(startT - fTs[index].fT)) {
1572            ++index;
1573        }
1574        int oIndex = 0;
1575        while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
1576            ++oIndex;
1577        }
1578        Span* test = &fTs[index];
1579        Span* oTest = &other.fTs[oIndex];
1580        SkTDArray<double> outsideTs;
1581        SkTDArray<double> oOutsideTs;
1582        do {
1583            // if either span has an opposite value and the operands don't match, resolve first
1584            SkASSERT(!test->fDone || !oTest->fDone);
1585            if (test->fDone || oTest->fDone) {
1586                index = advanceCoincidentThis(oTest, opp, index);
1587                oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
1588            } else {
1589                index = bumpCoincidentThis(oTest, opp, index, outsideTs);
1590                oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
1591            }
1592            test = &fTs[index];
1593            oTest = &other.fTs[oIndex];
1594        } while (!approximately_negative(endT - test->fT));
1595        SkASSERT(approximately_negative(oTest->fT - oEndT));
1596        SkASSERT(approximately_negative(oEndT - oTest->fT));
1597        if (!done() && outsideTs.count()) {
1598            addCoinOutsides(outsideTs, other, oEndT);
1599        }
1600        if (!other.done() && oOutsideTs.count()) {
1601            other.addCoinOutsides(oOutsideTs, *this, endT);
1602        }
1603    }
1604
1605    // FIXME: this doesn't prevent the same span from being added twice
1606    // fix in caller, assert here?
1607    void addTPair(double t, Segment& other, double otherT, bool borrowWind) {
1608        int tCount = fTs.count();
1609        for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1610            const Span& span = fTs[tIndex];
1611            if (!approximately_negative(span.fT - t)) {
1612                break;
1613            }
1614            if (approximately_negative(span.fT - t) && span.fOther == &other
1615                    && approximately_equal(span.fOtherT, otherT)) {
1616#if DEBUG_ADD_T_PAIR
1617                SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1618                        __FUNCTION__, fID, t, other.fID, otherT);
1619#endif
1620                return;
1621            }
1622        }
1623#if DEBUG_ADD_T_PAIR
1624        SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1625                __FUNCTION__, fID, t, other.fID, otherT);
1626#endif
1627        int insertedAt = addT(t, &other);
1628        int otherInsertedAt = other.addT(otherT, this);
1629        addOtherT(insertedAt, otherT, otherInsertedAt);
1630        other.addOtherT(otherInsertedAt, t, insertedAt);
1631        matchWindingValue(insertedAt, t, borrowWind);
1632        other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
1633    }
1634
1635    void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
1636        // add edge leading into junction
1637        int min = SkMin32(end, start);
1638        if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
1639            addAngle(angles, end, start);
1640        }
1641        // add edge leading away from junction
1642        int step = SkSign32(end - start);
1643        int tIndex = nextExactSpan(end, step);
1644        min = SkMin32(end, tIndex);
1645        if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
1646            addAngle(angles, end, tIndex);
1647        }
1648    }
1649
1650    int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
1651        Span* const test = &fTs[index];
1652        Span* end = test;
1653        do {
1654            end = &fTs[++index];
1655        } while (approximately_negative(end->fT - test->fT));
1656        return index;
1657    }
1658
1659    int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
1660        Span* const oTest = &fTs[oIndex];
1661        Span* oEnd = oTest;
1662        const double oStartT = oTest->fT;
1663        while (!approximately_negative(oEndT - oEnd->fT)
1664                && approximately_negative(oEnd->fT - oStartT)) {
1665            oEnd = &fTs[++oIndex];
1666        }
1667        return oIndex;
1668    }
1669
1670    const Bounds& bounds() const {
1671        return fBounds;
1672    }
1673
1674    void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
1675        double referenceT = fTs[index].fT;
1676        int lesser = index;
1677        while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
1678                && precisely_negative(referenceT - fTs[lesser].fT)) {
1679            buildAnglesInner(lesser, angles);
1680        }
1681        do {
1682            buildAnglesInner(index, angles);
1683        } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
1684                && precisely_negative(fTs[index].fT - referenceT));
1685    }
1686
1687    void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
1688        Span* span = &fTs[index];
1689        Segment* other = span->fOther;
1690    // if there is only one live crossing, and no coincidence, continue
1691    // in the same direction
1692    // if there is coincidence, the only choice may be to reverse direction
1693        // find edge on either side of intersection
1694        int oIndex = span->fOtherIndex;
1695        // if done == -1, prior span has already been processed
1696        int step = 1;
1697        int next = other->nextExactSpan(oIndex, step);
1698       if (next < 0) {
1699            step = -step;
1700            next = other->nextExactSpan(oIndex, step);
1701        }
1702        // add candidate into and away from junction
1703        other->addTwoAngles(next, oIndex, angles);
1704    }
1705
1706    int computeSum(int startIndex, int endIndex, bool binary) {
1707        SkTDArray<Angle> angles;
1708        addTwoAngles(startIndex, endIndex, angles);
1709        buildAngles(endIndex, angles, false);
1710        // OPTIMIZATION: check all angles to see if any have computed wind sum
1711        // before sorting (early exit if none)
1712        SkTDArray<Angle*> sorted;
1713        bool sortable = SortAngles(angles, sorted);
1714#if DEBUG_SORT
1715        sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
1716#endif
1717        if (!sortable) {
1718            return SK_MinS32;
1719        }
1720        int angleCount = angles.count();
1721        const Angle* angle;
1722        const Segment* base;
1723        int winding;
1724        int oWinding;
1725        int firstIndex = 0;
1726        do {
1727            angle = sorted[firstIndex];
1728            base = angle->segment();
1729            winding = base->windSum(angle);
1730            if (winding != SK_MinS32) {
1731                oWinding = base->oppSum(angle);
1732                break;
1733            }
1734            if (++firstIndex == angleCount) {
1735                return SK_MinS32;
1736            }
1737        } while (true);
1738        // turn winding into contourWinding
1739        int spanWinding = base->spanSign(angle);
1740        bool inner = useInnerWinding(winding + spanWinding, winding);
1741    #if DEBUG_WINDING
1742        SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
1743            spanWinding, winding, angle->sign(), inner,
1744            inner ? winding + spanWinding : winding);
1745    #endif
1746        if (inner) {
1747            winding += spanWinding;
1748        }
1749    #if DEBUG_SORT
1750        base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
1751    #endif
1752        int nextIndex = firstIndex + 1;
1753        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1754        winding -= base->spanSign(angle);
1755        oWinding -= base->oppSign(angle);
1756        do {
1757            if (nextIndex == angleCount) {
1758                nextIndex = 0;
1759            }
1760            angle = sorted[nextIndex];
1761            Segment* segment = angle->segment();
1762            bool opp = base->fOperand ^ segment->fOperand;
1763            int maxWinding, oMaxWinding;
1764            int spanSign = segment->spanSign(angle);
1765            int oppoSign = segment->oppSign(angle);
1766            if (opp) {
1767                oMaxWinding = oWinding;
1768                oWinding -= spanSign;
1769                maxWinding = winding;
1770                if (oppoSign) {
1771                    winding -= oppoSign;
1772                }
1773            } else {
1774                maxWinding = winding;
1775                winding -= spanSign;
1776                oMaxWinding = oWinding;
1777                if (oppoSign) {
1778                    oWinding -= oppoSign;
1779                }
1780            }
1781            if (segment->windSum(angle) == SK_MinS32) {
1782                if (opp) {
1783                    if (useInnerWinding(oMaxWinding, oWinding)) {
1784                        oMaxWinding = oWinding;
1785                    }
1786                    if (oppoSign && useInnerWinding(maxWinding, winding)) {
1787                        maxWinding = winding;
1788                    }
1789                    (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
1790                } else {
1791                    if (useInnerWinding(maxWinding, winding)) {
1792                        maxWinding = winding;
1793                    }
1794                    if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
1795                        oMaxWinding = oWinding;
1796                    }
1797                    (void) segment->markAndChaseWinding(angle, maxWinding, binary ? oMaxWinding : 0);
1798                }
1799            }
1800        } while (++nextIndex != lastIndex);
1801        int minIndex = SkMin32(startIndex, endIndex);
1802        return windSum(minIndex);
1803    }
1804
1805    int crossedSpan(const SkPoint& basePt, SkScalar& bestY, double& hitT) const {
1806        int bestT = -1;
1807        SkScalar top = bounds().fTop;
1808        SkScalar bottom = bounds().fBottom;
1809        int end = 0;
1810        do {
1811            int start = end;
1812            end = nextSpan(start, 1);
1813            if (fTs[start].fWindValue == 0) {
1814                continue;
1815            }
1816            SkPoint edge[4];
1817            double startT = fTs[start].fT;
1818            double endT = fTs[end].fT;
1819            (*SegmentSubDivide[fVerb])(fPts, startT, endT, edge);
1820            // intersect ray starting at basePt with edge
1821            Intersections intersections;
1822            // FIXME: always use original and limit results to T values within
1823            // start t and end t.
1824            // OPTIMIZE: use specialty function that intersects ray with curve,
1825            // returning t values only for curve (we don't care about t on ray)
1826            int pts = (*VSegmentIntersect[fVerb])(edge, top, bottom, basePt.fX,
1827                    false, intersections);
1828            if (pts == 0) {
1829                continue;
1830            }
1831            if (pts > 1 && fVerb == SkPath::kLine_Verb) {
1832            // if the intersection is edge on, wait for another one
1833                continue;
1834            }
1835            for (int index = 0; index < pts; ++index) {
1836                SkPoint pt;
1837                double foundT = intersections.fT[0][index];
1838                double testT = startT + (endT - startT) * foundT;
1839                (*SegmentXYAtT[fVerb])(fPts, testT, &pt);
1840                if (bestY < pt.fY && pt.fY < basePt.fY) {
1841                    if (fVerb > SkPath::kLine_Verb
1842                            && !approximately_less_than_zero(foundT)
1843                            && !approximately_greater_than_one(foundT)) {
1844                        SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, testT);
1845                        if (approximately_zero(dx)) {
1846                            continue;
1847                        }
1848                    }
1849                    bestY = pt.fY;
1850                    bestT = foundT < 1 ? start : end;
1851                    hitT = testT;
1852                }
1853            }
1854        } while (fTs[end].fT != 1);
1855        return bestT;
1856    }
1857
1858    bool crossedSpanHalves(const SkPoint& basePt, bool leftHalf, bool rightHalf) {
1859        // if a segment is connected to this one, consider it crossing
1860        int tIndex;
1861        if (fPts[0].fX == basePt.fX) {
1862            tIndex = 0;
1863            do {
1864                const Span& sSpan = fTs[tIndex];
1865                const Segment* sOther = sSpan.fOther;
1866                if (!sOther->fTs[sSpan.fOtherIndex].fWindValue) {
1867                    continue;
1868                }
1869                if (leftHalf ? sOther->fBounds.fLeft < basePt.fX
1870                        : sOther->fBounds.fRight > basePt.fX) {
1871                    return true;
1872                }
1873            } while (fTs[++tIndex].fT == 0);
1874        }
1875        if (fPts[fVerb].fX == basePt.fX) {
1876            tIndex = fTs.count() - 1;
1877            do {
1878                const Span& eSpan = fTs[tIndex];
1879                const Segment* eOther = eSpan.fOther;
1880                if (!eOther->fTs[eSpan.fOtherIndex].fWindValue) {
1881                    continue;
1882                }
1883                if (leftHalf ? eOther->fBounds.fLeft < basePt.fX
1884                        : eOther->fBounds.fRight > basePt.fX) {
1885                    return true;
1886                }
1887            } while (fTs[--tIndex].fT == 1);
1888        }
1889        return false;
1890    }
1891
1892    void decrementSpan(Span* span) {
1893        SkASSERT(span->fWindValue > 0);
1894        if (--(span->fWindValue) == 0) {
1895            if (!span->fOppValue && !span->fDone) {
1896                span->fDone = true;
1897                ++fDoneSpans;
1898            }
1899        }
1900    }
1901
1902    bool bumpSpan(Span* span, int windDelta, int oppDelta) {
1903        SkASSERT(!span->fDone);
1904        span->fWindValue += windDelta;
1905        SkASSERT(span->fWindValue >= 0);
1906        span->fOppValue += oppDelta;
1907        SkASSERT(span->fOppValue >= 0);
1908        if (fXor) {
1909            span->fWindValue &= 1;
1910        }
1911        if (fOppXor) {
1912            span->fOppValue &= 1;
1913        }
1914        if (!span->fWindValue && !span->fOppValue) {
1915            span->fDone = true;
1916            ++fDoneSpans;
1917            return true;
1918        }
1919        return false;
1920    }
1921
1922    // OPTIMIZE
1923    // when the edges are initially walked, they don't automatically get the prior and next
1924    // edges assigned to positions t=0 and t=1. Doing that would remove the need for this check,
1925    // and would additionally remove the need for similar checks in condition edges. It would
1926    // also allow intersection code to assume end of segment intersections (maybe?)
1927    bool complete() const {
1928        int count = fTs.count();
1929        return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
1930    }
1931
1932    bool done() const {
1933        SkASSERT(fDoneSpans <= fTs.count());
1934        return fDoneSpans == fTs.count();
1935    }
1936
1937    bool done(int min) const {
1938        return fTs[min].fDone;
1939    }
1940
1941    bool done(const Angle* angle) const {
1942        return done(SkMin32(angle->start(), angle->end()));
1943    }
1944
1945    /*
1946     The M and S variable name parts stand for the operators.
1947       Mi stands for Minuend (see wiki subtraction, analogous to difference)
1948       Su stands for Subtrahend
1949     The Opp variable name part designates that the value is for the Opposite operator.
1950     Opposite values result from combining coincident spans.
1951     */
1952
1953    Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
1954            bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
1955        const int startIndex = nextStart;
1956        const int endIndex = nextEnd;
1957        SkASSERT(startIndex != endIndex);
1958        const int count = fTs.count();
1959        SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
1960        const int step = SkSign32(endIndex - startIndex);
1961        const int end = nextExactSpan(startIndex, step);
1962        SkASSERT(end >= 0);
1963        Span* endSpan = &fTs[end];
1964        Segment* other;
1965        if (isSimple(end)) {
1966        // mark the smaller of startIndex, endIndex done, and all adjacent
1967        // spans with the same T value (but not 'other' spans)
1968    #if DEBUG_WINDING
1969            SkDebugf("%s simple\n", __FUNCTION__);
1970    #endif
1971            markDoneBinary(SkMin32(startIndex, endIndex));
1972            other = endSpan->fOther;
1973            nextStart = endSpan->fOtherIndex;
1974            double startT = other->fTs[nextStart].fT;
1975            nextEnd = nextStart;
1976            do {
1977                nextEnd += step;
1978            }
1979            while (precisely_zero(startT - other->fTs[nextEnd].fT));
1980            SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
1981            return other;
1982        }
1983        // more than one viable candidate -- measure angles to find best
1984        SkTDArray<Angle> angles;
1985        SkASSERT(startIndex - endIndex != 0);
1986        SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
1987        addTwoAngles(startIndex, end, angles);
1988        buildAngles(end, angles, true);
1989        SkTDArray<Angle*> sorted;
1990        bool sortable = SortAngles(angles, sorted);
1991        int angleCount = angles.count();
1992        int firstIndex = findStartingEdge(sorted, startIndex, end);
1993        SkASSERT(firstIndex >= 0);
1994    #if DEBUG_SORT
1995        debugShowSort(__FUNCTION__, sorted, firstIndex);
1996    #endif
1997        if (!sortable) {
1998            unsortable = true;
1999            return NULL;
2000        }
2001        SkASSERT(sorted[firstIndex]->segment() == this);
2002    #if DEBUG_WINDING
2003        SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2004                sorted[firstIndex]->sign());
2005    #endif
2006        int sumMiWinding = updateWinding(endIndex, startIndex);
2007        int sumSuWinding = updateOppWinding(endIndex, startIndex);
2008        if (operand()) {
2009            SkTSwap<int>(sumMiWinding, sumSuWinding);
2010        }
2011        int nextIndex = firstIndex + 1;
2012        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2013        const Angle* foundAngle = NULL;
2014        bool foundDone = false;
2015        // iterate through the angle, and compute everyone's winding
2016        Segment* nextSegment;
2017        do {
2018            SkASSERT(nextIndex != firstIndex);
2019            if (nextIndex == angleCount) {
2020                nextIndex = 0;
2021            }
2022            const Angle* nextAngle = sorted[nextIndex];
2023            nextSegment = nextAngle->segment();
2024            int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2025            bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2026                    nextAngle->end(), op, sumMiWinding, sumSuWinding,
2027                    maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
2028            if (activeAngle && (!foundAngle || foundDone)) {
2029                foundAngle = nextAngle;
2030                foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
2031            }
2032            if (nextSegment->done()) {
2033                continue;
2034            }
2035            if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2036                continue;
2037            }
2038            Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2039                    oppSumWinding, activeAngle, nextAngle);
2040            if (last) {
2041                *chase.append() = last;
2042#if DEBUG_WINDING
2043                SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2044                        last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2045#endif
2046            }
2047        } while (++nextIndex != lastIndex);
2048        markDoneBinary(SkMin32(startIndex, endIndex));
2049        if (!foundAngle) {
2050            return NULL;
2051        }
2052        nextStart = foundAngle->start();
2053        nextEnd = foundAngle->end();
2054        nextSegment = foundAngle->segment();
2055
2056    #if DEBUG_WINDING
2057        SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2058                __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2059     #endif
2060        return nextSegment;
2061    }
2062
2063    // so the span needs to contain the pairing info found here
2064    // this should include the winding computed for the edge, and
2065    //  what edge it connects to, and whether it is discarded
2066    //  (maybe discarded == abs(winding) > 1) ?
2067    // only need derivatives for duration of sorting, add a new struct
2068    // for pairings, remove extra spans that have zero length and
2069    //  reference an unused other
2070    // for coincident, the last span on the other may be marked done
2071    //  (always?)
2072
2073    // if loop is exhausted, contour may be closed.
2074    // FIXME: pass in close point so we can check for closure
2075
2076    // given a segment, and a sense of where 'inside' is, return the next
2077    // segment. If this segment has an intersection, or ends in multiple
2078    // segments, find the mate that continues the outside.
2079    // note that if there are multiples, but no coincidence, we can limit
2080    // choices to connections in the correct direction
2081
2082    // mark found segments as done
2083
2084    // start is the index of the beginning T of this edge
2085    // it is guaranteed to have an end which describes a non-zero length (?)
2086    // winding -1 means ccw, 1 means cw
2087    Segment* findNextWinding(SkTDArray<Span*>& chase, bool active,
2088            int& nextStart, int& nextEnd, int& winding, int& spanWinding,
2089            bool& unsortable) {
2090        const int startIndex = nextStart;
2091        const int endIndex = nextEnd;
2092        int outerWinding = winding;
2093        int innerWinding = winding + spanWinding;
2094    #if DEBUG_WINDING
2095        SkDebugf("%s winding=%d spanWinding=%d outerWinding=%d innerWinding=%d\n",
2096                __FUNCTION__, winding, spanWinding, outerWinding, innerWinding);
2097    #endif
2098        if (useInnerWinding(outerWinding, innerWinding)) {
2099            outerWinding = innerWinding;
2100        }
2101        SkASSERT(startIndex != endIndex);
2102        int count = fTs.count();
2103        SkASSERT(startIndex < endIndex ? startIndex < count - 1
2104                : startIndex > 0);
2105        int step = SkSign32(endIndex - startIndex);
2106        int end = nextExactSpan(startIndex, step);
2107        SkASSERT(end >= 0);
2108        Span* endSpan = &fTs[end];
2109        Segment* other;
2110        if (isSimple(end)) {
2111        // mark the smaller of startIndex, endIndex done, and all adjacent
2112        // spans with the same T value (but not 'other' spans)
2113    #if DEBUG_WINDING
2114            SkDebugf("%s simple\n", __FUNCTION__);
2115    #endif
2116            markDone(SkMin32(startIndex, endIndex), outerWinding);
2117            other = endSpan->fOther;
2118            nextStart = endSpan->fOtherIndex;
2119            double startT = other->fTs[nextStart].fT;
2120            nextEnd = nextStart;
2121            do {
2122                nextEnd += step;
2123            }
2124             while (precisely_zero(startT - other->fTs[nextEnd].fT));
2125            SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2126            return other;
2127        }
2128        // more than one viable candidate -- measure angles to find best
2129        SkTDArray<Angle> angles;
2130        SkASSERT(startIndex - endIndex != 0);
2131        SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2132        addTwoAngles(startIndex, end, angles);
2133        buildAngles(end, angles, false);
2134        SkTDArray<Angle*> sorted;
2135        bool sortable = SortAngles(angles, sorted);
2136        int angleCount = angles.count();
2137        int firstIndex = findStartingEdge(sorted, startIndex, end);
2138        SkASSERT(firstIndex >= 0);
2139    #if DEBUG_SORT
2140        debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
2141    #endif
2142        if (!sortable) {
2143            unsortable = true;
2144            return NULL;
2145        }
2146        SkASSERT(sorted[firstIndex]->segment() == this);
2147    #if DEBUG_WINDING
2148        SkDebugf("%s [%d] sign=%d\n", __FUNCTION__, firstIndex, sorted[firstIndex]->sign());
2149    #endif
2150        int sumWinding = winding - spanSign(sorted[firstIndex]);
2151        int nextIndex = firstIndex + 1;
2152        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2153        const Angle* foundAngle = NULL;
2154        // FIXME: found done logic probably fails if there are more than 4
2155        // sorted angles. It should bias towards the first and last undone
2156        // edges -- but not sure that it won't choose a middle (incorrect)
2157        // edge if one is undone
2158        bool foundDone = false;
2159        bool foundDone2 = false;
2160        // iterate through the angle, and compute everyone's winding
2161        bool altFlipped = false;
2162        bool foundFlipped = false;
2163        int foundSum = SK_MinS32;
2164        Segment* nextSegment;
2165        int lastNonZeroSum = winding;
2166        do {
2167            if (nextIndex == angleCount) {
2168                nextIndex = 0;
2169            }
2170            const Angle* nextAngle = sorted[nextIndex];
2171            int maxWinding = sumWinding;
2172            if (sumWinding) {
2173                lastNonZeroSum = sumWinding;
2174            }
2175            nextSegment = nextAngle->segment();
2176            bool nextDone = nextSegment->done(nextAngle);
2177            bool nextTiny = nextSegment->tiny(nextAngle);
2178            sumWinding -= nextSegment->spanSign(nextAngle);
2179            altFlipped ^= lastNonZeroSum * sumWinding < 0; // flip if different signs
2180    #if 0 && DEBUG_WINDING
2181            SkASSERT(abs(sumWinding) <= gDebugMaxWindSum);
2182            SkDebugf("%s [%d] maxWinding=%d sumWinding=%d sign=%d altFlipped=%d\n", __FUNCTION__,
2183                    nextIndex, maxWinding, sumWinding, nextAngle->sign(), altFlipped);
2184    #endif
2185           if (!sumWinding) {
2186                if (!active) {
2187                    // FIXME: shouldn't this call mark and chase done ?
2188                    markDone(SkMin32(startIndex, endIndex), outerWinding);
2189                    // FIXME: shouldn't this call mark and chase winding ?
2190                    nextSegment->markWinding(SkMin32(nextAngle->start(),
2191                                nextAngle->end()), maxWinding);
2192    #if DEBUG_WINDING
2193                    SkDebugf("%s [%d] inactive\n", __FUNCTION__, nextIndex);
2194    #endif
2195                    return NULL;
2196                }
2197                if (!foundAngle || foundDone) {
2198                    foundAngle = nextAngle;
2199                    foundDone = nextDone && !nextTiny;
2200                    foundFlipped = altFlipped;
2201                }
2202                continue;
2203            }
2204
2205            if (!maxWinding && (!foundAngle || foundDone2)) {
2206        #if DEBUG_WINDING
2207                if (foundAngle && foundDone2) {
2208                    SkDebugf("%s [%d] !foundAngle && foundDone2\n", __FUNCTION__, nextIndex);
2209                }
2210        #endif
2211                foundAngle = nextAngle;
2212                foundDone2 = nextDone && !nextTiny;
2213                foundFlipped = altFlipped;
2214                foundSum = sumWinding;
2215            }
2216            if (nextSegment->done()) {
2217                continue;
2218            }
2219            // if the winding is non-zero, nextAngle does not connect to
2220            // current chain. If we haven't done so already, mark the angle
2221            // as done, record the winding value, and mark connected unambiguous
2222            // segments as well.
2223            if (nextSegment->windSum(nextAngle) == SK_MinS32) {
2224                if (useInnerWinding(maxWinding, sumWinding)) {
2225                    maxWinding = sumWinding;
2226                }
2227                Span* last;
2228                if (foundAngle) {
2229                    last = nextSegment->markAndChaseWinding(nextAngle, maxWinding);
2230                } else {
2231                    last = nextSegment->markAndChaseDone(nextAngle, maxWinding);
2232                }
2233                if (last) {
2234                    *chase.append() = last;
2235    #if DEBUG_WINDING
2236                    SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2237                            last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2238    #endif
2239                }
2240            }
2241        } while (++nextIndex != lastIndex);
2242        markDone(SkMin32(startIndex, endIndex), outerWinding);
2243        if (!foundAngle) {
2244            return NULL;
2245        }
2246        nextStart = foundAngle->start();
2247        nextEnd = foundAngle->end();
2248        nextSegment = foundAngle->segment();
2249        int flipped = foundFlipped ? -1 : 1;
2250        spanWinding = SkSign32(spanWinding) * flipped * nextSegment->windValue(
2251                SkMin32(nextStart, nextEnd));
2252        if (winding) {
2253    #if DEBUG_WINDING
2254            SkDebugf("%s ---6 winding=%d foundSum=", __FUNCTION__, winding);
2255            if (foundSum == SK_MinS32) {
2256                SkDebugf("?");
2257            } else {
2258                SkDebugf("%d", foundSum);
2259            }
2260            SkDebugf("\n");
2261     #endif
2262            winding = foundSum;
2263        }
2264    #if DEBUG_WINDING
2265        SkDebugf("%s spanWinding=%d flipped=%d\n", __FUNCTION__, spanWinding, flipped);
2266    #endif
2267        return nextSegment;
2268    }
2269
2270    Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
2271        const int startIndex = nextStart;
2272        const int endIndex = nextEnd;
2273        SkASSERT(startIndex != endIndex);
2274        int count = fTs.count();
2275        SkASSERT(startIndex < endIndex ? startIndex < count - 1
2276                : startIndex > 0);
2277        int step = SkSign32(endIndex - startIndex);
2278        int end = nextExactSpan(startIndex, step);
2279        SkASSERT(end >= 0);
2280        Span* endSpan = &fTs[end];
2281        Segment* other;
2282        markDone(SkMin32(startIndex, endIndex), 1);
2283        if (isSimple(end)) {
2284    #if DEBUG_WINDING
2285            SkDebugf("%s simple\n", __FUNCTION__);
2286    #endif
2287            other = endSpan->fOther;
2288            nextStart = endSpan->fOtherIndex;
2289            double startT = other->fTs[nextStart].fT;
2290            SkDEBUGCODE(bool firstLoop = true;)
2291            if ((approximately_less_than_zero(startT) && step < 0)
2292                    || (approximately_greater_than_one(startT) && step > 0)) {
2293                step = -step;
2294                SkDEBUGCODE(firstLoop = false;)
2295            }
2296            do {
2297                nextEnd = nextStart;
2298                do {
2299                    nextEnd += step;
2300                }
2301                 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2302                if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2303                    break;
2304                }
2305 #ifdef SK_DEBUG
2306                SkASSERT(firstLoop);
2307 #endif
2308                SkDEBUGCODE(firstLoop = false;)
2309                step = -step;
2310            } while (true);
2311            SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2312            return other;
2313        }
2314        SkTDArray<Angle> angles;
2315        SkASSERT(startIndex - endIndex != 0);
2316        SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2317        addTwoAngles(startIndex, end, angles);
2318        buildAngles(end, angles, false);
2319        SkTDArray<Angle*> sorted;
2320        bool sortable = SortAngles(angles, sorted);
2321        int angleCount = angles.count();
2322        int firstIndex = findStartingEdge(sorted, startIndex, end);
2323        SkASSERT(firstIndex >= 0);
2324    #if DEBUG_SORT
2325        debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
2326    #endif
2327        if (!sortable) {
2328            unsortable = true;
2329            return NULL;
2330        }
2331        SkASSERT(sorted[firstIndex]->segment() == this);
2332        int nextIndex = firstIndex + 1;
2333        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2334        const Angle* nextAngle;
2335        Segment* nextSegment;
2336        do {
2337            if (nextIndex == angleCount) {
2338                nextIndex = 0;
2339            }
2340            nextAngle = sorted[nextIndex];
2341            nextSegment = nextAngle->segment();
2342            if (!nextSegment->done(nextAngle)) {
2343                break;
2344            }
2345            if (++nextIndex == lastIndex) {
2346                return NULL;
2347            }
2348        } while (true);
2349        nextStart = nextAngle->start();
2350        nextEnd = nextAngle->end();
2351        return nextSegment;
2352    }
2353
2354    int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2355        int angleCount = sorted.count();
2356        int firstIndex = -1;
2357        for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2358            const Angle* angle = sorted[angleIndex];
2359            if (angle->segment() == this && angle->start() == end &&
2360                    angle->end() == start) {
2361                firstIndex = angleIndex;
2362                break;
2363            }
2364        }
2365        return firstIndex;
2366    }
2367
2368    // FIXME: this is tricky code; needs its own unit test
2369    void findTooCloseToCall() {
2370        int count = fTs.count();
2371        if (count < 3) { // require t=0, x, 1 at minimum
2372            return;
2373        }
2374        int matchIndex = 0;
2375        int moCount;
2376        Span* match;
2377        Segment* mOther;
2378        do {
2379            match = &fTs[matchIndex];
2380            mOther = match->fOther;
2381            // FIXME: allow quads, cubics to be near coincident?
2382            if (mOther->fVerb == SkPath::kLine_Verb) {
2383                moCount = mOther->fTs.count();
2384                if (moCount >= 3) {
2385                    break;
2386                }
2387            }
2388            if (++matchIndex >= count) {
2389                return;
2390            }
2391        } while (true); // require t=0, x, 1 at minimum
2392        // OPTIMIZATION: defer matchPt until qualifying toCount is found?
2393        const SkPoint* matchPt = &xyAtT(match);
2394        // look for a pair of nearby T values that map to the same (x,y) value
2395        // if found, see if the pair of other segments share a common point. If
2396        // so, the span from here to there is coincident.
2397        for (int index = matchIndex + 1; index < count; ++index) {
2398            Span* test = &fTs[index];
2399            if (test->fDone) {
2400                continue;
2401            }
2402            Segment* tOther = test->fOther;
2403            if (tOther->fVerb != SkPath::kLine_Verb) {
2404                continue; // FIXME: allow quads, cubics to be near coincident?
2405            }
2406            int toCount = tOther->fTs.count();
2407            if (toCount < 3) { // require t=0, x, 1 at minimum
2408                continue;
2409            }
2410            const SkPoint* testPt = &xyAtT(test);
2411            if (*matchPt != *testPt) {
2412                matchIndex = index;
2413                moCount = toCount;
2414                match = test;
2415                mOther = tOther;
2416                matchPt = testPt;
2417                continue;
2418            }
2419            int moStart = -1;
2420            int moEnd = -1;
2421            double moStartT, moEndT;
2422            for (int moIndex = 0; moIndex < moCount; ++moIndex) {
2423                Span& moSpan = mOther->fTs[moIndex];
2424                if (moSpan.fDone) {
2425                    continue;
2426                }
2427                if (moSpan.fOther == this) {
2428                    if (moSpan.fOtherT == match->fT) {
2429                        moStart = moIndex;
2430                        moStartT = moSpan.fT;
2431                    }
2432                    continue;
2433                }
2434                if (moSpan.fOther == tOther) {
2435                    if (tOther->fTs[moSpan.fOtherIndex].fWindValue == 0) {
2436                        moStart = -1;
2437                        break;
2438                    }
2439                    SkASSERT(moEnd == -1);
2440                    moEnd = moIndex;
2441                    moEndT = moSpan.fT;
2442                }
2443            }
2444            if (moStart < 0 || moEnd < 0) {
2445                continue;
2446            }
2447            // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
2448            if (approximately_equal(moStartT, moEndT)) {
2449                continue;
2450            }
2451            int toStart = -1;
2452            int toEnd = -1;
2453            double toStartT, toEndT;
2454            for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2455                Span& toSpan = tOther->fTs[toIndex];
2456                if (toSpan.fDone) {
2457                    continue;
2458                }
2459                if (toSpan.fOther == this) {
2460                    if (toSpan.fOtherT == test->fT) {
2461                        toStart = toIndex;
2462                        toStartT = toSpan.fT;
2463                    }
2464                    continue;
2465                }
2466                if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
2467                    if (mOther->fTs[toSpan.fOtherIndex].fWindValue == 0) {
2468                        moStart = -1;
2469                        break;
2470                    }
2471                    SkASSERT(toEnd == -1);
2472                    toEnd = toIndex;
2473                    toEndT = toSpan.fT;
2474                }
2475            }
2476            // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2477            if (toStart <= 0 || toEnd <= 0) {
2478                continue;
2479            }
2480            if (approximately_equal(toStartT, toEndT)) {
2481                continue;
2482            }
2483            // test to see if the segment between there and here is linear
2484            if (!mOther->isLinear(moStart, moEnd)
2485                    || !tOther->isLinear(toStart, toEnd)) {
2486                continue;
2487            }
2488            bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
2489            if (flipped) {
2490                mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
2491            } else {
2492                mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
2493            }
2494        }
2495    }
2496
2497 //   start here;
2498    // either:
2499    // a) mark spans with either end unsortable as done, or
2500    // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2501    //    when encountering an unsortable span
2502
2503    // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2504    // and use more concise logic like the old edge walker code?
2505    // FIXME: this needs to deal with coincident edges
2506    Segment* findTop(int& tIndex, int& endIndex) {
2507        // iterate through T intersections and return topmost
2508        // topmost tangent from y-min to first pt is closer to horizontal
2509        SkASSERT(!done());
2510        int firstT = -1;
2511        SkPoint topPt;
2512        topPt.fY = SK_ScalarMax;
2513        int count = fTs.count();
2514        // see if either end is not done since we want smaller Y of the pair
2515        bool lastDone = true;
2516        bool lastUnsortable = false;
2517        for (int index = 0; index < count; ++index) {
2518            const Span& span = fTs[index];
2519            if (span.fUnsortableStart | lastUnsortable) {
2520                goto next;
2521            }
2522            if (!span.fDone | !lastDone) {
2523                const SkPoint& intercept = xyAtT(&span);
2524                if (topPt.fY > intercept.fY || (topPt.fY == intercept.fY
2525                        && topPt.fX > intercept.fX)) {
2526                    topPt = intercept;
2527                    firstT = index;
2528                }
2529            }
2530    next:
2531            lastDone = span.fDone;
2532            lastUnsortable = span.fUnsortableEnd;
2533        }
2534        SkASSERT(firstT >= 0);
2535        // sort the edges to find the leftmost
2536        int step = 1;
2537        int end = nextSpan(firstT, step);
2538        if (end == -1) {
2539            step = -1;
2540            end = nextSpan(firstT, step);
2541            SkASSERT(end != -1);
2542        }
2543        // if the topmost T is not on end, or is three-way or more, find left
2544        // look for left-ness from tLeft to firstT (matching y of other)
2545        SkTDArray<Angle> angles;
2546        SkASSERT(firstT - end != 0);
2547        addTwoAngles(end, firstT, angles);
2548        buildAngles(firstT, angles, true);
2549        SkTDArray<Angle*> sorted;
2550        bool sortable = SortAngles(angles, sorted);
2551    #if DEBUG_SORT
2552        sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
2553    #endif
2554        if (!sortable) {
2555            return NULL;
2556        }
2557        // skip edges that have already been processed
2558        firstT = -1;
2559        Segment* leftSegment;
2560        do {
2561            const Angle* angle = sorted[++firstT];
2562            SkASSERT(!angle->unsortable());
2563            leftSegment = angle->segment();
2564            tIndex = angle->end();
2565            endIndex = angle->start();
2566        } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
2567        return leftSegment;
2568    }
2569
2570    // FIXME: not crazy about this
2571    // when the intersections are performed, the other index is into an
2572    // incomplete array. as the array grows, the indices become incorrect
2573    // while the following fixes the indices up again, it isn't smart about
2574    // skipping segments whose indices are already correct
2575    // assuming we leave the code that wrote the index in the first place
2576    void fixOtherTIndex() {
2577        int iCount = fTs.count();
2578        for (int i = 0; i < iCount; ++i) {
2579            Span& iSpan = fTs[i];
2580            double oT = iSpan.fOtherT;
2581            Segment* other = iSpan.fOther;
2582            int oCount = other->fTs.count();
2583            for (int o = 0; o < oCount; ++o) {
2584                Span& oSpan = other->fTs[o];
2585                if (oT == oSpan.fT && this == oSpan.fOther) {
2586                    iSpan.fOtherIndex = o;
2587                    break;
2588                }
2589            }
2590        }
2591    }
2592
2593    void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
2594        fDoneSpans = 0;
2595        fOperand = operand;
2596        fXor = evenOdd;
2597        fPts = pts;
2598        fVerb = verb;
2599    }
2600
2601    void initWinding(int start, int end, int winding, int oppWinding) {
2602        int local = spanSign(start, end);
2603        if (local * winding >= 0) {
2604            winding += local;
2605        }
2606        local = oppSign(start, end);
2607        if (local * oppWinding >= 0) {
2608            oppWinding += local;
2609        }
2610        (void) markAndChaseWinding(start, end, winding, oppWinding);
2611    }
2612
2613    bool intersected() const {
2614        return fTs.count() > 0;
2615    }
2616
2617    bool isConnected(int startIndex, int endIndex) const {
2618        return fTs[startIndex].fWindSum != SK_MinS32
2619                || fTs[endIndex].fWindSum != SK_MinS32;
2620    }
2621
2622    bool isHorizontal() const {
2623        return fBounds.fTop == fBounds.fBottom;
2624    }
2625
2626    bool isLinear(int start, int end) const {
2627        if (fVerb == SkPath::kLine_Verb) {
2628            return true;
2629        }
2630        if (fVerb == SkPath::kQuad_Verb) {
2631            SkPoint qPart[3];
2632            QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
2633            return QuadIsLinear(qPart);
2634        } else {
2635            SkASSERT(fVerb == SkPath::kCubic_Verb);
2636            SkPoint cPart[4];
2637            CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
2638            return CubicIsLinear(cPart);
2639        }
2640    }
2641
2642    // OPTIMIZE: successive calls could start were the last leaves off
2643    // or calls could specialize to walk forwards or backwards
2644    bool isMissing(double startT) const {
2645        size_t tCount = fTs.count();
2646        for (size_t index = 0; index < tCount; ++index) {
2647            if (approximately_zero(startT - fTs[index].fT)) {
2648                return false;
2649            }
2650        }
2651        return true;
2652    }
2653
2654    bool isSimple(int end) const {
2655        int count = fTs.count();
2656        if (count == 2) {
2657            return true;
2658        }
2659        double t = fTs[end].fT;
2660        if (approximately_less_than_zero(t)) {
2661            return !approximately_less_than_zero(fTs[1].fT);
2662        }
2663        if (approximately_greater_than_one(t)) {
2664            return !approximately_greater_than_one(fTs[count - 2].fT);
2665        }
2666        return false;
2667    }
2668
2669    bool isVertical() const {
2670        return fBounds.fLeft == fBounds.fRight;
2671    }
2672
2673    SkScalar leftMost(int start, int end) const {
2674        return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
2675    }
2676
2677    // this span is excluded by the winding rule -- chase the ends
2678    // as long as they are unambiguous to mark connections as done
2679    // and give them the same winding value
2680    Span* markAndChaseDone(const Angle* angle, int winding) {
2681        int index = angle->start();
2682        int endIndex = angle->end();
2683        return markAndChaseDone(index, endIndex, winding);
2684    }
2685
2686    Span* markAndChaseDone(int index, int endIndex, int winding) {
2687        int step = SkSign32(endIndex - index);
2688        int min = SkMin32(index, endIndex);
2689        markDone(min, winding);
2690        Span* last;
2691        Segment* other = this;
2692        while ((other = other->nextChase(index, step, min, last))) {
2693            other->markDone(min, winding);
2694        }
2695        return last;
2696    }
2697
2698    Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
2699        int index = angle->start();
2700        int endIndex = angle->end();
2701        int step = SkSign32(endIndex - index);
2702        int min = SkMin32(index, endIndex);
2703        markDoneBinary(min, winding, oppWinding);
2704        Span* last;
2705        Segment* other = this;
2706        while ((other = other->nextChase(index, step, min, last))) {
2707            other->markDoneBinary(min, winding, oppWinding);
2708        }
2709        return last;
2710    }
2711
2712    Span* markAndChaseDoneBinary(int index, int endIndex) {
2713        int step = SkSign32(endIndex - index);
2714        int min = SkMin32(index, endIndex);
2715        markDoneBinary(min);
2716        Span* last;
2717        Segment* other = this;
2718        while ((other = other->nextChase(index, step, min, last))) {
2719            other->markDoneBinary(min);
2720        }
2721        return last;
2722    }
2723
2724    Span* markAndChaseWinding(const Angle* angle, const int winding) {
2725        int index = angle->start();
2726        int endIndex = angle->end();
2727        int step = SkSign32(endIndex - index);
2728        int min = SkMin32(index, endIndex);
2729        markWinding(min, winding);
2730        Span* last;
2731        Segment* other = this;
2732        while ((other = other->nextChase(index, step, min, last))) {
2733            if (other->fTs[min].fWindSum != SK_MinS32) {
2734                SkASSERT(other->fTs[min].fWindSum == winding);
2735                return NULL;
2736            }
2737            other->markWinding(min, winding);
2738        }
2739        return last;
2740    }
2741
2742    Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
2743        int min = SkMin32(index, endIndex);
2744        int step = SkSign32(endIndex - index);
2745        markWinding(min, winding, oppWinding);
2746        Span* last;
2747        Segment* other = this;
2748        while ((other = other->nextChase(index, step, min, last))) {
2749            if (other->fTs[min].fWindSum != SK_MinS32) {
2750                SkASSERT(other->fTs[min].fWindSum == winding);
2751                return NULL;
2752            }
2753            other->markWinding(min, winding, oppWinding);
2754        }
2755        return last;
2756    }
2757
2758    Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
2759        int start = angle->start();
2760        int end = angle->end();
2761        return markAndChaseWinding(start, end, winding, oppWinding);
2762    }
2763
2764    Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
2765            bool activeAngle, const Angle* angle) {
2766        SkASSERT(angle->segment() == this);
2767        if (useInnerWinding(maxWinding, sumWinding)) {
2768            maxWinding = sumWinding;
2769        }
2770        if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
2771            oppMaxWinding = oppSumWinding;
2772        }
2773        Span* last;
2774        if (activeAngle) {
2775            last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
2776        } else {
2777            last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
2778        }
2779        return last;
2780    }
2781
2782    // FIXME: this should also mark spans with equal (x,y)
2783    // This may be called when the segment is already marked done. While this
2784    // wastes time, it shouldn't do any more than spin through the T spans.
2785    // OPTIMIZATION: abort on first done found (assuming that this code is
2786    // always called to mark segments done).
2787    void markDone(int index, int winding) {
2788      //  SkASSERT(!done());
2789        SkASSERT(winding);
2790        double referenceT = fTs[index].fT;
2791        int lesser = index;
2792        while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2793            markOneDone(__FUNCTION__, lesser, winding);
2794        }
2795        do {
2796            markOneDone(__FUNCTION__, index, winding);
2797        } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2798    }
2799
2800    void markDoneBinary(int index, int winding, int oppWinding) {
2801      //  SkASSERT(!done());
2802        SkASSERT(winding || oppWinding);
2803        double referenceT = fTs[index].fT;
2804        int lesser = index;
2805        while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2806            markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
2807        }
2808        do {
2809            markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
2810        } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2811    }
2812
2813    void markDoneBinary(int index) {
2814        double referenceT = fTs[index].fT;
2815        int lesser = index;
2816        while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2817            markOneDoneBinary(__FUNCTION__, lesser);
2818        }
2819        do {
2820            markOneDoneBinary(__FUNCTION__, index);
2821        } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2822    }
2823
2824    void markOneDone(const char* funName, int tIndex, int winding) {
2825        Span* span = markOneWinding(funName, tIndex, winding);
2826        if (!span) {
2827            return;
2828        }
2829        span->fDone = true;
2830        fDoneSpans++;
2831    }
2832
2833    void markOneDoneBinary(const char* funName, int tIndex) {
2834        Span* span = verifyOneWinding(funName, tIndex);
2835        if (!span) {
2836            return;
2837        }
2838        span->fDone = true;
2839        fDoneSpans++;
2840    }
2841
2842    void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
2843        Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
2844        if (!span) {
2845            return;
2846        }
2847        span->fDone = true;
2848        fDoneSpans++;
2849    }
2850
2851    Span* markOneWinding(const char* funName, int tIndex, int winding) {
2852        Span& span = fTs[tIndex];
2853        if (span.fDone) {
2854            return NULL;
2855        }
2856    #if DEBUG_MARK_DONE
2857        debugShowNewWinding(funName, span, winding);
2858    #endif
2859        SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
2860   #ifdef SK_DEBUG
2861        SkASSERT(abs(winding) <= gDebugMaxWindSum);
2862   #endif
2863        span.fWindSum = winding;
2864        return &span;
2865    }
2866
2867    Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
2868        Span& span = fTs[tIndex];
2869        if (span.fDone) {
2870            return NULL;
2871        }
2872    #if DEBUG_MARK_DONE
2873        debugShowNewWinding(funName, span, winding, oppWinding);
2874    #endif
2875        SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
2876   #ifdef SK_DEBUG
2877        SkASSERT(abs(winding) <= gDebugMaxWindSum);
2878   #endif
2879        span.fWindSum = winding;
2880        SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
2881   #ifdef SK_DEBUG
2882        SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
2883   #endif
2884        span.fOppSum = oppWinding;
2885        return &span;
2886    }
2887
2888    Span* verifyOneWinding(const char* funName, int tIndex) {
2889        Span& span = fTs[tIndex];
2890        if (span.fDone) {
2891            return NULL;
2892        }
2893    #if DEBUG_MARK_DONE
2894        debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
2895    #endif
2896        SkASSERT(span.fWindSum != SK_MinS32);
2897        SkASSERT(span.fOppSum != SK_MinS32);
2898        return &span;
2899    }
2900
2901    // note that just because a span has one end that is unsortable, that's
2902    // not enough to mark it done. The other end may be sortable, allowing the
2903    // span to be added.
2904    void markUnsortable(int start, int end) {
2905        Span* span = &fTs[start];
2906        if (start < end) {
2907            span->fUnsortableStart = true;
2908        } else {
2909            --span;
2910            span->fUnsortableEnd = true;
2911        }
2912        if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
2913            return;
2914        }
2915        span->fDone = true;
2916        fDoneSpans++;
2917    }
2918
2919    void markWinding(int index, int winding) {
2920    //    SkASSERT(!done());
2921        SkASSERT(winding);
2922        double referenceT = fTs[index].fT;
2923        int lesser = index;
2924        while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2925            markOneWinding(__FUNCTION__, lesser, winding);
2926        }
2927        do {
2928            markOneWinding(__FUNCTION__, index, winding);
2929       } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2930    }
2931
2932    void markWinding(int index, int winding, int oppWinding) {
2933    //    SkASSERT(!done());
2934        SkASSERT(winding || oppWinding);
2935        double referenceT = fTs[index].fT;
2936        int lesser = index;
2937        while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2938            markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
2939        }
2940        do {
2941            markOneWinding(__FUNCTION__, index, winding, oppWinding);
2942       } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2943    }
2944
2945    void matchWindingValue(int tIndex, double t, bool borrowWind) {
2946        int nextDoorWind = SK_MaxS32;
2947        int nextOppWind = SK_MaxS32;
2948        if (tIndex > 0) {
2949            const Span& below = fTs[tIndex - 1];
2950            if (approximately_negative(t - below.fT)) {
2951                nextDoorWind = below.fWindValue;
2952                nextOppWind = below.fOppValue;
2953            }
2954        }
2955        if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
2956            const Span& above = fTs[tIndex + 1];
2957            if (approximately_negative(above.fT - t)) {
2958                nextDoorWind = above.fWindValue;
2959                nextOppWind = above.fOppValue;
2960            }
2961        }
2962        if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
2963            const Span& below = fTs[tIndex - 1];
2964            nextDoorWind = below.fWindValue;
2965            nextOppWind = below.fOppValue;
2966        }
2967        if (nextDoorWind != SK_MaxS32) {
2968            Span& newSpan = fTs[tIndex];
2969            newSpan.fWindValue = nextDoorWind;
2970            newSpan.fOppValue = nextOppWind;
2971            if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
2972                newSpan.fDone = true;
2973                ++fDoneSpans;
2974            }
2975        }
2976    }
2977
2978    // return span if when chasing, two or more radiating spans are not done
2979    // OPTIMIZATION: ? multiple spans is detected when there is only one valid
2980    // candidate and the remaining spans have windValue == 0 (canceled by
2981    // coincidence). The coincident edges could either be removed altogether,
2982    // or this code could be more complicated in detecting this case. Worth it?
2983    bool multipleSpans(int end) const {
2984        return end > 0 && end < fTs.count() - 1;
2985    }
2986
2987    Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
2988        int end = nextExactSpan(index, step);
2989        SkASSERT(end >= 0);
2990        if (multipleSpans(end)) {
2991            last = &fTs[end];
2992            return NULL;
2993        }
2994        const Span& endSpan = fTs[end];
2995        Segment* other = endSpan.fOther;
2996        index = endSpan.fOtherIndex;
2997        int otherEnd = other->nextExactSpan(index, step);
2998        min = SkMin32(index, otherEnd);
2999        return other;
3000    }
3001
3002    // This has callers for two different situations: one establishes the end
3003    // of the current span, and one establishes the beginning of the next span
3004    // (thus the name). When this is looking for the end of the current span,
3005    // coincidence is found when the beginning Ts contain -step and the end
3006    // contains step. When it is looking for the beginning of the next, the
3007    // first Ts found can be ignored and the last Ts should contain -step.
3008    // OPTIMIZATION: probably should split into two functions
3009    int nextSpan(int from, int step) const {
3010        const Span& fromSpan = fTs[from];
3011        int count = fTs.count();
3012        int to = from;
3013        while (step > 0 ? ++to < count : --to >= 0) {
3014            const Span& span = fTs[to];
3015            if (approximately_zero(span.fT - fromSpan.fT)) {
3016                continue;
3017            }
3018            return to;
3019        }
3020        return -1;
3021    }
3022
3023    // FIXME
3024    // this returns at any difference in T, vs. a preset minimum. It may be
3025    // that all callers to nextSpan should use this instead.
3026    // OPTIMIZATION splitting this into separate loops for up/down steps
3027    // would allow using precisely_negative instead of precisely_zero
3028    int nextExactSpan(int from, int step) const {
3029        const Span& fromSpan = fTs[from];
3030        int count = fTs.count();
3031        int to = from;
3032        while (step > 0 ? ++to < count : --to >= 0) {
3033            const Span& span = fTs[to];
3034            if (precisely_zero(span.fT - fromSpan.fT)) {
3035                continue;
3036            }
3037            return to;
3038        }
3039        return -1;
3040    }
3041
3042    bool operand() const {
3043        return fOperand;
3044    }
3045
3046    int oppSign(const Angle* angle) const {
3047        SkASSERT(angle->segment() == this);
3048        return oppSign(angle->start(), angle->end());
3049    }
3050
3051    int oppSign(int startIndex, int endIndex) const {
3052        int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3053                : fTs[endIndex].fOppValue;
3054#if DEBUG_WIND_BUMP
3055        SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3056#endif
3057        return result;
3058    }
3059
3060    int oppSum(int tIndex) const {
3061        return fTs[tIndex].fOppSum;
3062    }
3063
3064    int oppSum(const Angle* angle) const {
3065        int lesser = SkMin32(angle->start(), angle->end());
3066        return fTs[lesser].fOppSum;
3067    }
3068
3069    int oppValue(int tIndex) const {
3070        return fTs[tIndex].fOppValue;
3071    }
3072
3073    const SkPoint* pts() const {
3074        return fPts;
3075    }
3076
3077    void reset() {
3078        init(NULL, (SkPath::Verb) -1, false, false);
3079        fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3080        fTs.reset();
3081    }
3082
3083    void setOppXor(bool isOppXor) {
3084        fOppXor = isOppXor;
3085    }
3086
3087    void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3088            int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3089        int deltaSum = spanSign(index, endIndex);
3090        int oppDeltaSum = oppSign(index, endIndex);
3091        if (operand()) {
3092            maxWinding = sumSuWinding;
3093            sumWinding = sumSuWinding -= deltaSum;
3094            oppMaxWinding = sumMiWinding;
3095            oppSumWinding = sumMiWinding -= oppDeltaSum;
3096        } else {
3097            maxWinding = sumMiWinding;
3098            sumWinding = sumMiWinding -= deltaSum;
3099            oppMaxWinding = sumSuWinding;
3100            oppSumWinding = sumSuWinding -= oppDeltaSum;
3101        }
3102    }
3103
3104    // This marks all spans unsortable so that this info is available for early
3105    // exclusion in find top and others. This could be optimized to only mark
3106    // adjacent spans that unsortable. However, this makes it difficult to later
3107    // determine starting points for edge detection in find top and the like.
3108    static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
3109        bool sortable = true;
3110        int angleCount = angles.count();
3111        int angleIndex;
3112        angleList.setReserve(angleCount);
3113        for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3114            Angle& angle = angles[angleIndex];
3115            *angleList.append() = &angle;
3116            sortable &= !angle.unsortable();
3117        }
3118        if (sortable) {
3119            QSort<Angle>(angleList.begin(), angleList.end() - 1);
3120            for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3121                if (angles[angleIndex].unsortable()) {
3122                    sortable = false;
3123                    break;
3124                }
3125            }
3126        }
3127        if (!sortable) {
3128            for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3129                Angle& angle = angles[angleIndex];
3130                angle.segment()->markUnsortable(angle.start(), angle.end());
3131            }
3132        }
3133        return sortable;
3134    }
3135
3136    // OPTIMIZATION: mark as debugging only if used solely by tests
3137    const Span& span(int tIndex) const {
3138        return fTs[tIndex];
3139    }
3140
3141    int spanSign(const Angle* angle) const {
3142        SkASSERT(angle->segment() == this);
3143        return spanSign(angle->start(), angle->end());
3144    }
3145
3146    int spanSign(int startIndex, int endIndex) const {
3147        int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3148                : fTs[endIndex].fWindValue;
3149#if DEBUG_WIND_BUMP
3150        SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3151#endif
3152        return result;
3153    }
3154
3155    // OPTIMIZATION: mark as debugging only if used solely by tests
3156    double t(int tIndex) const {
3157        return fTs[tIndex].fT;
3158    }
3159
3160    bool tiny(const Angle* angle) const {
3161        int start = angle->start();
3162        int end = angle->end();
3163        const Span& mSpan = fTs[SkMin32(start, end)];
3164        return mSpan.fTiny;
3165    }
3166
3167    static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3168            double start) {
3169        int outCount = outsideTs.count();
3170        if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
3171            *outsideTs.append() = end;
3172            *outsideTs.append() = start;
3173        }
3174    }
3175
3176    void undoneSpan(int& start, int& end) {
3177        size_t tCount = fTs.count();
3178        size_t index;
3179        for (index = 0; index < tCount; ++index) {
3180            if (!fTs[index].fDone) {
3181                break;
3182            }
3183        }
3184        SkASSERT(index < tCount - 1);
3185        start = index;
3186        double startT = fTs[index].fT;
3187        while (approximately_negative(fTs[++index].fT - startT))
3188            SkASSERT(index < tCount);
3189        SkASSERT(index < tCount);
3190        end = index;
3191    }
3192
3193    bool unsortable(int index) const {
3194        return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3195    }
3196
3197    void updatePts(const SkPoint pts[]) {
3198        fPts = pts;
3199    }
3200
3201    int updateOppWinding(int index, int endIndex) const {
3202        int lesser = SkMin32(index, endIndex);
3203        int oppWinding = oppSum(lesser);
3204        int oppSpanWinding = oppSign(index, endIndex);
3205        if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)) {
3206            oppWinding -= oppSpanWinding;
3207        }
3208        return oppWinding;
3209    }
3210
3211    int updateOppWinding(const Angle* angle) const {
3212        int startIndex = angle->start();
3213        int endIndex = angle->end();
3214        return updateOppWinding(endIndex, startIndex);
3215    }
3216
3217    int updateOppWindingReverse(const Angle* angle) const {
3218        int startIndex = angle->start();
3219        int endIndex = angle->end();
3220        return updateOppWinding(startIndex, endIndex);
3221    }
3222
3223    int updateWinding(int index, int endIndex) const {
3224        int lesser = SkMin32(index, endIndex);
3225        int winding = windSum(lesser);
3226        int spanWinding = spanSign(index, endIndex);
3227        if (winding && useInnerWinding(winding - spanWinding, winding)) {
3228            winding -= spanWinding;
3229        }
3230        return winding;
3231    }
3232
3233    int updateWinding(const Angle* angle) const {
3234        int startIndex = angle->start();
3235        int endIndex = angle->end();
3236        return updateWinding(endIndex, startIndex);
3237    }
3238
3239    int updateWindingReverse(const Angle* angle) const {
3240        int startIndex = angle->start();
3241        int endIndex = angle->end();
3242        return updateWinding(startIndex, endIndex);
3243    }
3244
3245    SkPath::Verb verb() const {
3246        return fVerb;
3247    }
3248
3249    int windSum(int tIndex) const {
3250        return fTs[tIndex].fWindSum;
3251    }
3252
3253    int windSum(const Angle* angle) const {
3254        int start = angle->start();
3255        int end = angle->end();
3256        int index = SkMin32(start, end);
3257        return windSum(index);
3258    }
3259
3260    int windValue(int tIndex) const {
3261        return fTs[tIndex].fWindValue;
3262    }
3263
3264    int windValue(const Angle* angle) const {
3265        int start = angle->start();
3266        int end = angle->end();
3267        int index = SkMin32(start, end);
3268        return windValue(index);
3269    }
3270
3271    SkScalar xAtT(const Span* span) const {
3272        return xyAtT(span).fX;
3273    }
3274
3275    const SkPoint& xyAtT(int index) const {
3276        return xyAtT(&fTs[index]);
3277    }
3278
3279    const SkPoint& xyAtT(const Span* span) const {
3280        if (SkScalarIsNaN(span->fPt.fX)) {
3281            if (span->fT == 0) {
3282                span->fPt = fPts[0];
3283            } else if (span->fT == 1) {
3284                span->fPt = fPts[fVerb];
3285            } else {
3286                (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
3287            }
3288        }
3289        return span->fPt;
3290    }
3291
3292    SkScalar yAtT(int index) const {
3293        return yAtT(&fTs[index]);
3294    }
3295
3296    SkScalar yAtT(const Span* span) const {
3297        return xyAtT(span).fY;
3298    }
3299
3300    void zeroCoincidentOpp(Span* oTest, int index) {
3301        Span* const test = &fTs[index];
3302        Span* end = test;
3303        do {
3304            end->fOppValue = 0;
3305            end = &fTs[++index];
3306        } while (approximately_negative(end->fT - test->fT));
3307    }
3308
3309    void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
3310        Span* const oTest = &fTs[oIndex];
3311        Span* oEnd = oTest;
3312        const double startT = test->fT;
3313        const double oStartT = oTest->fT;
3314        double otherTMatch = (test->fT - startT) * tRatio + oStartT;
3315        while (!approximately_negative(oEndT - oEnd->fT)
3316                && approximately_negative(oEnd->fT - otherTMatch)) {
3317            oEnd->fOppValue = 0;
3318            oEnd = &fTs[++oIndex];
3319        }
3320    }
3321
3322    void zeroSpan(Span* span) {
3323        SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
3324        span->fWindValue = 0;
3325        span->fOppValue = 0;
3326        SkASSERT(!span->fDone);
3327        span->fDone = true;
3328        ++fDoneSpans;
3329    }
3330
3331#if DEBUG_DUMP
3332    void dump() const {
3333        const char className[] = "Segment";
3334        const int tab = 4;
3335        for (int i = 0; i < fTs.count(); ++i) {
3336            SkPoint out;
3337            (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
3338            SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
3339                    " otherT=%1.9g windSum=%d\n",
3340                    tab + sizeof(className), className, fID,
3341                    kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
3342                    fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
3343        }
3344        SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
3345                tab + sizeof(className), className, fID,
3346                fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
3347    }
3348#endif
3349
3350#if DEBUG_CONCIDENT
3351    // assert if pair has not already been added
3352     void debugAddTPair(double t, const Segment& other, double otherT) const {
3353        for (int i = 0; i < fTs.count(); ++i) {
3354            if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
3355                return;
3356            }
3357        }
3358        SkASSERT(0);
3359     }
3360#endif
3361
3362#if DEBUG_DUMP
3363    int debugID() const {
3364        return fID;
3365    }
3366#endif
3367
3368#if DEBUG_WINDING
3369    void debugShowSums() const {
3370        SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
3371            fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
3372        for (int i = 0; i < fTs.count(); ++i) {
3373            const Span& span = fTs[i];
3374            SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
3375            if (span.fWindSum == SK_MinS32) {
3376                SkDebugf("?");
3377            } else {
3378                SkDebugf("%d", span.fWindSum);
3379            }
3380            SkDebugf("]");
3381        }
3382        SkDebugf("\n");
3383    }
3384#endif
3385
3386#if DEBUG_CONCIDENT
3387    void debugShowTs() const {
3388        SkDebugf("%s id=%d", __FUNCTION__, fID);
3389        int lastWind = -1;
3390        int lastOpp = -1;
3391        double lastT = -1;
3392        int i;
3393        for (i = 0; i < fTs.count(); ++i) {
3394            bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
3395                    || lastOpp != fTs[i].fOppValue;
3396            if (change && lastWind >= 0) {
3397                SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3398                        lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3399            }
3400            if (change) {
3401                SkDebugf(" [o=%d", fTs[i].fOther->fID);
3402                lastWind = fTs[i].fWindValue;
3403                lastOpp = fTs[i].fOppValue;
3404                lastT = fTs[i].fT;
3405            } else {
3406                SkDebugf(",%d", fTs[i].fOther->fID);
3407            }
3408        }
3409        if (i <= 0) {
3410            return;
3411        }
3412        SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3413                lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3414        if (fOperand) {
3415            SkDebugf(" operand");
3416        }
3417        if (done()) {
3418            SkDebugf(" done");
3419        }
3420        SkDebugf("\n");
3421    }
3422#endif
3423
3424#if DEBUG_ACTIVE_SPANS
3425    void debugShowActiveSpans() const {
3426        if (done()) {
3427            return;
3428        }
3429#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3430        int lastId = -1;
3431        double lastT = -1;
3432#endif
3433        for (int i = 0; i < fTs.count(); ++i) {
3434            if (fTs[i].fDone) {
3435                continue;
3436            }
3437#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3438            if (lastId == fID && lastT == fTs[i].fT) {
3439                continue;
3440            }
3441            lastId = fID;
3442            lastT = fTs[i].fT;
3443#endif
3444            SkDebugf("%s id=%d", __FUNCTION__, fID);
3445            SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3446            for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3447                SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3448            }
3449            const Span* span = &fTs[i];
3450            SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
3451                     xAtT(span), yAtT(span));
3452            const Segment* other = fTs[i].fOther;
3453            SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
3454                    other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
3455            if (fTs[i].fWindSum == SK_MinS32) {
3456                SkDebugf("?");
3457            } else {
3458                SkDebugf("%d", fTs[i].fWindSum);
3459            }
3460            SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
3461        }
3462    }
3463
3464    // This isn't useful yet -- but leaving it in for now in case i think of something
3465    // to use it for
3466    void validateActiveSpans() const {
3467        if (done()) {
3468            return;
3469        }
3470        int tCount = fTs.count();
3471        for (int index = 0; index < tCount; ++index) {
3472            if (fTs[index].fDone) {
3473                continue;
3474            }
3475            // count number of connections which are not done
3476            int first = index;
3477            double baseT = fTs[index].fT;
3478            while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
3479                --first;
3480            }
3481            int last = index;
3482            while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
3483                ++last;
3484            }
3485            int connections = 0;
3486            connections += first > 0 && !fTs[first - 1].fDone;
3487            for (int test = first; test <= last; ++test) {
3488                connections += !fTs[test].fDone;
3489                const Segment* other = fTs[test].fOther;
3490                int oIndex = fTs[test].fOtherIndex;
3491                connections += !other->fTs[oIndex].fDone;
3492                connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
3493            }
3494      //      SkASSERT(!(connections & 1));
3495        }
3496    }
3497#endif
3498
3499#if DEBUG_MARK_DONE
3500    void debugShowNewWinding(const char* fun, const Span& span, int winding) {
3501        const SkPoint& pt = xyAtT(&span);
3502        SkDebugf("%s id=%d", fun, fID);
3503        SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3504        for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3505            SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3506        }
3507        SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3508                fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3509        SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d windSum=",
3510                span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, winding);
3511        if (span.fWindSum == SK_MinS32) {
3512            SkDebugf("?");
3513        } else {
3514            SkDebugf("%d", span.fWindSum);
3515        }
3516        SkDebugf(" windValue=%d\n", span.fWindValue);
3517    }
3518
3519    void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
3520        const SkPoint& pt = xyAtT(&span);
3521        SkDebugf("%s id=%d", fun, fID);
3522        SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3523        for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3524            SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3525        }
3526        SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3527                fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3528        SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=",
3529                span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
3530                winding, oppWinding);
3531        if (span.fOppSum == SK_MinS32) {
3532            SkDebugf("?");
3533        } else {
3534            SkDebugf("%d", span.fOppSum);
3535        }
3536        SkDebugf(" windSum=");
3537        if (span.fWindSum == SK_MinS32) {
3538            SkDebugf("?");
3539        } else {
3540            SkDebugf("%d", span.fWindSum);
3541        }
3542        SkDebugf(" windValue=%d\n", span.fWindValue);
3543    }
3544#endif
3545
3546#if DEBUG_SORT
3547    void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
3548            const int contourWinding, const int oppContourWinding) const {
3549        SkASSERT(angles[first]->segment() == this);
3550        SkASSERT(angles.count() > 1);
3551        int lastSum = contourWinding;
3552        int oppLastSum = oppContourWinding;
3553        const Angle* firstAngle = angles[first];
3554        int windSum = lastSum - spanSign(firstAngle);
3555        int oppoSign = oppSign(firstAngle);
3556        int oppWindSum = oppLastSum - oppoSign;
3557        SkDebugf("%s %s contourWinding=%d oppContourWinding=%d sign=%d\n", fun, __FUNCTION__,
3558                contourWinding, oppContourWinding, spanSign(angles[first]));
3559        int index = first;
3560        bool firstTime = true;
3561        do {
3562            const Angle& angle = *angles[index];
3563            const Segment& segment = *angle.segment();
3564            int start = angle.start();
3565            int end = angle.end();
3566            const Span& sSpan = segment.fTs[start];
3567            const Span& eSpan = segment.fTs[end];
3568            const Span& mSpan = segment.fTs[SkMin32(start, end)];
3569            bool opp = segment.fOperand ^ fOperand;
3570            if (!firstTime) {
3571                oppoSign = segment.oppSign(&angle);
3572                if (opp) {
3573                    oppLastSum = oppWindSum;
3574                    oppWindSum -= segment.spanSign(&angle);
3575                    if (oppoSign) {
3576                        lastSum = windSum;
3577                        windSum -= oppoSign;
3578                    }
3579                } else {
3580                    lastSum = windSum;
3581                    windSum -= segment.spanSign(&angle);
3582                    if (oppoSign) {
3583                        oppLastSum = oppWindSum;
3584                        oppWindSum -= oppoSign;
3585                    }
3586                }
3587            }
3588            SkDebugf("%s [%d] %sid=%d %s start=%d (%1.9g,%,1.9g) end=%d (%1.9g,%,1.9g)"
3589                    " sign=%d windValue=%d windSum=",
3590                    __FUNCTION__, index, angle.unsortable() ? "*** UNSORTABLE *** " : "",
3591                    segment.fID, kLVerbStr[segment.fVerb],
3592                    start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
3593                    segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(),
3594                    mSpan.fWindValue);
3595            if (mSpan.fWindSum == SK_MinS32) {
3596                SkDebugf("?");
3597            } else {
3598                SkDebugf("%d", mSpan.fWindSum);
3599            }
3600            int last, wind;
3601            if (opp) {
3602                last = oppLastSum;
3603                wind = oppWindSum;
3604            } else {
3605                last = lastSum;
3606                wind = windSum;
3607            }
3608            if (!oppoSign) {
3609                SkDebugf(" %d->%d (max=%d)", last, wind,
3610                        useInnerWinding(last, wind) ? wind : last);
3611            } else {
3612                SkDebugf(" %d->%d (%d->%d)", last, wind, opp ? lastSum : oppLastSum,
3613                        opp ? windSum : oppWindSum);
3614            }
3615            SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
3616#if false && DEBUG_ANGLE
3617            angle.debugShow(segment.xyAtT(&sSpan));
3618#endif
3619            ++index;
3620            if (index == angles.count()) {
3621                index = 0;
3622            }
3623            if (firstTime) {
3624                firstTime = false;
3625            }
3626        } while (index != first);
3627    }
3628
3629    void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
3630        const Angle* firstAngle = angles[first];
3631        const Segment* segment = firstAngle->segment();
3632        int winding = segment->updateWinding(firstAngle);
3633        int oppWinding = segment->updateOppWinding(firstAngle);
3634        debugShowSort(fun, angles, first, winding, oppWinding);
3635    }
3636
3637#endif
3638
3639#if DEBUG_WINDING
3640    static char as_digit(int value) {
3641        return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
3642    }
3643#endif
3644
3645#if DEBUG_SHOW_WINDING
3646    int debugShowWindingValues(int slotCount, int ofInterest) const {
3647        if (!(1 << fID & ofInterest)) {
3648            return 0;
3649        }
3650        int sum = 0;
3651        SkTDArray<char> slots;
3652        slots.setCount(slotCount * 2);
3653        memset(slots.begin(), ' ', slotCount * 2);
3654        for (int i = 0; i < fTs.count(); ++i) {
3655       //     if (!(1 << fTs[i].fOther->fID & ofInterest)) {
3656       //         continue;
3657       //     }
3658            sum += fTs[i].fWindValue;
3659            slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
3660            sum += fTs[i].fOppValue;
3661            slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
3662        }
3663        SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
3664                slots.begin() + slotCount);
3665        return sum;
3666    }
3667#endif
3668
3669private:
3670    const SkPoint* fPts;
3671    Bounds fBounds;
3672    SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
3673    // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
3674    int fDoneSpans; // quick check that segment is finished
3675    // OPTIMIZATION: force the following to be byte-sized
3676    SkPath::Verb fVerb;
3677    bool fOperand;
3678    bool fXor; // set if original contour had even-odd fill
3679    bool fOppXor; // set if opposite operand had even-odd fill
3680#if DEBUG_DUMP
3681    int fID;
3682#endif
3683};
3684
3685class Contour;
3686
3687struct Coincidence {
3688    Contour* fContours[2];
3689    int fSegments[2];
3690    double fTs[2][2];
3691};
3692
3693class Contour {
3694public:
3695    Contour() {
3696        reset();
3697#if DEBUG_DUMP
3698        fID = ++gContourID;
3699#endif
3700    }
3701
3702    bool operator<(const Contour& rh) const {
3703        return fBounds.fTop == rh.fBounds.fTop
3704                ? fBounds.fLeft < rh.fBounds.fLeft
3705                : fBounds.fTop < rh.fBounds.fTop;
3706    }
3707
3708    void addCoincident(int index, Contour* other, int otherIndex,
3709            const Intersections& ts, bool swap) {
3710        Coincidence& coincidence = *fCoincidences.append();
3711        coincidence.fContours[0] = this; // FIXME: no need to store
3712        coincidence.fContours[1] = other;
3713        coincidence.fSegments[0] = index;
3714        coincidence.fSegments[1] = otherIndex;
3715        if (fSegments[index].verb() == SkPath::kLine_Verb &&
3716                other->fSegments[otherIndex].verb() == SkPath::kLine_Verb) {
3717            // FIXME: coincident lines use legacy Ts instead of coincident Ts
3718            coincidence.fTs[swap][0] = ts.fT[0][0];
3719            coincidence.fTs[swap][1] = ts.fT[0][1];
3720            coincidence.fTs[!swap][0] = ts.fT[1][0];
3721            coincidence.fTs[!swap][1] = ts.fT[1][1];
3722        } else if (fSegments[index].verb() == SkPath::kQuad_Verb &&
3723                other->fSegments[otherIndex].verb() == SkPath::kQuad_Verb) {
3724            coincidence.fTs[swap][0] = ts.fCoincidentT[0][0];
3725            coincidence.fTs[swap][1] = ts.fCoincidentT[0][1];
3726            coincidence.fTs[!swap][0] = ts.fCoincidentT[1][0];
3727            coincidence.fTs[!swap][1] = ts.fCoincidentT[1][1];
3728        }
3729    }
3730
3731    void addCross(const Contour* crosser) {
3732#ifdef DEBUG_CROSS
3733        for (int index = 0; index < fCrosses.count(); ++index) {
3734            SkASSERT(fCrosses[index] != crosser);
3735        }
3736#endif
3737        *fCrosses.append() = crosser;
3738    }
3739
3740    void addCubic(const SkPoint pts[4]) {
3741        fSegments.push_back().addCubic(pts, fOperand, fXor);
3742        fContainsCurves = true;
3743    }
3744
3745    int addLine(const SkPoint pts[2]) {
3746        fSegments.push_back().addLine(pts, fOperand, fXor);
3747        return fSegments.count();
3748    }
3749
3750    void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
3751        fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
3752    }
3753
3754    int addQuad(const SkPoint pts[3]) {
3755        fSegments.push_back().addQuad(pts, fOperand, fXor);
3756        fContainsCurves = true;
3757        return fSegments.count();
3758    }
3759
3760    int addT(int segIndex, double newT, Contour* other, int otherIndex) {
3761        containsIntercepts();
3762        return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex]);
3763    }
3764
3765    const Bounds& bounds() const {
3766        return fBounds;
3767    }
3768
3769    void complete() {
3770        setBounds();
3771        fContainsIntercepts = false;
3772    }
3773
3774    void containsIntercepts() {
3775        fContainsIntercepts = true;
3776    }
3777
3778    const Segment* crossedSegment(const SkPoint& basePt, SkScalar& bestY,
3779            int &tIndex, double& hitT) {
3780        int segmentCount = fSegments.count();
3781        const Segment* bestSegment = NULL;
3782        for (int test = 0; test < segmentCount; ++test) {
3783            Segment* testSegment = &fSegments[test];
3784            const SkRect& bounds = testSegment->bounds();
3785            if (bounds.fBottom <= bestY) {
3786                continue;
3787            }
3788            if (bounds.fTop >= basePt.fY) {
3789                continue;
3790            }
3791            if (bounds.fLeft > basePt.fX) {
3792                continue;
3793            }
3794            if (bounds.fRight < basePt.fX) {
3795                continue;
3796            }
3797            if (bounds.fLeft == bounds.fRight) {
3798                continue;
3799            }
3800     #if 0
3801            bool leftHalf = bounds.fLeft == basePt.fX;
3802            bool rightHalf = bounds.fRight == basePt.fX;
3803            if ((leftHalf || rightHalf) && !testSegment->crossedSpanHalves(
3804                    basePt, leftHalf, rightHalf)) {
3805                continue;
3806            }
3807     #endif
3808            double testHitT;
3809            int testT = testSegment->crossedSpan(basePt, bestY, testHitT);
3810            if (testT >= 0) {
3811                bestSegment = testSegment;
3812                tIndex = testT;
3813                hitT = testHitT;
3814            }
3815        }
3816        return bestSegment;
3817    }
3818
3819    bool crosses(const Contour* crosser) const {
3820        for (int index = 0; index < fCrosses.count(); ++index) {
3821            if (fCrosses[index] == crosser) {
3822                return true;
3823            }
3824        }
3825        return false;
3826    }
3827
3828    const SkPoint& end() const {
3829        const Segment& segment = fSegments.back();
3830        return segment.pts()[segment.verb()];
3831    }
3832
3833    void findTooCloseToCall() {
3834        int segmentCount = fSegments.count();
3835        for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
3836            fSegments[sIndex].findTooCloseToCall();
3837        }
3838    }
3839
3840    void fixOtherTIndex() {
3841        int segmentCount = fSegments.count();
3842        for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
3843            fSegments[sIndex].fixOtherTIndex();
3844        }
3845    }
3846
3847    bool operand() const {
3848        return fOperand;
3849    }
3850
3851    void reset() {
3852        fSegments.reset();
3853        fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3854        fContainsCurves = fContainsIntercepts = false;
3855    }
3856
3857    void resolveCoincidence(SkTDArray<Contour*>& contourList) {
3858        int count = fCoincidences.count();
3859        for (int index = 0; index < count; ++index) {
3860            Coincidence& coincidence = fCoincidences[index];
3861            SkASSERT(coincidence.fContours[0] == this);
3862            int thisIndex = coincidence.fSegments[0];
3863            Segment& thisOne = fSegments[thisIndex];
3864            Contour* otherContour = coincidence.fContours[1];
3865            int otherIndex = coincidence.fSegments[1];
3866            Segment& other = otherContour->fSegments[otherIndex];
3867            if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
3868                continue;
3869            }
3870        #if DEBUG_CONCIDENT
3871            thisOne.debugShowTs();
3872            other.debugShowTs();
3873        #endif
3874            double startT = coincidence.fTs[0][0];
3875            double endT = coincidence.fTs[0][1];
3876            bool cancelers = false;
3877            if (startT > endT) {
3878                SkTSwap<double>(startT, endT);
3879                cancelers ^= true; // FIXME: just assign true
3880            }
3881            SkASSERT(!approximately_negative(endT - startT));
3882            double oStartT = coincidence.fTs[1][0];
3883            double oEndT = coincidence.fTs[1][1];
3884            if (oStartT > oEndT) {
3885                SkTSwap<double>(oStartT, oEndT);
3886                cancelers ^= true;
3887            }
3888            SkASSERT(!approximately_negative(oEndT - oStartT));
3889            bool opp = fOperand ^ otherContour->fOperand;
3890            if (cancelers && !opp) {
3891                // make sure startT and endT have t entries
3892                if (startT > 0 || oEndT < 1
3893                        || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
3894                    thisOne.addTPair(startT, other, oEndT, true);
3895                }
3896                if (oStartT > 0 || endT < 1
3897                        || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
3898                    other.addTPair(oStartT, thisOne, endT, true);
3899                }
3900                if (!thisOne.done() && !other.done()) {
3901                    thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
3902                }
3903            } else {
3904                if (startT > 0 || oStartT > 0
3905                        || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
3906                    thisOne.addTPair(startT, other, oStartT, true);
3907                }
3908                if (endT < 1 || oEndT < 1
3909                        || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
3910                    other.addTPair(oEndT, thisOne, endT, true);
3911                }
3912                if (!thisOne.done() && !other.done()) {
3913                    thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
3914                }
3915            }
3916        #if DEBUG_CONCIDENT
3917            thisOne.debugShowTs();
3918            other.debugShowTs();
3919        #endif
3920        #if DEBUG_SHOW_WINDING
3921            debugShowWindingValues(contourList);
3922        #endif
3923        }
3924    }
3925
3926    const SkTArray<Segment>& segments() {
3927        return fSegments;
3928    }
3929
3930    void setOperand(bool isOp) {
3931        fOperand = isOp;
3932    }
3933
3934    void setOppXor(bool isOppXor) {
3935        fOppXor = isOppXor;
3936        int segmentCount = fSegments.count();
3937        for (int test = 0; test < segmentCount; ++test) {
3938            fSegments[test].setOppXor(isOppXor);
3939        }
3940    }
3941
3942    void setXor(bool isXor) {
3943        fXor = isXor;
3944    }
3945
3946    void sortSegments() {
3947        int segmentCount = fSegments.count();
3948        fSortedSegments.setReserve(segmentCount);
3949        for (int test = 0; test < segmentCount; ++test) {
3950            *fSortedSegments.append() = &fSegments[test];
3951        }
3952        QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
3953        fFirstSorted = 0;
3954    }
3955
3956    const SkPoint& start() const {
3957        return fSegments.front().pts()[0];
3958    }
3959
3960    void toPath(PathWrapper& path) const {
3961        int segmentCount = fSegments.count();
3962        const SkPoint& pt = fSegments.front().pts()[0];
3963        path.deferredMove(pt);
3964        for (int test = 0; test < segmentCount; ++test) {
3965            fSegments[test].addCurveTo(0, 1, path, true);
3966        }
3967        path.close();
3968    }
3969
3970    void toPartialBackward(PathWrapper& path) const {
3971        int segmentCount = fSegments.count();
3972        for (int test = segmentCount - 1; test >= 0; --test) {
3973            fSegments[test].addCurveTo(1, 0, path, true);
3974        }
3975    }
3976
3977    void toPartialForward(PathWrapper& path) const {
3978        int segmentCount = fSegments.count();
3979        for (int test = 0; test < segmentCount; ++test) {
3980            fSegments[test].addCurveTo(0, 1, path, true);
3981        }
3982    }
3983
3984#if 0 // FIXME: obsolete, remove
3985    // OPTIMIZATION: feel pretty uneasy about this. It seems like once again
3986    // we need to sort and walk edges in y, but that on the surface opens the
3987    // same can of worms as before. But then, this is a rough sort based on
3988    // segments' top, and not a true sort, so it could be ameniable to regular
3989    // sorting instead of linear searching. Still feel like I'm missing something
3990    Segment* topSegment(SkScalar& bestY) {
3991        int segmentCount = fSegments.count();
3992        SkASSERT(segmentCount > 0);
3993        int best = -1;
3994        Segment* bestSegment = NULL;
3995        while (++best < segmentCount) {
3996            Segment* testSegment = &fSegments[best];
3997            if (testSegment->done()) {
3998                continue;
3999            }
4000            bestSegment = testSegment;
4001            break;
4002        }
4003        if (!bestSegment) {
4004            return NULL;
4005        }
4006        SkScalar bestTop = bestSegment->activeTop();
4007        for (int test = best + 1; test < segmentCount; ++test) {
4008            Segment* testSegment = &fSegments[test];
4009            if (testSegment->done()) {
4010                continue;
4011            }
4012            if (testSegment->bounds().fTop > bestTop) {
4013                continue;
4014            }
4015            SkScalar testTop = testSegment->activeTop();
4016            if (bestTop > testTop) {
4017                bestTop = testTop;
4018                bestSegment = testSegment;
4019            }
4020        }
4021        bestY = bestTop;
4022        return bestSegment;
4023    }
4024#endif
4025
4026    Segment* topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY) {
4027        int segmentCount = fSortedSegments.count();
4028        SkASSERT(segmentCount > 0);
4029        Segment* bestSegment = NULL;
4030        int sortedIndex = fFirstSorted;
4031        for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4032            Segment* testSegment = fSortedSegments[sortedIndex];
4033            if (testSegment->done()) {
4034                if (sortedIndex == fFirstSorted) {
4035                    ++fFirstSorted;
4036                }
4037                continue;
4038            }
4039            SkPoint testXY;
4040            testSegment->activeLeftTop(testXY);
4041            if (testXY.fY < topLeft.fY) {
4042                continue;
4043            }
4044            if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4045                continue;
4046            }
4047            if (bestXY.fY < testXY.fY) {
4048                continue;
4049            }
4050            if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4051                continue;
4052            }
4053            bestSegment = testSegment;
4054            bestXY = testXY;
4055        }
4056        return bestSegment;
4057    }
4058
4059    Segment* undoneSegment(int& start, int& end) {
4060        int segmentCount = fSegments.count();
4061        for (int test = 0; test < segmentCount; ++test) {
4062            Segment* testSegment = &fSegments[test];
4063            if (testSegment->done()) {
4064                continue;
4065            }
4066            testSegment->undoneSpan(start, end);
4067            return testSegment;
4068        }
4069        return NULL;
4070    }
4071
4072    int updateSegment(int index, const SkPoint* pts) {
4073        Segment& segment = fSegments[index];
4074        segment.updatePts(pts);
4075        return segment.verb() + 1;
4076    }
4077
4078#if DEBUG_TEST
4079    SkTArray<Segment>& debugSegments() {
4080        return fSegments;
4081    }
4082#endif
4083
4084#if DEBUG_DUMP
4085    void dump() {
4086        int i;
4087        const char className[] = "Contour";
4088        const int tab = 4;
4089        SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4090        for (i = 0; i < fSegments.count(); ++i) {
4091            SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4092                    className, i);
4093            fSegments[i].dump();
4094        }
4095        SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4096                tab + sizeof(className), className,
4097                fBounds.fLeft, fBounds.fTop,
4098                fBounds.fRight, fBounds.fBottom);
4099        SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4100                className, fContainsIntercepts);
4101        SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4102                className, fContainsCurves);
4103    }
4104#endif
4105
4106#if DEBUG_ACTIVE_SPANS
4107    void debugShowActiveSpans() {
4108        for (int index = 0; index < fSegments.count(); ++index) {
4109            fSegments[index].debugShowActiveSpans();
4110        }
4111    }
4112
4113    void validateActiveSpans() {
4114        for (int index = 0; index < fSegments.count(); ++index) {
4115            fSegments[index].validateActiveSpans();
4116        }
4117    }
4118#endif
4119
4120#if DEBUG_SHOW_WINDING
4121    int debugShowWindingValues(int totalSegments, int ofInterest) {
4122        int count = fSegments.count();
4123        int sum = 0;
4124        for (int index = 0; index < count; ++index) {
4125            sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4126        }
4127  //      SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4128        return sum;
4129    }
4130
4131    static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4132   //     int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4133    //    int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4134        int ofInterest = 1 << 5 | 1 << 8;
4135        int total = 0;
4136        int index;
4137        for (index = 0; index < contourList.count(); ++index) {
4138            total += contourList[index]->segments().count();
4139        }
4140        int sum = 0;
4141        for (index = 0; index < contourList.count(); ++index) {
4142            sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4143        }
4144 //       SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4145    }
4146#endif
4147
4148protected:
4149    void setBounds() {
4150        int count = fSegments.count();
4151        if (count == 0) {
4152            SkDebugf("%s empty contour\n", __FUNCTION__);
4153            SkASSERT(0);
4154            // FIXME: delete empty contour?
4155            return;
4156        }
4157        fBounds = fSegments.front().bounds();
4158        for (int index = 1; index < count; ++index) {
4159            fBounds.add(fSegments[index].bounds());
4160        }
4161    }
4162
4163private:
4164    SkTArray<Segment> fSegments;
4165    SkTDArray<Segment*> fSortedSegments;
4166    int fFirstSorted;
4167    SkTDArray<Coincidence> fCoincidences;
4168    SkTDArray<const Contour*> fCrosses;
4169    Bounds fBounds;
4170    bool fContainsIntercepts;
4171    bool fContainsCurves;
4172    bool fOperand; // true for the second argument to a binary operator
4173    bool fXor;
4174    bool fOppXor;
4175#if DEBUG_DUMP
4176    int fID;
4177#endif
4178};
4179
4180class EdgeBuilder {
4181public:
4182
4183EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
4184    : fPath(path.nativePath())
4185    , fContours(contours)
4186{
4187    init();
4188}
4189
4190EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
4191    : fPath(&path)
4192    , fContours(contours)
4193{
4194    init();
4195}
4196
4197void init() {
4198    fCurrentContour = NULL;
4199    fOperand = false;
4200    fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
4201#if DEBUG_DUMP
4202    gContourID = 0;
4203    gSegmentID = 0;
4204#endif
4205    fSecondHalf = preFetch();
4206}
4207
4208void addOperand(const SkPath& path) {
4209    SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
4210    fPathVerbs.pop();
4211    fPath = &path;
4212    fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
4213    preFetch();
4214}
4215
4216void finish() {
4217    walk();
4218    complete();
4219    if (fCurrentContour && !fCurrentContour->segments().count()) {
4220        fContours.pop_back();
4221    }
4222    // correct pointers in contours since fReducePts may have moved as it grew
4223    int cIndex = 0;
4224    int extraCount = fExtra.count();
4225    SkASSERT(extraCount == 0 || fExtra[0] == -1);
4226    int eIndex = 0;
4227    int rIndex = 0;
4228    while (++eIndex < extraCount) {
4229        int offset = fExtra[eIndex];
4230        if (offset < 0) {
4231            ++cIndex;
4232            continue;
4233        }
4234        fCurrentContour = &fContours[cIndex];
4235        rIndex += fCurrentContour->updateSegment(offset - 1,
4236                &fReducePts[rIndex]);
4237    }
4238    fExtra.reset(); // we're done with this
4239}
4240
4241ShapeOpMask xorMask() const {
4242    return fXorMask[fOperand];
4243}
4244
4245protected:
4246
4247void complete() {
4248    if (fCurrentContour && fCurrentContour->segments().count()) {
4249        fCurrentContour->complete();
4250        fCurrentContour = NULL;
4251    }
4252}
4253
4254// FIXME:remove once we can access path pts directly
4255int preFetch() {
4256    SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
4257    SkPoint pts[4];
4258    SkPath::Verb verb;
4259    do {
4260        verb = iter.next(pts);
4261        *fPathVerbs.append() = verb;
4262        if (verb == SkPath::kMove_Verb) {
4263            *fPathPts.append() = pts[0];
4264        } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
4265            fPathPts.append(verb, &pts[1]);
4266        }
4267    } while (verb != SkPath::kDone_Verb);
4268    return fPathVerbs.count() - 1;
4269}
4270
4271void walk() {
4272    SkPath::Verb reducedVerb;
4273    uint8_t* verbPtr = fPathVerbs.begin();
4274    uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
4275    const SkPoint* pointsPtr = fPathPts.begin();
4276    const SkPoint* finalCurveStart = NULL;
4277    const SkPoint* finalCurveEnd = NULL;
4278    SkPath::Verb verb;
4279    while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
4280        switch (verb) {
4281            case SkPath::kMove_Verb:
4282                complete();
4283                if (!fCurrentContour) {
4284                    fCurrentContour = fContours.push_back_n(1);
4285                    fCurrentContour->setOperand(fOperand);
4286                    fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
4287                    *fExtra.append() = -1; // start new contour
4288                }
4289                finalCurveEnd = pointsPtr++;
4290                goto nextVerb;
4291            case SkPath::kLine_Verb:
4292                // skip degenerate points
4293                if (pointsPtr[-1].fX != pointsPtr[0].fX
4294                        || pointsPtr[-1].fY != pointsPtr[0].fY) {
4295                    fCurrentContour->addLine(&pointsPtr[-1]);
4296                }
4297                break;
4298            case SkPath::kQuad_Verb:
4299
4300                reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
4301                if (reducedVerb == 0) {
4302                    break; // skip degenerate points
4303                }
4304                if (reducedVerb == 1) {
4305                    *fExtra.append() =
4306                            fCurrentContour->addLine(fReducePts.end() - 2);
4307                    break;
4308                }
4309                fCurrentContour->addQuad(&pointsPtr[-1]);
4310                break;
4311            case SkPath::kCubic_Verb:
4312                reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
4313                if (reducedVerb == 0) {
4314                    break; // skip degenerate points
4315                }
4316                if (reducedVerb == 1) {
4317                    *fExtra.append() =
4318                            fCurrentContour->addLine(fReducePts.end() - 2);
4319                    break;
4320                }
4321                if (reducedVerb == 2) {
4322                    *fExtra.append() =
4323                            fCurrentContour->addQuad(fReducePts.end() - 3);
4324                    break;
4325                }
4326                fCurrentContour->addCubic(&pointsPtr[-1]);
4327                break;
4328            case SkPath::kClose_Verb:
4329                SkASSERT(fCurrentContour);
4330                if (finalCurveStart && finalCurveEnd
4331                        && *finalCurveStart != *finalCurveEnd) {
4332                    *fReducePts.append() = *finalCurveStart;
4333                    *fReducePts.append() = *finalCurveEnd;
4334                    *fExtra.append() =
4335                            fCurrentContour->addLine(fReducePts.end() - 2);
4336                }
4337                complete();
4338                goto nextVerb;
4339            default:
4340                SkDEBUGFAIL("bad verb");
4341                return;
4342        }
4343        finalCurveStart = &pointsPtr[verb - 1];
4344        pointsPtr += verb;
4345        SkASSERT(fCurrentContour);
4346    nextVerb:
4347        if (verbPtr == endOfFirstHalf) {
4348            fOperand = true;
4349        }
4350    }
4351}
4352
4353private:
4354    const SkPath* fPath;
4355    SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
4356    SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
4357    Contour* fCurrentContour;
4358    SkTArray<Contour>& fContours;
4359    SkTDArray<SkPoint> fReducePts; // segments created on the fly
4360    SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
4361    ShapeOpMask fXorMask[2];
4362    int fSecondHalf;
4363    bool fOperand;
4364};
4365
4366class Work {
4367public:
4368    enum SegmentType {
4369        kHorizontalLine_Segment = -1,
4370        kVerticalLine_Segment = 0,
4371        kLine_Segment = SkPath::kLine_Verb,
4372        kQuad_Segment = SkPath::kQuad_Verb,
4373        kCubic_Segment = SkPath::kCubic_Verb,
4374    };
4375
4376    void addCoincident(Work& other, const Intersections& ts, bool swap) {
4377        fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
4378    }
4379
4380    // FIXME: does it make sense to write otherIndex now if we're going to
4381    // fix it up later?
4382    void addOtherT(int index, double otherT, int otherIndex) {
4383        fContour->addOtherT(fIndex, index, otherT, otherIndex);
4384    }
4385
4386    // Avoid collapsing t values that are close to the same since
4387    // we walk ts to describe consecutive intersections. Since a pair of ts can
4388    // be nearly equal, any problems caused by this should be taken care
4389    // of later.
4390    // On the edge or out of range values are negative; add 2 to get end
4391    int addT(double newT, const Work& other) {
4392        return fContour->addT(fIndex, newT, other.fContour, other.fIndex);
4393    }
4394
4395    bool advance() {
4396        return ++fIndex < fLast;
4397    }
4398
4399    SkScalar bottom() const {
4400        return bounds().fBottom;
4401    }
4402
4403    const Bounds& bounds() const {
4404        return fContour->segments()[fIndex].bounds();
4405    }
4406
4407    const SkPoint* cubic() const {
4408        return fCubic;
4409    }
4410
4411    void init(Contour* contour) {
4412        fContour = contour;
4413        fIndex = 0;
4414        fLast = contour->segments().count();
4415    }
4416
4417    bool isAdjacent(const Work& next) {
4418        return fContour == next.fContour && fIndex + 1 == next.fIndex;
4419    }
4420
4421    bool isFirstLast(const Work& next) {
4422        return fContour == next.fContour && fIndex == 0
4423                && next.fIndex == fLast - 1;
4424    }
4425
4426    SkScalar left() const {
4427        return bounds().fLeft;
4428    }
4429
4430    void promoteToCubic() {
4431        fCubic[0] = pts()[0];
4432        fCubic[2] = pts()[1];
4433        fCubic[3] = pts()[2];
4434        fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
4435        fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
4436        fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
4437        fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
4438    }
4439
4440    const SkPoint* pts() const {
4441        return fContour->segments()[fIndex].pts();
4442    }
4443
4444    SkScalar right() const {
4445        return bounds().fRight;
4446    }
4447
4448    ptrdiff_t segmentIndex() const {
4449        return fIndex;
4450    }
4451
4452    SegmentType segmentType() const {
4453        const Segment& segment = fContour->segments()[fIndex];
4454        SegmentType type = (SegmentType) segment.verb();
4455        if (type != kLine_Segment) {
4456            return type;
4457        }
4458        if (segment.isHorizontal()) {
4459            return kHorizontalLine_Segment;
4460        }
4461        if (segment.isVertical()) {
4462            return kVerticalLine_Segment;
4463        }
4464        return kLine_Segment;
4465    }
4466
4467    bool startAfter(const Work& after) {
4468        fIndex = after.fIndex;
4469        return advance();
4470    }
4471
4472    SkScalar top() const {
4473        return bounds().fTop;
4474    }
4475
4476    SkPath::Verb verb() const {
4477        return fContour->segments()[fIndex].verb();
4478    }
4479
4480    SkScalar x() const {
4481        return bounds().fLeft;
4482    }
4483
4484    bool xFlipped() const {
4485        return x() != pts()[0].fX;
4486    }
4487
4488    SkScalar y() const {
4489        return bounds().fTop;
4490    }
4491
4492    bool yFlipped() const {
4493        return y() != pts()[0].fY;
4494    }
4495
4496protected:
4497    Contour* fContour;
4498    SkPoint fCubic[4];
4499    int fIndex;
4500    int fLast;
4501};
4502
4503#if DEBUG_ADD_INTERSECTING_TS
4504static void debugShowLineIntersection(int pts, const Work& wt,
4505        const Work& wn, const double wtTs[2], const double wnTs[2]) {
4506    return;
4507    if (!pts) {
4508        SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n",
4509                __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
4510                wt.pts()[1].fX, wt.pts()[1].fY, wn.pts()[0].fX, wn.pts()[0].fY,
4511                wn.pts()[1].fX, wn.pts()[1].fY);
4512        return;
4513    }
4514    SkPoint wtOutPt, wnOutPt;
4515    LineXYAtT(wt.pts(), wtTs[0], &wtOutPt);
4516    LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
4517    SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
4518            __FUNCTION__,
4519            wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
4520            wt.pts()[1].fX, wt.pts()[1].fY, wtOutPt.fX, wtOutPt.fY);
4521    if (pts == 2) {
4522        SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
4523    }
4524    SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
4525            wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
4526            wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
4527    if (pts == 2) {
4528        SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
4529    }
4530    SkDebugf("\n");
4531}
4532
4533static void debugShowQuadLineIntersection(int pts, const Work& wt,
4534        const Work& wn, const double wtTs[2], const double wnTs[2]) {
4535    if (!pts) {
4536        SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
4537                " (%1.9g,%1.9g %1.9g,%1.9g)\n",
4538                __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
4539                wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
4540                wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
4541        return;
4542    }
4543    SkPoint wtOutPt, wnOutPt;
4544    QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
4545    LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
4546    SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
4547            __FUNCTION__,
4548            wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
4549            wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
4550            wtOutPt.fX, wtOutPt.fY);
4551    if (pts == 2) {
4552        QuadXYAtT(wt.pts(), wtTs[1], &wtOutPt);
4553        SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", wtTs[1], wtOutPt.fX, wtOutPt.fY);
4554    }
4555    SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
4556            wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
4557            wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
4558    if (pts == 2) {
4559        LineXYAtT(wn.pts(), wnTs[1], &wnOutPt);
4560        SkDebugf(" wnTs[1]=%1.9g (%1.9g,%1.9g)", wnTs[1], wnOutPt.fX, wnOutPt.fY);
4561    }
4562    SkDebugf("\n");
4563}
4564
4565static void debugShowQuadIntersection(int pts, const Work& wt,
4566        const Work& wn, const double wtTs[2], const double wnTs[2]) {
4567    if (!pts) {
4568        SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
4569                " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
4570                __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
4571                wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
4572                wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
4573                wn.pts()[2].fX, wn.pts()[2].fY );
4574        return;
4575    }
4576    SkPoint wtOutPt, wnOutPt;
4577    QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
4578    QuadXYAtT(wn.pts(), wnTs[0], &wnOutPt);
4579    SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
4580            __FUNCTION__,
4581            wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
4582            wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
4583            wtOutPt.fX, wtOutPt.fY);
4584    if (pts == 2) {
4585        SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
4586    }
4587    SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
4588            wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
4589            wn.pts()[1].fX, wn.pts()[1].fY, wn.pts()[2].fX, wn.pts()[2].fY,
4590            wnOutPt.fX, wnOutPt.fY);
4591    if (pts == 2) {
4592        SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
4593    }
4594    SkDebugf("\n");
4595}
4596#else
4597static void debugShowLineIntersection(int , const Work& ,
4598        const Work& , const double [2], const double [2]) {
4599}
4600
4601static void debugShowQuadLineIntersection(int , const Work& ,
4602        const Work& , const double [2], const double [2]) {
4603}
4604
4605static void debugShowQuadIntersection(int , const Work& ,
4606        const Work& , const double [2], const double [2]) {
4607}
4608#endif
4609
4610static bool addIntersectTs(Contour* test, Contour* next) {
4611
4612    if (test != next) {
4613        if (test->bounds().fBottom < next->bounds().fTop) {
4614            return false;
4615        }
4616        if (!Bounds::Intersects(test->bounds(), next->bounds())) {
4617            return true;
4618        }
4619    }
4620    Work wt;
4621    wt.init(test);
4622    bool foundCommonContour = test == next;
4623    do {
4624        Work wn;
4625        wn.init(next);
4626        if (test == next && !wn.startAfter(wt)) {
4627            continue;
4628        }
4629        do {
4630            if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
4631                continue;
4632            }
4633            int pts;
4634            Intersections ts;
4635            bool swap = false;
4636            switch (wt.segmentType()) {
4637                case Work::kHorizontalLine_Segment:
4638                    swap = true;
4639                    switch (wn.segmentType()) {
4640                        case Work::kHorizontalLine_Segment:
4641                        case Work::kVerticalLine_Segment:
4642                        case Work::kLine_Segment: {
4643                            pts = HLineIntersect(wn.pts(), wt.left(),
4644                                    wt.right(), wt.y(), wt.xFlipped(), ts);
4645                            debugShowLineIntersection(pts, wt, wn,
4646                                    ts.fT[1], ts.fT[0]);
4647                            break;
4648                        }
4649                        case Work::kQuad_Segment: {
4650                            pts = HQuadIntersect(wn.pts(), wt.left(),
4651                                    wt.right(), wt.y(), wt.xFlipped(), ts);
4652                            break;
4653                        }
4654                        case Work::kCubic_Segment: {
4655                            pts = HCubicIntersect(wn.pts(), wt.left(),
4656                                    wt.right(), wt.y(), wt.xFlipped(), ts);
4657                            break;
4658                        }
4659                        default:
4660                            SkASSERT(0);
4661                    }
4662                    break;
4663                case Work::kVerticalLine_Segment:
4664                    swap = true;
4665                    switch (wn.segmentType()) {
4666                        case Work::kHorizontalLine_Segment:
4667                        case Work::kVerticalLine_Segment:
4668                        case Work::kLine_Segment: {
4669                            pts = VLineIntersect(wn.pts(), wt.top(),
4670                                    wt.bottom(), wt.x(), wt.yFlipped(), ts);
4671                            debugShowLineIntersection(pts, wt, wn,
4672                                    ts.fT[1], ts.fT[0]);
4673                            break;
4674                        }
4675                        case Work::kQuad_Segment: {
4676                            pts = VQuadIntersect(wn.pts(), wt.top(),
4677                                    wt.bottom(), wt.x(), wt.yFlipped(), ts);
4678                            break;
4679                        }
4680                        case Work::kCubic_Segment: {
4681                            pts = VCubicIntersect(wn.pts(), wt.top(),
4682                                    wt.bottom(), wt.x(), wt.yFlipped(), ts);
4683                            break;
4684                        }
4685                        default:
4686                            SkASSERT(0);
4687                    }
4688                    break;
4689                case Work::kLine_Segment:
4690                    switch (wn.segmentType()) {
4691                        case Work::kHorizontalLine_Segment:
4692                            pts = HLineIntersect(wt.pts(), wn.left(),
4693                                    wn.right(), wn.y(), wn.xFlipped(), ts);
4694                            debugShowLineIntersection(pts, wt, wn,
4695                                    ts.fT[1], ts.fT[0]);
4696                            break;
4697                        case Work::kVerticalLine_Segment:
4698                            pts = VLineIntersect(wt.pts(), wn.top(),
4699                                    wn.bottom(), wn.x(), wn.yFlipped(), ts);
4700                            debugShowLineIntersection(pts, wt, wn,
4701                                    ts.fT[1], ts.fT[0]);
4702                            break;
4703                        case Work::kLine_Segment: {
4704                            pts = LineIntersect(wt.pts(), wn.pts(), ts);
4705                            debugShowLineIntersection(pts, wt, wn,
4706                                    ts.fT[1], ts.fT[0]);
4707                            break;
4708                        }
4709                        case Work::kQuad_Segment: {
4710                            swap = true;
4711                            pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
4712                            debugShowQuadLineIntersection(pts, wn, wt,
4713                                    ts.fT[0], ts.fT[1]);
4714                            break;
4715                        }
4716                        case Work::kCubic_Segment: {
4717                            swap = true;
4718                            pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
4719                            break;
4720                        }
4721                        default:
4722                            SkASSERT(0);
4723                    }
4724                    break;
4725                case Work::kQuad_Segment:
4726                    switch (wn.segmentType()) {
4727                        case Work::kHorizontalLine_Segment:
4728                            pts = HQuadIntersect(wt.pts(), wn.left(),
4729                                    wn.right(), wn.y(), wn.xFlipped(), ts);
4730                            break;
4731                        case Work::kVerticalLine_Segment:
4732                            pts = VQuadIntersect(wt.pts(), wn.top(),
4733                                    wn.bottom(), wn.x(), wn.yFlipped(), ts);
4734                            break;
4735                        case Work::kLine_Segment: {
4736                            pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
4737                            debugShowQuadLineIntersection(pts, wt, wn,
4738                                    ts.fT[0], ts.fT[1]);
4739                            break;
4740                        }
4741                        case Work::kQuad_Segment: {
4742                            pts = QuadIntersect(wt.pts(), wn.pts(), ts);
4743                            debugShowQuadIntersection(pts, wt, wn,
4744                                    ts.fT[0], ts.fT[1]);
4745                            break;
4746                        }
4747                        case Work::kCubic_Segment: {
4748                            wt.promoteToCubic();
4749                            pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
4750                            break;
4751                        }
4752                        default:
4753                            SkASSERT(0);
4754                    }
4755                    break;
4756                case Work::kCubic_Segment:
4757                    switch (wn.segmentType()) {
4758                        case Work::kHorizontalLine_Segment:
4759                            pts = HCubicIntersect(wt.pts(), wn.left(),
4760                                    wn.right(), wn.y(), wn.xFlipped(), ts);
4761                            break;
4762                        case Work::kVerticalLine_Segment:
4763                            pts = VCubicIntersect(wt.pts(), wn.top(),
4764                                    wn.bottom(), wn.x(), wn.yFlipped(), ts);
4765                            break;
4766                        case Work::kLine_Segment: {
4767                            pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
4768                            break;
4769                        }
4770                        case Work::kQuad_Segment: {
4771                            wn.promoteToCubic();
4772                            pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
4773                            break;
4774                        }
4775                        case Work::kCubic_Segment: {
4776                            pts = CubicIntersect(wt.pts(), wn.pts(), ts);
4777                            break;
4778                        }
4779                        default:
4780                            SkASSERT(0);
4781                    }
4782                    break;
4783                default:
4784                    SkASSERT(0);
4785            }
4786            if (!foundCommonContour && pts > 0) {
4787                test->addCross(next);
4788                next->addCross(test);
4789                foundCommonContour = true;
4790            }
4791            // in addition to recording T values, record matching segment
4792            if (pts == 2) {
4793                if (wn.segmentType() <= Work::kLine_Segment
4794                        && wt.segmentType() <= Work::kLine_Segment) {
4795                    wt.addCoincident(wn, ts, swap);
4796                    continue;
4797                }
4798                if (wn.segmentType() == Work::kQuad_Segment
4799                        && wt.segmentType() == Work::kQuad_Segment
4800                        && ts.coincidentUsed() == 2) {
4801                    wt.addCoincident(wn, ts, swap);
4802                    continue;
4803                }
4804
4805            }
4806            for (int pt = 0; pt < pts; ++pt) {
4807                SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
4808                SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
4809                int testTAt = wt.addT(ts.fT[swap][pt], wn);
4810                int nextTAt = wn.addT(ts.fT[!swap][pt], wt);
4811                wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
4812                wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
4813            }
4814        } while (wn.advance());
4815    } while (wt.advance());
4816    return true;
4817}
4818
4819// resolve any coincident pairs found while intersecting, and
4820// see if coincidence is formed by clipping non-concident segments
4821static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
4822    int contourCount = contourList.count();
4823    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
4824        Contour* contour = contourList[cIndex];
4825        contour->resolveCoincidence(contourList);
4826    }
4827    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
4828        Contour* contour = contourList[cIndex];
4829        contour->findTooCloseToCall();
4830    }
4831}
4832
4833// project a ray from the top of the contour up and see if it hits anything
4834// note: when we compute line intersections, we keep track of whether
4835// two contours touch, so we need only look at contours not touching this one.
4836// OPTIMIZATION: sort contourList vertically to avoid linear walk
4837static int innerContourCheck(SkTDArray<Contour*>& contourList,
4838        const Segment* current, int index, int endIndex, bool opp) {
4839    const SkPoint& basePt = current->xyAtT(endIndex);
4840    int contourCount = contourList.count();
4841    SkScalar bestY = SK_ScalarMin;
4842    const Segment* test = NULL;
4843    int tIndex;
4844    double tHit;
4845    for (int cTest = 0; cTest < contourCount; ++cTest) {
4846        Contour* contour = contourList[cTest];
4847        if ((contour->operand() ^ current->operand()) != opp) {
4848            continue;
4849        }
4850        if (basePt.fY < contour->bounds().fTop) {
4851            continue;
4852        }
4853        if (bestY > contour->bounds().fBottom) {
4854            continue;
4855        }
4856        const Segment* next = contour->crossedSegment(basePt, bestY, tIndex, tHit);
4857        if (next) {
4858            test = next;
4859        }
4860    }
4861    if (!test) {
4862        return 0;
4863    }
4864    int winding, windValue;
4865    // If the ray hit the end of a span, we need to construct the wheel of
4866    // angles to find the span closest to the ray -- even if there are just
4867    // two spokes on the wheel.
4868    const Angle* angle = NULL;
4869    if (approximately_zero(tHit - test->t(tIndex))) {
4870        SkTDArray<Angle> angles;
4871        int end = test->nextSpan(tIndex, 1);
4872        if (end < 0) {
4873            end = test->nextSpan(tIndex, -1);
4874        }
4875        test->addTwoAngles(end, tIndex, angles);
4876        SkASSERT(angles.count() > 0);
4877        if (angles[0].segment()->yAtT(angles[0].start()) >= basePt.fY) {
4878#if DEBUG_SORT
4879            SkDebugf("%s early return\n", __FUNCTION__);
4880#endif
4881            return 0;
4882        }
4883        test->buildAngles(tIndex, angles, false);
4884        SkTDArray<Angle*> sorted;
4885        // OPTIMIZATION: call a sort that, if base point is the leftmost,
4886        // returns the first counterclockwise hour before 6 o'clock,
4887        // or if the base point is rightmost, returns the first clockwise
4888        // hour after 6 o'clock
4889        (void) Segment::SortAngles(angles, sorted);
4890#if DEBUG_SORT
4891        sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
4892#endif
4893        // walk the sorted angle fan to find the lowest angle
4894        // above the base point. Currently, the first angle in the sorted array
4895        // is 12 noon or an earlier hour (the next counterclockwise)
4896        int count = sorted.count();
4897        int left = -1;
4898        int mid = -1;
4899        int right = -1;
4900        bool baseMatches = test->yAtT(tIndex) == basePt.fY;
4901        for (int index = 0; index < count; ++index) {
4902            angle = sorted[index];
4903            if (angle->unsortable()) {
4904                continue;
4905            }
4906            if (baseMatches && angle->isHorizontal()) {
4907                continue;
4908            }
4909            double indexDx = angle->dx();
4910            test = angle->segment();
4911            if (test->verb() > SkPath::kLine_Verb && approximately_zero(indexDx)) {
4912                const SkPoint* pts = test->pts();
4913                indexDx = pts[2].fX - pts[1].fX - indexDx;
4914            }
4915            if (indexDx < 0) {
4916                left = index;
4917            } else if (indexDx > 0) {
4918                right = index;
4919                int previous = index - 1;
4920                if (previous < 0) {
4921                    previous = count - 1;
4922                }
4923                const Angle* prev = sorted[previous];
4924                if (prev->dy() >= 0 && prev->dx() > 0 && angle->dy() < 0) {
4925#if DEBUG_SORT
4926                    SkDebugf("%s use prev\n", __FUNCTION__);
4927#endif
4928                    right = previous;
4929                }
4930                break;
4931            } else {
4932                mid = index;
4933            }
4934        }
4935        if (left < 0 && right < 0) {
4936            left = mid;
4937        }
4938        SkASSERT(left >= 0 || right >= 0);
4939        if (left < 0) {
4940            left = right;
4941        } else if (left >= 0 && mid >= 0 && right >= 0
4942                && sorted[mid]->sign() == sorted[right]->sign()) {
4943            left = right;
4944        }
4945        angle = sorted[left];
4946        test = angle->segment();
4947        winding = test->windSum(angle);
4948        SkASSERT(winding != SK_MinS32);
4949        windValue = test->windValue(angle);
4950#if DEBUG_WINDING
4951        SkDebugf("%s angle winding=%d windValue=%d sign=%d\n", __FUNCTION__, winding,
4952                windValue, angle->sign());
4953#endif
4954    } else {
4955        winding = test->windSum(tIndex);
4956        SkASSERT(winding != SK_MinS32);
4957        windValue = test->windValue(tIndex);
4958#if DEBUG_WINDING
4959        SkDebugf("%s single winding=%d windValue=%d\n", __FUNCTION__, winding,
4960                windValue);
4961#endif
4962    }
4963    // see if a + change in T results in a +/- change in X (compute x'(T))
4964    SkScalar dx = (*SegmentDXAtT[test->verb()])(test->pts(), tHit);
4965    if (test->verb() > SkPath::kLine_Verb && approximately_zero(dx)) {
4966        const SkPoint* pts = test->pts();
4967        dx = pts[2].fX - pts[1].fX - dx;
4968    }
4969#if DEBUG_WINDING
4970    SkDebugf("%s dx=%1.9g\n", __FUNCTION__, dx);
4971#endif
4972    SkASSERT(dx != 0);
4973    if (winding * dx > 0) { // if same signs, result is negative
4974        winding += dx > 0 ? -windValue : windValue;
4975#if DEBUG_WINDING
4976        SkDebugf("%s final winding=%d\n", __FUNCTION__, winding);
4977#endif
4978    }
4979    return winding;
4980}
4981
4982static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
4983    int contourCount = contourList.count();
4984    Segment* result;
4985    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
4986        Contour* contour = contourList[cIndex];
4987        result = contour->undoneSegment(start, end);
4988        if (result) {
4989            return result;
4990        }
4991    }
4992    return NULL;
4993}
4994
4995
4996
4997static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
4998    while (chase.count()) {
4999        Span* span;
5000        chase.pop(&span);
5001        const Span& backPtr = span->fOther->span(span->fOtherIndex);
5002        Segment* segment = backPtr.fOther;
5003        tIndex = backPtr.fOtherIndex;
5004        SkTDArray<Angle> angles;
5005        int done = 0;
5006        if (segment->activeAngle(tIndex, done, angles)) {
5007            Angle* last = angles.end() - 1;
5008            tIndex = last->start();
5009            endIndex = last->end();
5010   #if TRY_ROTATE
5011            *chase.insert(0) = span;
5012   #else
5013            *chase.append() = span;
5014   #endif
5015            return last->segment();
5016        }
5017        if (done == angles.count()) {
5018            continue;
5019        }
5020        SkTDArray<Angle*> sorted;
5021        bool sortable = Segment::SortAngles(angles, sorted);
5022#if DEBUG_SORT
5023        sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
5024#endif
5025        if (!sortable) {
5026            continue;
5027        }
5028        // find first angle, initialize winding to computed fWindSum
5029        int firstIndex = -1;
5030        const Angle* angle;
5031        int winding;
5032        do {
5033            angle = sorted[++firstIndex];
5034            segment = angle->segment();
5035            winding = segment->windSum(angle);
5036        } while (winding == SK_MinS32);
5037        int spanWinding = segment->spanSign(angle->start(), angle->end());
5038    #if DEBUG_WINDING
5039        SkDebugf("%s winding=%d spanWinding=%d\n",
5040                __FUNCTION__, winding, spanWinding);
5041    #endif
5042        // turn span winding into contour winding
5043        if (spanWinding * winding < 0) {
5044            winding += spanWinding;
5045        }
5046    #if DEBUG_SORT
5047        segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
5048    #endif
5049        // we care about first sign and whether wind sum indicates this
5050        // edge is inside or outside. Maybe need to pass span winding
5051        // or first winding or something into this function?
5052        // advance to first undone angle, then return it and winding
5053        // (to set whether edges are active or not)
5054        int nextIndex = firstIndex + 1;
5055        int angleCount = sorted.count();
5056        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5057        angle = sorted[firstIndex];
5058        winding -= angle->segment()->spanSign(angle);
5059        do {
5060            SkASSERT(nextIndex != firstIndex);
5061            if (nextIndex == angleCount) {
5062                nextIndex = 0;
5063            }
5064            angle = sorted[nextIndex];
5065            segment = angle->segment();
5066            int maxWinding = winding;
5067            winding -= segment->spanSign(angle);
5068    #if DEBUG_SORT
5069            SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
5070                    segment->debugID(), maxWinding, winding, angle->sign());
5071    #endif
5072            tIndex = angle->start();
5073            endIndex = angle->end();
5074            int lesser = SkMin32(tIndex, endIndex);
5075            const Span& nextSpan = segment->span(lesser);
5076            if (!nextSpan.fDone) {
5077#if 1
5078            // FIXME: this be wrong. assign startWinding if edge is in
5079            // same direction. If the direction is opposite, winding to
5080            // assign is flipped sign or +/- 1?
5081                if (useInnerWinding(maxWinding, winding)) {
5082                    maxWinding = winding;
5083                }
5084                segment->markWinding(lesser, maxWinding);
5085#endif
5086                break;
5087            }
5088        } while (++nextIndex != lastIndex);
5089   #if TRY_ROTATE
5090        *chase.insert(0) = span;
5091   #else
5092        *chase.append() = span;
5093   #endif
5094        return segment;
5095    }
5096    return NULL;
5097}
5098
5099#if DEBUG_ACTIVE_SPANS
5100static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
5101    int index;
5102    for (index = 0; index < contourList.count(); ++ index) {
5103        contourList[index]->debugShowActiveSpans();
5104    }
5105    for (index = 0; index < contourList.count(); ++ index) {
5106        contourList[index]->validateActiveSpans();
5107    }
5108}
5109#endif
5110
5111static bool windingIsActive(int winding, int spanWinding) {
5112    // FIXME: !spanWinding test must be superflorous, true?
5113    return winding * spanWinding <= 0 && abs(winding) <= abs(spanWinding)
5114            && (!winding || !spanWinding || winding == -spanWinding);
5115}
5116
5117static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
5118        int& endIndex, SkPoint& topLeft) {
5119    Segment* result;
5120    do {
5121        SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
5122        int contourCount = contourList.count();
5123        Segment* topStart = NULL;
5124        for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5125            Contour* contour = contourList[cIndex];
5126            const Bounds& bounds = contour->bounds();
5127            if (bounds.fBottom < topLeft.fY) {
5128                continue;
5129            }
5130            if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
5131                continue;
5132            }
5133            Segment* test = contour->topSortableSegment(topLeft, bestXY);
5134            if (test) {
5135                topStart = test;
5136            }
5137        }
5138        if (!topStart) {
5139            return NULL;
5140        }
5141        topLeft = bestXY;
5142        result = topStart->findTop(index, endIndex);
5143    } while (!result);
5144    return result;
5145}
5146
5147static int updateWindings(const Segment* current, int index, int endIndex, int& spanWinding) {
5148    int lesser = SkMin32(index, endIndex);
5149    spanWinding = current->spanSign(index, endIndex);
5150    int winding = current->windSum(lesser);
5151    bool inner = useInnerWinding(winding - spanWinding, winding);
5152#if DEBUG_WINDING
5153    SkDebugf("%s id=%d t=%1.9g spanWinding=%d winding=%d sign=%d"
5154            " inner=%d result=%d\n",
5155            __FUNCTION__, current->debugID(), current->t(lesser),
5156            spanWinding, winding, SkSign32(index - endIndex),
5157            useInnerWinding(winding - spanWinding, winding),
5158            inner ? winding - spanWinding : winding);
5159#endif
5160    if (inner) {
5161        winding -= spanWinding;
5162    }
5163    return winding;
5164}
5165
5166// Each segment may have an inside or an outside. Segments contained within
5167// winding may have insides on either side, and form a contour that should be
5168// ignored. Segments that are coincident with opposing direction segments may
5169// have outsides on either side, and should also disappear.
5170// 'Normal' segments will have one inside and one outside. Subsequent connections
5171// when winding should follow the intersection direction. If more than one edge
5172// is an option, choose first edge that continues the inside.
5173    // since we start with leftmost top edge, we'll traverse through a
5174    // smaller angle counterclockwise to get to the next edge.
5175// returns true if all edges were processed
5176static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
5177    bool firstContour = true;
5178    bool unsortable = false;
5179    bool closable = true;
5180    SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
5181    do {
5182        int index, endIndex;
5183        // iterates while top is unsortable
5184        Segment* current = findSortableTop(contourList, index, endIndex, topLeft);
5185        if (!current) {
5186            break;
5187        }
5188        int contourWinding;
5189        if (firstContour) {
5190            contourWinding = 0;
5191            firstContour = false;
5192        } else {
5193            int sumWinding = current->windSum(SkMin32(index, endIndex));
5194            // FIXME: don't I have to adjust windSum to get contourWinding?
5195            if (sumWinding == SK_MinS32) {
5196                sumWinding = current->computeSum(index, endIndex, false);
5197            }
5198            if (sumWinding == SK_MinS32) {
5199                contourWinding = innerContourCheck(contourList, current,
5200                        index, endIndex, false);
5201            } else {
5202                contourWinding = sumWinding;
5203                int spanWinding = current->spanSign(index, endIndex);
5204                bool inner = useInnerWinding(sumWinding - spanWinding, sumWinding);
5205                if (inner) {
5206                    contourWinding -= spanWinding;
5207                }
5208#if DEBUG_WINDING
5209                SkDebugf("%s sumWinding=%d spanWinding=%d sign=%d inner=%d result=%d\n",
5210                        __FUNCTION__, sumWinding, spanWinding, SkSign32(index - endIndex),
5211                        inner, contourWinding);
5212#endif
5213            }
5214#if DEBUG_WINDING
5215            SkDebugf("%s contourWinding=%d\n", __FUNCTION__, contourWinding);
5216#endif
5217        }
5218        int winding = contourWinding;
5219        int spanWinding = current->spanSign(index, endIndex);
5220        // FIXME: needs work. While it works in limited situations, it does
5221        // not always compute winding correctly. Active should be removed and instead
5222        // the initial winding should be correctly passed in so that if the
5223        // inner contour is wound the same way, it never finds an accumulated
5224        // winding of zero. Inside 'find next', we need to look for transitions
5225        // other than zero when resolving sorted angles.
5226        SkTDArray<Span*> chaseArray;
5227        do {
5228            bool active = windingIsActive(winding, spanWinding);
5229        #if DEBUG_WINDING
5230            SkDebugf("%s active=%s winding=%d spanWinding=%d\n",
5231                    __FUNCTION__, active ? "true" : "false",
5232                    winding, spanWinding);
5233        #endif
5234            do {
5235                SkASSERT(unsortable || !current->done());
5236                int nextStart = index;
5237                int nextEnd = endIndex;
5238                Segment* next = current->findNextWinding(chaseArray, active,
5239                        nextStart, nextEnd, winding, spanWinding, unsortable);
5240                if (!next) {
5241                    if (active && !unsortable && simple.hasMove()
5242                            && current->verb() != SkPath::kLine_Verb
5243                            && !simple.isClosed()) {
5244                        current->addCurveTo(index, endIndex, simple, true);
5245                        SkASSERT(simple.isClosed());
5246                    }
5247                    break;
5248                }
5249                current->addCurveTo(index, endIndex, simple, active);
5250                current = next;
5251                index = nextStart;
5252                endIndex = nextEnd;
5253            } while (!simple.isClosed()
5254                    && ((active && !unsortable) || !current->done()));
5255            if (active) {
5256                if (!simple.isClosed()) {
5257                    SkASSERT(unsortable);
5258                    int min = SkMin32(index, endIndex);
5259                    if (!current->done(min)) {
5260                        current->addCurveTo(index, endIndex, simple, true);
5261                        current->markDone(SkMin32(index, endIndex),
5262                                winding ? winding : spanWinding);
5263                    }
5264                    closable = false;
5265                }
5266                simple.close();
5267            }
5268            current = findChase(chaseArray, index, endIndex);
5269        #if DEBUG_ACTIVE_SPANS
5270            debugShowActiveSpans(contourList);
5271        #endif
5272            if (!current) {
5273                break;
5274            }
5275            winding = updateWindings(current, index, endIndex, spanWinding);
5276        } while (true);
5277    } while (true);
5278    return closable;
5279}
5280
5281// returns true if all edges were processed
5282static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
5283    Segment* current;
5284    int start, end;
5285    bool unsortable = false;
5286    while ((current = findUndone(contourList, start, end))) {
5287        do {
5288            SkASSERT(unsortable || !current->done());
5289            int nextStart = start;
5290            int nextEnd = end;
5291            Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
5292            if (!next) {
5293                if (simple.hasMove()
5294                        && current->verb() != SkPath::kLine_Verb
5295                        && !simple.isClosed()) {
5296                    current->addCurveTo(start, end, simple, true);
5297                    SkASSERT(simple.isClosed());
5298                }
5299                break;
5300            }
5301            current->addCurveTo(start, end, simple, true);
5302            current = next;
5303            start = nextStart;
5304            end = nextEnd;
5305        } while (!simple.isClosed());
5306        // FIXME: add unsortable test
5307        if (simple.hasMove()) {
5308            simple.close();
5309        }
5310    #if DEBUG_ACTIVE_SPANS
5311        debugShowActiveSpans(contourList);
5312    #endif
5313    }
5314    return !unsortable;
5315}
5316
5317static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
5318    int contourCount = contourList.count();
5319    for (int cTest = 0; cTest < contourCount; ++cTest) {
5320        Contour* contour = contourList[cTest];
5321        contour->fixOtherTIndex();
5322    }
5323}
5324
5325static void sortSegments(SkTDArray<Contour*>& contourList) {
5326    int contourCount = contourList.count();
5327    for (int cTest = 0; cTest < contourCount; ++cTest) {
5328        Contour* contour = contourList[cTest];
5329        contour->sortSegments();
5330    }
5331}
5332
5333static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
5334        bool evenOdd, bool oppEvenOdd) {
5335    int count = contours.count();
5336    if (count == 0) {
5337        return;
5338    }
5339    for (int index = 0; index < count; ++index) {
5340        Contour& contour = contours[index];
5341        contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
5342        *list.append() = &contour;
5343    }
5344    QSort<Contour>(list.begin(), list.end() - 1);
5345}
5346
5347static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
5348    return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
5349}
5350
5351    /*
5352        check start and end of each contour
5353        if not the same, record them
5354        match them up
5355        connect closest
5356        reassemble contour pieces into new path
5357    */
5358static void assemble(const PathWrapper& path, PathWrapper& simple) {
5359#if DEBUG_PATH_CONSTRUCTION
5360    SkDebugf("%s\n", __FUNCTION__);
5361#endif
5362    SkTArray<Contour> contours;
5363    EdgeBuilder builder(path, contours);
5364    builder.finish();
5365    int count = contours.count();
5366    int outer;
5367    SkTDArray<int> runs; // indices of partial contours
5368    for (outer = 0; outer < count; ++outer) {
5369        const Contour& eContour = contours[outer];
5370        const SkPoint& eStart = eContour.start();
5371        const SkPoint& eEnd = eContour.end();
5372        if (approximatelyEqual(eStart, eEnd)) {
5373            eContour.toPath(simple);
5374            continue;
5375        }
5376        *runs.append() = outer;
5377    }
5378    count = runs.count();
5379    if (count == 0) {
5380        return;
5381    }
5382    SkTDArray<int> sLink, eLink;
5383    sLink.setCount(count);
5384    eLink.setCount(count);
5385    SkTDArray<double> sBest, eBest;
5386    sBest.setCount(count);
5387    eBest.setCount(count);
5388    int rIndex;
5389    for (rIndex = 0; rIndex < count; ++rIndex) {
5390        outer = runs[rIndex];
5391        const Contour& oContour = contours[outer];
5392        const SkPoint& oStart = oContour.start();
5393        const SkPoint& oEnd = oContour.end();
5394        double dx = oEnd.fX - oStart.fX;
5395        double dy = oEnd.fY - oStart.fY;
5396        double dist = dx * dx + dy * dy;
5397        sBest[rIndex] = eBest[rIndex] = dist;
5398        sLink[rIndex] = eLink[rIndex] = rIndex;
5399    }
5400    for (rIndex = 0; rIndex < count - 1; ++rIndex) {
5401        outer = runs[rIndex];
5402        const Contour& oContour = contours[outer];
5403        const SkPoint& oStart = oContour.start();
5404        const SkPoint& oEnd = oContour.end();
5405        double bestStartDist = sBest[rIndex];
5406        double bestEndDist = eBest[rIndex];
5407        for (int iIndex = rIndex + 1; iIndex < count; ++iIndex) {
5408            int inner = runs[iIndex];
5409            const Contour& iContour = contours[inner];
5410            const SkPoint& iStart = iContour.start();
5411            const SkPoint& iEnd = iContour.end();
5412            double dx = iStart.fX - oStart.fX;
5413            double dy = iStart.fY - oStart.fY;
5414            double dist = dx * dx + dy * dy;
5415            if (bestStartDist > dist) {
5416                bestStartDist = dist;
5417                sLink[rIndex] = ~iIndex;
5418                sLink[iIndex] = ~rIndex;
5419            }
5420            dx = iEnd.fX - oStart.fX;
5421            dy = iEnd.fY - oStart.fY;
5422            dist = dx * dx + dy * dy;
5423            if (bestStartDist > dist) {
5424                bestStartDist = dist;
5425                sLink[rIndex] = iIndex;
5426                eLink[iIndex] = rIndex;
5427            }
5428            dx = iStart.fX - oEnd.fX;
5429            dy = iStart.fY - oEnd.fY;
5430            dist = dx * dx + dy * dy;
5431            if (bestEndDist > dist) {
5432                bestEndDist = dist;
5433                sLink[iIndex] = rIndex;
5434                eLink[rIndex] = iIndex;
5435            }
5436            dx = iEnd.fX - oEnd.fX;
5437            dy = iEnd.fY - oEnd.fY;
5438            dist = dx * dx + dy * dy;
5439            if (bestEndDist > dist) {
5440                bestEndDist = dist;
5441                eLink[iIndex] = ~rIndex;
5442                eLink[rIndex] = ~iIndex;
5443            }
5444       }
5445    }
5446    rIndex = 0;
5447    bool forward = true;
5448    bool first = true;
5449    const SkPoint* startPtr;
5450    int sIndex = sLink[rIndex];
5451    SkASSERT(sIndex != INT_MAX);
5452    sLink[rIndex] = INT_MAX;
5453    int eIndex;
5454    if (sIndex < 0) {
5455        eIndex = sLink[~sIndex];
5456        sLink[~sIndex] = INT_MAX;
5457    } else {
5458        eIndex = eLink[sIndex];
5459        eLink[sIndex] = INT_MAX;
5460    }
5461    SkASSERT(eIndex != INT_MAX);
5462    do {
5463        do {
5464            outer = runs[rIndex];
5465            const Contour& contour = contours[outer];
5466            if (first) {
5467                startPtr = &contour.start();
5468                first = false;
5469                simple.deferredMove(startPtr[0]);
5470            }
5471            if (forward) {
5472                contour.toPartialForward(simple);
5473            } else {
5474                contour.toPartialBackward(simple);
5475            }
5476            if (sIndex == eIndex) {
5477                simple.close();
5478                first = forward = true;
5479                break;
5480            }
5481            if (forward) {
5482                eIndex = eLink[rIndex];
5483                SkASSERT(eIndex != INT_MAX);
5484                eLink[rIndex] = INT_MAX;
5485                if (eIndex >= 0) {
5486                    SkASSERT(sLink[eIndex] == rIndex);
5487                    sLink[eIndex] = INT_MAX;
5488                } else {
5489                    SkASSERT(eLink[~eIndex] == ~rIndex);
5490                    eLink[~eIndex] = INT_MAX;
5491                }
5492            } else {
5493                eIndex = sLink[rIndex];
5494                SkASSERT(eIndex != INT_MAX);
5495                sLink[rIndex] = INT_MAX;
5496                if (eIndex >= 0) {
5497                    SkASSERT(eLink[eIndex] == rIndex);
5498                    eLink[eIndex] = INT_MAX;
5499                } else {
5500                    SkASSERT(sLink[~eIndex] == ~rIndex);
5501                    sLink[~eIndex] = INT_MAX;
5502                }
5503            }
5504            rIndex = eIndex;
5505            if (rIndex < 0) {
5506                forward ^= 1;
5507                rIndex = ~rIndex;
5508            }
5509        } while (true);
5510        for (rIndex = 0; rIndex < count; ++rIndex) {
5511            if (sLink[rIndex] != INT_MAX) {
5512                break;
5513            }
5514        }
5515    } while (rIndex < count);
5516    SkASSERT(first);
5517}
5518
5519void simplifyx(const SkPath& path, SkPath& result) {
5520    // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
5521    result.reset();
5522    result.setFillType(SkPath::kEvenOdd_FillType);
5523    PathWrapper simple(result);
5524
5525    // turn path into list of segments
5526    SkTArray<Contour> contours;
5527    // FIXME: add self-intersecting cubics' T values to segment
5528    EdgeBuilder builder(path, contours);
5529    builder.finish();
5530    SkTDArray<Contour*> contourList;
5531    makeContourList(contours, contourList, false, false);
5532    Contour** currentPtr = contourList.begin();
5533    if (!currentPtr) {
5534        return;
5535    }
5536    Contour** listEnd = contourList.end();
5537    // find all intersections between segments
5538    do {
5539        Contour** nextPtr = currentPtr;
5540        Contour* current = *currentPtr++;
5541        Contour* next;
5542        do {
5543            next = *nextPtr++;
5544        } while (addIntersectTs(current, next) && nextPtr != listEnd);
5545    } while (currentPtr != listEnd);
5546    // eat through coincident edges
5547    coincidenceCheck(contourList, 0);
5548    fixOtherTIndex(contourList);
5549    sortSegments(contourList);
5550#if DEBUG_ACTIVE_SPANS
5551    debugShowActiveSpans(contourList);
5552#endif
5553    // construct closed contours
5554    if (builder.xorMask() == kWinding_Mask
5555                ? !bridgeWinding(contourList, simple)
5556                : !bridgeXor(contourList, simple))
5557    { // if some edges could not be resolved, assemble remaining fragments
5558        SkPath temp;
5559        temp.setFillType(SkPath::kEvenOdd_FillType);
5560        PathWrapper assembled(temp);
5561        assemble(simple, assembled);
5562        result = *assembled.nativePath();
5563    }
5564}
5565
5566