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