Simplify.cpp revision 6aea33f92c611d6fdc88bc2352c5c966168af83b
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 DEBUG_UNUSED 0 // set to expose unused functions
29
30#if 0 // set to 1 for multiple thread -- no debugging
31
32const bool gRunTestsInOneThread = false;
33
34#define DEBUG_ACTIVE_SPANS 0
35#define DEBUG_ADD_INTERSECTING_TS 0
36#define DEBUG_ADD_T_PAIR 0
37#define DEBUG_ANGLE 0
38#define DEBUG_CONCIDENT 0
39#define DEBUG_CROSS 0
40#define DEBUG_MARK_DONE 0
41#define DEBUG_PATH_CONSTRUCTION 1
42#define DEBUG_SORT 0
43#define DEBUG_WIND_BUMP 0
44#define DEBUG_WINDING 0
45
46#else
47
48const bool gRunTestsInOneThread = true;
49
50#define DEBUG_ACTIVE_SPANS 1
51#define DEBUG_ADD_INTERSECTING_TS 1
52#define DEBUG_ADD_T_PAIR 1
53#define DEBUG_ANGLE 1
54#define DEBUG_CONCIDENT 1
55#define DEBUG_CROSS 0
56#define DEBUG_MARK_DONE 1
57#define DEBUG_PATH_CONSTRUCTION 1
58#define DEBUG_SORT 1
59#define DEBUG_WIND_BUMP 0
60#define DEBUG_WINDING 1
61
62#endif
63
64#define DEBUG_DUMP (DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | DEBUG_PATH_CONSTRUCTION)
65
66#if DEBUG_DUMP
67static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
68// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
69static int gContourID;
70static int gSegmentID;
71#endif
72
73#ifndef DEBUG_TEST
74#define DEBUG_TEST 0
75#endif
76
77#define MAKE_CONST_LINE(line, pts) \
78    const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}
79#define MAKE_CONST_QUAD(quad, pts) \
80    const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
81            {pts[2].fX, pts[2].fY}}
82#define MAKE_CONST_CUBIC(cubic, pts) \
83    const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
84            {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}}
85
86static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
87        Intersections& intersections) {
88    MAKE_CONST_LINE(aLine, a);
89    MAKE_CONST_LINE(bLine, b);
90    return intersect(aLine, bLine, intersections.fT[0], intersections.fT[1]);
91}
92
93static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
94        Intersections& intersections) {
95    MAKE_CONST_QUAD(aQuad, a);
96    MAKE_CONST_LINE(bLine, b);
97    return intersect(aQuad, bLine, intersections);
98}
99
100static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2],
101        Intersections& intersections) {
102    MAKE_CONST_CUBIC(aCubic, a);
103    MAKE_CONST_LINE(bLine, b);
104    return intersect(aCubic, bLine, intersections.fT[0], intersections.fT[1]);
105}
106
107static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
108        Intersections& intersections) {
109    MAKE_CONST_QUAD(aQuad, a);
110    MAKE_CONST_QUAD(bQuad, b);
111#define TRY_QUARTIC_SOLUTION 1
112#if TRY_QUARTIC_SOLUTION
113    intersect2(aQuad, bQuad, intersections);
114#else
115    intersect(aQuad, bQuad, intersections);
116#endif
117    return intersections.fUsed ? intersections.fUsed : intersections.fCoincidentUsed;
118}
119
120static int CubicIntersect(const SkPoint a[4], const SkPoint b[4],
121        Intersections& intersections) {
122    MAKE_CONST_CUBIC(aCubic, a);
123    MAKE_CONST_CUBIC(bCubic, b);
124    intersect(aCubic, bCubic, intersections);
125    return intersections.fUsed;
126}
127
128static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
129        SkScalar y, bool flipped, Intersections& intersections) {
130    MAKE_CONST_LINE(aLine, a);
131    return horizontalIntersect(aLine, left, right, y, flipped, intersections);
132}
133
134static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
135        SkScalar y, bool flipped, Intersections& intersections) {
136    MAKE_CONST_QUAD(aQuad, a);
137    return horizontalIntersect(aQuad, left, right, y, flipped, intersections);
138}
139
140static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
141        SkScalar y, bool flipped, Intersections& intersections) {
142    MAKE_CONST_CUBIC(aCubic, a);
143    return horizontalIntersect(aCubic, left, right, y, flipped, intersections);
144}
145
146static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom,
147        SkScalar x, bool flipped, Intersections& intersections) {
148    MAKE_CONST_LINE(aLine, a);
149    return verticalIntersect(aLine, top, bottom, x, flipped, intersections);
150}
151
152static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom,
153        SkScalar x, bool flipped, Intersections& intersections) {
154    MAKE_CONST_QUAD(aQuad, a);
155    return verticalIntersect(aQuad, top, bottom, x, flipped, intersections);
156}
157
158static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom,
159        SkScalar x, bool flipped, Intersections& intersections) {
160    MAKE_CONST_CUBIC(aCubic, a);
161    return verticalIntersect(aCubic, top, bottom, x, flipped, intersections);
162}
163
164static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar ,
165        SkScalar , SkScalar , bool , Intersections& ) = {
166    NULL,
167    VLineIntersect,
168    VQuadIntersect,
169    VCubicIntersect
170};
171
172static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
173    MAKE_CONST_LINE(line, a);
174    double x, y;
175    xy_at_t(line, t, x, y);
176    out->fX = SkDoubleToScalar(x);
177    out->fY = SkDoubleToScalar(y);
178}
179
180static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
181    MAKE_CONST_QUAD(quad, a);
182    double x, y;
183    xy_at_t(quad, t, x, y);
184    out->fX = SkDoubleToScalar(x);
185    out->fY = SkDoubleToScalar(y);
186}
187
188static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
189    MAKE_CONST_QUAD(quad, a);
190    xy_at_t(quad, t, out->x, out->y);
191}
192
193static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
194    MAKE_CONST_CUBIC(cubic, a);
195    double x, y;
196    xy_at_t(cubic, t, x, y);
197    out->fX = SkDoubleToScalar(x);
198    out->fY = SkDoubleToScalar(y);
199}
200
201static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
202    NULL,
203    LineXYAtT,
204    QuadXYAtT,
205    CubicXYAtT
206};
207
208static SkScalar LineXAtT(const SkPoint a[2], double t) {
209    MAKE_CONST_LINE(aLine, a);
210    double x;
211    xy_at_t(aLine, t, x, *(double*) 0);
212    return SkDoubleToScalar(x);
213}
214
215static SkScalar QuadXAtT(const SkPoint a[3], double t) {
216    MAKE_CONST_QUAD(quad, a);
217    double x;
218    xy_at_t(quad, t, x, *(double*) 0);
219    return SkDoubleToScalar(x);
220}
221
222static SkScalar CubicXAtT(const SkPoint a[4], double t) {
223    MAKE_CONST_CUBIC(cubic, a);
224    double x;
225    xy_at_t(cubic, t, x, *(double*) 0);
226    return SkDoubleToScalar(x);
227}
228
229static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
230    NULL,
231    LineXAtT,
232    QuadXAtT,
233    CubicXAtT
234};
235
236static SkScalar LineYAtT(const SkPoint a[2], double t) {
237    MAKE_CONST_LINE(aLine, a);
238    double y;
239    xy_at_t(aLine, t, *(double*) 0, y);
240    return SkDoubleToScalar(y);
241}
242
243static SkScalar QuadYAtT(const SkPoint a[3], double t) {
244    MAKE_CONST_QUAD(quad, a);
245    double y;
246    xy_at_t(quad, t, *(double*) 0, y);
247    return SkDoubleToScalar(y);
248}
249
250static SkScalar CubicYAtT(const SkPoint a[4], double t) {
251    MAKE_CONST_CUBIC(cubic, a);
252    double y;
253    xy_at_t(cubic, t, *(double*) 0, y);
254    return SkDoubleToScalar(y);
255}
256
257static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
258    NULL,
259    LineYAtT,
260    QuadYAtT,
261    CubicYAtT
262};
263
264static SkScalar LineDXAtT(const SkPoint a[2], double ) {
265    return a[1].fX - a[0].fX;
266}
267
268static SkScalar QuadDXAtT(const SkPoint a[3], double t) {
269    MAKE_CONST_QUAD(quad, a);
270    double x;
271    dxdy_at_t(quad, t, x, *(double*) 0);
272    return SkDoubleToScalar(x);
273}
274
275static SkScalar CubicDXAtT(const SkPoint a[4], double t) {
276    MAKE_CONST_CUBIC(cubic, a);
277    double x;
278    dxdy_at_t(cubic, t, x, *(double*) 0);
279    return SkDoubleToScalar(x);
280}
281
282static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
283    NULL,
284    LineDXAtT,
285    QuadDXAtT,
286    CubicDXAtT
287};
288
289static void LineSubDivide(const SkPoint a[2], double startT, double endT,
290        SkPoint sub[2]) {
291    MAKE_CONST_LINE(aLine, a);
292    _Line dst;
293    sub_divide(aLine, startT, endT, dst);
294    sub[0].fX = SkDoubleToScalar(dst[0].x);
295    sub[0].fY = SkDoubleToScalar(dst[0].y);
296    sub[1].fX = SkDoubleToScalar(dst[1].x);
297    sub[1].fY = SkDoubleToScalar(dst[1].y);
298}
299
300static void QuadSubDivide(const SkPoint a[3], double startT, double endT,
301        SkPoint sub[3]) {
302    MAKE_CONST_QUAD(aQuad, a);
303    Quadratic dst;
304    sub_divide(aQuad, startT, endT, dst);
305    sub[0].fX = SkDoubleToScalar(dst[0].x);
306    sub[0].fY = SkDoubleToScalar(dst[0].y);
307    sub[1].fX = SkDoubleToScalar(dst[1].x);
308    sub[1].fY = SkDoubleToScalar(dst[1].y);
309    sub[2].fX = SkDoubleToScalar(dst[2].x);
310    sub[2].fY = SkDoubleToScalar(dst[2].y);
311}
312
313static void CubicSubDivide(const SkPoint a[4], double startT, double endT,
314        SkPoint sub[4]) {
315    MAKE_CONST_CUBIC(aCubic, a);
316    Cubic dst;
317    sub_divide(aCubic, startT, endT, dst);
318    sub[0].fX = SkDoubleToScalar(dst[0].x);
319    sub[0].fY = SkDoubleToScalar(dst[0].y);
320    sub[1].fX = SkDoubleToScalar(dst[1].x);
321    sub[1].fY = SkDoubleToScalar(dst[1].y);
322    sub[2].fX = SkDoubleToScalar(dst[2].x);
323    sub[2].fY = SkDoubleToScalar(dst[2].y);
324    sub[3].fX = SkDoubleToScalar(dst[3].x);
325    sub[3].fY = SkDoubleToScalar(dst[3].y);
326}
327
328static void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
329        SkPoint []) = {
330    NULL,
331    LineSubDivide,
332    QuadSubDivide,
333    CubicSubDivide
334};
335
336static void LineSubDivideHD(const SkPoint a[2], double startT, double endT,
337        _Line sub) {
338    MAKE_CONST_LINE(aLine, a);
339    _Line dst;
340    sub_divide(aLine, startT, endT, dst);
341    sub[0] = dst[0];
342    sub[1] = dst[1];
343}
344
345static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT,
346        Quadratic sub) {
347    MAKE_CONST_QUAD(aQuad, a);
348    Quadratic dst;
349    sub_divide(aQuad, startT, endT, dst);
350    sub[0] = dst[0];
351    sub[1] = dst[1];
352    sub[2] = dst[2];
353}
354
355static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT,
356        Cubic sub) {
357    MAKE_CONST_CUBIC(aCubic, a);
358    Cubic dst;
359    sub_divide(aCubic, startT, endT, dst);
360    sub[0] = dst[0];
361    sub[1] = dst[1];
362    sub[2] = dst[2];
363    sub[3] = dst[3];
364}
365
366#if DEBUG_UNUSED
367static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
368        SkRect& bounds) {
369    SkPoint dst[3];
370    QuadSubDivide(a, startT, endT, dst);
371    bounds.fLeft = bounds.fRight = dst[0].fX;
372    bounds.fTop = bounds.fBottom = dst[0].fY;
373    for (int index = 1; index < 3; ++index) {
374        bounds.growToInclude(dst[index].fX, dst[index].fY);
375    }
376}
377
378static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
379        SkRect& bounds) {
380    SkPoint dst[4];
381    CubicSubDivide(a, startT, endT, dst);
382    bounds.fLeft = bounds.fRight = dst[0].fX;
383    bounds.fTop = bounds.fBottom = dst[0].fY;
384    for (int index = 1; index < 4; ++index) {
385        bounds.growToInclude(dst[index].fX, dst[index].fY);
386    }
387}
388#endif
389
390static SkPath::Verb QuadReduceOrder(const SkPoint a[3],
391        SkTDArray<SkPoint>& reducePts) {
392    MAKE_CONST_QUAD(aQuad, a);
393    Quadratic dst;
394    int order = reduceOrder(aQuad, dst);
395    if (order == 2) { // quad became line
396        for (int index = 0; index < order; ++index) {
397            SkPoint* pt = reducePts.append();
398            pt->fX = SkDoubleToScalar(dst[index].x);
399            pt->fY = SkDoubleToScalar(dst[index].y);
400        }
401    }
402    return (SkPath::Verb) (order - 1);
403}
404
405static SkPath::Verb CubicReduceOrder(const SkPoint a[4],
406        SkTDArray<SkPoint>& reducePts) {
407    MAKE_CONST_CUBIC(aCubic, a);
408    Cubic dst;
409    int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed);
410    if (order == 2 || order == 3) { // cubic became line or quad
411        for (int index = 0; index < order; ++index) {
412            SkPoint* pt = reducePts.append();
413            pt->fX = SkDoubleToScalar(dst[index].x);
414            pt->fY = SkDoubleToScalar(dst[index].y);
415        }
416    }
417    return (SkPath::Verb) (order - 1);
418}
419
420static bool QuadIsLinear(const SkPoint a[3]) {
421    MAKE_CONST_QUAD(aQuad, a);
422    return isLinear(aQuad, 0, 2);
423}
424
425static bool CubicIsLinear(const SkPoint a[4]) {
426    MAKE_CONST_CUBIC(aCubic, a);
427    return isLinear(aCubic, 0, 3);
428}
429
430static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
431    MAKE_CONST_LINE(aLine, a);
432    double x[2];
433    xy_at_t(aLine, startT, x[0], *(double*) 0);
434    xy_at_t(aLine, endT, x[1], *(double*) 0);
435    return SkMinScalar((float) x[0], (float) x[1]);
436}
437
438static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
439    MAKE_CONST_QUAD(aQuad, a);
440    return (float) leftMostT(aQuad, startT, endT);
441}
442
443static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
444    MAKE_CONST_CUBIC(aCubic, a);
445    return (float) leftMostT(aCubic, startT, endT);
446}
447
448static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
449    NULL,
450    LineLeftMost,
451    QuadLeftMost,
452    CubicLeftMost
453};
454
455#if 0 // currently unused
456static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
457        Intersections& intersections) {
458    MAKE_CONST_QUAD(aQuad, a);
459    MAKE_CONST_LINE(bLine, b);
460    return intersectRay(aQuad, bLine, intersections);
461}
462#endif
463
464static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine,
465        Intersections& intersections) {
466    MAKE_CONST_QUAD(aQuad, a);
467    return intersectRay(aQuad, bLine, intersections);
468}
469
470class Segment;
471
472struct Span {
473    Segment* fOther;
474    mutable SkPoint fPt; // lazily computed as needed
475    double fT;
476    double fOtherT; // value at fOther[fOtherIndex].fT
477    int fOtherIndex;  // can't be used during intersection
478    int fWindSum; // accumulated from contours surrounding this one
479    int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
480    int fWindValueOpp; // opposite value, if any (for binary ops with coincidence)
481    bool fDone; // if set, this span to next higher T has been processed
482};
483
484// sorting angles
485// given angles of {dx dy ddx ddy dddx dddy} sort them
486class Angle {
487public:
488    // FIXME: this is bogus for quads and cubics
489    // if the quads and cubics' line from end pt to ctrl pt are coincident,
490    // there's no obvious way to determine the curve ordering from the
491    // derivatives alone. In particular, if one quadratic's coincident tangent
492    // is longer than the other curve, the final control point can place the
493    // longer curve on either side of the shorter one.
494    // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
495    // may provide some help, but nothing has been figured out yet.
496
497 //   start here
498    /*(
499    for quads and cubics, set up a parameterized line (e.g. LineParameters )
500    for points [0] to [1]. See if point [2] is on that line, or on one side
501    or the other. If it both quads' end points are on the same side, choose
502    the shorter tangent. If the tangents are equal, choose the better second
503    tangent angle
504
505    maybe I could set up LineParameters lazily
506    */
507    bool operator<(const Angle& rh) const {
508        double y = dy();
509        double ry = rh.dy();
510        if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
511            return y < 0;
512        }
513        double x = dx();
514        double rx = rh.dx();
515        if (y == 0 && ry == 0 && x * rx < 0) {
516            return x < rx;
517        }
518        double x_ry = x * ry;
519        double rx_y = rx * y;
520        double cmp = x_ry - rx_y;
521        if (!approximately_zero(cmp)) {
522            return cmp < 0;
523        }
524        if (approximately_zero(x_ry) && approximately_zero(rx_y)
525                && !approximately_zero_squared(cmp)) {
526            return cmp < 0;
527        }
528        // see if either curve can be lengthened and try the tangent compare again
529        if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
530                && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
531            Angle longer = *this;
532            Angle rhLonger = rh;
533            if (longer.lengthen() | rhLonger.lengthen()) {
534                return longer < rhLonger;
535            }
536        }
537        // at this point, the initial tangent line is coincident
538        if (fSide * rh.fSide <= 0) {
539            // FIXME: running demo will trigger this assertion
540            // (don't know if commenting out will trigger further assertion or not)
541            // commenting it out allows demo to run in release, though
542     //       SkASSERT(fSide != rh.fSide);
543            return fSide < rh.fSide;
544        }
545        SkASSERT(fVerb == SkPath::kQuad_Verb); // worry about cubics later
546        SkASSERT(rh.fVerb == SkPath::kQuad_Verb);
547        // FIXME: until I can think of something better, project a ray from the
548        // end of the shorter tangent to midway between the end points
549        // through both curves and use the resulting angle to sort
550        // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
551        double len = fTangent1.normalSquared();
552        double rlen = rh.fTangent1.normalSquared();
553        _Line ray;
554        Intersections i, ri;
555        int roots, rroots;
556        bool flip = false;
557        do {
558            const Quadratic& q = (len < rlen) ^ flip ? fQ : rh.fQ;
559            double midX = (q[0].x + q[2].x) / 2;
560            double midY = (q[0].y + q[2].y) / 2;
561            ray[0] = q[1];
562            ray[1].x = midX;
563            ray[1].y = midY;
564            SkASSERT(ray[0] != ray[1]);
565            roots = QuadRayIntersect(fPts, ray, i);
566            rroots = QuadRayIntersect(rh.fPts, ray, ri);
567        } while ((roots == 0 || rroots == 0) && (flip ^= true));
568        SkASSERT(roots > 0);
569        SkASSERT(rroots > 0);
570        _Point loc;
571        double best = SK_ScalarInfinity;
572        double dx, dy, dist;
573        int index;
574        for (index = 0; index < roots; ++index) {
575            QuadXYAtT(fPts, i.fT[0][index], &loc);
576            dx = loc.x - ray[0].x;
577            dy = loc.y - ray[0].y;
578            dist = dx * dx + dy * dy;
579            if (best > dist) {
580                best = dist;
581            }
582        }
583        for (index = 0; index < rroots; ++index) {
584            QuadXYAtT(rh.fPts, ri.fT[0][index], &loc);
585            dx = loc.x - ray[0].x;
586            dy = loc.y - ray[0].y;
587            dist = dx * dx + dy * dy;
588            if (best > dist) {
589                return fSide < 0;
590            }
591        }
592        return fSide > 0;
593    }
594
595    double dx() const {
596        return fTangent1.dx();
597    }
598
599    double dy() const {
600        return fTangent1.dy();
601    }
602
603    int end() const {
604        return fEnd;
605    }
606
607    bool isHorizontal() const {
608        return dy() == 0 && fVerb == SkPath::kLine_Verb;
609    }
610
611    bool lengthen() {
612        int newEnd = fEnd;
613        if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
614            fEnd = newEnd;
615            setSpans();
616            return true;
617        }
618        return false;
619    }
620
621    void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
622            int start, int end, const SkTDArray<Span>& spans) {
623        fSegment = segment;
624        fStart = start;
625        fEnd = end;
626        fPts = orig;
627        fVerb = verb;
628        fSpans = &spans;
629        setSpans();
630    }
631
632    void setSpans() {
633        double startT = (*fSpans)[fStart].fT;
634        double endT = (*fSpans)[fEnd].fT;
635        switch (fVerb) {
636        case SkPath::kLine_Verb:
637            _Line l;
638            LineSubDivideHD(fPts, startT, endT, l);
639            // OPTIMIZATION: for pure line compares, we never need fTangent1.c
640            fTangent1.lineEndPoints(l);
641            fSide = 0;
642            break;
643        case SkPath::kQuad_Verb:
644            QuadSubDivideHD(fPts, startT, endT, fQ);
645            fTangent1.quadEndPoints(fQ, 0, 1);
646            fSide = -fTangent1.pointDistance(fQ[2]); // not normalized -- compare sign only
647            break;
648        case SkPath::kCubic_Verb:
649            Cubic c;
650            CubicSubDivideHD(fPts, startT, endT, c);
651            fTangent1.cubicEndPoints(c, 0, 1);
652            fSide = -fTangent1.pointDistance(c[2]); // not normalized -- compare sign only
653            break;
654        default:
655            SkASSERT(0);
656        }
657    }
658
659    Segment* segment() const {
660        return const_cast<Segment*>(fSegment);
661    }
662
663    int sign() const {
664        return SkSign32(fStart - fEnd);
665    }
666
667    int start() const {
668        return fStart;
669    }
670
671#if DEBUG_ANGLE
672    const SkPoint* pts() const {
673        return fPts;
674    }
675
676    const SkTDArray<Span>* spans() const {
677        return fSpans;
678    }
679
680    SkPath::Verb verb() const {
681        return fVerb;
682    }
683
684    void debugShow(const SkPoint& a) const {
685        SkDebugf("    d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
686    }
687#endif
688
689private:
690    const SkPoint* fPts;
691    Quadratic fQ;
692    SkPath::Verb fVerb;
693    double fSide;
694    LineParameters fTangent1;
695    const SkTDArray<Span>* fSpans;
696    const Segment* fSegment;
697    int fStart;
698    int fEnd;
699};
700
701static void sortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
702    int angleCount = angles.count();
703    int angleIndex;
704    angleList.setReserve(angleCount);
705    for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
706        *angleList.append() = &angles[angleIndex];
707    }
708    QSort<Angle>(angleList.begin(), angleList.end() - 1);
709}
710
711// Bounds, unlike Rect, does not consider a line to be empty.
712struct Bounds : public SkRect {
713    static bool Intersects(const Bounds& a, const Bounds& b) {
714        return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
715                a.fTop <= b.fBottom && b.fTop <= a.fBottom;
716    }
717
718    void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
719        if (left < fLeft) {
720            fLeft = left;
721        }
722        if (top < fTop) {
723            fTop = top;
724        }
725        if (right > fRight) {
726            fRight = right;
727        }
728        if (bottom > fBottom) {
729            fBottom = bottom;
730        }
731    }
732
733    void add(const Bounds& toAdd) {
734        add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
735    }
736
737    bool isEmpty() {
738        return fLeft > fRight || fTop > fBottom
739                || (fLeft == fRight && fTop == fBottom)
740                || isnan(fLeft) || isnan(fRight)
741                || isnan(fTop) || isnan(fBottom);
742    }
743
744    void setCubicBounds(const SkPoint a[4]) {
745        _Rect dRect;
746        MAKE_CONST_CUBIC(cubic, a);
747        dRect.setBounds(cubic);
748        set((float) dRect.left, (float) dRect.top, (float) dRect.right,
749                (float) dRect.bottom);
750    }
751
752    void setQuadBounds(const SkPoint a[3]) {
753        MAKE_CONST_QUAD(quad, a);
754        _Rect dRect;
755        dRect.setBounds(quad);
756        set((float) dRect.left, (float) dRect.top, (float) dRect.right,
757                (float) dRect.bottom);
758    }
759};
760
761static bool useInnerWinding(int outerWinding, int innerWinding) {
762    SkASSERT(outerWinding != innerWinding);
763    int absOut = abs(outerWinding);
764    int absIn = abs(innerWinding);
765    bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
766    if (outerWinding * innerWinding < 0) {
767#if DEBUG_WINDING
768        SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
769                outerWinding, innerWinding, result ? "true" : "false");
770#endif
771    }
772    return result;
773}
774
775static const bool opLookup[][2][2] = {
776    //     ==0             !=0
777    //  b      a        b      a
778    {{true , false}, {false, true }}, // a - b
779    {{false, false}, {true , true }}, // a & b
780    {{true , true }, {false, false}}, // a | b
781    {{true , true }, {true , true }}, // a ^ b
782};
783
784static bool activeOp(bool angleIsOp, int otherNonZero, ShapeOp op) {
785    return opLookup[op][otherNonZero][angleIsOp];
786}
787
788class Segment {
789public:
790    Segment() {
791#if DEBUG_DUMP
792        fID = ++gSegmentID;
793#endif
794    }
795
796    bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) const {
797        if (activeAngleInner(index, done, angles)) {
798            return true;
799        }
800        double referenceT = fTs[index].fT;
801        int lesser = index;
802        while (--lesser >= 0 && approximately_negative(referenceT - fTs[lesser].fT)) {
803            if (activeAngleOther(lesser, done, angles)) {
804                return true;
805            }
806        }
807        do {
808            if (activeAngleOther(index, done, angles)) {
809                return true;
810            }
811        } while (++index < fTs.count() && approximately_negative(fTs[index].fT - referenceT));
812        return false;
813    }
814
815    bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) const {
816        Span* span = &fTs[index];
817        Segment* other = span->fOther;
818        int oIndex = span->fOtherIndex;
819        return other->activeAngleInner(oIndex, done, angles);
820    }
821
822    bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) const {
823        int next = nextSpan(index, 1);
824        if (next > 0) {
825            const Span& upSpan = fTs[index];
826            if (upSpan.fWindValue) {
827                addAngle(angles, index, next);
828                if (upSpan.fDone) {
829                    done++;
830                } else if (upSpan.fWindSum != SK_MinS32) {
831                    return true;
832                }
833            }
834        }
835        int prev = nextSpan(index, -1);
836        // edge leading into junction
837        if (prev >= 0) {
838            const Span& downSpan = fTs[prev];
839            if (downSpan.fWindValue) {
840                addAngle(angles, index, prev);
841                if (downSpan.fDone) {
842                    done++;
843                 } else if (downSpan.fWindSum != SK_MinS32) {
844                    return true;
845                }
846            }
847        }
848        return false;
849    }
850
851    SkScalar activeTop() const {
852        SkASSERT(!done());
853        int count = fTs.count();
854        SkScalar result = SK_ScalarMax;
855        bool lastDone = true;
856        for (int index = 0; index < count; ++index) {
857            bool done = fTs[index].fDone;
858            if (!done || !lastDone) {
859                SkScalar y = yAtT(index);
860                if (result > y) {
861                    result = y;
862                }
863            }
864            lastDone = done;
865        }
866        SkASSERT(result < SK_ScalarMax);
867        return result;
868    }
869
870    void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
871        SkASSERT(start != end);
872        Angle* angle = angles.append();
873#if DEBUG_ANGLE
874        if (angles.count() > 1) {
875            SkPoint angle0Pt, newPt;
876            (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
877                    (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
878            (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
879            SkASSERT(approximately_equal(angle0Pt.fX, newPt.fX));
880            SkASSERT(approximately_equal(angle0Pt.fY, newPt.fY));
881        }
882#endif
883        angle->set(fPts, fVerb, this, start, end, fTs);
884    }
885
886    void addCancelOutsides(double tStart, double oStart, Segment& other,
887            double oEnd) {
888        int tIndex = -1;
889        int tCount = fTs.count();
890        int oIndex = -1;
891        int oCount = other.fTs.count();
892        do {
893            ++tIndex;
894        } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
895        int tIndexStart = tIndex;
896        do {
897            ++oIndex;
898        } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
899        int oIndexStart = oIndex;
900        double nextT;
901        do {
902            nextT = fTs[++tIndex].fT;
903        } while (nextT < 1 && approximately_negative(nextT - tStart));
904        double oNextT;
905        do {
906            oNextT = other.fTs[++oIndex].fT;
907        } while (oNextT < 1 && approximately_negative(oNextT - oStart));
908        // at this point, spans before and after are at:
909        //  fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
910        // if tIndexStart == 0, no prior span
911        // if nextT == 1, no following span
912
913        // advance the span with zero winding
914        // if the following span exists (not past the end, non-zero winding)
915        // connect the two edges
916        if (!fTs[tIndexStart].fWindValue) {
917            if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
918    #if DEBUG_CONCIDENT
919                SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
920                        __FUNCTION__, fID, other.fID, tIndexStart - 1,
921                        fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
922                        xyAtT(tIndexStart).fY);
923    #endif
924                addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false);
925            }
926            if (nextT < 1 && fTs[tIndex].fWindValue) {
927    #if DEBUG_CONCIDENT
928                SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
929                        __FUNCTION__, fID, other.fID, tIndex,
930                        fTs[tIndex].fT, xyAtT(tIndex).fX,
931                        xyAtT(tIndex).fY);
932    #endif
933                addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false);
934            }
935        } else {
936            SkASSERT(!other.fTs[oIndexStart].fWindValue);
937            if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
938    #if DEBUG_CONCIDENT
939                SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
940                        __FUNCTION__, fID, other.fID, oIndexStart - 1,
941                        other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
942                        other.xyAtT(oIndexStart).fY);
943                other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
944    #endif
945            }
946            if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
947    #if DEBUG_CONCIDENT
948                SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
949                        __FUNCTION__, fID, other.fID, oIndex,
950                        other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
951                        other.xyAtT(oIndex).fY);
952                other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
953    #endif
954            }
955        }
956    }
957
958    void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
959            double oEnd) {
960        // walk this to outsideTs[0]
961        // walk other to outsideTs[1]
962        // if either is > 0, add a pointer to the other, copying adjacent winding
963        int tIndex = -1;
964        int oIndex = -1;
965        double tStart = outsideTs[0];
966        double oStart = outsideTs[1];
967        do {
968            ++tIndex;
969        } while (!approximately_negative(tStart - fTs[tIndex].fT));
970        do {
971            ++oIndex;
972        } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
973        if (tIndex > 0 || oIndex > 0) {
974            addTPair(tStart, other, oStart, false);
975        }
976        tStart = fTs[tIndex].fT;
977        oStart = other.fTs[oIndex].fT;
978        do {
979            double nextT;
980            do {
981                nextT = fTs[++tIndex].fT;
982            } while (approximately_negative(nextT - tStart));
983            tStart = nextT;
984            do {
985                nextT = other.fTs[++oIndex].fT;
986            } while (approximately_negative(nextT - oStart));
987            oStart = nextT;
988            if (tStart == 1 && oStart == 1) {
989                break;
990            }
991            addTPair(tStart, other, oStart, false);
992        } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
993    }
994
995    void addCubic(const SkPoint pts[4], bool operand) {
996        init(pts, SkPath::kCubic_Verb, operand);
997        fBounds.setCubicBounds(pts);
998    }
999
1000    // FIXME: this needs to defer add for aligned consecutive line segments
1001    SkPoint addCurveTo(int start, int end, SkPath& path, bool active) {
1002        SkPoint edge[4];
1003        // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
1004        (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
1005        if (active) {
1006    #if DEBUG_PATH_CONSTRUCTION
1007            SkDebugf("path.%sTo(%1.9g,%1.9g",
1008                    kLVerbStr[fVerb], edge[1].fX, edge[1].fY);
1009            if (fVerb > 1) {
1010                SkDebugf(", %1.9g,%1.9g", edge[2].fX, edge[2].fY);
1011            }
1012            if (fVerb > 2) {
1013                SkDebugf(", %1.9g,%1.9g", edge[3].fX, edge[3].fY);
1014            }
1015            SkDebugf(");\n");
1016    #endif
1017            switch (fVerb) {
1018                case SkPath::kLine_Verb:
1019                    path.lineTo(edge[1].fX, edge[1].fY);
1020                    break;
1021                case SkPath::kQuad_Verb:
1022                    path.quadTo(edge[1].fX, edge[1].fY, edge[2].fX, edge[2].fY);
1023                    break;
1024                case SkPath::kCubic_Verb:
1025                    path.cubicTo(edge[1].fX, edge[1].fY, edge[2].fX, edge[2].fY,
1026                            edge[3].fX, edge[3].fY);
1027                    break;
1028                default:
1029                    SkASSERT(0);
1030            }
1031        }
1032        return edge[fVerb];
1033    }
1034
1035    void addLine(const SkPoint pts[2], bool operand) {
1036        init(pts, SkPath::kLine_Verb, operand);
1037        fBounds.set(pts, 2);
1038    }
1039
1040    const SkPoint& addMoveTo(int tIndex, SkPath& path, bool active) {
1041        const SkPoint& pt = xyAtT(tIndex);
1042        if (active) {
1043    #if DEBUG_PATH_CONSTRUCTION
1044            SkDebugf("path.moveTo(%1.9g, %1.9g);\n", pt.fX, pt.fY);
1045    #endif
1046            path.moveTo(pt.fX, pt.fY);
1047        }
1048        return pt;
1049    }
1050
1051    // add 2 to edge or out of range values to get T extremes
1052    void addOtherT(int index, double otherT, int otherIndex) {
1053        Span& span = fTs[index];
1054        span.fOtherT = otherT;
1055        span.fOtherIndex = otherIndex;
1056    }
1057
1058    void addQuad(const SkPoint pts[3], bool operand) {
1059        init(pts, SkPath::kQuad_Verb, operand);
1060        fBounds.setQuadBounds(pts);
1061    }
1062
1063    // Defer all coincident edge processing until
1064    // after normal intersections have been computed
1065
1066// no need to be tricky; insert in normal T order
1067// resolve overlapping ts when considering coincidence later
1068
1069    // add non-coincident intersection. Resulting edges are sorted in T.
1070    int addT(double newT, Segment* other) {
1071        // FIXME: in the pathological case where there is a ton of intercepts,
1072        //  binary search?
1073        int insertedAt = -1;
1074        size_t tCount = fTs.count();
1075        // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
1076        if (approximately_less_than_zero(newT)) {
1077            newT = 0;
1078        }
1079        if (approximately_greater_than_one(newT)) {
1080            newT = 1;
1081        }
1082        for (size_t index = 0; index < tCount; ++index) {
1083            // OPTIMIZATION: if there are three or more identical Ts, then
1084            // the fourth and following could be further insertion-sorted so
1085            // that all the edges are clockwise or counterclockwise.
1086            // This could later limit segment tests to the two adjacent
1087            // neighbors, although it doesn't help with determining which
1088            // circular direction to go in.
1089            if (newT < fTs[index].fT) {
1090                insertedAt = index;
1091                break;
1092            }
1093        }
1094        Span* span;
1095        if (insertedAt >= 0) {
1096            span = fTs.insert(insertedAt);
1097        } else {
1098            insertedAt = tCount;
1099            span = fTs.append();
1100        }
1101        span->fT = newT;
1102        span->fOther = other;
1103        span->fPt.fX = SK_ScalarNaN;
1104        span->fWindSum = SK_MinS32;
1105        span->fWindValue = 1;
1106        span->fWindValueOpp = 0;
1107        if ((span->fDone = newT == 1)) {
1108            ++fDoneSpans;
1109        }
1110        return insertedAt;
1111    }
1112
1113    // set spans from start to end to decrement by one
1114    // note this walks other backwards
1115    // FIMXE: there's probably an edge case that can be constructed where
1116    // two span in one segment are separated by float epsilon on one span but
1117    // not the other, if one segment is very small. For this
1118    // case the counts asserted below may or may not be enough to separate the
1119    // spans. Even if the counts work out, what if the spans aren't correctly
1120    // sorted? It feels better in such a case to match the span's other span
1121    // pointer since both coincident segments must contain the same spans.
1122    void addTCancel(double startT, double endT, Segment& other,
1123            double oStartT, double oEndT) {
1124        SkASSERT(!approximately_negative(endT - startT));
1125        SkASSERT(!approximately_negative(oEndT - oStartT));
1126        bool binary = fOperand != other.fOperand;
1127        int index = 0;
1128        while (!approximately_negative(startT - fTs[index].fT)) {
1129            ++index;
1130        }
1131        int oIndex = other.fTs.count();
1132        while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
1133            ;
1134        double tRatio = (oEndT - oStartT) / (endT - startT);
1135        Span* test = &fTs[index];
1136        Span* oTest = &other.fTs[oIndex];
1137        SkTDArray<double> outsideTs;
1138        SkTDArray<double> oOutsideTs;
1139        do {
1140            bool decrement = test->fWindValue && oTest->fWindValue;
1141            bool track = test->fWindValue || oTest->fWindValue;
1142            double testT = test->fT;
1143            double oTestT = oTest->fT;
1144            Span* span = test;
1145            do {
1146                if (decrement) {
1147                    if (binary) {
1148                        --(span->fWindValueOpp);
1149                    } else {
1150                        decrementSpan(span);
1151                    }
1152                } else if (track && span->fT < 1 && oTestT < 1) {
1153                    TrackOutside(outsideTs, span->fT, oTestT);
1154                }
1155                span = &fTs[++index];
1156            } while (approximately_negative(span->fT - testT));
1157            Span* oSpan = oTest;
1158            double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1159            double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1160            SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
1161            while (approximately_negative(otherTMatchStart - oSpan->fT)
1162                    && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
1163        #ifdef SK_DEBUG
1164                SkASSERT(originalWindValue == oSpan->fWindValue);
1165        #endif
1166                if (decrement) {
1167                    other.decrementSpan(oSpan);
1168                } else if (track && oSpan->fT < 1 && testT < 1) {
1169                    TrackOutside(oOutsideTs, oSpan->fT, testT);
1170                }
1171                if (!oIndex) {
1172                    break;
1173                }
1174                oSpan = &other.fTs[--oIndex];
1175            }
1176            test = span;
1177            oTest = oSpan;
1178        } while (!approximately_negative(endT - test->fT));
1179        SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
1180        // FIXME: determine if canceled edges need outside ts added
1181        if (!done() && outsideTs.count()) {
1182            double tStart = outsideTs[0];
1183            double oStart = outsideTs[1];
1184            addCancelOutsides(tStart, oStart, other, oEndT);
1185            int count = outsideTs.count();
1186            if (count > 2) {
1187                double tStart = outsideTs[count - 2];
1188                double oStart = outsideTs[count - 1];
1189                addCancelOutsides(tStart, oStart, other, oEndT);
1190            }
1191        }
1192        if (!other.done() && oOutsideTs.count()) {
1193            double tStart = oOutsideTs[0];
1194            double oStart = oOutsideTs[1];
1195            other.addCancelOutsides(tStart, oStart, *this, endT);
1196        }
1197    }
1198
1199    // set spans from start to end to increment the greater by one and decrement
1200    // the lesser
1201    void addTCoincident(const bool isXor, double startT, double endT,
1202            Segment& other, double oStartT, double oEndT) {
1203        SkASSERT(!approximately_negative(endT - startT));
1204        SkASSERT(!approximately_negative(oEndT - oStartT));
1205        bool binary = fOperand != other.fOperand;
1206        int index = 0;
1207        while (!approximately_negative(startT - fTs[index].fT)) {
1208            ++index;
1209        }
1210        int oIndex = 0;
1211        while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
1212            ++oIndex;
1213        }
1214        double tRatio = (oEndT - oStartT) / (endT - startT);
1215        Span* test = &fTs[index];
1216        Span* oTest = &other.fTs[oIndex];
1217        SkTDArray<double> outsideTs;
1218        SkTDArray<double> xOutsideTs;
1219        SkTDArray<double> oOutsideTs;
1220        SkTDArray<double> oxOutsideTs;
1221        do {
1222            bool transfer = test->fWindValue && oTest->fWindValue;
1223            bool decrementThis = (test->fWindValue < oTest->fWindValue) & !isXor;
1224            bool decrementOther = (test->fWindValue >= oTest->fWindValue) & !isXor;
1225            Span* end = test;
1226            double startT = end->fT;
1227            int startIndex = index;
1228            double oStartT = oTest->fT;
1229            int oStartIndex = oIndex;
1230            do {
1231                if (transfer) {
1232                    if (decrementOther) {
1233                #ifdef SK_DEBUG
1234                        SkASSERT(abs(end->fWindValue) < gDebugMaxWindValue);
1235                #endif
1236                        if (binary) {
1237                            ++(end->fWindValueOpp);
1238                        } else {
1239                            ++(end->fWindValue);
1240                        }
1241                    } else if (decrementSpan(end)) {
1242                        TrackOutside(outsideTs, end->fT, oStartT);
1243                    }
1244                } else if (oTest->fWindValue) {
1245                    SkASSERT(!decrementOther);
1246                    if (startIndex > 0 && fTs[startIndex - 1].fWindValue) {
1247                        TrackOutside(xOutsideTs, end->fT, oStartT);
1248                    }
1249                }
1250                end = &fTs[++index];
1251            } while (approximately_negative(end->fT - test->fT));
1252        // because of the order in which coincidences are resolved, this and other
1253        // may not have the same intermediate points. Compute the corresponding
1254        // intermediate T values (using this as the master, other as the follower)
1255        // and walk other conditionally -- hoping that it catches up in the end
1256            double otherTMatch = (test->fT - startT) * tRatio + oStartT;
1257            Span* oEnd = oTest;
1258            while (!approximately_negative(oEndT - oEnd->fT) && approximately_negative(oEnd->fT - otherTMatch)) {
1259                if (transfer) {
1260                    if (decrementThis) {
1261                 #ifdef SK_DEBUG
1262                       SkASSERT(abs(oEnd->fWindValue) < gDebugMaxWindValue);
1263                #endif
1264                        if (binary) {
1265                            ++(oEnd->fWindValueOpp);
1266                        } else {
1267                            ++(oEnd->fWindValue);
1268                        }
1269                    } else if (other.decrementSpan(oEnd)) {
1270                        TrackOutside(oOutsideTs, oEnd->fT, startT);
1271                    }
1272                } else if (test->fWindValue) {
1273                    SkASSERT(!decrementOther);
1274                    if (oStartIndex > 0 && other.fTs[oStartIndex - 1].fWindValue) {
1275                        SkASSERT(0); // track for later?
1276                    }
1277                }
1278                oEnd = &other.fTs[++oIndex];
1279            }
1280            test = end;
1281            oTest = oEnd;
1282        } while (!approximately_negative(endT - test->fT));
1283        SkASSERT(approximately_negative(oTest->fT - oEndT));
1284        SkASSERT(approximately_negative(oEndT - oTest->fT));
1285        if (!done()) {
1286            if (outsideTs.count()) {
1287                addCoinOutsides(outsideTs, other, oEndT);
1288            }
1289            if (xOutsideTs.count()) {
1290                addCoinOutsides(xOutsideTs, other, oEndT);
1291            }
1292        }
1293        if (!other.done() && oOutsideTs.count()) {
1294            other.addCoinOutsides(oOutsideTs, *this, endT);
1295        }
1296    }
1297
1298    // FIXME: this doesn't prevent the same span from being added twice
1299    // fix in caller, assert here?
1300    void addTPair(double t, Segment& other, double otherT, bool borrowWind) {
1301        int tCount = fTs.count();
1302        for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1303            const Span& span = fTs[tIndex];
1304            if (!approximately_negative(span.fT - t)) {
1305                break;
1306            }
1307            if (approximately_negative(span.fT - t) && span.fOther == &other
1308                    && approximately_equal(span.fOtherT, otherT)) {
1309#if DEBUG_ADD_T_PAIR
1310                SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1311                        __FUNCTION__, fID, t, other.fID, otherT);
1312#endif
1313                return;
1314            }
1315        }
1316#if DEBUG_ADD_T_PAIR
1317        SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1318                __FUNCTION__, fID, t, other.fID, otherT);
1319#endif
1320        int insertedAt = addT(t, &other);
1321        int otherInsertedAt = other.addT(otherT, this);
1322        addOtherT(insertedAt, otherT, otherInsertedAt);
1323        other.addOtherT(otherInsertedAt, t, insertedAt);
1324        matchWindingValue(insertedAt, t, borrowWind);
1325        other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
1326    }
1327
1328    void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
1329        // add edge leading into junction
1330        if (fTs[SkMin32(end, start)].fWindValue > 0) {
1331            addAngle(angles, end, start);
1332        }
1333        // add edge leading away from junction
1334        int step = SkSign32(end - start);
1335        int tIndex = nextSpan(end, step);
1336        if (tIndex >= 0 && fTs[SkMin32(end, tIndex)].fWindValue > 0) {
1337            addAngle(angles, end, tIndex);
1338        }
1339    }
1340
1341    const Bounds& bounds() const {
1342        return fBounds;
1343    }
1344
1345    void buildAngles(int index, SkTDArray<Angle>& angles) const {
1346        double referenceT = fTs[index].fT;
1347        int lesser = index;
1348        while (--lesser >= 0 && approximately_negative(referenceT - fTs[lesser].fT)) {
1349            buildAnglesInner(lesser, angles);
1350        }
1351        do {
1352            buildAnglesInner(index, angles);
1353        } while (++index < fTs.count() && approximately_negative(fTs[index].fT - referenceT));
1354    }
1355
1356    void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
1357        Span* span = &fTs[index];
1358        Segment* other = span->fOther;
1359    // if there is only one live crossing, and no coincidence, continue
1360    // in the same direction
1361    // if there is coincidence, the only choice may be to reverse direction
1362        // find edge on either side of intersection
1363        int oIndex = span->fOtherIndex;
1364        // if done == -1, prior span has already been processed
1365        int step = 1;
1366        int next = other->nextSpan(oIndex, step);
1367        if (next < 0) {
1368            step = -step;
1369            next = other->nextSpan(oIndex, step);
1370        }
1371        // add candidate into and away from junction
1372        other->addTwoAngles(next, oIndex, angles);
1373    }
1374
1375    // figure out if the segment's ascending T goes clockwise or not
1376    // not enough context to write this as shown
1377    // instead, add all segments meeting at the top
1378    // sort them using buildAngleList
1379    // find the first in the sort
1380    // see if ascendingT goes to top
1381    bool clockwise(int /* tIndex */) const {
1382        SkASSERT(0); // incomplete
1383        return false;
1384    }
1385
1386    // FIXME may not need this at all
1387    // FIXME once I figure out the logic, merge this and too close to call
1388    // NOTE not sure if tiny triangles can ever form at the edge, so until we
1389    // see one, only worry about triangles that happen away from 0 and 1
1390    void collapseTriangles(bool isXor) {
1391        if (fTs.count() < 3) { // require t=0, x, 1 at minimum
1392            return;
1393        }
1394        int lastIndex = 1;
1395        double lastT;
1396        while (approximately_less_than_zero((lastT = fTs[lastIndex].fT))) {
1397            ++lastIndex;
1398        }
1399        if (approximately_greater_than_one(lastT)) {
1400            return;
1401        }
1402        int matchIndex = lastIndex;
1403        do {
1404            Span& match = fTs[++matchIndex];
1405            double matchT = match.fT;
1406            if (approximately_greater_than_one(matchT)) {
1407                return;
1408            }
1409            if (matchT == lastT) {
1410                goto nextSpan;
1411            }
1412            if (approximately_negative(matchT - lastT)) {
1413                Span& last = fTs[lastIndex];
1414                Segment* lOther = last.fOther;
1415                double lT = last.fOtherT;
1416                if (approximately_less_than_zero(lT) || approximately_greater_than_one(lT)) {
1417                    goto nextSpan;
1418                }
1419                Segment* mOther = match.fOther;
1420                double mT = match.fOtherT;
1421                if (approximately_less_than_zero(mT) || approximately_greater_than_one(mT)) {
1422                    goto nextSpan;
1423                }
1424                // add new point to connect adjacent spurs
1425                int count = lOther->fTs.count();
1426                for (int index = 0; index < count; ++index) {
1427                    Span& span = lOther->fTs[index];
1428                    if (span.fOther == mOther && approximately_zero(span.fOtherT - mT)) {
1429                        goto nextSpan;
1430                    }
1431                }
1432                mOther->addTPair(mT, *lOther, lT, false);
1433                // FIXME ? this could go on to detect that spans on mOther, lOther are now coincident
1434            }
1435    nextSpan:
1436            lastIndex = matchIndex;
1437            lastT = matchT;
1438        } while (true);
1439    }
1440
1441    int computeSum(int startIndex, int endIndex) {
1442        SkTDArray<Angle> angles;
1443        addTwoAngles(startIndex, endIndex, angles);
1444        buildAngles(endIndex, angles);
1445        // OPTIMIZATION: check all angles to see if any have computed wind sum
1446        // before sorting (early exit if none)
1447        SkTDArray<Angle*> sorted;
1448        sortAngles(angles, sorted);
1449#if DEBUG_SORT
1450        sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0);
1451#endif
1452        int angleCount = angles.count();
1453        const Angle* angle;
1454        const Segment* base;
1455        int winding;
1456        int firstIndex = 0;
1457        do {
1458            angle = sorted[firstIndex];
1459            base = angle->segment();
1460            winding = base->windSum(angle);
1461            if (winding != SK_MinS32) {
1462                break;
1463            }
1464            if (++firstIndex == angleCount) {
1465                return SK_MinS32;
1466            }
1467        } while (true);
1468        // turn winding into contourWinding
1469        int spanWinding = base->spanSign(angle);
1470        bool inner = useInnerWinding(winding + spanWinding, winding);
1471    #if DEBUG_WINDING
1472        SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
1473            spanWinding, winding, angle->sign(), inner,
1474            inner ? winding + spanWinding : winding);
1475    #endif
1476        if (inner) {
1477            winding += spanWinding;
1478        }
1479    #if DEBUG_SORT
1480        base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding);
1481    #endif
1482        int nextIndex = firstIndex + 1;
1483        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1484        winding -= base->spanSign(angle);
1485        do {
1486            if (nextIndex == angleCount) {
1487                nextIndex = 0;
1488            }
1489            angle = sorted[nextIndex];
1490            Segment* segment = angle->segment();
1491            int maxWinding = winding;
1492            winding -= segment->spanSign(angle);
1493            if (segment->windSum(angle) == SK_MinS32) {
1494                if (useInnerWinding(maxWinding, winding)) {
1495                    maxWinding = winding;
1496                }
1497                segment->markAndChaseWinding(angle, maxWinding);
1498            }
1499        } while (++nextIndex != lastIndex);
1500        return windSum(SkMin32(startIndex, endIndex));
1501    }
1502
1503    int crossedSpan(const SkPoint& basePt, SkScalar& bestY, double& hitT) const {
1504        int bestT = -1;
1505        SkScalar top = bounds().fTop;
1506        SkScalar bottom = bounds().fBottom;
1507        int end = 0;
1508        do {
1509            int start = end;
1510            end = nextSpan(start, 1);
1511            if (fTs[start].fWindValue == 0) {
1512                continue;
1513            }
1514            SkPoint edge[4];
1515            double startT = fTs[start].fT;
1516            double endT = fTs[end].fT;
1517            (*SegmentSubDivide[fVerb])(fPts, startT, endT, edge);
1518            // intersect ray starting at basePt with edge
1519            Intersections intersections;
1520            // FIXME: always use original and limit results to T values within
1521            // start t and end t.
1522            // OPTIMIZE: use specialty function that intersects ray with curve,
1523            // returning t values only for curve (we don't care about t on ray)
1524            int pts = (*VSegmentIntersect[fVerb])(edge, top, bottom, basePt.fX,
1525                    false, intersections);
1526            if (pts == 0) {
1527                continue;
1528            }
1529            if (pts > 1 && fVerb == SkPath::kLine_Verb) {
1530            // if the intersection is edge on, wait for another one
1531                continue;
1532            }
1533            for (int index = 0; index < pts; ++index) {
1534                SkPoint pt;
1535                double foundT = intersections.fT[0][index];
1536                double testT = startT + (endT - startT) * foundT;
1537                (*SegmentXYAtT[fVerb])(fPts, testT, &pt);
1538                if (bestY < pt.fY && pt.fY < basePt.fY) {
1539                    if (fVerb > SkPath::kLine_Verb
1540                            && !approximately_less_than_zero(foundT)
1541                            && !approximately_greater_than_one(foundT)) {
1542                        SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, testT);
1543                        if (approximately_zero(dx)) {
1544                            continue;
1545                        }
1546                    }
1547                    bestY = pt.fY;
1548                    bestT = foundT < 1 ? start : end;
1549                    hitT = testT;
1550                }
1551            }
1552        } while (fTs[end].fT != 1);
1553        return bestT;
1554    }
1555
1556    bool crossedSpanHalves(const SkPoint& basePt, bool leftHalf, bool rightHalf) {
1557        // if a segment is connected to this one, consider it crossing
1558        int tIndex;
1559        if (fPts[0].fX == basePt.fX) {
1560            tIndex = 0;
1561            do {
1562                const Span& sSpan = fTs[tIndex];
1563                const Segment* sOther = sSpan.fOther;
1564                if (!sOther->fTs[sSpan.fOtherIndex].fWindValue) {
1565                    continue;
1566                }
1567                if (leftHalf ? sOther->fBounds.fLeft < basePt.fX
1568                        : sOther->fBounds.fRight > basePt.fX) {
1569                    return true;
1570                }
1571            } while (fTs[++tIndex].fT == 0);
1572        }
1573        if (fPts[fVerb].fX == basePt.fX) {
1574            tIndex = fTs.count() - 1;
1575            do {
1576                const Span& eSpan = fTs[tIndex];
1577                const Segment* eOther = eSpan.fOther;
1578                if (!eOther->fTs[eSpan.fOtherIndex].fWindValue) {
1579                    continue;
1580                }
1581                if (leftHalf ? eOther->fBounds.fLeft < basePt.fX
1582                        : eOther->fBounds.fRight > basePt.fX) {
1583                    return true;
1584                }
1585            } while (fTs[--tIndex].fT == 1);
1586        }
1587        return false;
1588    }
1589
1590    bool decrementSpan(Span* span) {
1591        SkASSERT(span->fWindValue > 0);
1592        if (--(span->fWindValue) == 0) {
1593            span->fDone = true;
1594            ++fDoneSpans;
1595            return true;
1596        }
1597        return false;
1598    }
1599
1600    bool done() const {
1601        SkASSERT(fDoneSpans <= fTs.count());
1602        return fDoneSpans == fTs.count();
1603    }
1604
1605    bool done(const Angle& angle) const {
1606        int start = angle.start();
1607        int end = angle.end();
1608        const Span& mSpan = fTs[SkMin32(start, end)];
1609        return mSpan.fDone;
1610    }
1611
1612    Segment* findNextOp(SkTDArray<Span*>& chase, bool active,
1613            int& nextStart, int& nextEnd, int& winding, int& spanWinding, ShapeOp op,
1614            const int aXorMask, const int bXorMask) {
1615        const int startIndex = nextStart;
1616        const int endIndex = nextEnd;
1617        int outerWinding = winding;
1618        int innerWinding = winding + spanWinding;
1619    #if DEBUG_WINDING
1620        SkDebugf("%s winding=%d spanWinding=%d outerWinding=%d innerWinding=%d\n",
1621                __FUNCTION__, winding, spanWinding, outerWinding, innerWinding);
1622    #endif
1623        if (useInnerWinding(outerWinding, innerWinding)) {
1624            outerWinding = innerWinding;
1625        }
1626        SkASSERT(startIndex != endIndex);
1627        int count = fTs.count();
1628        SkASSERT(startIndex < endIndex ? startIndex < count - 1
1629                : startIndex > 0);
1630        int step = SkSign32(endIndex - startIndex);
1631        int end = nextSpan(startIndex, step);
1632        SkASSERT(end >= 0);
1633        Span* endSpan = &fTs[end];
1634        Segment* other;
1635        if (isSimple(end)) {
1636        // mark the smaller of startIndex, endIndex done, and all adjacent
1637        // spans with the same T value (but not 'other' spans)
1638    #if DEBUG_WINDING
1639            SkDebugf("%s simple\n", __FUNCTION__);
1640    #endif
1641            markDone(SkMin32(startIndex, endIndex), outerWinding);
1642            other = endSpan->fOther;
1643            nextStart = endSpan->fOtherIndex;
1644            double startT = other->fTs[nextStart].fT;
1645            nextEnd = nextStart;
1646            do {
1647                nextEnd += step;
1648            } while (approximately_zero(startT - other->fTs[nextEnd].fT));
1649            SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
1650            return other;
1651        }
1652        // more than one viable candidate -- measure angles to find best
1653        SkTDArray<Angle> angles;
1654        SkASSERT(startIndex - endIndex != 0);
1655        SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
1656        addTwoAngles(startIndex, end, angles);
1657        buildAngles(end, angles);
1658        SkTDArray<Angle*> sorted;
1659        sortAngles(angles, sorted);
1660        int angleCount = angles.count();
1661        int firstIndex = findStartingEdge(sorted, startIndex, end);
1662        SkASSERT(firstIndex >= 0);
1663    #if DEBUG_SORT
1664        debugShowSort(__FUNCTION__, sorted, firstIndex, winding);
1665    #endif
1666        SkASSERT(sorted[firstIndex]->segment() == this);
1667    #if DEBUG_WINDING
1668        SkDebugf("%s [%d] sign=%d\n", __FUNCTION__, firstIndex, sorted[firstIndex]->sign());
1669    #endif
1670        int aSumWinding = winding;
1671        int bSumWinding = winding;
1672        bool angleIsOp = sorted[firstIndex]->segment()->operand();
1673        int angleSpan = spanSign(sorted[firstIndex]);
1674        if (angleIsOp) {
1675            bSumWinding -= angleSpan;
1676        } else {
1677            aSumWinding -= angleSpan;
1678        }
1679        int nextIndex = firstIndex + 1;
1680        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1681        const Angle* foundAngle = NULL;
1682        // FIXME: found done logic probably fails if there are more than 4
1683        // sorted angles. It should bias towards the first and last undone
1684        // edges -- but not sure that it won't choose a middle (incorrect)
1685        // edge if one is undone
1686        bool foundDone = false;
1687        bool foundDone2 = false;
1688        // iterate through the angle, and compute everyone's winding
1689        bool altFlipped = false;
1690        bool foundFlipped = false;
1691        int foundMax = SK_MinS32;
1692        int foundSum = SK_MinS32;
1693        Segment* nextSegment;
1694        int lastNonZeroSum = winding;
1695        do {
1696            if (nextIndex == angleCount) {
1697                nextIndex = 0;
1698            }
1699            const Angle* nextAngle = sorted[nextIndex];
1700            nextSegment = nextAngle->segment();
1701            angleIsOp = nextSegment->operand();
1702            int sumWinding = angleIsOp ? bSumWinding : aSumWinding;
1703            int maxWinding = sumWinding;
1704            if (sumWinding) {
1705                lastNonZeroSum = sumWinding;
1706            }
1707            sumWinding -= nextSegment->spanSign(nextAngle);
1708            int xorMask = nextSegment->operand() ? bXorMask : aXorMask;
1709            bool otherNonZero;
1710            if (angleIsOp) {
1711                bSumWinding = sumWinding;
1712                otherNonZero = aSumWinding & aXorMask;
1713            } else {
1714                aSumWinding = sumWinding;
1715                otherNonZero = bSumWinding & bXorMask;
1716            }
1717            altFlipped ^= lastNonZeroSum * sumWinding < 0; // flip if different signs
1718    #if 0 &&  DEBUG_WINDING
1719            SkASSERT(abs(sumWinding) <= gDebugMaxWindSum);
1720            SkDebugf("%s [%d] maxWinding=%d sumWinding=%d sign=%d altFlipped=%d\n", __FUNCTION__,
1721                    nextIndex, maxWinding, sumWinding, nextAngle->sign(), altFlipped);
1722    #endif
1723
1724            if (!(sumWinding & xorMask) && activeOp(angleIsOp, otherNonZero, op)) {
1725                if (!active) {
1726                    markDone(SkMin32(startIndex, endIndex), outerWinding);
1727                    // FIXME: seems like a bug that this isn't calling userInnerWinding
1728                    nextSegment->markWinding(SkMin32(nextAngle->start(),
1729                                nextAngle->end()), maxWinding);
1730    #if DEBUG_WINDING
1731                    SkDebugf("%s [%d] inactive\n", __FUNCTION__, nextIndex);
1732    #endif
1733                    return NULL;
1734                }
1735                if (!foundAngle || foundDone) {
1736                    foundAngle = nextAngle;
1737                    foundDone = nextSegment->done(*nextAngle);
1738                    foundFlipped = altFlipped;
1739                    foundMax = maxWinding;
1740                }
1741                continue;
1742            }
1743            if (!(maxWinding & xorMask) && (!foundAngle || foundDone2)
1744                    && activeOp(angleIsOp, otherNonZero, op)) {
1745        #if DEBUG_WINDING
1746                if (foundAngle && foundDone2) {
1747                    SkDebugf("%s [%d] !foundAngle && foundDone2\n", __FUNCTION__, nextIndex);
1748                }
1749        #endif
1750                foundAngle = nextAngle;
1751                foundDone2 = nextSegment->done(*nextAngle);
1752                foundFlipped = altFlipped;
1753                foundSum = sumWinding;
1754            }
1755            if (nextSegment->done()) {
1756                continue;
1757            }
1758            // if the winding is non-zero, nextAngle does not connect to
1759            // current chain. If we haven't done so already, mark the angle
1760            // as done, record the winding value, and mark connected unambiguous
1761            // segments as well.
1762            if (nextSegment->windSum(nextAngle) == SK_MinS32) {
1763                if (useInnerWinding(maxWinding, sumWinding)) {
1764                    maxWinding = sumWinding;
1765                }
1766                Span* last;
1767                if (foundAngle) {
1768                    last = nextSegment->markAndChaseWinding(nextAngle, maxWinding);
1769                } else {
1770                    last = nextSegment->markAndChaseDone(nextAngle, maxWinding);
1771                }
1772                if (last) {
1773                    *chase.append() = last;
1774                }
1775            }
1776        } while (++nextIndex != lastIndex);
1777        markDone(SkMin32(startIndex, endIndex), outerWinding);
1778        if (!foundAngle) {
1779            return NULL;
1780        }
1781        nextStart = foundAngle->start();
1782        nextEnd = foundAngle->end();
1783        nextSegment = foundAngle->segment();
1784        int flipped = foundFlipped ? -1 : 1;
1785        spanWinding = SkSign32(spanWinding) * flipped * nextSegment->windValue(
1786                SkMin32(nextStart, nextEnd));
1787        if (winding) {
1788    #if DEBUG_WINDING
1789            SkDebugf("%s ---6 winding=%d foundSum=", __FUNCTION__, winding);
1790            if (foundSum == SK_MinS32) {
1791                SkDebugf("?");
1792            } else {
1793                SkDebugf("%d", foundSum);
1794            }
1795            SkDebugf(" foundMax=");
1796            if (foundMax == SK_MinS32) {
1797                SkDebugf("?");
1798            } else {
1799                SkDebugf("%d", foundMax);
1800            }
1801            SkDebugf("\n");
1802     #endif
1803            winding = foundSum;
1804        }
1805    #if DEBUG_WINDING
1806        SkDebugf("%s spanWinding=%d flipped=%d\n", __FUNCTION__, spanWinding, flipped);
1807    #endif
1808        return nextSegment;
1809    }
1810
1811    // so the span needs to contain the pairing info found here
1812    // this should include the winding computed for the edge, and
1813    //  what edge it connects to, and whether it is discarded
1814    //  (maybe discarded == abs(winding) > 1) ?
1815    // only need derivatives for duration of sorting, add a new struct
1816    // for pairings, remove extra spans that have zero length and
1817    //  reference an unused other
1818    // for coincident, the last span on the other may be marked done
1819    //  (always?)
1820
1821    // if loop is exhausted, contour may be closed.
1822    // FIXME: pass in close point so we can check for closure
1823
1824    // given a segment, and a sense of where 'inside' is, return the next
1825    // segment. If this segment has an intersection, or ends in multiple
1826    // segments, find the mate that continues the outside.
1827    // note that if there are multiples, but no coincidence, we can limit
1828    // choices to connections in the correct direction
1829
1830    // mark found segments as done
1831
1832    // start is the index of the beginning T of this edge
1833    // it is guaranteed to have an end which describes a non-zero length (?)
1834    // winding -1 means ccw, 1 means cw
1835    Segment* findNextWinding(SkTDArray<Span*>& chase, bool active,
1836            int& nextStart, int& nextEnd, int& winding, int& spanWinding) {
1837        const int startIndex = nextStart;
1838        const int endIndex = nextEnd;
1839        int outerWinding = winding;
1840        int innerWinding = winding + spanWinding;
1841    #if DEBUG_WINDING
1842        SkDebugf("%s winding=%d spanWinding=%d outerWinding=%d innerWinding=%d\n",
1843                __FUNCTION__, winding, spanWinding, outerWinding, innerWinding);
1844    #endif
1845        if (useInnerWinding(outerWinding, innerWinding)) {
1846            outerWinding = innerWinding;
1847        }
1848        SkASSERT(startIndex != endIndex);
1849        int count = fTs.count();
1850        SkASSERT(startIndex < endIndex ? startIndex < count - 1
1851                : startIndex > 0);
1852        int step = SkSign32(endIndex - startIndex);
1853        int end = nextSpan(startIndex, step);
1854        SkASSERT(end >= 0);
1855        Span* endSpan = &fTs[end];
1856        Segment* other;
1857        if (isSimple(end)) {
1858        // mark the smaller of startIndex, endIndex done, and all adjacent
1859        // spans with the same T value (but not 'other' spans)
1860    #if DEBUG_WINDING
1861            SkDebugf("%s simple\n", __FUNCTION__);
1862    #endif
1863            markDone(SkMin32(startIndex, endIndex), outerWinding);
1864            other = endSpan->fOther;
1865            nextStart = endSpan->fOtherIndex;
1866            double startT = other->fTs[nextStart].fT;
1867            nextEnd = nextStart;
1868            do {
1869                nextEnd += step;
1870            } while (approximately_zero(startT - other->fTs[nextEnd].fT));
1871            SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
1872            return other;
1873        }
1874        // more than one viable candidate -- measure angles to find best
1875        SkTDArray<Angle> angles;
1876        SkASSERT(startIndex - endIndex != 0);
1877        SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
1878        addTwoAngles(startIndex, end, angles);
1879        buildAngles(end, angles);
1880        SkTDArray<Angle*> sorted;
1881        sortAngles(angles, sorted);
1882        int angleCount = angles.count();
1883        int firstIndex = findStartingEdge(sorted, startIndex, end);
1884        SkASSERT(firstIndex >= 0);
1885    #if DEBUG_SORT
1886        debugShowSort(__FUNCTION__, sorted, firstIndex, winding);
1887    #endif
1888        SkASSERT(sorted[firstIndex]->segment() == this);
1889    #if DEBUG_WINDING
1890        SkDebugf("%s [%d] sign=%d\n", __FUNCTION__, firstIndex, sorted[firstIndex]->sign());
1891    #endif
1892        int sumWinding = winding - spanSign(sorted[firstIndex]);
1893        int nextIndex = firstIndex + 1;
1894        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1895        const Angle* foundAngle = NULL;
1896        // FIXME: found done logic probably fails if there are more than 4
1897        // sorted angles. It should bias towards the first and last undone
1898        // edges -- but not sure that it won't choose a middle (incorrect)
1899        // edge if one is undone
1900        bool foundDone = false;
1901        bool foundDone2 = false;
1902        // iterate through the angle, and compute everyone's winding
1903        bool altFlipped = false;
1904        bool foundFlipped = false;
1905        int foundMax = SK_MinS32;
1906        int foundSum = SK_MinS32;
1907        Segment* nextSegment;
1908        int lastNonZeroSum = winding;
1909        do {
1910            if (nextIndex == angleCount) {
1911                nextIndex = 0;
1912            }
1913            const Angle* nextAngle = sorted[nextIndex];
1914            int maxWinding = sumWinding;
1915            if (sumWinding) {
1916                lastNonZeroSum = sumWinding;
1917            }
1918            nextSegment = nextAngle->segment();
1919            sumWinding -= nextSegment->spanSign(nextAngle);
1920            altFlipped ^= lastNonZeroSum * sumWinding < 0; // flip if different signs
1921    #if 0 && DEBUG_WINDING
1922            SkASSERT(abs(sumWinding) <= gDebugMaxWindSum);
1923            SkDebugf("%s [%d] maxWinding=%d sumWinding=%d sign=%d altFlipped=%d\n", __FUNCTION__,
1924                    nextIndex, maxWinding, sumWinding, nextAngle->sign(), altFlipped);
1925    #endif
1926           if (!sumWinding) {
1927                if (!active) {
1928                    markDone(SkMin32(startIndex, endIndex), outerWinding);
1929                    // FIXME: seems like a bug that this isn't calling userInnerWinding
1930                    nextSegment->markWinding(SkMin32(nextAngle->start(),
1931                                nextAngle->end()), maxWinding);
1932    #if DEBUG_WINDING
1933                    SkDebugf("%s [%d] inactive\n", __FUNCTION__, nextIndex);
1934    #endif
1935                    return NULL;
1936                }
1937                if (!foundAngle || foundDone) {
1938                    foundAngle = nextAngle;
1939                    foundDone = nextSegment->done(*nextAngle);
1940                    foundFlipped = altFlipped;
1941                    foundMax = maxWinding;
1942                }
1943                continue;
1944            }
1945            if (!maxWinding && (!foundAngle || foundDone2)) {
1946        #if DEBUG_WINDING
1947                if (foundAngle && foundDone2) {
1948                    SkDebugf("%s [%d] !foundAngle && foundDone2\n", __FUNCTION__, nextIndex);
1949                }
1950        #endif
1951                foundAngle = nextAngle;
1952                foundDone2 = nextSegment->done(*nextAngle);
1953                foundFlipped = altFlipped;
1954                foundSum = sumWinding;
1955            }
1956            if (nextSegment->done()) {
1957                continue;
1958            }
1959            // if the winding is non-zero, nextAngle does not connect to
1960            // current chain. If we haven't done so already, mark the angle
1961            // as done, record the winding value, and mark connected unambiguous
1962            // segments as well.
1963            if (nextSegment->windSum(nextAngle) == SK_MinS32) {
1964                if (useInnerWinding(maxWinding, sumWinding)) {
1965                    maxWinding = sumWinding;
1966                }
1967                Span* last;
1968                if (foundAngle) {
1969                    last = nextSegment->markAndChaseWinding(nextAngle, maxWinding);
1970                } else {
1971                    last = nextSegment->markAndChaseDone(nextAngle, maxWinding);
1972                }
1973                if (last) {
1974                    *chase.append() = last;
1975                }
1976            }
1977        } while (++nextIndex != lastIndex);
1978        markDone(SkMin32(startIndex, endIndex), outerWinding);
1979        if (!foundAngle) {
1980            return NULL;
1981        }
1982        nextStart = foundAngle->start();
1983        nextEnd = foundAngle->end();
1984        nextSegment = foundAngle->segment();
1985        int flipped = foundFlipped ? -1 : 1;
1986        spanWinding = SkSign32(spanWinding) * flipped * nextSegment->windValue(
1987                SkMin32(nextStart, nextEnd));
1988        if (winding) {
1989    #if DEBUG_WINDING
1990            SkDebugf("%s ---6 winding=%d foundSum=", __FUNCTION__, winding);
1991            if (foundSum == SK_MinS32) {
1992                SkDebugf("?");
1993            } else {
1994                SkDebugf("%d", foundSum);
1995            }
1996            SkDebugf(" foundMax=");
1997            if (foundMax == SK_MinS32) {
1998                SkDebugf("?");
1999            } else {
2000                SkDebugf("%d", foundMax);
2001            }
2002            SkDebugf("\n");
2003     #endif
2004            winding = foundSum;
2005        }
2006    #if DEBUG_WINDING
2007        SkDebugf("%s spanWinding=%d flipped=%d\n", __FUNCTION__, spanWinding, flipped);
2008    #endif
2009        return nextSegment;
2010    }
2011
2012    Segment* findNextXor(int& nextStart, int& nextEnd) {
2013        const int startIndex = nextStart;
2014        const int endIndex = nextEnd;
2015        SkASSERT(startIndex != endIndex);
2016        int count = fTs.count();
2017        SkASSERT(startIndex < endIndex ? startIndex < count - 1
2018                : startIndex > 0);
2019        int step = SkSign32(endIndex - startIndex);
2020        int end = nextSpan(startIndex, step);
2021        SkASSERT(end >= 0);
2022        Span* endSpan = &fTs[end];
2023        Segment* other;
2024        markDone(SkMin32(startIndex, endIndex), 1);
2025        if (isSimple(end)) {
2026    #if DEBUG_WINDING
2027            SkDebugf("%s simple\n", __FUNCTION__);
2028    #endif
2029            other = endSpan->fOther;
2030            nextStart = endSpan->fOtherIndex;
2031            double startT = other->fTs[nextStart].fT;
2032            SkDEBUGCODE(bool firstLoop = true;)
2033            if ((approximately_less_than_zero(startT) && step < 0)
2034                    || (approximately_greater_than_one(startT) && step > 0)) {
2035                step = -step;
2036                SkDEBUGCODE(firstLoop = false;)
2037            }
2038            do {
2039                nextEnd = nextStart;
2040                do {
2041                    nextEnd += step;
2042                } while (approximately_zero(startT - other->fTs[nextEnd].fT));
2043                if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2044                    break;
2045                }
2046 #ifdef SK_DEBUG
2047                SkASSERT(firstLoop);
2048 #endif
2049                SkDEBUGCODE(firstLoop = false;)
2050                step = -step;
2051            } while (true);
2052            SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2053            return other;
2054        }
2055        SkTDArray<Angle> angles;
2056        SkASSERT(startIndex - endIndex != 0);
2057        SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2058        addTwoAngles(startIndex, end, angles);
2059        buildAngles(end, angles);
2060        SkTDArray<Angle*> sorted;
2061        sortAngles(angles, sorted);
2062        int angleCount = angles.count();
2063        int firstIndex = findStartingEdge(sorted, startIndex, end);
2064        SkASSERT(firstIndex >= 0);
2065    #if DEBUG_SORT
2066        debugShowSort(__FUNCTION__, sorted, firstIndex, 0);
2067    #endif
2068        SkASSERT(sorted[firstIndex]->segment() == this);
2069        int nextIndex = firstIndex + 1;
2070        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2071        const Angle* nextAngle;
2072        Segment* nextSegment;
2073        do {
2074            if (nextIndex == angleCount) {
2075                nextIndex = 0;
2076            }
2077            nextAngle = sorted[nextIndex];
2078            nextSegment = nextAngle->segment();
2079            if (!nextSegment->done(*nextAngle)) {
2080                break;
2081            }
2082            if (++nextIndex == lastIndex) {
2083                return NULL;
2084            }
2085        } while (true);
2086        nextStart = nextAngle->start();
2087        nextEnd = nextAngle->end();
2088        return nextSegment;
2089    }
2090
2091    int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2092        int angleCount = sorted.count();
2093        int firstIndex = -1;
2094        for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2095            const Angle* angle = sorted[angleIndex];
2096            if (angle->segment() == this && angle->start() == end &&
2097                    angle->end() == start) {
2098                firstIndex = angleIndex;
2099                break;
2100            }
2101        }
2102        return firstIndex;
2103    }
2104
2105    // FIXME: this is tricky code; needs its own unit test
2106    void findTooCloseToCall(bool isXor) {
2107        int count = fTs.count();
2108        if (count < 3) { // require t=0, x, 1 at minimum
2109            return;
2110        }
2111        int matchIndex = 0;
2112        int moCount;
2113        Span* match;
2114        Segment* mOther;
2115        do {
2116            match = &fTs[matchIndex];
2117            mOther = match->fOther;
2118            // FIXME: allow quads, cubics to be near coincident?
2119            if (mOther->fVerb == SkPath::kLine_Verb) {
2120                moCount = mOther->fTs.count();
2121                if (moCount >= 3) {
2122                    break;
2123                }
2124            }
2125            if (++matchIndex >= count) {
2126                return;
2127            }
2128        } while (true); // require t=0, x, 1 at minimum
2129        // OPTIMIZATION: defer matchPt until qualifying toCount is found?
2130        const SkPoint* matchPt = &xyAtT(match);
2131        // look for a pair of nearby T values that map to the same (x,y) value
2132        // if found, see if the pair of other segments share a common point. If
2133        // so, the span from here to there is coincident.
2134        for (int index = matchIndex + 1; index < count; ++index) {
2135            Span* test = &fTs[index];
2136            if (test->fDone) {
2137                continue;
2138            }
2139            Segment* tOther = test->fOther;
2140            if (tOther->fVerb != SkPath::kLine_Verb) {
2141                continue; // FIXME: allow quads, cubics to be near coincident?
2142            }
2143            int toCount = tOther->fTs.count();
2144            if (toCount < 3) { // require t=0, x, 1 at minimum
2145                continue;
2146            }
2147            const SkPoint* testPt = &xyAtT(test);
2148            if (*matchPt != *testPt) {
2149                matchIndex = index;
2150                moCount = toCount;
2151                match = test;
2152                mOther = tOther;
2153                matchPt = testPt;
2154                continue;
2155            }
2156            int moStart = -1;
2157            int moEnd = -1;
2158            double moStartT, moEndT;
2159            for (int moIndex = 0; moIndex < moCount; ++moIndex) {
2160                Span& moSpan = mOther->fTs[moIndex];
2161                if (moSpan.fDone) {
2162                    continue;
2163                }
2164                if (moSpan.fOther == this) {
2165                    if (moSpan.fOtherT == match->fT) {
2166                        moStart = moIndex;
2167                        moStartT = moSpan.fT;
2168                    }
2169                    continue;
2170                }
2171                if (moSpan.fOther == tOther) {
2172                    if (tOther->fTs[moSpan.fOtherIndex].fWindValue == 0) {
2173                        moStart = -1;
2174                        break;
2175                    }
2176                    SkASSERT(moEnd == -1);
2177                    moEnd = moIndex;
2178                    moEndT = moSpan.fT;
2179                }
2180            }
2181            if (moStart < 0 || moEnd < 0) {
2182                continue;
2183            }
2184            // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
2185            if (approximately_equal(moStartT, moEndT)) {
2186                continue;
2187            }
2188            int toStart = -1;
2189            int toEnd = -1;
2190            double toStartT, toEndT;
2191            for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2192                Span& toSpan = tOther->fTs[toIndex];
2193                if (toSpan.fDone) {
2194                    continue;
2195                }
2196                if (toSpan.fOther == this) {
2197                    if (toSpan.fOtherT == test->fT) {
2198                        toStart = toIndex;
2199                        toStartT = toSpan.fT;
2200                    }
2201                    continue;
2202                }
2203                if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
2204                    if (mOther->fTs[toSpan.fOtherIndex].fWindValue == 0) {
2205                        moStart = -1;
2206                        break;
2207                    }
2208                    SkASSERT(toEnd == -1);
2209                    toEnd = toIndex;
2210                    toEndT = toSpan.fT;
2211                }
2212            }
2213            // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2214            if (toStart <= 0 || toEnd <= 0) {
2215                continue;
2216            }
2217            if (approximately_equal(toStartT, toEndT)) {
2218                continue;
2219            }
2220            // test to see if the segment between there and here is linear
2221            if (!mOther->isLinear(moStart, moEnd)
2222                    || !tOther->isLinear(toStart, toEnd)) {
2223                continue;
2224            }
2225            bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
2226            if (flipped) {
2227                mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
2228            } else {
2229                // FIXME: this is bogus for multiple ops
2230                // the xorMask needs to be accumulated from the union of the two
2231                // edges -- which means that the segment must have its own copy of the mask
2232                mOther->addTCoincident(isXor, moStartT, moEndT, *tOther, toStartT, toEndT);
2233            }
2234        }
2235    }
2236
2237    // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2238    // and use more concise logic like the old edge walker code?
2239    // FIXME: this needs to deal with coincident edges
2240    Segment* findTop(int& tIndex, int& endIndex) {
2241        // iterate through T intersections and return topmost
2242        // topmost tangent from y-min to first pt is closer to horizontal
2243        SkASSERT(!done());
2244        int firstT;
2245        int lastT;
2246        SkPoint topPt;
2247        topPt.fY = SK_ScalarMax;
2248        int count = fTs.count();
2249        // see if either end is not done since we want smaller Y of the pair
2250        bool lastDone = true;
2251        for (int index = 0; index < count; ++index) {
2252            const Span& span = fTs[index];
2253            if (!span.fDone || !lastDone) {
2254                const SkPoint& intercept = xyAtT(&span);
2255                if (topPt.fY > intercept.fY || (topPt.fY == intercept.fY
2256                        && topPt.fX > intercept.fX)) {
2257                    topPt = intercept;
2258                    firstT = lastT = index;
2259                } else if (topPt == intercept) {
2260                    lastT = index;
2261                }
2262            }
2263            lastDone = span.fDone;
2264        }
2265        // sort the edges to find the leftmost
2266        int step = 1;
2267        int end = nextSpan(firstT, step);
2268        if (end == -1) {
2269            step = -1;
2270            end = nextSpan(firstT, step);
2271            SkASSERT(end != -1);
2272        }
2273        // if the topmost T is not on end, or is three-way or more, find left
2274        // look for left-ness from tLeft to firstT (matching y of other)
2275        SkTDArray<Angle> angles;
2276        SkASSERT(firstT - end != 0);
2277        addTwoAngles(end, firstT, angles);
2278        buildAngles(firstT, angles);
2279        SkTDArray<Angle*> sorted;
2280        sortAngles(angles, sorted);
2281    #if DEBUG_SORT
2282        sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0);
2283    #endif
2284        // skip edges that have already been processed
2285        firstT = -1;
2286        Segment* leftSegment;
2287        do {
2288            const Angle* angle = sorted[++firstT];
2289            leftSegment = angle->segment();
2290            tIndex = angle->end();
2291            endIndex = angle->start();
2292        } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
2293        return leftSegment;
2294    }
2295
2296    // FIXME: not crazy about this
2297    // when the intersections are performed, the other index is into an
2298    // incomplete array. as the array grows, the indices become incorrect
2299    // while the following fixes the indices up again, it isn't smart about
2300    // skipping segments whose indices are already correct
2301    // assuming we leave the code that wrote the index in the first place
2302    void fixOtherTIndex() {
2303        int iCount = fTs.count();
2304        for (int i = 0; i < iCount; ++i) {
2305            Span& iSpan = fTs[i];
2306            double oT = iSpan.fOtherT;
2307            Segment* other = iSpan.fOther;
2308            int oCount = other->fTs.count();
2309            for (int o = 0; o < oCount; ++o) {
2310                Span& oSpan = other->fTs[o];
2311                if (oT == oSpan.fT && this == oSpan.fOther) {
2312                    iSpan.fOtherIndex = o;
2313                    break;
2314                }
2315            }
2316        }
2317    }
2318
2319    // OPTIMIZATION: uses tail recursion. Unwise?
2320    Span* innerChaseDone(int index, int step, int winding) {
2321        int end = nextSpan(index, step);
2322        SkASSERT(end >= 0);
2323        if (multipleSpans(end)) {
2324            return &fTs[end];
2325        }
2326        const Span& endSpan = fTs[end];
2327        Segment* other = endSpan.fOther;
2328        index = endSpan.fOtherIndex;
2329        int otherEnd = other->nextSpan(index, step);
2330        Span* last = other->innerChaseDone(index, step, winding);
2331        other->markDone(SkMin32(index, otherEnd), winding);
2332        return last;
2333    }
2334
2335    Span* innerChaseWinding(int index, int step, int winding) {
2336        int end = nextSpan(index, step);
2337        SkASSERT(end >= 0);
2338        if (multipleSpans(end)) {
2339            return &fTs[end];
2340        }
2341        const Span& endSpan = fTs[end];
2342        Segment* other = endSpan.fOther;
2343        index = endSpan.fOtherIndex;
2344        int otherEnd = other->nextSpan(index, step);
2345        int min = SkMin32(index, otherEnd);
2346        if (other->fTs[min].fWindSum != SK_MinS32) {
2347            SkASSERT(other->fTs[min].fWindSum == winding);
2348            return NULL;
2349        }
2350        Span* last = other->innerChaseWinding(index, step, winding);
2351        other->markWinding(min, winding);
2352        return last;
2353    }
2354
2355    void init(const SkPoint pts[], SkPath::Verb verb, bool operand) {
2356        fDoneSpans = 0;
2357        fOperand = operand;
2358        fPts = pts;
2359        fVerb = verb;
2360    }
2361
2362    bool intersected() const {
2363        return fTs.count() > 0;
2364    }
2365
2366    bool isConnected(int startIndex, int endIndex) const {
2367        return fTs[startIndex].fWindSum != SK_MinS32
2368                || fTs[endIndex].fWindSum != SK_MinS32;
2369    }
2370
2371    bool isHorizontal() const {
2372        return fBounds.fTop == fBounds.fBottom;
2373    }
2374
2375    bool isLinear(int start, int end) const {
2376        if (fVerb == SkPath::kLine_Verb) {
2377            return true;
2378        }
2379        if (fVerb == SkPath::kQuad_Verb) {
2380            SkPoint qPart[3];
2381            QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
2382            return QuadIsLinear(qPart);
2383        } else {
2384            SkASSERT(fVerb == SkPath::kCubic_Verb);
2385            SkPoint cPart[4];
2386            CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
2387            return CubicIsLinear(cPart);
2388        }
2389    }
2390
2391    // OPTIMIZE: successive calls could start were the last leaves off
2392    // or calls could specialize to walk forwards or backwards
2393    bool isMissing(double startT) const {
2394        size_t tCount = fTs.count();
2395        for (size_t index = 0; index < tCount; ++index) {
2396            if (approximately_zero(startT - fTs[index].fT)) {
2397                return false;
2398            }
2399        }
2400        return true;
2401    }
2402
2403    bool isSimple(int end) const {
2404        int count = fTs.count();
2405        if (count == 2) {
2406            return true;
2407        }
2408        double t = fTs[end].fT;
2409        if (approximately_less_than_zero(t)) {
2410            return !approximately_less_than_zero(fTs[1].fT);
2411        }
2412        if (approximately_greater_than_one(t)) {
2413            return !approximately_greater_than_one(fTs[count - 2].fT);
2414        }
2415        return false;
2416    }
2417
2418    bool isVertical() const {
2419        return fBounds.fLeft == fBounds.fRight;
2420    }
2421
2422    SkScalar leftMost(int start, int end) const {
2423        return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
2424    }
2425
2426    // this span is excluded by the winding rule -- chase the ends
2427    // as long as they are unambiguous to mark connections as done
2428    // and give them the same winding value
2429    Span* markAndChaseDone(const Angle* angle, int winding) {
2430        int index = angle->start();
2431        int endIndex = angle->end();
2432        int step = SkSign32(endIndex - index);
2433        Span* last = innerChaseDone(index, step, winding);
2434        markDone(SkMin32(index, endIndex), winding);
2435        return last;
2436    }
2437
2438    Span* markAndChaseWinding(const Angle* angle, int winding) {
2439        int index = angle->start();
2440        int endIndex = angle->end();
2441        int min = SkMin32(index, endIndex);
2442        int step = SkSign32(endIndex - index);
2443        Span* last = innerChaseWinding(index, step, winding);
2444        markWinding(min, winding);
2445        return last;
2446    }
2447
2448    // FIXME: this should also mark spans with equal (x,y)
2449    // This may be called when the segment is already marked done. While this
2450    // wastes time, it shouldn't do any more than spin through the T spans.
2451    // OPTIMIZATION: abort on first done found (assuming that this code is
2452    // always called to mark segments done).
2453    void markDone(int index, int winding) {
2454      //  SkASSERT(!done());
2455        SkASSERT(winding);
2456        double referenceT = fTs[index].fT;
2457        int lesser = index;
2458        while (--lesser >= 0 && approximately_negative(referenceT - fTs[lesser].fT)) {
2459            markOneDone(__FUNCTION__, lesser, winding);
2460        }
2461        do {
2462            markOneDone(__FUNCTION__, index, winding);
2463        } while (++index < fTs.count() && approximately_negative(fTs[index].fT - referenceT));
2464    }
2465
2466    void markOneDone(const char* funName, int tIndex, int winding) {
2467        Span* span = markOneWinding(funName, tIndex, winding);
2468        if (!span) {
2469            return;
2470        }
2471        span->fDone = true;
2472        fDoneSpans++;
2473    }
2474
2475    Span* markOneWinding(const char* funName, int tIndex, int winding) {
2476        Span& span = fTs[tIndex];
2477        if (span.fDone) {
2478            return NULL;
2479        }
2480    #if DEBUG_MARK_DONE
2481        debugShowNewWinding(funName, span, winding);
2482    #endif
2483        SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
2484   #ifdef SK_DEBUG
2485        SkASSERT(abs(winding) <= gDebugMaxWindSum);
2486   #endif
2487        span.fWindSum = winding;
2488        return &span;
2489    }
2490
2491    void markWinding(int index, int winding) {
2492    //    SkASSERT(!done());
2493        SkASSERT(winding);
2494        double referenceT = fTs[index].fT;
2495        int lesser = index;
2496        while (--lesser >= 0 && approximately_negative(referenceT - fTs[lesser].fT)) {
2497            markOneWinding(__FUNCTION__, lesser, winding);
2498        }
2499        do {
2500            markOneWinding(__FUNCTION__, index, winding);
2501       } while (++index < fTs.count() && approximately_negative(fTs[index].fT - referenceT));
2502    }
2503
2504    void matchWindingValue(int tIndex, double t, bool borrowWind) {
2505        int nextDoorWind = SK_MaxS32;
2506        if (tIndex > 0) {
2507            const Span& below = fTs[tIndex - 1];
2508            if (approximately_negative(t - below.fT)) {
2509                nextDoorWind = below.fWindValue;
2510            }
2511        }
2512        if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
2513            const Span& above = fTs[tIndex + 1];
2514            if (approximately_negative(above.fT - t)) {
2515                nextDoorWind = above.fWindValue;
2516            }
2517        }
2518        if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
2519            const Span& below = fTs[tIndex - 1];
2520            nextDoorWind = below.fWindValue;
2521        }
2522        if (nextDoorWind != SK_MaxS32) {
2523            Span& newSpan = fTs[tIndex];
2524            newSpan.fWindValue = nextDoorWind;
2525            if (!nextDoorWind) {
2526                newSpan.fDone = true;
2527                ++fDoneSpans;
2528            }
2529        }
2530    }
2531
2532    // return span if when chasing, two or more radiating spans are not done
2533    // OPTIMIZATION: ? multiple spans is detected when there is only one valid
2534    // candidate and the remaining spans have windValue == 0 (canceled by
2535    // coincidence). The coincident edges could either be removed altogether,
2536    // or this code could be more complicated in detecting this case. Worth it?
2537    bool multipleSpans(int end) const {
2538        return end > 0 && end < fTs.count() - 1;
2539    }
2540
2541    // This has callers for two different situations: one establishes the end
2542    // of the current span, and one establishes the beginning of the next span
2543    // (thus the name). When this is looking for the end of the current span,
2544    // coincidence is found when the beginning Ts contain -step and the end
2545    // contains step. When it is looking for the beginning of the next, the
2546    // first Ts found can be ignored and the last Ts should contain -step.
2547    // OPTIMIZATION: probably should split into two functions
2548    int nextSpan(int from, int step) const {
2549        const Span& fromSpan = fTs[from];
2550        int count = fTs.count();
2551        int to = from;
2552        while (step > 0 ? ++to < count : --to >= 0) {
2553            const Span& span = fTs[to];
2554            if (approximately_zero(span.fT - fromSpan.fT)) {
2555                continue;
2556            }
2557            return to;
2558        }
2559        return -1;
2560    }
2561
2562    // FIXME
2563    // this returns at any difference in T, vs. a preset minimum. It may be
2564    // that all callers to nextSpan should use this instead.
2565    int nextExactSpan(int from, int step) const {
2566        const Span& fromSpan = fTs[from];
2567        int count = fTs.count();
2568        int to = from;
2569        while (step > 0 ? ++to < count : --to >= 0) {
2570            const Span& span = fTs[to];
2571            if (span.fT == fromSpan.fT) {
2572                continue;
2573            }
2574            return to;
2575        }
2576        return -1;
2577    }
2578
2579    bool operand() const {
2580        return fOperand;
2581    }
2582
2583    int oppSign(int startIndex, int endIndex) const {
2584        int result = startIndex < endIndex ? -fTs[startIndex].fWindValueOpp :
2585                fTs[endIndex].fWindValueOpp;
2586#if DEBUG_WIND_BUMP
2587        SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
2588#endif
2589        return result;
2590    }
2591
2592    const SkPoint* pts() const {
2593        return fPts;
2594    }
2595
2596    void reset() {
2597        init(NULL, (SkPath::Verb) -1, false);
2598        fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
2599        fTs.reset();
2600    }
2601
2602    // OPTIMIZATION: mark as debugging only if used solely by tests
2603    const Span& span(int tIndex) const {
2604        return fTs[tIndex];
2605    }
2606
2607    int spanSign(const Angle* angle) const {
2608        SkASSERT(angle->segment() == this);
2609        return spanSign(angle->start(), angle->end());
2610    }
2611
2612    int spanSign(int startIndex, int endIndex) const {
2613        int result = startIndex < endIndex ? -fTs[startIndex].fWindValue :
2614                fTs[endIndex].fWindValue;
2615#if DEBUG_WIND_BUMP
2616        SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
2617#endif
2618        return result;
2619    }
2620
2621    // OPTIMIZATION: mark as debugging only if used solely by tests
2622    double t(int tIndex) const {
2623        return fTs[tIndex].fT;
2624    }
2625
2626    static void TrackOutside(SkTDArray<double>& outsideTs, double end,
2627            double start) {
2628        int outCount = outsideTs.count();
2629        if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
2630            *outsideTs.append() = end;
2631            *outsideTs.append() = start;
2632        }
2633    }
2634
2635    void undoneSpan(int& start, int& end) {
2636        size_t tCount = fTs.count();
2637        size_t index;
2638        for (index = 0; index < tCount; ++index) {
2639            if (!fTs[index].fDone) {
2640                break;
2641            }
2642        }
2643        SkASSERT(index < tCount - 1);
2644        start = index;
2645        double startT = fTs[index].fT;
2646        while (approximately_negative(fTs[++index].fT - startT))
2647            SkASSERT(index < tCount);
2648        SkASSERT(index < tCount);
2649        end = index;
2650    }
2651
2652    void updatePts(const SkPoint pts[]) {
2653        fPts = pts;
2654    }
2655
2656    SkPath::Verb verb() const {
2657        return fVerb;
2658    }
2659
2660    int windSum(int tIndex) const {
2661        return fTs[tIndex].fWindSum;
2662    }
2663
2664    int windSum(const Angle* angle) const {
2665        int start = angle->start();
2666        int end = angle->end();
2667        int index = SkMin32(start, end);
2668        return windSum(index);
2669    }
2670
2671    int windValue(int tIndex) const {
2672        return fTs[tIndex].fWindValue;
2673    }
2674
2675    int windValue(const Angle* angle) const {
2676        int start = angle->start();
2677        int end = angle->end();
2678        int index = SkMin32(start, end);
2679        return windValue(index);
2680    }
2681
2682    SkScalar xAtT(const Span* span) const {
2683        return xyAtT(span).fX;
2684    }
2685
2686    const SkPoint& xyAtT(int index) const {
2687        return xyAtT(&fTs[index]);
2688    }
2689
2690    const SkPoint& xyAtT(const Span* span) const {
2691        if (SkScalarIsNaN(span->fPt.fX)) {
2692            if (span->fT == 0) {
2693                span->fPt = fPts[0];
2694            } else if (span->fT == 1) {
2695                span->fPt = fPts[fVerb];
2696            } else {
2697                (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
2698            }
2699        }
2700        return span->fPt;
2701    }
2702
2703    SkScalar yAtT(int index) const {
2704        return yAtT(&fTs[index]);
2705    }
2706
2707    SkScalar yAtT(const Span* span) const {
2708        return xyAtT(span).fY;
2709    }
2710
2711#if DEBUG_DUMP
2712    void dump() const {
2713        const char className[] = "Segment";
2714        const int tab = 4;
2715        for (int i = 0; i < fTs.count(); ++i) {
2716            SkPoint out;
2717            (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
2718            SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
2719                    " otherT=%1.9g windSum=%d\n",
2720                    tab + sizeof(className), className, fID,
2721                    kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
2722                    fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
2723        }
2724        SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
2725                tab + sizeof(className), className, fID,
2726                fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
2727    }
2728#endif
2729
2730#if DEBUG_CONCIDENT
2731    // assert if pair has not already been added
2732     void debugAddTPair(double t, const Segment& other, double otherT) const {
2733        for (int i = 0; i < fTs.count(); ++i) {
2734            if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
2735                return;
2736            }
2737        }
2738        SkASSERT(0);
2739     }
2740#endif
2741
2742#if DEBUG_DUMP
2743    int debugID() const {
2744        return fID;
2745    }
2746#endif
2747
2748#if DEBUG_WINDING
2749    void debugShowSums() const {
2750        SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
2751            fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
2752        for (int i = 0; i < fTs.count(); ++i) {
2753            const Span& span = fTs[i];
2754            SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
2755            if (span.fWindSum == SK_MinS32) {
2756                SkDebugf("?");
2757            } else {
2758                SkDebugf("%d", span.fWindSum);
2759            }
2760            SkDebugf("]");
2761        }
2762        SkDebugf("\n");
2763    }
2764#endif
2765
2766#if DEBUG_CONCIDENT
2767    void debugShowTs() const {
2768        SkDebugf("%s id=%d", __FUNCTION__, fID);
2769        for (int i = 0; i < fTs.count(); ++i) {
2770            SkDebugf(" [o=%d t=%1.3g %1.9g,%1.9g w=%d]", fTs[i].fOther->fID,
2771                    fTs[i].fT, xAtT(&fTs[i]), yAtT(&fTs[i]), fTs[i].fWindValue);
2772        }
2773        SkDebugf("\n");
2774    }
2775#endif
2776
2777#if DEBUG_ACTIVE_SPANS
2778    void debugShowActiveSpans() const {
2779        if (done()) {
2780            return;
2781        }
2782        for (int i = 0; i < fTs.count(); ++i) {
2783            if (fTs[i].fDone) {
2784                continue;
2785            }
2786            SkDebugf("%s id=%d", __FUNCTION__, fID);
2787            SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
2788            for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
2789                SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
2790            }
2791            const Span* span = &fTs[i];
2792            SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
2793                     xAtT(span), yAtT(span));
2794            const Segment* other = fTs[i].fOther;
2795            SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
2796                    other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
2797            if (fTs[i].fWindSum == SK_MinS32) {
2798                SkDebugf("?");
2799            } else {
2800                SkDebugf("%d", fTs[i].fWindSum);
2801            }
2802            SkDebugf(" windValue=%d\n", fTs[i].fWindValue);
2803        }
2804    }
2805
2806    // This isn't useful yet -- but leaving it in for now in case i think of something
2807    // to use it for
2808    void validateActiveSpans() const {
2809        if (done()) {
2810            return;
2811        }
2812        int tCount = fTs.count();
2813        for (int index = 0; index < tCount; ++index) {
2814            if (fTs[index].fDone) {
2815                continue;
2816            }
2817            // count number of connections which are not done
2818            int first = index;
2819            double baseT = fTs[index].fT;
2820            while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
2821                --first;
2822            }
2823            int last = index;
2824            while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
2825                ++last;
2826            }
2827            int connections = 0;
2828            connections += first > 0 && !fTs[first - 1].fDone;
2829            for (int test = first; test <= last; ++test) {
2830                connections += !fTs[test].fDone;
2831                const Segment* other = fTs[test].fOther;
2832                int oIndex = fTs[test].fOtherIndex;
2833                connections += !other->fTs[oIndex].fDone;
2834                connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
2835            }
2836      //      SkASSERT(!(connections & 1));
2837        }
2838    }
2839#endif
2840
2841#if DEBUG_MARK_DONE
2842    void debugShowNewWinding(const char* fun, const Span& span, int winding) {
2843        const SkPoint& pt = xyAtT(&span);
2844        SkDebugf("%s id=%d", fun, fID);
2845        SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
2846        for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
2847            SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
2848        }
2849        SkDebugf(") t=%1.9g (%1.9g,%1.9g) newWindSum=%d windSum=",
2850                span.fT, pt.fX, pt.fY, winding);
2851        if (span.fWindSum == SK_MinS32) {
2852            SkDebugf("?");
2853        } else {
2854            SkDebugf("%d", span.fWindSum);
2855        }
2856        SkDebugf(" windValue=%d\n", span.fWindValue);
2857    }
2858#endif
2859
2860#if DEBUG_SORT
2861    void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
2862            const int contourWinding) const {
2863        SkASSERT(angles[first]->segment() == this);
2864        SkASSERT(angles.count() > 1);
2865        int lastSum = contourWinding;
2866        int windSum = lastSum - spanSign(angles[first]);
2867        SkDebugf("%s %s contourWinding=%d sign=%d\n", fun, __FUNCTION__,
2868                contourWinding, spanSign(angles[first]));
2869        int index = first;
2870        bool firstTime = true;
2871        do {
2872            const Angle& angle = *angles[index];
2873            const Segment& segment = *angle.segment();
2874            int start = angle.start();
2875            int end = angle.end();
2876            const Span& sSpan = segment.fTs[start];
2877            const Span& eSpan = segment.fTs[end];
2878            const Span& mSpan = segment.fTs[SkMin32(start, end)];
2879            if (!firstTime) {
2880                lastSum = windSum;
2881                windSum -= segment.spanSign(&angle);
2882            }
2883            SkDebugf("%s [%d] id=%d %s start=%d (%1.9g,%,1.9g) end=%d (%1.9g,%,1.9g)"
2884                    " sign=%d windValue=%d winding: %d->%d (max=%d) done=%d\n",
2885                    __FUNCTION__, index, segment.fID, kLVerbStr[segment.fVerb],
2886                    start, segment.xAtT(&sSpan),
2887                    segment.yAtT(&sSpan), end, segment.xAtT(&eSpan),
2888                    segment.yAtT(&eSpan), angle.sign(), mSpan.fWindValue,
2889                    lastSum, windSum, useInnerWinding(lastSum, windSum)
2890                    ? windSum : lastSum, mSpan.fDone);
2891#if false && DEBUG_ANGLE
2892            angle.debugShow(segment.xyAtT(&sSpan));
2893#endif
2894            ++index;
2895            if (index == angles.count()) {
2896                index = 0;
2897            }
2898            if (firstTime) {
2899                firstTime = false;
2900            }
2901        } while (index != first);
2902    }
2903#endif
2904
2905#if DEBUG_WINDING
2906    bool debugVerifyWinding(int start, int end, int winding) const {
2907        const Span& span = fTs[SkMin32(start, end)];
2908        int spanWinding = span.fWindSum;
2909        if (spanWinding == SK_MinS32) {
2910            return true;
2911        }
2912        int spanSign = SkSign32(start - end);
2913        int signedVal = spanSign * span.fWindValue;
2914        if (signedVal < 0) {
2915            spanWinding -= signedVal;
2916        }
2917        return span.fWindSum == winding;
2918    }
2919#endif
2920
2921private:
2922    const SkPoint* fPts;
2923    SkPath::Verb fVerb;
2924    Bounds fBounds;
2925    SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
2926    int fDoneSpans; // quick check that segment is finished
2927    bool fOperand;
2928#if DEBUG_DUMP
2929    int fID;
2930#endif
2931};
2932
2933class Contour;
2934
2935struct Coincidence {
2936    Contour* fContours[2];
2937    int fSegments[2];
2938    double fTs[2][2];
2939    bool fXor;
2940};
2941
2942class Contour {
2943public:
2944    Contour() {
2945        reset();
2946#if DEBUG_DUMP
2947        fID = ++gContourID;
2948#endif
2949    }
2950
2951    bool operator<(const Contour& rh) const {
2952        return fBounds.fTop == rh.fBounds.fTop
2953                ? fBounds.fLeft < rh.fBounds.fLeft
2954                : fBounds.fTop < rh.fBounds.fTop;
2955    }
2956
2957    void addCoincident(int index, Contour* other, int otherIndex,
2958            const Intersections& ts, bool swap) {
2959        Coincidence& coincidence = *fCoincidences.append();
2960        coincidence.fContours[0] = this;
2961        coincidence.fContours[1] = other;
2962        coincidence.fSegments[0] = index;
2963        coincidence.fSegments[1] = otherIndex;
2964        if (fSegments[index].verb() == SkPath::kLine_Verb &&
2965                other->fSegments[otherIndex].verb() == SkPath::kLine_Verb) {
2966            // FIXME: coincident lines use legacy Ts instead of coincident Ts
2967            coincidence.fTs[swap][0] = ts.fT[0][0];
2968            coincidence.fTs[swap][1] = ts.fT[0][1];
2969            coincidence.fTs[!swap][0] = ts.fT[1][0];
2970            coincidence.fTs[!swap][1] = ts.fT[1][1];
2971        } else if (fSegments[index].verb() == SkPath::kQuad_Verb &&
2972                other->fSegments[otherIndex].verb() == SkPath::kQuad_Verb) {
2973            coincidence.fTs[swap][0] = ts.fCoincidentT[0][0];
2974            coincidence.fTs[swap][1] = ts.fCoincidentT[0][1];
2975            coincidence.fTs[!swap][0] = ts.fCoincidentT[1][0];
2976            coincidence.fTs[!swap][1] = ts.fCoincidentT[1][1];
2977        }
2978        coincidence.fXor = fOperand == other->fOperand ? fXor : true;
2979    }
2980
2981    void addCross(const Contour* crosser) {
2982#ifdef DEBUG_CROSS
2983        for (int index = 0; index < fCrosses.count(); ++index) {
2984            SkASSERT(fCrosses[index] != crosser);
2985        }
2986#endif
2987        *fCrosses.append() = crosser;
2988    }
2989
2990    void addCubic(const SkPoint pts[4]) {
2991        fSegments.push_back().addCubic(pts, fOperand);
2992        fContainsCurves = true;
2993    }
2994
2995    int addLine(const SkPoint pts[2]) {
2996        fSegments.push_back().addLine(pts, fOperand);
2997        return fSegments.count();
2998    }
2999
3000    void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
3001        fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
3002    }
3003
3004    int addQuad(const SkPoint pts[3]) {
3005        fSegments.push_back().addQuad(pts, fOperand);
3006        fContainsCurves = true;
3007        return fSegments.count();
3008    }
3009
3010    int addT(int segIndex, double newT, Contour* other, int otherIndex) {
3011        containsIntercepts();
3012        return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex]);
3013    }
3014
3015    const Bounds& bounds() const {
3016        return fBounds;
3017    }
3018
3019    void collapseTriangles() {
3020        int segmentCount = fSegments.count();
3021        for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
3022            fSegments[sIndex].collapseTriangles(fXor);
3023        }
3024    }
3025
3026    void complete() {
3027        setBounds();
3028        fContainsIntercepts = false;
3029    }
3030
3031    void containsIntercepts() {
3032        fContainsIntercepts = true;
3033    }
3034
3035    const Segment* crossedSegment(const SkPoint& basePt, SkScalar& bestY,
3036            int &tIndex, double& hitT) {
3037        int segmentCount = fSegments.count();
3038        const Segment* bestSegment = NULL;
3039        for (int test = 0; test < segmentCount; ++test) {
3040            Segment* testSegment = &fSegments[test];
3041            const SkRect& bounds = testSegment->bounds();
3042            if (bounds.fBottom <= bestY) {
3043                continue;
3044            }
3045            if (bounds.fTop >= basePt.fY) {
3046                continue;
3047            }
3048            if (bounds.fLeft > basePt.fX) {
3049                continue;
3050            }
3051            if (bounds.fRight < basePt.fX) {
3052                continue;
3053            }
3054            if (bounds.fLeft == bounds.fRight) {
3055                continue;
3056            }
3057     #if 0
3058            bool leftHalf = bounds.fLeft == basePt.fX;
3059            bool rightHalf = bounds.fRight == basePt.fX;
3060            if ((leftHalf || rightHalf) && !testSegment->crossedSpanHalves(
3061                    basePt, leftHalf, rightHalf)) {
3062                continue;
3063            }
3064     #endif
3065            double testHitT;
3066            int testT = testSegment->crossedSpan(basePt, bestY, testHitT);
3067            if (testT >= 0) {
3068                bestSegment = testSegment;
3069                tIndex = testT;
3070                hitT = testHitT;
3071            }
3072        }
3073        return bestSegment;
3074    }
3075
3076    bool crosses(const Contour* crosser) const {
3077        for (int index = 0; index < fCrosses.count(); ++index) {
3078            if (fCrosses[index] == crosser) {
3079                return true;
3080            }
3081        }
3082        return false;
3083    }
3084
3085    void findTooCloseToCall() {
3086        int segmentCount = fSegments.count();
3087        for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
3088            fSegments[sIndex].findTooCloseToCall(fXor);
3089        }
3090    }
3091
3092    void fixOtherTIndex() {
3093        int segmentCount = fSegments.count();
3094        for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
3095            fSegments[sIndex].fixOtherTIndex();
3096        }
3097    }
3098
3099    void reset() {
3100        fSegments.reset();
3101        fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3102        fContainsCurves = fContainsIntercepts = false;
3103    }
3104
3105    // FIXME: for binary ops, need to keep both ops winding contributions separately
3106    // in edge array
3107    void resolveCoincidence() {
3108        int count = fCoincidences.count();
3109        for (int index = 0; index < count; ++index) {
3110            Coincidence& coincidence = fCoincidences[index];
3111            Contour* thisContour = coincidence.fContours[0];
3112            Contour* otherContour = coincidence.fContours[1];
3113            int thisIndex = coincidence.fSegments[0];
3114            int otherIndex = coincidence.fSegments[1];
3115            Segment& thisOne = thisContour->fSegments[thisIndex];
3116            Segment& other = otherContour->fSegments[otherIndex];
3117        #if DEBUG_CONCIDENT
3118            thisOne.debugShowTs();
3119            other.debugShowTs();
3120        #endif
3121            double startT = coincidence.fTs[0][0];
3122            double endT = coincidence.fTs[0][1];
3123            bool opposite = false;
3124            if (startT > endT) {
3125                SkTSwap<double>(startT, endT);
3126                opposite ^= true;
3127            }
3128            SkASSERT(!approximately_negative(endT - startT));
3129            double oStartT = coincidence.fTs[1][0];
3130            double oEndT = coincidence.fTs[1][1];
3131            if (oStartT > oEndT) {
3132                SkTSwap<double>(oStartT, oEndT);
3133                opposite ^= true;
3134            }
3135            SkASSERT(!approximately_negative(oEndT - oStartT));
3136            if (opposite) {
3137                        // make sure startT and endT have t entries
3138                SkASSERT(opposite);
3139                if (startT > 0 || oEndT < 1
3140                        || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
3141                    thisOne.addTPair(startT, other, oEndT, true);
3142                }
3143                if (oStartT > 0 || endT < 1
3144                        || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
3145                    other.addTPair(oStartT, thisOne, endT, true);
3146                }
3147                thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
3148            } else {
3149                if (startT > 0 || oStartT > 0
3150                        || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
3151                    thisOne.addTPair(startT, other, oStartT, true);
3152                }
3153                if (endT < 1 || oEndT < 1
3154                        || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
3155                    other.addTPair(oEndT, thisOne, endT, true);
3156                }
3157                thisOne.addTCoincident(coincidence.fXor, startT, endT, other, oStartT, oEndT);
3158            }
3159        #if DEBUG_CONCIDENT
3160            thisOne.debugShowTs();
3161            other.debugShowTs();
3162        #endif
3163        }
3164    }
3165
3166    const SkTArray<Segment>& segments() {
3167        return fSegments;
3168    }
3169
3170    void setOperand(bool isOp) {
3171        fOperand = isOp;
3172    }
3173
3174    void setXor(bool isXor) {
3175        fXor = isXor;
3176    }
3177
3178    // OPTIMIZATION: feel pretty uneasy about this. It seems like once again
3179    // we need to sort and walk edges in y, but that on the surface opens the
3180    // same can of worms as before. But then, this is a rough sort based on
3181    // segments' top, and not a true sort, so it could be ameniable to regular
3182    // sorting instead of linear searching. Still feel like I'm missing something
3183    Segment* topSegment(SkScalar& bestY) {
3184        int segmentCount = fSegments.count();
3185        SkASSERT(segmentCount > 0);
3186        int best = -1;
3187        Segment* bestSegment = NULL;
3188        while (++best < segmentCount) {
3189            Segment* testSegment = &fSegments[best];
3190            if (testSegment->done()) {
3191                continue;
3192            }
3193            bestSegment = testSegment;
3194            break;
3195        }
3196        if (!bestSegment) {
3197            return NULL;
3198        }
3199        SkScalar bestTop = bestSegment->activeTop();
3200        for (int test = best + 1; test < segmentCount; ++test) {
3201            Segment* testSegment = &fSegments[test];
3202            if (testSegment->done()) {
3203                continue;
3204            }
3205            if (testSegment->bounds().fTop > bestTop) {
3206                continue;
3207            }
3208            SkScalar testTop = testSegment->activeTop();
3209            if (bestTop > testTop) {
3210                bestTop = testTop;
3211                bestSegment = testSegment;
3212            }
3213        }
3214        bestY = bestTop;
3215        return bestSegment;
3216    }
3217
3218    Segment* undoneSegment(int& start, int& end) {
3219        int segmentCount = fSegments.count();
3220        for (int test = 0; test < segmentCount; ++test) {
3221            Segment* testSegment = &fSegments[test];
3222            if (testSegment->done()) {
3223                continue;
3224            }
3225            testSegment->undoneSpan(start, end);
3226            return testSegment;
3227        }
3228        return NULL;
3229    }
3230
3231    int updateSegment(int index, const SkPoint* pts) {
3232        Segment& segment = fSegments[index];
3233        segment.updatePts(pts);
3234        return segment.verb() + 1;
3235    }
3236
3237#if DEBUG_TEST
3238    SkTArray<Segment>& debugSegments() {
3239        return fSegments;
3240    }
3241#endif
3242
3243#if DEBUG_DUMP
3244    void dump() {
3245        int i;
3246        const char className[] = "Contour";
3247        const int tab = 4;
3248        SkDebugf("%s %p (contour=%d)\n", className, this, fID);
3249        for (i = 0; i < fSegments.count(); ++i) {
3250            SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
3251                    className, i);
3252            fSegments[i].dump();
3253        }
3254        SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
3255                tab + sizeof(className), className,
3256                fBounds.fLeft, fBounds.fTop,
3257                fBounds.fRight, fBounds.fBottom);
3258        SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
3259                className, fContainsIntercepts);
3260        SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
3261                className, fContainsCurves);
3262    }
3263#endif
3264
3265#if DEBUG_ACTIVE_SPANS
3266    void debugShowActiveSpans() {
3267        for (int index = 0; index < fSegments.count(); ++index) {
3268            fSegments[index].debugShowActiveSpans();
3269        }
3270    }
3271
3272    void validateActiveSpans() {
3273        for (int index = 0; index < fSegments.count(); ++index) {
3274            fSegments[index].validateActiveSpans();
3275        }
3276    }
3277#endif
3278
3279protected:
3280    void setBounds() {
3281        int count = fSegments.count();
3282        if (count == 0) {
3283            SkDebugf("%s empty contour\n", __FUNCTION__);
3284            SkASSERT(0);
3285            // FIXME: delete empty contour?
3286            return;
3287        }
3288        fBounds = fSegments.front().bounds();
3289        for (int index = 1; index < count; ++index) {
3290            fBounds.add(fSegments[index].bounds());
3291        }
3292    }
3293
3294private:
3295    SkTArray<Segment> fSegments;
3296    SkTDArray<Coincidence> fCoincidences;
3297    SkTDArray<const Contour*> fCrosses;
3298    Bounds fBounds;
3299    bool fContainsIntercepts;
3300    bool fContainsCurves;
3301    bool fOperand; // true for the second argument to a binary operator
3302    bool fXor;
3303#if DEBUG_DUMP
3304    int fID;
3305#endif
3306};
3307
3308class EdgeBuilder {
3309public:
3310
3311EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
3312    : fPath(&path)
3313    , fContours(contours)
3314    , fCurrentContour(NULL)
3315    , fOperand(false)
3316{
3317    fXorMask = (path.getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
3318#if DEBUG_DUMP
3319    gContourID = 0;
3320    gSegmentID = 0;
3321#endif
3322    fSecondHalf = preFetch();
3323}
3324
3325void addOperand(const SkPath& path) {
3326    fPath = &path;
3327    fXorMask = (path.getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
3328    preFetch();
3329}
3330
3331void finish() {
3332    walk();
3333    complete();
3334    if (fCurrentContour && !fCurrentContour->segments().count()) {
3335        fContours.pop_back();
3336    }
3337    // correct pointers in contours since fReducePts may have moved as it grew
3338    int cIndex = 0;
3339    int extraCount = fExtra.count();
3340    SkASSERT(extraCount == 0 || fExtra[0] == -1);
3341    int eIndex = 0;
3342    int rIndex = 0;
3343    while (++eIndex < extraCount) {
3344        int offset = fExtra[eIndex];
3345        if (offset < 0) {
3346            ++cIndex;
3347            continue;
3348        }
3349        fCurrentContour = &fContours[cIndex];
3350        rIndex += fCurrentContour->updateSegment(offset - 1,
3351                &fReducePts[rIndex]);
3352    }
3353    fExtra.reset(); // we're done with this
3354}
3355
3356ShapeOpMask xorMask() const {
3357    return fXorMask;
3358}
3359
3360protected:
3361
3362void complete() {
3363    if (fCurrentContour && fCurrentContour->segments().count()) {
3364        fCurrentContour->complete();
3365        fCurrentContour = NULL;
3366    }
3367}
3368
3369// FIXME:remove once we can access path pts directly
3370int preFetch() {
3371    SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
3372    SkPoint pts[4];
3373    SkPath::Verb verb;
3374    do {
3375        verb = iter.next(pts);
3376        *fPathVerbs.append() = verb;
3377        if (verb == SkPath::kMove_Verb) {
3378            *fPathPts.append() = pts[0];
3379        } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
3380            fPathPts.append(verb, &pts[1]);
3381        }
3382    } while (verb != SkPath::kDone_Verb);
3383    return fPathVerbs.count();
3384}
3385
3386void walk() {
3387    SkPath::Verb reducedVerb;
3388    uint8_t* verbPtr = fPathVerbs.begin();
3389    uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
3390    const SkPoint* pointsPtr = fPathPts.begin();
3391    const SkPoint* finalCurveStart = NULL;
3392    const SkPoint* finalCurveEnd = NULL;
3393    SkPath::Verb verb;
3394    while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
3395        switch (verb) {
3396            case SkPath::kMove_Verb:
3397                complete();
3398                if (!fCurrentContour) {
3399                    fCurrentContour = fContours.push_back_n(1);
3400                    fCurrentContour->setOperand(fOperand);
3401                    fCurrentContour->setXor(fXorMask == kEvenOdd_Mask);
3402                    *fExtra.append() = -1; // start new contour
3403                }
3404                finalCurveEnd = pointsPtr++;
3405                continue;
3406            case SkPath::kLine_Verb:
3407                // skip degenerate points
3408                if (pointsPtr[-1].fX != pointsPtr[0].fX
3409                        || pointsPtr[-1].fY != pointsPtr[0].fY) {
3410                    fCurrentContour->addLine(&pointsPtr[-1]);
3411                }
3412                break;
3413            case SkPath::kQuad_Verb:
3414
3415                reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
3416                if (reducedVerb == 0) {
3417                    break; // skip degenerate points
3418                }
3419                if (reducedVerb == 1) {
3420                    *fExtra.append() =
3421                            fCurrentContour->addLine(fReducePts.end() - 2);
3422                    break;
3423                }
3424                fCurrentContour->addQuad(&pointsPtr[-1]);
3425                break;
3426            case SkPath::kCubic_Verb:
3427                reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
3428                if (reducedVerb == 0) {
3429                    break; // skip degenerate points
3430                }
3431                if (reducedVerb == 1) {
3432                    *fExtra.append() =
3433                            fCurrentContour->addLine(fReducePts.end() - 2);
3434                    break;
3435                }
3436                if (reducedVerb == 2) {
3437                    *fExtra.append() =
3438                            fCurrentContour->addQuad(fReducePts.end() - 3);
3439                    break;
3440                }
3441                fCurrentContour->addCubic(&pointsPtr[-1]);
3442                break;
3443            case SkPath::kClose_Verb:
3444                SkASSERT(fCurrentContour);
3445                if (finalCurveStart && finalCurveEnd
3446                        && *finalCurveStart != *finalCurveEnd) {
3447                    *fReducePts.append() = *finalCurveStart;
3448                    *fReducePts.append() = *finalCurveEnd;
3449                    *fExtra.append() =
3450                            fCurrentContour->addLine(fReducePts.end() - 2);
3451                }
3452                complete();
3453                continue;
3454            default:
3455                SkDEBUGFAIL("bad verb");
3456                return;
3457        }
3458        finalCurveStart = &pointsPtr[verb - 1];
3459        pointsPtr += verb;
3460        SkASSERT(fCurrentContour);
3461        if (verbPtr == endOfFirstHalf) {
3462            fOperand = true;
3463        }
3464    }
3465}
3466
3467private:
3468    const SkPath* fPath;
3469    SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
3470    SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
3471    Contour* fCurrentContour;
3472    SkTArray<Contour>& fContours;
3473    SkTDArray<SkPoint> fReducePts; // segments created on the fly
3474    SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
3475    ShapeOpMask fXorMask;
3476    int fSecondHalf;
3477    bool fOperand;
3478};
3479
3480class Work {
3481public:
3482    enum SegmentType {
3483        kHorizontalLine_Segment = -1,
3484        kVerticalLine_Segment = 0,
3485        kLine_Segment = SkPath::kLine_Verb,
3486        kQuad_Segment = SkPath::kQuad_Verb,
3487        kCubic_Segment = SkPath::kCubic_Verb,
3488    };
3489
3490    void addCoincident(Work& other, const Intersections& ts, bool swap) {
3491        fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
3492    }
3493
3494    // FIXME: does it make sense to write otherIndex now if we're going to
3495    // fix it up later?
3496    void addOtherT(int index, double otherT, int otherIndex) {
3497        fContour->addOtherT(fIndex, index, otherT, otherIndex);
3498    }
3499
3500    // Avoid collapsing t values that are close to the same since
3501    // we walk ts to describe consecutive intersections. Since a pair of ts can
3502    // be nearly equal, any problems caused by this should be taken care
3503    // of later.
3504    // On the edge or out of range values are negative; add 2 to get end
3505    int addT(double newT, const Work& other) {
3506        return fContour->addT(fIndex, newT, other.fContour, other.fIndex);
3507    }
3508
3509    bool advance() {
3510        return ++fIndex < fLast;
3511    }
3512
3513    SkScalar bottom() const {
3514        return bounds().fBottom;
3515    }
3516
3517    const Bounds& bounds() const {
3518        return fContour->segments()[fIndex].bounds();
3519    }
3520
3521    const SkPoint* cubic() const {
3522        return fCubic;
3523    }
3524
3525    void init(Contour* contour) {
3526        fContour = contour;
3527        fIndex = 0;
3528        fLast = contour->segments().count();
3529    }
3530
3531    bool isAdjacent(const Work& next) {
3532        return fContour == next.fContour && fIndex + 1 == next.fIndex;
3533    }
3534
3535    bool isFirstLast(const Work& next) {
3536        return fContour == next.fContour && fIndex == 0
3537                && next.fIndex == fLast - 1;
3538    }
3539
3540    SkScalar left() const {
3541        return bounds().fLeft;
3542    }
3543
3544    void promoteToCubic() {
3545        fCubic[0] = pts()[0];
3546        fCubic[2] = pts()[1];
3547        fCubic[3] = pts()[2];
3548        fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
3549        fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
3550        fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
3551        fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
3552    }
3553
3554    const SkPoint* pts() const {
3555        return fContour->segments()[fIndex].pts();
3556    }
3557
3558    SkScalar right() const {
3559        return bounds().fRight;
3560    }
3561
3562    ptrdiff_t segmentIndex() const {
3563        return fIndex;
3564    }
3565
3566    SegmentType segmentType() const {
3567        const Segment& segment = fContour->segments()[fIndex];
3568        SegmentType type = (SegmentType) segment.verb();
3569        if (type != kLine_Segment) {
3570            return type;
3571        }
3572        if (segment.isHorizontal()) {
3573            return kHorizontalLine_Segment;
3574        }
3575        if (segment.isVertical()) {
3576            return kVerticalLine_Segment;
3577        }
3578        return kLine_Segment;
3579    }
3580
3581    bool startAfter(const Work& after) {
3582        fIndex = after.fIndex;
3583        return advance();
3584    }
3585
3586    SkScalar top() const {
3587        return bounds().fTop;
3588    }
3589
3590    SkPath::Verb verb() const {
3591        return fContour->segments()[fIndex].verb();
3592    }
3593
3594    SkScalar x() const {
3595        return bounds().fLeft;
3596    }
3597
3598    bool xFlipped() const {
3599        return x() != pts()[0].fX;
3600    }
3601
3602    SkScalar y() const {
3603        return bounds().fTop;
3604    }
3605
3606    bool yFlipped() const {
3607        return y() != pts()[0].fY;
3608    }
3609
3610protected:
3611    Contour* fContour;
3612    SkPoint fCubic[4];
3613    int fIndex;
3614    int fLast;
3615};
3616
3617#if DEBUG_ADD_INTERSECTING_TS
3618static void debugShowLineIntersection(int pts, const Work& wt,
3619        const Work& wn, const double wtTs[2], const double wnTs[2]) {
3620    if (!pts) {
3621        SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n",
3622                __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
3623                wt.pts()[1].fX, wt.pts()[1].fY, wn.pts()[0].fX, wn.pts()[0].fY,
3624                wn.pts()[1].fX, wn.pts()[1].fY);
3625        return;
3626    }
3627    SkPoint wtOutPt, wnOutPt;
3628    LineXYAtT(wt.pts(), wtTs[0], &wtOutPt);
3629    LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
3630    SkDebugf("%s wtTs[0]=%g (%g,%g, %g,%g) (%g,%g)",
3631            __FUNCTION__,
3632            wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
3633            wt.pts()[1].fX, wt.pts()[1].fY, wtOutPt.fX, wtOutPt.fY);
3634    if (pts == 2) {
3635        SkDebugf(" wtTs[1]=%g", wtTs[1]);
3636    }
3637    SkDebugf(" wnTs[0]=%g (%g,%g, %g,%g) (%g,%g)",
3638            wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
3639            wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
3640    if (pts == 2) {
3641        SkDebugf(" wnTs[1]=%g", wnTs[1]);
3642    }
3643    SkDebugf("\n");
3644}
3645#else
3646static void debugShowLineIntersection(int , const Work& ,
3647        const Work& , const double [2], const double [2]) {
3648}
3649#endif
3650
3651static bool addIntersectTs(Contour* test, Contour* next) {
3652
3653    if (test != next) {
3654        if (test->bounds().fBottom < next->bounds().fTop) {
3655            return false;
3656        }
3657        if (!Bounds::Intersects(test->bounds(), next->bounds())) {
3658            return true;
3659        }
3660    }
3661    Work wt;
3662    wt.init(test);
3663    bool foundCommonContour = test == next;
3664    do {
3665        Work wn;
3666        wn.init(next);
3667        if (test == next && !wn.startAfter(wt)) {
3668            continue;
3669        }
3670        do {
3671            if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
3672                continue;
3673            }
3674            int pts;
3675            Intersections ts;
3676            bool swap = false;
3677            switch (wt.segmentType()) {
3678                case Work::kHorizontalLine_Segment:
3679                    swap = true;
3680                    switch (wn.segmentType()) {
3681                        case Work::kHorizontalLine_Segment:
3682                        case Work::kVerticalLine_Segment:
3683                        case Work::kLine_Segment: {
3684                            pts = HLineIntersect(wn.pts(), wt.left(),
3685                                    wt.right(), wt.y(), wt.xFlipped(), ts);
3686                            debugShowLineIntersection(pts, wt, wn,
3687                                    ts.fT[1], ts.fT[0]);
3688                            break;
3689                        }
3690                        case Work::kQuad_Segment: {
3691                            pts = HQuadIntersect(wn.pts(), wt.left(),
3692                                    wt.right(), wt.y(), wt.xFlipped(), ts);
3693                            break;
3694                        }
3695                        case Work::kCubic_Segment: {
3696                            pts = HCubicIntersect(wn.pts(), wt.left(),
3697                                    wt.right(), wt.y(), wt.xFlipped(), ts);
3698                            break;
3699                        }
3700                        default:
3701                            SkASSERT(0);
3702                    }
3703                    break;
3704                case Work::kVerticalLine_Segment:
3705                    swap = true;
3706                    switch (wn.segmentType()) {
3707                        case Work::kHorizontalLine_Segment:
3708                        case Work::kVerticalLine_Segment:
3709                        case Work::kLine_Segment: {
3710                            pts = VLineIntersect(wn.pts(), wt.top(),
3711                                    wt.bottom(), wt.x(), wt.yFlipped(), ts);
3712                            debugShowLineIntersection(pts, wt, wn,
3713                                    ts.fT[1], ts.fT[0]);
3714                            break;
3715                        }
3716                        case Work::kQuad_Segment: {
3717                            pts = VQuadIntersect(wn.pts(), wt.top(),
3718                                    wt.bottom(), wt.x(), wt.yFlipped(), ts);
3719                            break;
3720                        }
3721                        case Work::kCubic_Segment: {
3722                            pts = VCubicIntersect(wn.pts(), wt.top(),
3723                                    wt.bottom(), wt.x(), wt.yFlipped(), ts);
3724                            break;
3725                        }
3726                        default:
3727                            SkASSERT(0);
3728                    }
3729                    break;
3730                case Work::kLine_Segment:
3731                    switch (wn.segmentType()) {
3732                        case Work::kHorizontalLine_Segment:
3733                            pts = HLineIntersect(wt.pts(), wn.left(),
3734                                    wn.right(), wn.y(), wn.xFlipped(), ts);
3735                            debugShowLineIntersection(pts, wt, wn,
3736                                    ts.fT[1], ts.fT[0]);
3737                            break;
3738                        case Work::kVerticalLine_Segment:
3739                            pts = VLineIntersect(wt.pts(), wn.top(),
3740                                    wn.bottom(), wn.x(), wn.yFlipped(), ts);
3741                            debugShowLineIntersection(pts, wt, wn,
3742                                    ts.fT[1], ts.fT[0]);
3743                            break;
3744                        case Work::kLine_Segment: {
3745                            pts = LineIntersect(wt.pts(), wn.pts(), ts);
3746                            debugShowLineIntersection(pts, wt, wn,
3747                                    ts.fT[1], ts.fT[0]);
3748                            break;
3749                        }
3750                        case Work::kQuad_Segment: {
3751                            swap = true;
3752                            pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
3753                            break;
3754                        }
3755                        case Work::kCubic_Segment: {
3756                            swap = true;
3757                            pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
3758                            break;
3759                        }
3760                        default:
3761                            SkASSERT(0);
3762                    }
3763                    break;
3764                case Work::kQuad_Segment:
3765                    switch (wn.segmentType()) {
3766                        case Work::kHorizontalLine_Segment:
3767                            pts = HQuadIntersect(wt.pts(), wn.left(),
3768                                    wn.right(), wn.y(), wn.xFlipped(), ts);
3769                            break;
3770                        case Work::kVerticalLine_Segment:
3771                            pts = VQuadIntersect(wt.pts(), wn.top(),
3772                                    wn.bottom(), wn.x(), wn.yFlipped(), ts);
3773                            break;
3774                        case Work::kLine_Segment: {
3775                            pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
3776                            break;
3777                        }
3778                        case Work::kQuad_Segment: {
3779                            pts = QuadIntersect(wt.pts(), wn.pts(), ts);
3780                            break;
3781                        }
3782                        case Work::kCubic_Segment: {
3783                            wt.promoteToCubic();
3784                            pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
3785                            break;
3786                        }
3787                        default:
3788                            SkASSERT(0);
3789                    }
3790                    break;
3791                case Work::kCubic_Segment:
3792                    switch (wn.segmentType()) {
3793                        case Work::kHorizontalLine_Segment:
3794                            pts = HCubicIntersect(wt.pts(), wn.left(),
3795                                    wn.right(), wn.y(), wn.xFlipped(), ts);
3796                            break;
3797                        case Work::kVerticalLine_Segment:
3798                            pts = VCubicIntersect(wt.pts(), wn.top(),
3799                                    wn.bottom(), wn.x(), wn.yFlipped(), ts);
3800                            break;
3801                        case Work::kLine_Segment: {
3802                            pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
3803                            break;
3804                        }
3805                        case Work::kQuad_Segment: {
3806                            wn.promoteToCubic();
3807                            pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
3808                            break;
3809                        }
3810                        case Work::kCubic_Segment: {
3811                            pts = CubicIntersect(wt.pts(), wn.pts(), ts);
3812                            break;
3813                        }
3814                        default:
3815                            SkASSERT(0);
3816                    }
3817                    break;
3818                default:
3819                    SkASSERT(0);
3820            }
3821            if (!foundCommonContour && pts > 0) {
3822                test->addCross(next);
3823                next->addCross(test);
3824                foundCommonContour = true;
3825            }
3826            // in addition to recording T values, record matching segment
3827            if (pts == 2) {
3828                if (wn.segmentType() <= Work::kLine_Segment
3829                        && wt.segmentType() <= Work::kLine_Segment) {
3830                    wt.addCoincident(wn, ts, swap);
3831                    continue;
3832                }
3833                if (wn.segmentType() == Work::kQuad_Segment
3834                        && wt.segmentType() == Work::kQuad_Segment
3835                        && ts.coincidentUsed() == 2) {
3836                    wt.addCoincident(wn, ts, swap);
3837                    continue;
3838                }
3839
3840            }
3841            int pt2 = 0;
3842            int pt2inc = 1;
3843            if (ts.fFlip) {
3844                pt2 = pts - 1;
3845                pt2inc = -1;
3846            }
3847            for (int pt = 0; pt < pts; ++pt) {
3848                SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
3849                SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
3850                int testTAt = wt.addT(ts.fT[swap][pt], wn);
3851                int nextTAt = wn.addT(ts.fT[!swap][pt], wt);
3852                wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
3853                wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
3854                pt2 += pt2inc;
3855            }
3856        } while (wn.advance());
3857    } while (wt.advance());
3858    return true;
3859}
3860
3861// resolve any coincident pairs found while intersecting, and
3862// see if coincidence is formed by clipping non-concident segments
3863static void coincidenceCheck(SkTDArray<Contour*>& contourList) {
3864    int contourCount = contourList.count();
3865    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
3866        Contour* contour = contourList[cIndex];
3867        contour->resolveCoincidence();
3868    }
3869    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
3870        Contour* contour = contourList[cIndex];
3871        contour->findTooCloseToCall();
3872    }
3873#if 0
3874    // OPTIMIZATION: this check could be folded in with findTooClose -- maybe
3875    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
3876        Contour* contour = contourList[cIndex];
3877        contour->collapseTriangles();
3878    }
3879#endif
3880}
3881
3882// project a ray from the top of the contour up and see if it hits anything
3883// note: when we compute line intersections, we keep track of whether
3884// two contours touch, so we need only look at contours not touching this one.
3885// OPTIMIZATION: sort contourList vertically to avoid linear walk
3886static int innerContourCheck(SkTDArray<Contour*>& contourList,
3887        const Segment* current, int index, int endIndex) {
3888    const SkPoint& basePt = current->xyAtT(endIndex);
3889    int contourCount = contourList.count();
3890    SkScalar bestY = SK_ScalarMin;
3891    const Segment* test = NULL;
3892    int tIndex;
3893    double tHit;
3894 //   bool checkCrosses = true;
3895    for (int cTest = 0; cTest < contourCount; ++cTest) {
3896        Contour* contour = contourList[cTest];
3897        if (basePt.fY < contour->bounds().fTop) {
3898            continue;
3899        }
3900        if (bestY > contour->bounds().fBottom) {
3901            continue;
3902        }
3903#if 0
3904        // even though the contours crossed, if spans cancel through concidence,
3905        // the contours may be not have any span links to chase, and the current
3906        // segment may be isolated. Detect this by seeing if current has
3907        // uninitialized wind sums. If so, project a ray instead of relying on
3908        // previously found intersections.
3909        if (baseContour == contour) {
3910            continue;
3911        }
3912        if (checkCrosses && baseContour->crosses(contour)) {
3913            if (current->isConnected(index, endIndex)) {
3914                continue;
3915            }
3916            checkCrosses = false;
3917        }
3918#endif
3919        const Segment* next = contour->crossedSegment(basePt, bestY, tIndex, tHit);
3920        if (next) {
3921            test = next;
3922        }
3923    }
3924    if (!test) {
3925        return 0;
3926    }
3927    int winding, windValue;
3928    // If the ray hit the end of a span, we need to construct the wheel of
3929    // angles to find the span closest to the ray -- even if there are just
3930    // two spokes on the wheel.
3931    const Angle* angle = NULL;
3932    if (approximately_zero(tHit - test->t(tIndex))) {
3933        SkTDArray<Angle> angles;
3934        int end = test->nextSpan(tIndex, 1);
3935        if (end < 0) {
3936            end = test->nextSpan(tIndex, -1);
3937        }
3938        test->addTwoAngles(end, tIndex, angles);
3939        SkASSERT(angles.count() > 0);
3940        if (angles[0].segment()->yAtT(angles[0].start()) >= basePt.fY) {
3941#if DEBUG_SORT
3942            SkDebugf("%s early return\n", __FUNCTION__);
3943#endif
3944            return 0;
3945        }
3946        test->buildAngles(tIndex, angles);
3947        SkTDArray<Angle*> sorted;
3948        // OPTIMIZATION: call a sort that, if base point is the leftmost,
3949        // returns the first counterclockwise hour before 6 o'clock,
3950        // or if the base point is rightmost, returns the first clockwise
3951        // hour after 6 o'clock
3952        sortAngles(angles, sorted);
3953#if DEBUG_SORT
3954        sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0);
3955#endif
3956        // walk the sorted angle fan to find the lowest angle
3957        // above the base point. Currently, the first angle in the sorted array
3958        // is 12 noon or an earlier hour (the next counterclockwise)
3959        int count = sorted.count();
3960        int left = -1;
3961        int mid = -1;
3962        int right = -1;
3963        bool baseMatches = test->yAtT(tIndex) == basePt.fY;
3964        for (int index = 0; index < count; ++index) {
3965            angle = sorted[index];
3966            if (baseMatches && angle->isHorizontal()) {
3967                continue;
3968            }
3969            double indexDx = angle->dx();
3970            test = angle->segment();
3971            if (test->verb() > SkPath::kLine_Verb && approximately_zero(indexDx)) {
3972                const SkPoint* pts = test->pts();
3973                indexDx = pts[2].fX - pts[1].fX - indexDx;
3974            }
3975            if (indexDx < 0) {
3976                left = index;
3977            } else if (indexDx > 0) {
3978                right = index;
3979                int previous = index - 1;
3980                if (previous < 0) {
3981                    previous = count - 1;
3982                }
3983                const Angle* prev = sorted[previous];
3984                if (prev->dy() >= 0 && prev->dx() > 0 && angle->dy() < 0) {
3985#if DEBUG_SORT
3986                    SkDebugf("%s use prev\n", __FUNCTION__);
3987#endif
3988                    right = previous;
3989                }
3990                break;
3991            } else {
3992                mid = index;
3993            }
3994        }
3995        if (left < 0 && right < 0) {
3996            left = mid;
3997        }
3998        SkASSERT(left >= 0 || right >= 0);
3999        if (left < 0) {
4000            left = right;
4001        } else if (left >= 0 && mid >= 0 && right >= 0
4002                && sorted[mid]->sign() == sorted[right]->sign()) {
4003            left = right;
4004        }
4005        angle = sorted[left];
4006        test = angle->segment();
4007        winding = test->windSum(angle);
4008        SkASSERT(winding != SK_MinS32);
4009        windValue = test->windValue(angle);
4010#if DEBUG_WINDING
4011        SkDebugf("%s angle winding=%d windValue=%d sign=%d\n", __FUNCTION__, winding,
4012                windValue, angle->sign());
4013#endif
4014    } else {
4015        winding = test->windSum(tIndex);
4016        SkASSERT(winding != SK_MinS32);
4017        windValue = test->windValue(tIndex);
4018#if DEBUG_WINDING
4019        SkDebugf("%s single winding=%d windValue=%d\n", __FUNCTION__, winding,
4020                windValue);
4021#endif
4022    }
4023    // see if a + change in T results in a +/- change in X (compute x'(T))
4024    SkScalar dx = (*SegmentDXAtT[test->verb()])(test->pts(), tHit);
4025    if (test->verb() > SkPath::kLine_Verb && approximately_zero(dx)) {
4026        const SkPoint* pts = test->pts();
4027        dx = pts[2].fX - pts[1].fX - dx;
4028    }
4029#if DEBUG_WINDING
4030    SkDebugf("%s dx=%1.9g\n", __FUNCTION__, dx);
4031#endif
4032    SkASSERT(dx != 0);
4033    if (winding * dx > 0) { // if same signs, result is negative
4034        winding += dx > 0 ? -windValue : windValue;
4035#if DEBUG_WINDING
4036        SkDebugf("%s final winding=%d\n", __FUNCTION__, winding);
4037#endif
4038    }
4039    return winding;
4040}
4041
4042// OPTIMIZATION: not crazy about linear search here to find top active y.
4043// seems like we should break down and do the sort, or maybe sort each
4044// contours' segments?
4045// Once the segment array is built, there's no reason I can think of not to
4046// sort it in Y. hmmm
4047// FIXME: return the contour found to pass to inner contour check
4048static Segment* findTopContour(SkTDArray<Contour*>& contourList) {
4049    int contourCount = contourList.count();
4050    int cIndex = 0;
4051    Segment* topStart;
4052    SkScalar bestY = SK_ScalarMax;
4053    Contour* contour;
4054    do {
4055        contour = contourList[cIndex];
4056        topStart = contour->topSegment(bestY);
4057    } while (!topStart && ++cIndex < contourCount);
4058    if (!topStart) {
4059        return NULL;
4060    }
4061    while (++cIndex < contourCount) {
4062        contour = contourList[cIndex];
4063        if (bestY < contour->bounds().fTop) {
4064            continue;
4065        }
4066        SkScalar testY = SK_ScalarMax;
4067        Segment* test = contour->topSegment(testY);
4068        if (!test || bestY <= testY) {
4069            continue;
4070        }
4071        topStart = test;
4072        bestY = testY;
4073    }
4074    return topStart;
4075}
4076
4077static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
4078    int contourCount = contourList.count();
4079    Segment* result;
4080    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
4081        Contour* contour = contourList[cIndex];
4082        result = contour->undoneSegment(start, end);
4083        if (result) {
4084            return result;
4085        }
4086    }
4087    return NULL;
4088}
4089
4090
4091
4092static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex,
4093        int contourWinding) {
4094    while (chase.count()) {
4095        Span* span = chase[chase.count() - 1];
4096        const Span& backPtr = span->fOther->span(span->fOtherIndex);
4097        Segment* segment = backPtr.fOther;
4098        tIndex = backPtr.fOtherIndex;
4099        SkTDArray<Angle> angles;
4100        int done = 0;
4101        if (segment->activeAngle(tIndex, done, angles)) {
4102            Angle* last = angles.end() - 1;
4103            tIndex = last->start();
4104            endIndex = last->end();
4105            return last->segment();
4106        }
4107        if (done == angles.count()) {
4108            chase.pop(&span);
4109            continue;
4110        }
4111        SkTDArray<Angle*> sorted;
4112        sortAngles(angles, sorted);
4113#if DEBUG_SORT
4114        sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0);
4115#endif
4116        // find first angle, initialize winding to computed fWindSum
4117        int firstIndex = -1;
4118        const Angle* angle;
4119        int winding;
4120        do {
4121            angle = sorted[++firstIndex];
4122            segment = angle->segment();
4123            winding = segment->windSum(angle);
4124        } while (winding == SK_MinS32);
4125        int spanWinding = segment->spanSign(angle->start(), angle->end());
4126    #if DEBUG_WINDING
4127        SkDebugf("%s winding=%d spanWinding=%d contourWinding=%d\n",
4128                __FUNCTION__, winding, spanWinding, contourWinding);
4129    #endif
4130        // turn swinding into contourWinding
4131        if (spanWinding * winding < 0) {
4132            winding += spanWinding;
4133        }
4134    #if DEBUG_SORT
4135        segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding);
4136    #endif
4137        // we care about first sign and whether wind sum indicates this
4138        // edge is inside or outside. Maybe need to pass span winding
4139        // or first winding or something into this function?
4140        // advance to first undone angle, then return it and winding
4141        // (to set whether edges are active or not)
4142        int nextIndex = firstIndex + 1;
4143        int angleCount = sorted.count();
4144        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
4145        angle = sorted[firstIndex];
4146        winding -= angle->segment()->spanSign(angle);
4147        do {
4148            SkASSERT(nextIndex != firstIndex);
4149            if (nextIndex == angleCount) {
4150                nextIndex = 0;
4151            }
4152            angle = sorted[nextIndex];
4153            segment = angle->segment();
4154            int maxWinding = winding;
4155            winding -= segment->spanSign(angle);
4156    #if DEBUG_SORT
4157            SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
4158                    segment->debugID(), maxWinding, winding, angle->sign());
4159    #endif
4160            tIndex = angle->start();
4161            endIndex = angle->end();
4162            int lesser = SkMin32(tIndex, endIndex);
4163            const Span& nextSpan = segment->span(lesser);
4164            if (!nextSpan.fDone) {
4165#if 1
4166            // FIXME: this be wrong. assign startWinding if edge is in
4167            // same direction. If the direction is opposite, winding to
4168            // assign is flipped sign or +/- 1?
4169                if (useInnerWinding(maxWinding, winding)) {
4170                    maxWinding = winding;
4171                }
4172                segment->markWinding(lesser, maxWinding);
4173#endif
4174                break;
4175            }
4176        } while (++nextIndex != lastIndex);
4177        return segment;
4178    }
4179    return NULL;
4180}
4181
4182#if DEBUG_ACTIVE_SPANS
4183static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
4184    int index;
4185    for (index = 0; index < contourList.count(); ++ index) {
4186        contourList[index]->debugShowActiveSpans();
4187    }
4188    for (index = 0; index < contourList.count(); ++ index) {
4189        contourList[index]->validateActiveSpans();
4190    }
4191}
4192#endif
4193
4194static bool windingIsActive(int winding, int spanWinding) {
4195    return winding * spanWinding <= 0 && abs(winding) <= abs(spanWinding)
4196            && (!winding || !spanWinding || winding == -spanWinding);
4197}
4198
4199// Each segment may have an inside or an outside. Segments contained within
4200// winding may have insides on either side, and form a contour that should be
4201// ignored. Segments that are coincident with opposing direction segments may
4202// have outsides on either side, and should also disappear.
4203// 'Normal' segments will have one inside and one outside. Subsequent connections
4204// when winding should follow the intersection direction. If more than one edge
4205// is an option, choose first edge that continues the inside.
4206    // since we start with leftmost top edge, we'll traverse through a
4207    // smaller angle counterclockwise to get to the next edge.
4208static void bridgeWinding(SkTDArray<Contour*>& contourList, SkPath& simple) {
4209    bool firstContour = true;
4210    do {
4211        Segment* topStart = findTopContour(contourList);
4212        if (!topStart) {
4213            break;
4214        }
4215        // Start at the top. Above the top is outside, below is inside.
4216        // follow edges to intersection by changing the index by direction.
4217        int index, endIndex;
4218        Segment* current = topStart->findTop(index, endIndex);
4219        int contourWinding;
4220        if (firstContour) {
4221            contourWinding = 0;
4222            firstContour = false;
4223        } else {
4224            int sumWinding = current->windSum(SkMin32(index, endIndex));
4225            // FIXME: don't I have to adjust windSum to get contourWinding?
4226            if (sumWinding == SK_MinS32) {
4227                sumWinding = current->computeSum(index, endIndex);
4228            }
4229            if (sumWinding == SK_MinS32) {
4230                contourWinding = innerContourCheck(contourList, current,
4231                        index, endIndex);
4232            } else {
4233                contourWinding = sumWinding;
4234                int spanWinding = current->spanSign(index, endIndex);
4235                bool inner = useInnerWinding(sumWinding - spanWinding, sumWinding);
4236                if (inner) {
4237                    contourWinding -= spanWinding;
4238                }
4239#if DEBUG_WINDING
4240                SkDebugf("%s sumWinding=%d spanWinding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
4241                        sumWinding, spanWinding, SkSign32(index - endIndex),
4242                        inner, contourWinding);
4243#endif
4244            }
4245#if DEBUG_WINDING
4246         //   SkASSERT(current->debugVerifyWinding(index, endIndex, contourWinding));
4247            SkDebugf("%s contourWinding=%d\n", __FUNCTION__, contourWinding);
4248#endif
4249        }
4250        SkPoint lastPt;
4251        int winding = contourWinding;
4252        int spanWinding = current->spanSign(index, endIndex);
4253        // FIXME: needs work. While it works in limited situations, it does
4254        // not always compute winding correctly. Active should be removed and instead
4255        // the initial winding should be correctly passed in so that if the
4256        // inner contour is wound the same way, it never finds an accumulated
4257        // winding of zero. Inside 'find next', we need to look for transitions
4258        // other than zero when resolving sorted angles.
4259        bool active = windingIsActive(winding, spanWinding);
4260        SkTDArray<Span*> chaseArray;
4261        do {
4262        #if DEBUG_WINDING
4263            SkDebugf("%s active=%s winding=%d spanWinding=%d\n",
4264                    __FUNCTION__, active ? "true" : "false",
4265                    winding, spanWinding);
4266        #endif
4267            const SkPoint* firstPt = NULL;
4268            do {
4269                SkASSERT(!current->done());
4270                int nextStart = index;
4271                int nextEnd = endIndex;
4272                Segment* next = current->findNextWinding(chaseArray, active,
4273                        nextStart, nextEnd, winding, spanWinding);
4274                if (!next) {
4275                    if (active && firstPt && current->verb() != SkPath::kLine_Verb && *firstPt != lastPt) {
4276                        lastPt = current->addCurveTo(index, endIndex, simple, true);
4277                        SkASSERT(*firstPt == lastPt);
4278                    }
4279                    break;
4280                }
4281                if (!firstPt) {
4282                    firstPt = &current->addMoveTo(index, simple, active);
4283                }
4284                lastPt = current->addCurveTo(index, endIndex, simple, active);
4285                current = next;
4286                index = nextStart;
4287                endIndex = nextEnd;
4288            } while (*firstPt != lastPt && (active || !current->done()));
4289            if (firstPt && active) {
4290        #if DEBUG_PATH_CONSTRUCTION
4291                SkDebugf("path.close();\n");
4292        #endif
4293                simple.close();
4294            }
4295            current = findChase(chaseArray, index, endIndex, contourWinding);
4296        #if DEBUG_ACTIVE_SPANS
4297            debugShowActiveSpans(contourList);
4298        #endif
4299            if (!current) {
4300                break;
4301            }
4302            int lesser = SkMin32(index, endIndex);
4303            spanWinding = current->spanSign(index, endIndex);
4304            winding = current->windSum(lesser);
4305            bool inner = useInnerWinding(winding - spanWinding, winding);
4306        #if DEBUG_WINDING
4307            SkDebugf("%s id=%d t=%1.9g spanWinding=%d winding=%d sign=%d"
4308                    " inner=%d result=%d\n",
4309                    __FUNCTION__, current->debugID(), current->t(lesser),
4310                    spanWinding, winding, SkSign32(index - endIndex),
4311                    useInnerWinding(winding - spanWinding, winding),
4312                    inner ? winding - spanWinding : winding);
4313        #endif
4314            if (inner) {
4315                winding -= spanWinding;
4316            }
4317            active = windingIsActive(winding, spanWinding);
4318        } while (true);
4319    } while (true);
4320}
4321
4322static void bridgeXor(SkTDArray<Contour*>& contourList, SkPath& simple) {
4323    Segment* current;
4324    int start, end;
4325    while ((current = findUndone(contourList, start, end))) {
4326        const SkPoint* firstPt = NULL;
4327        SkPoint lastPt;
4328        do {
4329            SkASSERT(!current->done());
4330            int nextStart = start;
4331            int nextEnd = end;
4332            Segment* next = current->findNextXor(nextStart, nextEnd);
4333            if (!next) {
4334                if (firstPt && current->verb() != SkPath::kLine_Verb && *firstPt != lastPt) {
4335                    lastPt = current->addCurveTo(start, end, simple, true);
4336                    SkASSERT(*firstPt == lastPt);
4337                }
4338                break;
4339            }
4340            if (!firstPt) {
4341                firstPt = &current->addMoveTo(start, simple, true);
4342            }
4343            lastPt = current->addCurveTo(start, end, simple, true);
4344            current = next;
4345            start = nextStart;
4346            end = nextEnd;
4347        } while (*firstPt != lastPt);
4348        if (firstPt) {
4349    #if DEBUG_PATH_CONSTRUCTION
4350            SkDebugf("%s close\n", __FUNCTION__);
4351    #endif
4352            simple.close();
4353        }
4354    #if DEBUG_ACTIVE_SPANS
4355        debugShowActiveSpans(contourList);
4356    #endif
4357    }
4358}
4359
4360static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
4361    int contourCount = contourList.count();
4362    for (int cTest = 0; cTest < contourCount; ++cTest) {
4363        Contour* contour = contourList[cTest];
4364        contour->fixOtherTIndex();
4365    }
4366}
4367
4368static void makeContourList(SkTArray<Contour>& contours,
4369        SkTDArray<Contour*>& list) {
4370    int count = contours.count();
4371    if (count == 0) {
4372        return;
4373    }
4374    for (int index = 0; index < count; ++index) {
4375        *list.append() = &contours[index];
4376    }
4377    QSort<Contour>(list.begin(), list.end() - 1);
4378}
4379
4380void simplifyx(const SkPath& path, SkPath& simple) {
4381    // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
4382    simple.reset();
4383    simple.setFillType(SkPath::kEvenOdd_FillType);
4384
4385    // turn path into list of segments
4386    SkTArray<Contour> contours;
4387    // FIXME: add self-intersecting cubics' T values to segment
4388    EdgeBuilder builder(path, contours);
4389    builder.finish();
4390    SkTDArray<Contour*> contourList;
4391    makeContourList(contours, contourList);
4392    Contour** currentPtr = contourList.begin();
4393    if (!currentPtr) {
4394        return;
4395    }
4396    Contour** listEnd = contourList.end();
4397    // find all intersections between segments
4398    do {
4399        Contour** nextPtr = currentPtr;
4400        Contour* current = *currentPtr++;
4401        Contour* next;
4402        do {
4403            next = *nextPtr++;
4404        } while (addIntersectTs(current, next) && nextPtr != listEnd);
4405    } while (currentPtr != listEnd);
4406    // eat through coincident edges
4407    coincidenceCheck(contourList);
4408    fixOtherTIndex(contourList);
4409    // construct closed contours
4410    if (builder.xorMask() == kWinding_Mask) {
4411        bridgeWinding(contourList, simple);
4412    } else {
4413        bridgeXor(contourList, simple);
4414    }
4415}
4416
4417