1fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com/*
2fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com * Copyright 2012 Google Inc.
3fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com *
4fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com * Use of this source code is governed by a BSD-style license that can be
5fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com * found in the LICENSE file.
6fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com */
7b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com#include "Simplify.h"
8fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
9fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#undef SkASSERT
10fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#define SkASSERT(cond) while (!(cond)) { sk_throw(); }
11fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
1215fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com// Terminology:
1315fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com// A Path contains one of more Contours
1415fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com// A Contour is made up of Segment array
15b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com// A Segment is described by a Verb and a Point array with 2, 3, or 4 points
16b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com// A Verb is one of Line, Quad(ratic), or Cubic
1715fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com// A Segment contains a Span array
1815fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com// A Span is describes a portion of a Segment using starting and ending T
1915fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com// T values range from 0 to 1, where 0 is the first Point in the Segment
2047580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com// An Edge is a Segment generated from a Span
2115fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com
22fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com// FIXME: remove once debugging is complete
2347580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com#ifdef SK_DEBUG
2447580694fbe974a065caf7c39c3d2075708c2018caryclark@google.comint gDebugMaxWindSum = SK_MaxS32;
2547580694fbe974a065caf7c39c3d2075708c2018caryclark@google.comint gDebugMaxWindValue = SK_MaxS32;
2647580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com#endif
2747580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com
28f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com#define PIN_ADD_T 0
290b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com#define TRY_ROTATE 1
308f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#define ONE_PASS_COINCIDENCE_CHECK 0
3173ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com#define APPROXIMATE_CUBICS 1
32d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define COMPACT_DEBUG_SORT 0
33a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com
3447580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com#define DEBUG_UNUSED 0 // set to expose unused functions
3545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com
3631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com#if FORCE_RELEASE || defined SK_RELEASE
37fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
3847580694fbe974a065caf7c39c3d2075708c2018caryclark@google.comconst bool gRunTestsInOneThread = false;
39fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
40beda389e646d6be3cfef853584a78ca8ba39d0fccaryclark@google.com#define DEBUG_ACTIVE_OP 0
4147580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com#define DEBUG_ACTIVE_SPANS 0
424eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0
43fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#define DEBUG_ADD_INTERSECTING_TS 0
4447580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com#define DEBUG_ADD_T_PAIR 0
45c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com#define DEBUG_ANGLE 0
467ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com#define DEBUG_AS_C_CODE 1
47e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#define DEBUG_ASSEMBLE 0
4847580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com#define DEBUG_CONCIDENT 0
498dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com#define DEBUG_CROSS 0
50e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#define DEBUG_FLOW 0
5147580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com#define DEBUG_MARK_DONE 0
52f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com#define DEBUG_PATH_CONSTRUCTION 0
53729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com#define DEBUG_SHOW_WINDING 0
54c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com#define DEBUG_SORT 0
555e0500fb5f17fe14db42fc3e0aad08e6b41ccc5fcaryclark@google.com#define DEBUG_SWAP_TOP 0
568f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#define DEBUG_UNSORTABLE 0
57afe56de6361a81eef537ddd8f6d5626c8546d4c7caryclark@google.com#define DEBUG_WIND_BUMP 0
588dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com#define DEBUG_WINDING 0
598f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#define DEBUG_WINDING_AT_T 0
60fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
61fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#else
62fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
6347580694fbe974a065caf7c39c3d2075708c2018caryclark@google.comconst bool gRunTestsInOneThread = true;
64fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
65beda389e646d6be3cfef853584a78ca8ba39d0fccaryclark@google.com#define DEBUG_ACTIVE_OP 1
66c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com#define DEBUG_ACTIVE_SPANS 1
671304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0
686aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com#define DEBUG_ADD_INTERSECTING_TS 1
696aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com#define DEBUG_ADD_T_PAIR 1
703350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com#define DEBUG_ANGLE 1
714aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com#define DEBUG_AS_C_CODE 1
72e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#define DEBUG_ASSEMBLE 1
733350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com#define DEBUG_CONCIDENT 1
74534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com#define DEBUG_CROSS 0
75e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#define DEBUG_FLOW 1
763350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com#define DEBUG_MARK_DONE 1
7765f9f0a1664a9cb38157ccfbcc3e0e936af0a58ecaryclark@google.com#define DEBUG_PATH_CONSTRUCTION 1
78729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com#define DEBUG_SHOW_WINDING 0
7947580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com#define DEBUG_SORT 1
8047d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com#define DEBUG_SWAP_TOP 1
818f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#define DEBUG_UNSORTABLE 1
82afe56de6361a81eef537ddd8f6d5626c8546d4c7caryclark@google.com#define DEBUG_WIND_BUMP 0
8347580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com#define DEBUG_WINDING 1
848f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#define DEBUG_WINDING_AT_T 1
85fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
86fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#endif
87fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
88beda389e646d6be3cfef853584a78ca8ba39d0fccaryclark@google.com#define DEBUG_DUMP (DEBUG_ACTIVE_OP | DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | \
89beda389e646d6be3cfef853584a78ca8ba39d0fccaryclark@google.com        DEBUG_PATH_CONSTRUCTION)
90027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com
91d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#if DEBUG_AS_C_CODE
92d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define CUBIC_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}}"
93d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define QUAD_DEBUG_STR  "{{%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}}"
94d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define LINE_DEBUG_STR  "{{%1.17g,%1.17g}, {%1.17g,%1.17g}}"
95d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define PT_DEBUG_STR "{{%1.17g,%1.17g}}"
96d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#else
97d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define CUBIC_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
98d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define QUAD_DEBUG_STR  "(%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
99d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define LINE_DEBUG_STR  "(%1.9g,%1.9g %1.9g,%1.9g)"
100d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define PT_DEBUG_STR "(%1.9g,%1.9g)"
101d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#endif
102d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define T_DEBUG_STR(t, n) #t "[" #n "]=%1.9g"
103d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define TX_DEBUG_STR(t) #t "[%d]=%1.9g"
104d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define CUBIC_DEBUG_DATA(c) c[0].fX, c[0].fY, c[1].fX, c[1].fY, c[2].fX, c[2].fY, c[3].fX, c[3].fY
105d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define QUAD_DEBUG_DATA(q)  q[0].fX, q[0].fY, q[1].fX, q[1].fY, q[2].fX, q[2].fY
106d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define LINE_DEBUG_DATA(l)  l[0].fX, l[0].fY, l[1].fX, l[1].fY
107d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com#define PT_DEBUG_DATA(i, n) i.fPt[n].x, i.fPt[n].y
108d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com
109fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#if DEBUG_DUMP
110fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
11165f9f0a1664a9cb38157ccfbcc3e0e936af0a58ecaryclark@google.com// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
112fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic int gContourID;
113fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic int gSegmentID;
114fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#endif
115fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
1161304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com#if DEBUG_SORT || DEBUG_SWAP_TOP
1174aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.comstatic int gDebugSortCountDefault = SK_MaxS32;
118c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.comstatic int gDebugSortCount;
119c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com#endif
120c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com
1215e0500fb5f17fe14db42fc3e0aad08e6b41ccc5fcaryclark@google.com#if DEBUG_ACTIVE_OP
1225e0500fb5f17fe14db42fc3e0aad08e6b41ccc5fcaryclark@google.comstatic const char* kShapeOpStr[] = {"diff", "sect", "union", "xor"};
1235e0500fb5f17fe14db42fc3e0aad08e6b41ccc5fcaryclark@google.com#endif
1245e0500fb5f17fe14db42fc3e0aad08e6b41ccc5fcaryclark@google.com
1258dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com#ifndef DEBUG_TEST
1268dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com#define DEBUG_TEST 0
1278dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com#endif
1288dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
12932546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com#define MAKE_CONST_LINE(line, pts) \
13032546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}
13132546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com#define MAKE_CONST_QUAD(quad, pts) \
13232546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
13332546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com            {pts[2].fX, pts[2].fY}}
13432546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com#define MAKE_CONST_CUBIC(cubic, pts) \
13532546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
13632546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com            {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}}
13732546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com
138fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic int LineIntersect(const SkPoint a[2], const SkPoint b[2],
139fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        Intersections& intersections) {
14032546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_LINE(aLine, a);
14132546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_LINE(bLine, b);
14245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    return intersect(aLine, bLine, intersections);
143fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
144fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
145fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
146fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        Intersections& intersections) {
14732546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_QUAD(aQuad, a);
14832546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_LINE(bLine, b);
1493350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    return intersect(aQuad, bLine, intersections);
150fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
151fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
15232546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.comstatic int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2],
153fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        Intersections& intersections) {
15432546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_CUBIC(aCubic, a);
15532546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_LINE(bLine, b);
15673ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    return intersect(aCubic, bLine, intersections);
157fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
158fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
159fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
160fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        Intersections& intersections) {
16132546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_QUAD(aQuad, a);
16232546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_QUAD(bQuad, b);
163235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#define TRY_QUARTIC_SOLUTION 1
164235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#if TRY_QUARTIC_SOLUTION
165235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    intersect2(aQuad, bQuad, intersections);
166235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#else
167fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    intersect(aQuad, bQuad, intersections);
168235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#endif
16945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    return intersections.fUsed;
170fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
171fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
17273ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com#if APPROXIMATE_CUBICS
17373ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.comstatic int CubicQuadIntersect(const SkPoint a[4], const SkPoint b[3],
174fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        Intersections& intersections) {
17532546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_CUBIC(aCubic, a);
17673ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    MAKE_CONST_QUAD(bQuad, b);
17773ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    return intersect(aCubic, bQuad, intersections);
17873ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com}
17973ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com#endif
18073ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com
18173ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.comstatic int CubicIntersect(const SkPoint a[4], const SkPoint b[4], Intersections& intersections) {
18273ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    MAKE_CONST_CUBIC(aCubic, a);
18332546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_CUBIC(bCubic, b);
18473ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com#if APPROXIMATE_CUBICS
18545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    intersect3(aCubic, bCubic, intersections);
18673ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com#else
187fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    intersect(aCubic, bCubic, intersections);
18873ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com#endif
18945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    return intersections.fUsed;
190fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
191fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
192c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.comstatic int CubicIntersect(const SkPoint a[4], Intersections& intersections) {
193c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    MAKE_CONST_CUBIC(aCubic, a);
194c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    return intersect(aCubic, intersections);
195c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com}
196c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com
197fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
198fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkScalar y, bool flipped, Intersections& intersections) {
19932546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_LINE(aLine, a);
200fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return horizontalIntersect(aLine, left, right, y, flipped, intersections);
201fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
202fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
203fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
204fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkScalar y, bool flipped, Intersections& intersections) {
20532546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_QUAD(aQuad, a);
206fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return horizontalIntersect(aQuad, left, right, y, flipped, intersections);
207fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
208fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
209fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
210fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkScalar y, bool flipped, Intersections& intersections) {
21132546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_CUBIC(aCubic, a);
212fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return horizontalIntersect(aCubic, left, right, y, flipped, intersections);
213fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
214fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
215e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.comstatic int (* const HSegmentIntersect[])(const SkPoint [], SkScalar ,
216e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        SkScalar , SkScalar , bool , Intersections& ) = {
217e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    NULL,
218e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    HLineIntersect,
219e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    HQuadIntersect,
220e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    HCubicIntersect
221e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com};
222e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com
2238dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.comstatic int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom,
2248dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        SkScalar x, bool flipped, Intersections& intersections) {
22532546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_LINE(aLine, a);
2268dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    return verticalIntersect(aLine, top, bottom, x, flipped, intersections);
2278dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com}
2288dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
2298dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.comstatic int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom,
2308dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        SkScalar x, bool flipped, Intersections& intersections) {
23132546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_QUAD(aQuad, a);
2328dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    return verticalIntersect(aQuad, top, bottom, x, flipped, intersections);
2338dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com}
2348dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
2358dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.comstatic int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom,
2368dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        SkScalar x, bool flipped, Intersections& intersections) {
23732546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_CUBIC(aCubic, a);
2388dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    return verticalIntersect(aCubic, top, bottom, x, flipped, intersections);
239fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
240fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
2418dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.comstatic int (* const VSegmentIntersect[])(const SkPoint [], SkScalar ,
2428dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        SkScalar , SkScalar , bool , Intersections& ) = {
2438dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    NULL,
2448dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    VLineIntersect,
2458dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    VQuadIntersect,
2468dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    VCubicIntersect
2478dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com};
2488dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
249fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
25032546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_LINE(line, a);
251fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    double x, y;
252fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    xy_at_t(line, t, x, y);
253fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    out->fX = SkDoubleToScalar(x);
254fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    out->fY = SkDoubleToScalar(y);
255fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
256fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
257f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.comstatic void LineXYAtT(const SkPoint a[2], double t, _Point* out) {
258f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    MAKE_CONST_LINE(line, a);
259f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    xy_at_t(line, t, out->x, out->y);
260f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com}
261f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com
262fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
26332546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_QUAD(quad, a);
264fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    double x, y;
265fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    xy_at_t(quad, t, x, y);
266fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    out->fX = SkDoubleToScalar(x);
267fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    out->fY = SkDoubleToScalar(y);
268fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
269fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
2706aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.comstatic void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
2716aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    MAKE_CONST_QUAD(quad, a);
2726aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    xy_at_t(quad, t, out->x, out->y);
2736aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com}
2746aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com
275fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
27632546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_CUBIC(cubic, a);
277fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    double x, y;
278fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    xy_at_t(cubic, t, x, y);
279fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    out->fX = SkDoubleToScalar(x);
280fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    out->fY = SkDoubleToScalar(y);
281fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
282fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
283f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.comstatic void CubicXYAtT(const SkPoint a[4], double t, _Point* out) {
284f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    MAKE_CONST_CUBIC(cubic, a);
285f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    xy_at_t(cubic, t, out->x, out->y);
286f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com}
287f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com
288fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
289fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    NULL,
290fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    LineXYAtT,
291fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    QuadXYAtT,
292fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    CubicXYAtT
293fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com};
294fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
295f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.comstatic void (* const SegmentXYAtT2[])(const SkPoint [], double , _Point* ) = {
296f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    NULL,
297f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    LineXYAtT,
298f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    QuadXYAtT,
299f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    CubicXYAtT
300f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com};
301f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com
302fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic SkScalar LineXAtT(const SkPoint a[2], double t) {
30332546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_LINE(aLine, a);
304fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    double x;
305fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    xy_at_t(aLine, t, x, *(double*) 0);
306fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return SkDoubleToScalar(x);
307fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
308fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
309fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic SkScalar QuadXAtT(const SkPoint a[3], double t) {
31032546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_QUAD(quad, a);
311fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    double x;
312fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    xy_at_t(quad, t, x, *(double*) 0);
313fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return SkDoubleToScalar(x);
314fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
315fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
316fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic SkScalar CubicXAtT(const SkPoint a[4], double t) {
31732546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_CUBIC(cubic, a);
318fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    double x;
319fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    xy_at_t(cubic, t, x, *(double*) 0);
320fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return SkDoubleToScalar(x);
321fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
322fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
323fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
324fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    NULL,
325fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    LineXAtT,
326fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    QuadXAtT,
327fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    CubicXAtT
328fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com};
329fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
330fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic SkScalar LineYAtT(const SkPoint a[2], double t) {
33132546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_LINE(aLine, a);
332fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    double y;
333fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    xy_at_t(aLine, t, *(double*) 0, y);
334fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return SkDoubleToScalar(y);
335fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
336fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
337fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic SkScalar QuadYAtT(const SkPoint a[3], double t) {
33832546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_QUAD(quad, a);
339fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    double y;
340fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    xy_at_t(quad, t, *(double*) 0, y);
341fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return SkDoubleToScalar(y);
342fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
343fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
344fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic SkScalar CubicYAtT(const SkPoint a[4], double t) {
34532546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_CUBIC(cubic, a);
346fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    double y;
347fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    xy_at_t(cubic, t, *(double*) 0, y);
348fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return SkDoubleToScalar(y);
349fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
350fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
351fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
352fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    NULL,
353fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    LineYAtT,
354fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    QuadYAtT,
355fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    CubicYAtT
356fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com};
357fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
3588dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.comstatic SkScalar LineDXAtT(const SkPoint a[2], double ) {
3598dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    return a[1].fX - a[0].fX;
3608dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com}
3618dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
3628dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.comstatic SkScalar QuadDXAtT(const SkPoint a[3], double t) {
36332546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_QUAD(quad, a);
36405c4bad470722bc4e5e6ae3d79aa8bcf9e732f06caryclark@google.com    double x = dx_at_t(quad, t);
3658dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    return SkDoubleToScalar(x);
3668dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com}
3678dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
3688dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.comstatic SkScalar CubicDXAtT(const SkPoint a[4], double t) {
36932546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_CUBIC(cubic, a);
37005c4bad470722bc4e5e6ae3d79aa8bcf9e732f06caryclark@google.com    double x = dx_at_t(cubic, t);
3718dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    return SkDoubleToScalar(x);
3728dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com}
3738dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
3748dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.comstatic SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
3758dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    NULL,
3768dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    LineDXAtT,
3778dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    QuadDXAtT,
3788dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    CubicDXAtT
3798dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com};
3808dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
381e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.comstatic SkScalar LineDYAtT(const SkPoint a[2], double ) {
382e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    return a[1].fY - a[0].fY;
383e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com}
384e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com
385e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.comstatic SkScalar QuadDYAtT(const SkPoint a[3], double t) {
386e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    MAKE_CONST_QUAD(quad, a);
38705c4bad470722bc4e5e6ae3d79aa8bcf9e732f06caryclark@google.com    double y = dy_at_t(quad, t);
388e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    return SkDoubleToScalar(y);
389e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com}
390e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com
391e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.comstatic SkScalar CubicDYAtT(const SkPoint a[4], double t) {
392e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    MAKE_CONST_CUBIC(cubic, a);
39305c4bad470722bc4e5e6ae3d79aa8bcf9e732f06caryclark@google.com    double y = dy_at_t(cubic, t);
394e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    return SkDoubleToScalar(y);
395e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com}
396e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com
397e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.comstatic SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = {
398e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    NULL,
399e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    LineDYAtT,
400e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    QuadDYAtT,
401e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    CubicDYAtT
402e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com};
403e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com
4047ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.comstatic SkVector LineDXDYAtT(const SkPoint a[2], double ) {
40545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    return a[1] - a[0];
40645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com}
40745a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com
4087ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.comstatic SkVector QuadDXDYAtT(const SkPoint a[3], double t) {
40945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    MAKE_CONST_QUAD(quad, a);
4107ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com    _Vector v = dxdy_at_t(quad, t);
4117ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com    return v.asSkVector();
41245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com}
41345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com
4147ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.comstatic SkVector CubicDXDYAtT(const SkPoint a[4], double t) {
41545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    MAKE_CONST_CUBIC(cubic, a);
4167ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com    _Vector v = dxdy_at_t(cubic, t);
4177ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com    return v.asSkVector();
41845a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com}
41945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com
4207ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.comstatic SkVector (* const SegmentDXDYAtT[])(const SkPoint [], double ) = {
42145a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    NULL,
42245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    LineDXDYAtT,
42345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    QuadDXDYAtT,
42445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    CubicDXDYAtT
42545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com};
42645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com
427fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic void LineSubDivide(const SkPoint a[2], double startT, double endT,
428fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkPoint sub[2]) {
42932546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_LINE(aLine, a);
430fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    _Line dst;
431fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub_divide(aLine, startT, endT, dst);
432fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[0].fX = SkDoubleToScalar(dst[0].x);
433fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[0].fY = SkDoubleToScalar(dst[0].y);
434fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[1].fX = SkDoubleToScalar(dst[1].x);
435fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[1].fY = SkDoubleToScalar(dst[1].y);
436fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
437fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
438fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic void QuadSubDivide(const SkPoint a[3], double startT, double endT,
439fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkPoint sub[3]) {
44032546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_QUAD(aQuad, a);
441fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    Quadratic dst;
442fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub_divide(aQuad, startT, endT, dst);
443fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[0].fX = SkDoubleToScalar(dst[0].x);
444fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[0].fY = SkDoubleToScalar(dst[0].y);
445fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[1].fX = SkDoubleToScalar(dst[1].x);
446fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[1].fY = SkDoubleToScalar(dst[1].y);
447fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[2].fX = SkDoubleToScalar(dst[2].x);
448fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[2].fY = SkDoubleToScalar(dst[2].y);
449fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
450fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
451fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic void CubicSubDivide(const SkPoint a[4], double startT, double endT,
452fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkPoint sub[4]) {
45332546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_CUBIC(aCubic, a);
454fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    Cubic dst;
455fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub_divide(aCubic, startT, endT, dst);
456fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[0].fX = SkDoubleToScalar(dst[0].x);
457fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[0].fY = SkDoubleToScalar(dst[0].y);
458fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[1].fX = SkDoubleToScalar(dst[1].x);
459fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[1].fY = SkDoubleToScalar(dst[1].y);
460fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[2].fX = SkDoubleToScalar(dst[2].x);
461fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[2].fY = SkDoubleToScalar(dst[2].y);
462fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[3].fX = SkDoubleToScalar(dst[3].x);
463fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    sub[3].fY = SkDoubleToScalar(dst[3].y);
464fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
465fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
466b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.comstatic void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
467b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        SkPoint []) = {
468b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    NULL,
469b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    LineSubDivide,
470b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    QuadSubDivide,
471b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    CubicSubDivide
472b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com};
473b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com
474aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.comstatic void LineSubDivideHD(const SkPoint a[2], double startT, double endT, _Line& dst) {
47532546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_LINE(aLine, a);
4763350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    sub_divide(aLine, startT, endT, dst);
4773350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com}
4783350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com
479aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.comstatic void QuadSubDivideHD(const SkPoint a[3], double startT, double endT, Quadratic& dst) {
48032546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_QUAD(aQuad, a);
4813350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    sub_divide(aQuad, startT, endT, dst);
4823350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com}
4833350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com
484aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.comstatic void CubicSubDivideHD(const SkPoint a[4], double startT, double endT, Cubic& dst) {
48532546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_CUBIC(aCubic, a);
4863350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    sub_divide(aCubic, startT, endT, dst);
4873350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com}
4883350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com
48945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.comstatic SkPoint QuadTop(const SkPoint a[3], double startT, double endT) {
49045a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    MAKE_CONST_QUAD(quad, a);
49145a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    _Point topPt = top(quad, startT, endT);
49245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    return topPt.asSkPoint();
49345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com}
49445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com
49545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.comstatic SkPoint CubicTop(const SkPoint a[3], double startT, double endT) {
49645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    MAKE_CONST_CUBIC(cubic, a);
49745a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    _Point topPt = top(cubic, startT, endT);
49845a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    return topPt.asSkPoint();
49945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com}
50045a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com
50145a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.comstatic SkPoint (* SegmentTop[])(const SkPoint[], double , double ) = {
50245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    NULL,
50345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    NULL,
50445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    QuadTop,
50545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    CubicTop
50645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com};
50745a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com
50865f9f0a1664a9cb38157ccfbcc3e0e936af0a58ecaryclark@google.com#if DEBUG_UNUSED
509fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic void QuadSubBounds(const SkPoint a[3], double startT, double endT,
510fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkRect& bounds) {
511fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkPoint dst[3];
512fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    QuadSubDivide(a, startT, endT, dst);
513fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    bounds.fLeft = bounds.fRight = dst[0].fX;
514fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    bounds.fTop = bounds.fBottom = dst[0].fY;
515fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    for (int index = 1; index < 3; ++index) {
516fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        bounds.growToInclude(dst[index].fX, dst[index].fY);
517fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
518fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
519fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
520fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic void CubicSubBounds(const SkPoint a[4], double startT, double endT,
521fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkRect& bounds) {
522fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkPoint dst[4];
523fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    CubicSubDivide(a, startT, endT, dst);
524fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    bounds.fLeft = bounds.fRight = dst[0].fX;
525fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    bounds.fTop = bounds.fBottom = dst[0].fY;
526fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    for (int index = 1; index < 4; ++index) {
527fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        bounds.growToInclude(dst[index].fX, dst[index].fY);
528fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
529fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
53065f9f0a1664a9cb38157ccfbcc3e0e936af0a58ecaryclark@google.com#endif
531fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
53215fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.comstatic SkPath::Verb QuadReduceOrder(const SkPoint a[3],
533fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkTDArray<SkPoint>& reducePts) {
53432546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_QUAD(aQuad, a);
535fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    Quadratic dst;
53647d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com    int order = reduceOrder(aQuad, dst, kReduceOrder_TreatAsFill);
53724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    if (order == 2) { // quad became line
53824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        for (int index = 0; index < order; ++index) {
53924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            SkPoint* pt = reducePts.append();
54024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            pt->fX = SkDoubleToScalar(dst[index].x);
54124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            pt->fY = SkDoubleToScalar(dst[index].y);
54224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
543fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
544fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return (SkPath::Verb) (order - 1);
545fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
546fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
547fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic SkPath::Verb CubicReduceOrder(const SkPoint a[4],
548fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkTDArray<SkPoint>& reducePts) {
54932546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_CUBIC(aCubic, a);
550fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    Cubic dst;
55147d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com    int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed, kReduceOrder_TreatAsFill);
55224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    if (order == 2 || order == 3) { // cubic became line or quad
55324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        for (int index = 0; index < order; ++index) {
55424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            SkPoint* pt = reducePts.append();
55524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            pt->fX = SkDoubleToScalar(dst[index].x);
55624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            pt->fY = SkDoubleToScalar(dst[index].y);
55724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
558fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
559fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return (SkPath::Verb) (order - 1);
560fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
561fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
56215fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.comstatic bool QuadIsLinear(const SkPoint a[3]) {
56332546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_QUAD(aQuad, a);
56415fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com    return isLinear(aQuad, 0, 2);
56515fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com}
56615fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com
56715fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.comstatic bool CubicIsLinear(const SkPoint a[4]) {
56832546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_CUBIC(aCubic, a);
56915fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com    return isLinear(aCubic, 0, 3);
57015fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com}
57115fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com
572fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
57332546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_LINE(aLine, a);
574fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    double x[2];
575fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    xy_at_t(aLine, startT, x[0], *(double*) 0);
576495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com    xy_at_t(aLine, endT, x[1], *(double*) 0);
577495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com    return SkMinScalar((float) x[0], (float) x[1]);
578fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
579fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
580fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
58132546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_QUAD(aQuad, a);
582b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    return (float) leftMostT(aQuad, startT, endT);
583fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
584fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
585fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
58632546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    MAKE_CONST_CUBIC(aCubic, a);
587b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    return (float) leftMostT(aCubic, startT, endT);
588fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
589fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
590fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
591fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    NULL,
592fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    LineLeftMost,
593fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    QuadLeftMost,
594fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    CubicLeftMost
595fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com};
596fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5976aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com#if 0 // currently unused
598235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comstatic int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
599235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        Intersections& intersections) {
600235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    MAKE_CONST_QUAD(aQuad, a);
601235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    MAKE_CONST_LINE(bLine, b);
602235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    return intersectRay(aQuad, bLine, intersections);
603235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
6046aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com#endif
6056aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com
606f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.comstatic int QuadRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
6076aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    MAKE_CONST_QUAD(aQuad, a);
6086aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    return intersectRay(aQuad, bLine, intersections);
6096aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com}
610235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
611f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.comstatic int CubicRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
612f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    MAKE_CONST_CUBIC(aCubic, a);
613f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    return intersectRay(aCubic, bLine, intersections);
614f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com}
615f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com
616f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.comstatic int (* const SegmentRayIntersect[])(const SkPoint [], const _Line& , Intersections&) = {
617f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    NULL,
618f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    NULL,
619f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    QuadRayIntersect,
620f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    CubicRayIntersect
621f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com};
622f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com
623f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com
624f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com
625db0b3e099f888213535c4ad4c785b84544309033caryclark@google.comstatic bool LineVertical(const SkPoint a[2], double startT, double endT) {
626db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    MAKE_CONST_LINE(aLine, a);
627db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    double x[2];
628db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    xy_at_t(aLine, startT, x[0], *(double*) 0);
629db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    xy_at_t(aLine, endT, x[1], *(double*) 0);
6306d0032a8ec680221c2a704cac2391f2a2d77546fcaryclark@google.com    return AlmostEqualUlps((float) x[0], (float) x[1]);
631db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com}
632db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com
633db0b3e099f888213535c4ad4c785b84544309033caryclark@google.comstatic bool QuadVertical(const SkPoint a[3], double startT, double endT) {
634db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    SkPoint dst[3];
635db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    QuadSubDivide(a, startT, endT, dst);
6366d0032a8ec680221c2a704cac2391f2a2d77546fcaryclark@google.com    return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
637db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com}
638db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com
639db0b3e099f888213535c4ad4c785b84544309033caryclark@google.comstatic bool CubicVertical(const SkPoint a[4], double startT, double endT) {
640db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    SkPoint dst[4];
641db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    CubicSubDivide(a, startT, endT, dst);
6426d0032a8ec680221c2a704cac2391f2a2d77546fcaryclark@google.com    return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX)
6436d0032a8ec680221c2a704cac2391f2a2d77546fcaryclark@google.com            && AlmostEqualUlps(dst[2].fX, dst[3].fX);
644db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com}
645db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com
646db0b3e099f888213535c4ad4c785b84544309033caryclark@google.comstatic bool (* const SegmentVertical[])(const SkPoint [], double , double) = {
647db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    NULL,
648db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    LineVertical,
649db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    QuadVertical,
650db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    CubicVertical
651db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com};
652db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com
653b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.comclass Segment;
654b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com
6556aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.comstruct Span {
6566aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    Segment* fOther;
6576aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    mutable SkPoint fPt; // lazily computed as needed
6586aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    double fT;
6596aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    double fOtherT; // value at fOther[fOtherIndex].fT
6606aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    int fOtherIndex;  // can't be used during intersection
66131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    int fWindSum; // accumulated from contours surrounding this one.
66231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    int fOppSum; // for binary operators: the opposite winding sum
6636aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
66457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
6656aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    bool fDone; // if set, this span to next higher T has been processed
666c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    bool fUnsortableStart; // set when start is part of an unsortable pair
667c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    bool fUnsortableEnd; // set when end is part of an unsortable pair
668f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    bool fTiny; // if set, span may still be considered once for edge following
6694aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com    bool fLoop; // set when a cubic loops back to this point
6706aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com};
6716aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com
67215fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com// sorting angles
67315fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com// given angles of {dx dy ddx ddy dddx dddy} sort them
67415fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.comclass Angle {
67515fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.compublic:
676b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // FIXME: this is bogus for quads and cubics
677b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // if the quads and cubics' line from end pt to ctrl pt are coincident,
678b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // there's no obvious way to determine the curve ordering from the
679b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // derivatives alone. In particular, if one quadratic's coincident tangent
680b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // is longer than the other curve, the final control point can place the
681b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // longer curve on either side of the shorter one.
682b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
683b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // may provide some help, but nothing has been figured out yet.
6844f55d39a175afe70c1231eb7389790633210106fskia.committer@gmail.com
68532546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    /*(
68632546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    for quads and cubics, set up a parameterized line (e.g. LineParameters )
68732546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    for points [0] to [1]. See if point [2] is on that line, or on one side
68832546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    or the other. If it both quads' end points are on the same side, choose
68932546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    the shorter tangent. If the tangents are equal, choose the better second
69032546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    tangent angle
6914f55d39a175afe70c1231eb7389790633210106fskia.committer@gmail.com
6926aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    maybe I could set up LineParameters lazily
69332546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    */
69415fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com    bool operator<(const Angle& rh) const {
695235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        double y = dy();
696235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        double ry = rh.dy();
697235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
698235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            return y < 0;
699b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        }
700235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        double x = dx();
701235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        double rx = rh.dx();
702235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        if (y == 0 && ry == 0 && x * rx < 0) {
703235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            return x < rx;
70415fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        }
7056aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        double x_ry = x * ry;
7066aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        double rx_y = rx * y;
7076aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        double cmp = x_ry - rx_y;
708c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com        if (!approximately_zero(cmp)) {
70915fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            return cmp < 0;
71015fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        }
711d1688744d537d928699b6069f99c4470a0f6e772caryclark@google.com        if (approximately_zero(x_ry) && approximately_zero(rx_y)
712d1688744d537d928699b6069f99c4470a0f6e772caryclark@google.com                && !approximately_zero_squared(cmp)) {
713d1688744d537d928699b6069f99c4470a0f6e772caryclark@google.com            return cmp < 0;
714d1688744d537d928699b6069f99c4470a0f6e772caryclark@google.com        }
715c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        // at this point, the initial tangent line is coincident
71686adc0d414496185972a7191aca904e9e7223d7dcaryclark@google.com        // see if edges curl away from each other
71731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
71831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                || !approximately_zero(rh.fSide))) {
719c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            // FIXME: running demo will trigger this assertion
720c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            // (don't know if commenting out will trigger further assertion or not)
721c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            // commenting it out allows demo to run in release, though
722c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com     //       SkASSERT(fSide != rh.fSide);
723c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            return fSide < rh.fSide;
724c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        }
7256aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        // see if either curve can be lengthened and try the tangent compare again
7266aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
7276aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
7286aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            Angle longer = *this;
7296aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            Angle rhLonger = rh;
7306aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            if (longer.lengthen() | rhLonger.lengthen()) {
7316aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                return longer < rhLonger;
7326aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            }
7338f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #if 0
734a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            // what if we extend in the other direction?
735a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            longer = *this;
736a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            rhLonger = rh;
737a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            if (longer.reverseLengthen() | rhLonger.reverseLengthen()) {
738a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com                return longer < rhLonger;
739a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            }
7408f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #endif
741b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        }
742185c7c47983dde02b5542cf45fe3fc58a3ecb055caryclark@google.com        if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
74331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                || (rh.fVerb == SkPath::kLine_Verb
74431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                && approximately_zero(rx) && approximately_zero(ry))) {
745185c7c47983dde02b5542cf45fe3fc58a3ecb055caryclark@google.com            // See general unsortable comment below. This case can happen when
746185c7c47983dde02b5542cf45fe3fc58a3ecb055caryclark@google.com            // one line has a non-zero change in t but no change in x and y.
747185c7c47983dde02b5542cf45fe3fc58a3ecb055caryclark@google.com            fUnsortable = true;
748185c7c47983dde02b5542cf45fe3fc58a3ecb055caryclark@google.com            rh.fUnsortable = true;
749185c7c47983dde02b5542cf45fe3fc58a3ecb055caryclark@google.com            return this < &rh; // even with no solution, return a stable sort
750185c7c47983dde02b5542cf45fe3fc58a3ecb055caryclark@google.com        }
751e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
752e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
753e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            fUnsortable = true;
754e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            rh.fUnsortable = true;
755e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            return this < &rh; // even with no solution, return a stable sort
756e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        }
757f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com        SkASSERT(fVerb >= SkPath::kQuad_Verb);
758f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com        SkASSERT(rh.fVerb >= SkPath::kQuad_Verb);
759c1ad0226087e10b1f300b5a45e3d6fdb23b8d1b8skia.committer@gmail.com        // FIXME: until I can think of something better, project a ray from the
760d1688744d537d928699b6069f99c4470a0f6e772caryclark@google.com        // end of the shorter tangent to midway between the end points
761d1688744d537d928699b6069f99c4470a0f6e772caryclark@google.com        // through both curves and use the resulting angle to sort
762235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
763235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        double len = fTangent1.normalSquared();
764235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        double rlen = rh.fTangent1.normalSquared();
7656aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        _Line ray;
766235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        Intersections i, ri;
767d1688744d537d928699b6069f99c4470a0f6e772caryclark@google.com        int roots, rroots;
768d1688744d537d928699b6069f99c4470a0f6e772caryclark@google.com        bool flip = false;
769d1688744d537d928699b6069f99c4470a0f6e772caryclark@google.com        do {
770f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            bool useThis = (len < rlen) ^ flip;
771f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            const Cubic& part = useThis ? fCurvePart : rh.fCurvePart;
772f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb;
773f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ?
774f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com                part[2] : part[1];
775f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            ray[1].x = (part[0].x + part[partVerb].x) / 2;
776f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            ray[1].y = (part[0].y + part[partVerb].y) / 2;
777d1688744d537d928699b6069f99c4470a0f6e772caryclark@google.com            SkASSERT(ray[0] != ray[1]);
778f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            roots = (*SegmentRayIntersect[fVerb])(fPts, ray, i);
779f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            rroots = (*SegmentRayIntersect[rh.fVerb])(rh.fPts, ray, ri);
780d1688744d537d928699b6069f99c4470a0f6e772caryclark@google.com        } while ((roots == 0 || rroots == 0) && (flip ^= true));
781c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        if (roots == 0 || rroots == 0) {
782c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            // FIXME: we don't have a solution in this case. The interim solution
783c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            // is to mark the edges as unsortable, exclude them from this and
784c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            // future computations, and allow the returned path to be fragmented
785c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            fUnsortable = true;
786c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            rh.fUnsortable = true;
787c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            return this < &rh; // even with no solution, return a stable sort
788c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        }
7896aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        _Point loc;
7906aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        double best = SK_ScalarInfinity;
7916aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        double dx, dy, dist;
792235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        int index;
793235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        for (index = 0; index < roots; ++index) {
794f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            (*SegmentXYAtT2[fVerb])(fPts, i.fT[0][index], &loc);
7956aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            dx = loc.x - ray[0].x;
7966aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            dy = loc.y - ray[0].y;
797235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            dist = dx * dx + dy * dy;
798235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            if (best > dist) {
799235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                best = dist;
800235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
801235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        }
802235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        for (index = 0; index < rroots; ++index) {
803f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            (*SegmentXYAtT2[rh.fVerb])(rh.fPts, ri.fT[0][index], &loc);
8046aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            dx = loc.x - ray[0].x;
8056aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            dy = loc.y - ray[0].y;
806235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            dist = dx * dx + dy * dy;
807235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            if (best > dist) {
808235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                return fSide < 0;
809235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
810235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        }
811235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        return fSide > 0;
812b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    }
813d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
81447580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com    double dx() const {
815235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        return fTangent1.dx();
81647580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com    }
817b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com
8187db7c6bba9e9a61ad574a1d60b65bce4563beee5caryclark@google.com    double dy() const {
819235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        return fTangent1.dy();
8207db7c6bba9e9a61ad574a1d60b65bce4563beee5caryclark@google.com    }
8217db7c6bba9e9a61ad574a1d60b65bce4563beee5caryclark@google.com
822b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    int end() const {
823b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        return fEnd;
82415fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com    }
82515fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com
82688f7d0cb09707355bc9079d4b0569537e8048fa9caryclark@google.com    bool isHorizontal() const {
827235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        return dy() == 0 && fVerb == SkPath::kLine_Verb;
82888f7d0cb09707355bc9079d4b0569537e8048fa9caryclark@google.com    }
829a27096b4740775ae141fd0abaf456d706065c5eeskia.committer@gmail.com
8306aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    bool lengthen() {
8316aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        int newEnd = fEnd;
8326aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
8336aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            fEnd = newEnd;
8346aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            setSpans();
8356aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            return true;
8366aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        }
8376aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        return false;
8386aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    }
8396aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com
840a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com    bool reverseLengthen() {
841a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        if (fReversed) {
842a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            return false;
843a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        }
844a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        int newEnd = fStart;
845a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
846a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            fEnd = newEnd;
847a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            fReversed = true;
848a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            setSpans();
849a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            return true;
850a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        }
851a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        return false;
852a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com    }
853a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com
8543350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
8556aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            int start, int end, const SkTDArray<Span>& spans) {
8563350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        fSegment = segment;
8573350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        fStart = start;
8583350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        fEnd = end;
859235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        fPts = orig;
860235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        fVerb = verb;
8616aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        fSpans = &spans;
862a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        fReversed = false;
863c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        fUnsortable = false;
8646aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        setSpans();
8656aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    }
866439cb51451ef6f55f65dab90eb7f91acf67ea8feskia.committer@gmail.com
8678f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com
8686aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    void setSpans() {
8696aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        double startT = (*fSpans)[fStart].fT;
8706aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        double endT = (*fSpans)[fEnd].fT;
8716aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        switch (fVerb) {
87232546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com        case SkPath::kLine_Verb:
87332546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com            _Line l;
8746aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            LineSubDivideHD(fPts, startT, endT, l);
87532546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com            // OPTIMIZATION: for pure line compares, we never need fTangent1.c
87632546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com            fTangent1.lineEndPoints(l);
877235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            fSide = 0;
87832546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com            break;
879f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com        case SkPath::kQuad_Verb: {
880f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            Quadratic& quad = (Quadratic&)fCurvePart;
881f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            QuadSubDivideHD(fPts, startT, endT, quad);
882f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            fTangent1.quadEndPoints(quad, 0, 1);
883aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com            if (dx() == 0 && dy() == 0) {
884f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com                fTangent1.quadEndPoints(quad);
885aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com            }
886f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- compare sign only
887f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            } break;
88886adc0d414496185972a7191aca904e9e7223d7dcaryclark@google.com        case SkPath::kCubic_Verb: {
88986adc0d414496185972a7191aca904e9e7223d7dcaryclark@google.com            int nextC = 2;
890f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            CubicSubDivideHD(fPts, startT, endT, fCurvePart);
891f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            fTangent1.cubicEndPoints(fCurvePart, 0, 1);
892aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com            if (dx() == 0 && dy() == 0) {
893f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com                fTangent1.cubicEndPoints(fCurvePart, 0, 2);
89486adc0d414496185972a7191aca904e9e7223d7dcaryclark@google.com                nextC = 3;
895aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com                if (dx() == 0 && dy() == 0) {
896f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com                    fTangent1.cubicEndPoints(fCurvePart, 0, 3);
897aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com                }
898aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com            }
899f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com            fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign only
90086adc0d414496185972a7191aca904e9e7223d7dcaryclark@google.com            if (nextC == 2 && approximately_zero(fSide)) {
901f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com                fSide = -fTangent1.pointDistance(fCurvePart[3]);
90286adc0d414496185972a7191aca904e9e7223d7dcaryclark@google.com            }
90386adc0d414496185972a7191aca904e9e7223d7dcaryclark@google.com            } break;
904235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        default:
905235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            SkASSERT(0);
9063350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        }
907db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        fUnsortable = dx() == 0 && dy() == 0;
908f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (fUnsortable) {
909f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            return;
910f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
911f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        SkASSERT(fStart != fEnd);
912f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
913f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        for (int index = fStart; index != fEnd; index += step) {
9148f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#if 1
9158f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            const Span& thisSpan = (*fSpans)[index];
9168f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            const Span& nextSpan = (*fSpans)[index + step];
91747d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com            if (thisSpan.fTiny || precisely_equal(thisSpan.fT, nextSpan.fT)) {
9188f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                continue;
919f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            }
9208f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
9218f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#if DEBUG_UNSORTABLE
9228f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (fUnsortable) {
9238f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                SkPoint iPt, ePt;
9248f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt);
9258f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt);
9268f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
9278f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                        index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
9288f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            }
9298f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#endif
9308f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            return;
9318f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#else
9328f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if ((*fSpans)[index].fUnsortableStart) {
933f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                fUnsortable = true;
934f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                return;
935f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            }
936e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#endif
937f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
9388f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#if 1
9398f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#if DEBUG_UNSORTABLE
9408f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        SkPoint iPt, ePt;
9418f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        (*SegmentXYAtT[fVerb])(fPts, startT, &iPt);
9428f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        (*SegmentXYAtT[fVerb])(fPts, endT, &ePt);
9438f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
9448f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
9458f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#endif
9468f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        fUnsortable = true;
9478f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#endif
9483350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    }
94988f7d0cb09707355bc9079d4b0569537e8048fa9caryclark@google.com
9501577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com    Segment* segment() const {
9518dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return const_cast<Segment*>(fSegment);
952b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    }
953d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
954b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    int sign() const {
955495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com        return SkSign32(fStart - fEnd);
956b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    }
957d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
958c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    const SkTDArray<Span>* spans() const {
959c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        return fSpans;
960c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    }
961c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com
962b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    int start() const {
963b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        return fStart;
96415fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com    }
96520c301bd1aa4578c6d0abb23ac2c72b5fbb436dbskia.committer@gmail.com
966c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    bool unsortable() const {
967c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        return fUnsortable;
968c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    }
96915fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com
970c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com#if DEBUG_ANGLE
9716aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    const SkPoint* pts() const {
9726aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        return fPts;
9736aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    }
9746aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com
9756aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    SkPath::Verb verb() const {
9766aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        return fVerb;
9776aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    }
978439cb51451ef6f55f65dab90eb7f91acf67ea8feskia.committer@gmail.com
979c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com    void debugShow(const SkPoint& a) const {
9806aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        SkDebugf("    d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
981c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com    }
982c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com#endif
983c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com
98415fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.comprivate:
985235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    const SkPoint* fPts;
986f9502d7dfad5b361a3cdaa42eb75b593c95f79d8caryclark@google.com    Cubic fCurvePart;
987235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    SkPath::Verb fVerb;
988235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    double fSide;
989235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    LineParameters fTangent1;
9906aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    const SkTDArray<Span>* fSpans;
9918dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    const Segment* fSegment;
992b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    int fStart;
993b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    int fEnd;
994a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com    bool fReversed;
995c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    mutable bool fUnsortable; // this alone is editable by the less than operator
99615fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com};
99715fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com
9988dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com// Bounds, unlike Rect, does not consider a line to be empty.
999fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstruct Bounds : public SkRect {
1000fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    static bool Intersects(const Bounds& a, const Bounds& b) {
1001fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
1002fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                a.fTop <= b.fBottom && b.fTop <= a.fBottom;
1003fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
1004fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
10058dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
10068dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        if (left < fLeft) {
10078dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            fLeft = left;
10088dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
10098dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        if (top < fTop) {
10108dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            fTop = top;
10118dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
10128dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        if (right > fRight) {
10138dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            fRight = right;
10148dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
10158dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        if (bottom > fBottom) {
10168dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            fBottom = bottom;
10178dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
10188dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
10198dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
10208dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    void add(const Bounds& toAdd) {
10218dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
10228dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
1023c7b4be7f110bc7b487c3c3f28d82877584e74c2fskia.committer@gmail.com
1024e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    void add(const SkPoint& pt) {
1025e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (pt.fX < fLeft) fLeft = pt.fX;
1026e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (pt.fY < fTop) fTop = pt.fY;
1027e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (pt.fX > fRight) fRight = pt.fX;
1028e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (pt.fY > fBottom) fBottom = pt.fY;
1029e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    }
1030e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com
1031fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    bool isEmpty() {
1032fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return fLeft > fRight || fTop > fBottom
1033235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                || (fLeft == fRight && fTop == fBottom)
1034beda389e646d6be3cfef853584a78ca8ba39d0fccaryclark@google.com                || sk_double_isnan(fLeft) || sk_double_isnan(fRight)
1035beda389e646d6be3cfef853584a78ca8ba39d0fccaryclark@google.com                || sk_double_isnan(fTop) || sk_double_isnan(fBottom);
1036fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
103703682beb8c1c5dfe714933e9419e1412b33c932dskia.committer@gmail.com
1038fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    void setCubicBounds(const SkPoint a[4]) {
1039fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        _Rect dRect;
104032546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com        MAKE_CONST_CUBIC(cubic, a);
1041fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        dRect.setBounds(cubic);
1042b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1043b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                (float) dRect.bottom);
1044fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
1045fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
10461304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    void setLineBounds(const SkPoint a[2]) {
10471304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        setPoint(a[0]);
10481304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        add(a[1]);
10491304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    }
10501304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com
1051fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    void setQuadBounds(const SkPoint a[3]) {
105232546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com        MAKE_CONST_QUAD(quad, a);
1053fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        _Rect dRect;
1054fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        dRect.setBounds(quad);
1055b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1056b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                (float) dRect.bottom);
1057fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
1058e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com
1059e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    void setPoint(const SkPoint& pt) {
1060e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        fLeft = fRight = pt.fX;
1061e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        fTop = fBottom = pt.fY;
1062e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    }
1063fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com};
1064fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
10651304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.comstatic void (Bounds::*setSegmentBounds[])(const SkPoint[]) = {
10661304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    NULL,
10671304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    &Bounds::setLineBounds,
10681304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    &Bounds::setQuadBounds,
10691304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    &Bounds::setCubicBounds
10701304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com};
10711304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com
10727ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com// OPTIMIZATION: does the following also work, and is it any faster?
10737ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com// return outerWinding * innerWinding > 0
10747ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com//      || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
10752ddff9388694263c7be9347de7eb768cd0847997caryclark@google.comstatic bool useInnerWinding(int outerWinding, int innerWinding) {
1076c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkASSERT(outerWinding != SK_MaxS32);
1077c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkASSERT(innerWinding != SK_MaxS32);
10782ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com    int absOut = abs(outerWinding);
10792ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com    int absIn = abs(innerWinding);
10802ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com    bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
10815e0500fb5f17fe14db42fc3e0aad08e6b41ccc5fcaryclark@google.com#if 0 && DEBUG_WINDING
1082c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    if (outerWinding * innerWinding < 0) {
108324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
10842ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com                outerWinding, innerWinding, result ? "true" : "false");
10852ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com    }
1086c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com#endif
10872ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com    return result;
10882ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com}
10892ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com
10909f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com#define F (false)      // discard the edge
10919f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com#define T (true)       // keep the edge
10929f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com
1093d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.comstatic const bool gUnaryActiveEdge[2][2] = {
1094d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com//  from=0  from=1
1095d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com//  to=0,1  to=0,1
1096d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    {F, T}, {T, F},
1097d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com};
1098d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
10999f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.comstatic const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
11009f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com//                 miFrom=0                              miFrom=1
11019f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com//         miTo=0            miTo=1              miTo=0             miTo=1
11029f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com//    suFrom=0    1     suFrom=0     1      suFrom=0    1      suFrom=0    1
11039f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com//   suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1
11049f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com    {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
11059f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com    {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
11069f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com    {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
11079f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com    {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su
1108235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com};
1109235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
11109f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com#undef F
11119f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com#undef T
1112235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
1113f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com// wrap path to keep track of whether the contour is initialized and non-empty
1114f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.comclass PathWrapper {
1115f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.compublic:
1116f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    PathWrapper(SkPath& path)
1117f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        : fPathPtr(&path)
1118d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        , fCloses(0)
1119d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        , fMoves(0)
1120f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    {
1121f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        init();
1122f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
1123f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
1124f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    void close() {
1125f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (!fHasMove) {
1126f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            return;
1127f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
1128f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        bool callClose = isClosed();
1129f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        lineTo();
1130f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (fEmpty) {
1131f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            return;
1132f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
1133f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (callClose) {
1134f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    #if DEBUG_PATH_CONSTRUCTION
1135f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            SkDebugf("path.close();\n");
1136f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    #endif
1137f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            fPathPtr->close();
1138d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            fCloses++;
1139f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
1140f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        init();
1141f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
1142f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
1143f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
1144f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        lineTo();
1145f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        moveTo();
114685ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com        fDefer[1] = pt3;
114785ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com        nudge();
114885ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com        fDefer[0] = fDefer[1];
1149f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com#if DEBUG_PATH_CONSTRUCTION
1150f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
115185ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com                pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
1152f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com#endif
115385ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com        fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
1154f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fEmpty = false;
1155f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
1156f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
1157f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    void deferredLine(const SkPoint& pt) {
1158f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (pt == fDefer[1]) {
1159f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            return;
1160f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
1161f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (changedSlopes(pt)) {
1162f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            lineTo();
1163f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            fDefer[0] = fDefer[1];
1164f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
1165f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fDefer[1] = pt;
1166f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
1167f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
1168f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    void deferredMove(const SkPoint& pt) {
1169f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fMoved = true;
1170f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fHasMove = true;
1171f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fEmpty = true;
1172f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fDefer[0] = fDefer[1] = pt;
1173f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
1174549c93ef979aeb4dcb65b3d0fca4b58e8ab62227skia.committer@gmail.com
1175f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    void deferredMoveLine(const SkPoint& pt) {
1176f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (!fHasMove) {
1177f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            deferredMove(pt);
1178f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
1179f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        deferredLine(pt);
1180f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
1181549c93ef979aeb4dcb65b3d0fca4b58e8ab62227skia.committer@gmail.com
1182f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    bool hasMove() const {
1183f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        return fHasMove;
1184f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
1185f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
1186f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    void init() {
1187f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fEmpty = true;
1188f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fHasMove = false;
1189f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fMoved = false;
1190f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
1191f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
1192f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    bool isClosed() const {
1193f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        return !fEmpty && fFirstPt == fDefer[1];
1194f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
1195549c93ef979aeb4dcb65b3d0fca4b58e8ab62227skia.committer@gmail.com
1196f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    void lineTo() {
1197f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (fDefer[0] == fDefer[1]) {
1198f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            return;
1199f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
1200f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        moveTo();
120185ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com        nudge();
1202f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fEmpty = false;
1203f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com#if DEBUG_PATH_CONSTRUCTION
1204f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
1205f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com#endif
1206f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
1207f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fDefer[0] = fDefer[1];
1208f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
1209f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
1210f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    const SkPath* nativePath() const {
1211f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        return fPathPtr;
1212f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
1213cdcb2ce2744c7e5c47453328dbf292edee79ab37skia.committer@gmail.com
121485ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com    void nudge() {
121585ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com        if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX)
121685ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com                || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) {
121785ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com            return;
121885ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com        }
121985ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com        fDefer[1] = fFirstPt;
122085ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com    }
1221f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
1222f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
1223f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        lineTo();
1224f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        moveTo();
122585ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com        fDefer[1] = pt2;
122685ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com        nudge();
122785ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com        fDefer[0] = fDefer[1];
1228f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com#if DEBUG_PATH_CONSTRUCTION
1229f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
123085ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com                pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
1231f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com#endif
123285ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com        fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
1233f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fEmpty = false;
1234f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
12357a03d86a3d9adcb13432fbd82039725149487c97skia.committer@gmail.com
1236d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    bool someAssemblyRequired() const {
1237d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        return fCloses < fMoves;
1238d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    }
1239f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
1240f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.comprotected:
1241f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    bool changedSlopes(const SkPoint& pt) const {
1242f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (fDefer[0] == fDefer[1]) {
1243f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            return false;
1244549c93ef979aeb4dcb65b3d0fca4b58e8ab62227skia.committer@gmail.com        }
1245f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
1246f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
1247f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        SkScalar lineDx = pt.fX - fDefer[1].fX;
1248f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        SkScalar lineDy = pt.fY - fDefer[1].fY;
1249f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        return deferDx * lineDy != deferDy * lineDx;
1250f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
1251f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
1252f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    void moveTo() {
1253f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (!fMoved) {
1254f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            return;
1255f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
1256f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fFirstPt = fDefer[0];
1257f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com#if DEBUG_PATH_CONSTRUCTION
1258f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
1259f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com#endif
1260f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
1261f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        fMoved = false;
1262d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        fMoves++;
1263f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
1264f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
1265f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.comprivate:
1266f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    SkPath* fPathPtr;
1267f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    SkPoint fDefer[2];
1268f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    SkPoint fFirstPt;
1269d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    int fCloses;
1270d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    int fMoves;
1271f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    bool fEmpty;
1272f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    bool fHasMove;
1273f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    bool fMoved;
1274f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com};
1275f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
1276fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comclass Segment {
1277fa0588ff672564af1c235a63589573829035a60bcaryclark@google.compublic:
1278fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    Segment() {
1279fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#if DEBUG_DUMP
1280fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fID = ++gSegmentID;
1281fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#endif
1282fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
128324c29d91caa4eaa31f9e77bad614627a252df35eskia.committer@gmail.com
1284fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    bool operator<(const Segment& rh) const {
1285fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        return fBounds.fTop < rh.fBounds.fTop;
1286fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
1287fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com
12884eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
12899764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        if (activeAngleInner(index, done, angles)) {
12909764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            return true;
12919764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        }
1292fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        int lesser = index;
1293db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        while (--lesser >= 0 && equalPoints(index, lesser)) {
12949764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            if (activeAngleOther(lesser, done, angles)) {
1295fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com                return true;
1296fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com            }
1297fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        }
1298db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        lesser = index;
1299fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        do {
13009764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            if (activeAngleOther(index, done, angles)) {
1301fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com                return true;
1302fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com            }
1303db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        } while (++index < fTs.count() && equalPoints(index, lesser));
1304fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        return false;
1305fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com    }
1306fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com
13074eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
1308fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        Span* span = &fTs[index];
1309fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        Segment* other = span->fOther;
1310fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        int oIndex = span->fOtherIndex;
13119764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        return other->activeAngleInner(oIndex, done, angles);
13129764cc6c109dba208592fe5f16447b8439375746caryclark@google.com    }
1313d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
13144eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
1315fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        int next = nextExactSpan(index, 1);
13169764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        if (next > 0) {
13174eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            Span& upSpan = fTs[index];
13184eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            if (upSpan.fWindValue || upSpan.fOppValue) {
1319210acafc5207765e12474064aa01640d5af92770caryclark@google.com                addAngle(angles, index, next);
1320f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                if (upSpan.fDone || upSpan.fUnsortableEnd) {
1321210acafc5207765e12474064aa01640d5af92770caryclark@google.com                    done++;
1322210acafc5207765e12474064aa01640d5af92770caryclark@google.com                } else if (upSpan.fWindSum != SK_MinS32) {
1323210acafc5207765e12474064aa01640d5af92770caryclark@google.com                    return true;
1324210acafc5207765e12474064aa01640d5af92770caryclark@google.com                }
13254eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            } else if (!upSpan.fDone) {
13264eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                upSpan.fDone = true;
13274eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                fDoneSpans++;
13289764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            }
1329fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        }
1330fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        int prev = nextExactSpan(index, -1);
1331fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        // edge leading into junction
13329764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        if (prev >= 0) {
13334eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            Span& downSpan = fTs[prev];
13344eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            if (downSpan.fWindValue || downSpan.fOppValue) {
1335210acafc5207765e12474064aa01640d5af92770caryclark@google.com                addAngle(angles, index, prev);
1336210acafc5207765e12474064aa01640d5af92770caryclark@google.com                if (downSpan.fDone) {
1337210acafc5207765e12474064aa01640d5af92770caryclark@google.com                    done++;
1338210acafc5207765e12474064aa01640d5af92770caryclark@google.com                 } else if (downSpan.fWindSum != SK_MinS32) {
1339210acafc5207765e12474064aa01640d5af92770caryclark@google.com                    return true;
1340210acafc5207765e12474064aa01640d5af92770caryclark@google.com                }
13414eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            } else if (!downSpan.fDone) {
13424eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                downSpan.fDone = true;
13434eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                fDoneSpans++;
13449764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            }
13459764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        }
13469764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        return false;
1347fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com    }
1348fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com
134945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    SkPoint activeLeftTop(bool onlySortable, int* firstT) const {
13508dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        SkASSERT(!done());
135145a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
13528dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        int count = fTs.count();
135345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        // see if either end is not done since we want smaller Y of the pair
13548dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        bool lastDone = true;
1355f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        bool lastUnsortable = false;
135645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        double lastT = -1;
13578dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        for (int index = 0; index < count; ++index) {
1358f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            const Span& span = fTs[index];
135945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
1360f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                goto next;
1361f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            }
136245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            if (span.fDone && lastDone) {
136345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                goto next;
136445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            }
136545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            if (approximately_negative(span.fT - lastT)) {
136645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                goto next;
136745a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            }
136845a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            {
136945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                const SkPoint& xy = xyAtT(&span);
137045a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
137145a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    topPt = xy;
137245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    if (firstT) {
137345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                        *firstT = index;
137445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    }
1375f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                }
137645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                if (fVerb != SkPath::kLine_Verb && !lastDone) {
137745a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    SkPoint curveTop = (*SegmentTop[fVerb])(fPts, lastT, span.fT);
137845a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
137945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            && topPt.fX > curveTop.fX)) {
138045a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                        topPt = curveTop;
138145a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                        if (firstT) {
138245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            *firstT = index;
138345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                        }
138445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    }
13858dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                }
138645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                lastT = span.fT;
13878dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            }
1388f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    next:
1389f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            lastDone = span.fDone;
1390f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            lastUnsortable = span.fUnsortableEnd;
13918dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
139245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        return topPt;
13938dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
13948dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
13957fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
13967fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int sumMiWinding = updateWinding(endIndex, index);
13977fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int sumSuWinding = updateOppWinding(endIndex, index);
13987fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        if (fOperand) {
13997fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            SkTSwap<int>(sumMiWinding, sumSuWinding);
14007fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
14017fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
14027fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
14039f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com                maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
14047fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
1405c7b4be7f110bc7b487c3c3f28d82877584e74c2fskia.committer@gmail.com
14069f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com    bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
1407c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com            int& sumMiWinding, int& sumSuWinding,
14087fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
14097fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
14107fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
14119f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com        bool miFrom;
14129f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com        bool miTo;
14139f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com        bool suFrom;
14149f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com        bool suTo;
14157fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        if (operand()) {
14169f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com            miFrom = (oppMaxWinding & xorMiMask) != 0;
14179f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com            miTo = (oppSumWinding & xorMiMask) != 0;
14189f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com            suFrom = (maxWinding & xorSuMask) != 0;
14199f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com            suTo = (sumWinding & xorSuMask) != 0;
14207fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        } else {
14219f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com            miFrom = (maxWinding & xorMiMask) != 0;
14229f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com            miTo = (sumWinding & xorMiMask) != 0;
14239f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com            suFrom = (oppMaxWinding & xorSuMask) != 0;
14249f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com            suTo = (oppSumWinding & xorSuMask) != 0;
14257fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
14269f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com        bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
1427beda389e646d6be3cfef853584a78ca8ba39d0fccaryclark@google.com#if DEBUG_ACTIVE_OP
1428beda389e646d6be3cfef853584a78ca8ba39d0fccaryclark@google.com        SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__,
1429beda389e646d6be3cfef853584a78ca8ba39d0fccaryclark@google.com                kShapeOpStr[op], miFrom, miTo, suFrom, suTo, result);
1430beda389e646d6be3cfef853584a78ca8ba39d0fccaryclark@google.com#endif
14319f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com        SkASSERT(result != -1);
14329f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com        return result;
14337fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
14347fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
1435d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    bool activeWinding(int index, int endIndex) {
1436d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int sumWinding = updateWinding(endIndex, index);
1437d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int maxWinding;
1438d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        return activeWinding(index, endIndex, maxWinding, sumWinding);
1439d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    }
1440d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
1441d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
1442d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        setUpWinding(index, endIndex, maxWinding, sumWinding);
1443d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        bool from = maxWinding != 0;
1444d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        bool to = sumWinding  != 0;
1445d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        bool result = gUnaryActiveEdge[from][to];
1446d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkASSERT(result != -1);
1447d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        return result;
1448d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    }
1449d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
14508dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
1451b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        SkASSERT(start != end);
14523350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        Angle* angle = angles.append();
14536aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com#if DEBUG_ANGLE
145431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        if (angles.count() > 1 && !fTs[start].fTiny) {
14556aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            SkPoint angle0Pt, newPt;
14566aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
14576aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                    (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
14586aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
14596d0032a8ec680221c2a704cac2391f2a2d77546fcaryclark@google.com            SkASSERT(AlmostEqualUlps(angle0Pt.fX, newPt.fX));
14606d0032a8ec680221c2a704cac2391f2a2d77546fcaryclark@google.com            SkASSERT(AlmostEqualUlps(angle0Pt.fY, newPt.fY));
14616aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        }
14623350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com#endif
14636aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        angle->set(fPts, fVerb, this, start, end, fTs);
1464fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
1465a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
14662ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com    void addCancelOutsides(double tStart, double oStart, Segment& other,
1467cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            double oEnd) {
1468cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        int tIndex = -1;
1469cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        int tCount = fTs.count();
1470cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        int oIndex = -1;
1471cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        int oCount = other.fTs.count();
1472cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        do {
1473cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            ++tIndex;
14743350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
1475cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        int tIndexStart = tIndex;
1476cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        do {
1477cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            ++oIndex;
14783350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
1479cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        int oIndexStart = oIndex;
1480cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        double nextT;
1481cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        do {
1482cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            nextT = fTs[++tIndex].fT;
14833350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        } while (nextT < 1 && approximately_negative(nextT - tStart));
1484cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        double oNextT;
1485cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        do {
1486cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            oNextT = other.fTs[++oIndex].fT;
14873350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        } while (oNextT < 1 && approximately_negative(oNextT - oStart));
1488cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        // at this point, spans before and after are at:
1489cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        //  fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1490cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        // if tIndexStart == 0, no prior span
1491cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        // if nextT == 1, no following span
1492d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
1493cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        // advance the span with zero winding
1494cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        // if the following span exists (not past the end, non-zero winding)
1495cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        // connect the two edges
1496cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        if (!fTs[tIndexStart].fWindValue) {
1497cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1498cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com    #if DEBUG_CONCIDENT
1499cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1500cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                        __FUNCTION__, fID, other.fID, tIndexStart - 1,
150127c449af06cd1d05db441593d08b84f3530fba52caryclark@google.com                        fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
150227c449af06cd1d05db441593d08b84f3530fba52caryclark@google.com                        xyAtT(tIndexStart).fY);
1503cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com    #endif
150445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false,
150545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                        fTs[tIndexStart].fPt);
1506cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            }
1507cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            if (nextT < 1 && fTs[tIndex].fWindValue) {
1508cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com    #if DEBUG_CONCIDENT
1509cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1510cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                        __FUNCTION__, fID, other.fID, tIndex,
1511cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                        fTs[tIndex].fT, xyAtT(tIndex).fX,
1512cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                        xyAtT(tIndex).fY);
1513cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com    #endif
151445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false, fTs[tIndex].fPt);
1515cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            }
1516cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        } else {
1517cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            SkASSERT(!other.fTs[oIndexStart].fWindValue);
1518cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1519cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com    #if DEBUG_CONCIDENT
1520cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1521cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                        __FUNCTION__, fID, other.fID, oIndexStart - 1,
152227c449af06cd1d05db441593d08b84f3530fba52caryclark@google.com                        other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
152327c449af06cd1d05db441593d08b84f3530fba52caryclark@google.com                        other.xyAtT(oIndexStart).fY);
152427c449af06cd1d05db441593d08b84f3530fba52caryclark@google.com                other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
1525cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com    #endif
1526cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            }
1527cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1528cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com    #if DEBUG_CONCIDENT
1529cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1530cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                        __FUNCTION__, fID, other.fID, oIndex,
1531cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                        other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1532cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                        other.xyAtT(oIndex).fY);
1533cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1534cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com    #endif
1535cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            }
1536cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        }
1537cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com    }
1538d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
1539cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com    void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1540cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            double oEnd) {
1541cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        // walk this to outsideTs[0]
1542cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        // walk other to outsideTs[1]
1543cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        // if either is > 0, add a pointer to the other, copying adjacent winding
1544cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        int tIndex = -1;
1545cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        int oIndex = -1;
1546cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        double tStart = outsideTs[0];
1547cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        double oStart = outsideTs[1];
1548cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        do {
1549cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            ++tIndex;
15503350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        } while (!approximately_negative(tStart - fTs[tIndex].fT));
155145a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        SkPoint ptStart = fTs[tIndex].fPt;
1552cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        do {
1553cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            ++oIndex;
15543350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
15554eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
155645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            addTPair(tStart, other, oStart, false, ptStart);
1557cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        }
1558cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        tStart = fTs[tIndex].fT;
1559cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        oStart = other.fTs[oIndex].fT;
1560cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        do {
1561cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            double nextT;
1562cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            do {
1563cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                nextT = fTs[++tIndex].fT;
15643350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            } while (approximately_negative(nextT - tStart));
1565cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            tStart = nextT;
156645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            ptStart = fTs[tIndex].fPt;
1567cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            do {
1568cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                nextT = other.fTs[++oIndex].fT;
15693350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            } while (approximately_negative(nextT - oStart));
1570cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            oStart = nextT;
15714eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
1572cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                break;
1573cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            }
157445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            addTPair(tStart, other, oStart, false, ptStart);
15753350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
1576cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com    }
1577d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
15784eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
15794eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        init(pts, SkPath::kCubic_Verb, operand, evenOdd);
1580fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fBounds.setCubicBounds(pts);
1581fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
1582549c93ef979aeb4dcb65b3d0fca4b58e8ab62227skia.committer@gmail.com
1583f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
15841577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com        SkPoint edge[4];
1585f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        const SkPoint* ePtr;
1586f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        int lastT = fTs.count() - 1;
1587f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1588f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            ePtr = fPts;
1589f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        } else {
15908dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
1591c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            subDivide(start, end, edge);
1592f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            ePtr = edge;
1593f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
15948dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        if (active) {
1595f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            bool reverse = ePtr == fPts && start != 0;
1596f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            if (reverse) {
1597f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                path.deferredMoveLine(ePtr[fVerb]);
1598f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                switch (fVerb) {
1599f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                    case SkPath::kLine_Verb:
1600f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        path.deferredLine(ePtr[0]);
1601f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        break;
1602f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                    case SkPath::kQuad_Verb:
1603f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        path.quadTo(ePtr[1], ePtr[0]);
1604f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        break;
1605f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                    case SkPath::kCubic_Verb:
1606f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1607f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        break;
1608f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                    default:
1609f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        SkASSERT(0);
1610f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                }
1611f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com       //         return ePtr[0];
1612f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com           } else {
1613f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                path.deferredMoveLine(ePtr[0]);
1614f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                switch (fVerb) {
1615f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                    case SkPath::kLine_Verb:
1616f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        path.deferredLine(ePtr[1]);
1617f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        break;
1618f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                    case SkPath::kQuad_Verb:
1619f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        path.quadTo(ePtr[1], ePtr[2]);
1620f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        break;
1621f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                    case SkPath::kCubic_Verb:
1622f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1623f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        break;
1624f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                    default:
1625f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        SkASSERT(0);
1626f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                }
16278dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            }
16281577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com        }
1629f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com      //  return ePtr[fVerb];
16301577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com    }
16311577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com
16324eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
16334eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        init(pts, SkPath::kLine_Verb, operand, evenOdd);
1634fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fBounds.set(pts, 2);
1635fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
1636a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
1637f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com#if 0
1638f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
16398dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        const SkPoint& pt = xyAtT(tIndex);
16408dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        if (active) {
1641f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            path.deferredMove(pt);
16428dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
164388f7d0cb09707355bc9079d4b0569537e8048fa9caryclark@google.com        return pt;
16441577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com    }
1645f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com#endif
16461577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com
1647fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    // add 2 to edge or out of range values to get T extremes
1648b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    void addOtherT(int index, double otherT, int otherIndex) {
1649b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        Span& span = fTs[index];
1650f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    #if PIN_ADD_T
1651185c7c47983dde02b5542cf45fe3fc58a3ecb055caryclark@google.com        if (precisely_less_than_zero(otherT)) {
1652185c7c47983dde02b5542cf45fe3fc58a3ecb055caryclark@google.com            otherT = 0;
1653185c7c47983dde02b5542cf45fe3fc58a3ecb055caryclark@google.com        } else if (precisely_greater_than_one(otherT)) {
1654185c7c47983dde02b5542cf45fe3fc58a3ecb055caryclark@google.com            otherT = 1;
1655185c7c47983dde02b5542cf45fe3fc58a3ecb055caryclark@google.com        }
1656f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    #endif
1657b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        span.fOtherT = otherT;
1658b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        span.fOtherIndex = otherIndex;
1659fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
1660a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
16614eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
16624eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        init(pts, SkPath::kQuad_Verb, operand, evenOdd);
1663fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fBounds.setQuadBounds(pts);
1664fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
1665d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
16668dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // Defer all coincident edge processing until
16678dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // after normal intersections have been computed
16688dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
16698dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com// no need to be tricky; insert in normal T order
16708dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com// resolve overlapping ts when considering coincidence later
1671a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
16728dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // add non-coincident intersection. Resulting edges are sorted in T.
16737ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com    int addT(Segment* other, const SkPoint& pt, double& newT) {
167415fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        // FIXME: in the pathological case where there is a ton of intercepts,
167515fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        //  binary search?
167615fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        int insertedAt = -1;
167715fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        size_t tCount = fTs.count();
1678f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    #if PIN_ADD_T
1679c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com        // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
1680185c7c47983dde02b5542cf45fe3fc58a3ecb055caryclark@google.com        if (precisely_less_than_zero(newT)) {
1681c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com            newT = 0;
1682185c7c47983dde02b5542cf45fe3fc58a3ecb055caryclark@google.com        } else if (precisely_greater_than_one(newT)) {
1683c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com            newT = 1;
1684c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com        }
1685f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    #endif
16868dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        for (size_t index = 0; index < tCount; ++index) {
168715fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            // OPTIMIZATION: if there are three or more identical Ts, then
168815fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            // the fourth and following could be further insertion-sorted so
168915fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            // that all the edges are clockwise or counterclockwise.
169015fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            // This could later limit segment tests to the two adjacent
169115fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            // neighbors, although it doesn't help with determining which
169215fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            // circular direction to go in.
16938dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            if (newT < fTs[index].fT) {
16948dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                insertedAt = index;
16958dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                break;
169615fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            }
169715fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        }
16988dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        Span* span;
16998dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        if (insertedAt >= 0) {
17008dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            span = fTs.insert(insertedAt);
17018dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        } else {
17028dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            insertedAt = tCount;
17038dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            span = fTs.append();
17048dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
170515fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        span->fT = newT;
17068dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        span->fOther = other;
170745a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        span->fPt = pt;
17088dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        span->fWindSum = SK_MinS32;
170931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        span->fOppSum = SK_MinS32;
17108dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        span->fWindValue = 1;
171157cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        span->fOppValue = 0;
1712f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        span->fTiny = false;
17134aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com        span->fLoop = false;
17148dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        if ((span->fDone = newT == 1)) {
171565f9f0a1664a9cb38157ccfbcc3e0e936af0a58ecaryclark@google.com            ++fDoneSpans;
1716d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        }
1717c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        span->fUnsortableStart = false;
1718c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        span->fUnsortableEnd = false;
17198f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        int less = -1;
17207ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com        while (&span[less + 1] - fTs.begin() > 0 && xyAtT(&span[less]) == xyAtT(span)) {
17217ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com#if 1
17227ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            if (span[less].fDone) {
17237ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                break;
17247ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            }
1725c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            double tInterval = newT - span[less].fT;
1726c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            if (precisely_negative(tInterval)) {
1727c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                break;
1728c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            }
1729c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            if (fVerb == SkPath::kCubic_Verb) {
1730c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                double tMid = newT - tInterval / 2;
1731c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                _Point midPt;
1732c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                CubicXYAtT(fPts, tMid, &midPt);
1733c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                if (!midPt.approximatelyEqual(xyAtT(span))) {
1734c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                    break;
1735c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                }
1736c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            }
17378f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            span[less].fTiny = true;
17388f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            span[less].fDone = true;
17398f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (approximately_negative(newT - span[less].fT)) {
17400b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com                if (approximately_greater_than_one(newT)) {
17418f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    span[less].fUnsortableStart = true;
17428f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    span[less - 1].fUnsortableEnd = true;
17430b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com                }
17448f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                if (approximately_less_than_zero(span[less].fT)) {
17458f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    span[less + 1].fUnsortableStart = true;
17468f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    span[less].fUnsortableEnd = true;
17470b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com                }
17480b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            }
1749f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            ++fDoneSpans;
17507ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com#else
17517ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            double tInterval = newT - span[less].fT;
17527ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            if (precisely_negative(tInterval)) {
17537ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                break;
17547ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            }
17557ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            if (fVerb == SkPath::kCubic_Verb) {
17567ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                double tMid = newT - tInterval / 2;
17577ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                _Point midPt;
17587ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                CubicXYAtT(fPts, tMid, &midPt);
17597ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                if (!midPt.approximatelyEqual(xyAtT(span))) {
17607ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                    break;
17617ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                }
17627ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            }
17637ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            SkASSERT(span[less].fDone == span->fDone);
17647ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            if (span[less].fT == 0) {
17657ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                span->fT = newT = 0;
17667ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            } else {
17677ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                setSpanT(less, newT);
17687ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            }
17697ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com#endif
17708f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            --less;
17718f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        }
17728f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        int more = 1;
17737ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com        while (fTs.end() - &span[more - 1] > 1 && xyAtT(&span[more]) == xyAtT(span)) {
17747ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com#if 1
17757ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            if (span[more - 1].fDone) {
17767ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                break;
17777ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            }
1778c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            double tEndInterval = span[more].fT - newT;
1779c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            if (precisely_negative(tEndInterval)) {
1780c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                break;
1781c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            }
1782c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            if (fVerb == SkPath::kCubic_Verb) {
1783c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                double tMid = newT - tEndInterval / 2;
1784c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                _Point midEndPt;
1785c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                CubicXYAtT(fPts, tMid, &midEndPt);
1786c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                if (!midEndPt.approximatelyEqual(xyAtT(span))) {
1787c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                    break;
1788c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                }
1789c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            }
17908f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            span[more - 1].fTiny = true;
17918f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            span[more - 1].fDone = true;
17928f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (approximately_negative(span[more].fT - newT)) {
17938f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                if (approximately_greater_than_one(span[more].fT)) {
17948f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    span[more + 1].fUnsortableStart = true;
17958f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    span[more].fUnsortableEnd = true;
17960b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com                }
17970b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com                if (approximately_less_than_zero(newT)) {
17988f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    span[more].fUnsortableStart = true;
17998f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    span[more - 1].fUnsortableEnd = true;
18000b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com                }
18010b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            }
1802f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            ++fDoneSpans;
18037ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com#else
18047ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            double tEndInterval = span[more].fT - newT;
18057ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            if (precisely_negative(tEndInterval)) {
18067ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                break;
18077ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            }
18087ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            if (fVerb == SkPath::kCubic_Verb) {
18097ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                double tMid = newT - tEndInterval / 2;
18107ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                _Point midEndPt;
18117ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                CubicXYAtT(fPts, tMid, &midEndPt);
18127ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                if (!midEndPt.approximatelyEqual(xyAtT(span))) {
18137ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                    break;
18147ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                }
18157ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            }
18167ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            SkASSERT(span[more - 1].fDone == span[more].fDone);
18177ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            if (newT == 0) {
18187ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                setSpanT(more, 0);
18197ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            } else {
18207ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                span->fT = newT = span[more].fT;
18217ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            }
18227ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com#endif
18238f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            ++more;
1824f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
182515fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        return insertedAt;
182615fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com    }
182715fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com
18288dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // set spans from start to end to decrement by one
18298dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // note this walks other backwards
18308dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // FIMXE: there's probably an edge case that can be constructed where
18318dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // two span in one segment are separated by float epsilon on one span but
18328dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // not the other, if one segment is very small. For this
18338dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // case the counts asserted below may or may not be enough to separate the
18342ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com    // spans. Even if the counts work out, what if the spans aren't correctly
18358dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // sorted? It feels better in such a case to match the span's other span
18368dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // pointer since both coincident segments must contain the same spans.
18378dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    void addTCancel(double startT, double endT, Segment& other,
18388dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            double oStartT, double oEndT) {
18393350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        SkASSERT(!approximately_negative(endT - startT));
18403350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        SkASSERT(!approximately_negative(oEndT - oStartT));
1841235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        bool binary = fOperand != other.fOperand;
18428dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        int index = 0;
18433350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        while (!approximately_negative(startT - fTs[index].fT)) {
18448dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            ++index;
18458dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
1846b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com        int oIndex = other.fTs.count();
18473350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
18488dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            ;
184959823f7f3ba43c7c6bc1fa8c600b093ecb4236aacaryclark@google.com        double tRatio = (oEndT - oStartT) / (endT - startT);
18508dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        Span* test = &fTs[index];
18518dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        Span* oTest = &other.fTs[oIndex];
185218063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com        SkTDArray<double> outsideTs;
185318063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com        SkTDArray<double> oOutsideTs;
18548dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        do {
185531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            bool decrement = test->fWindValue && oTest->fWindValue && !binary;
1856cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            bool track = test->fWindValue || oTest->fWindValue;
1857200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com            double testT = test->fT;
1858200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com            double oTestT = oTest->fT;
1859200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com            Span* span = test;
18608dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            do {
18618dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                if (decrement) {
186231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    decrementSpan(span);
1863200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com                } else if (track && span->fT < 1 && oTestT < 1) {
1864200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com                    TrackOutside(outsideTs, span->fT, oTestT);
18658dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                }
1866200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com                span = &fTs[++index];
18673350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            } while (approximately_negative(span->fT - testT));
1868200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com            Span* oSpan = oTest;
186959823f7f3ba43c7c6bc1fa8c600b093ecb4236aacaryclark@google.com            double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
187059823f7f3ba43c7c6bc1fa8c600b093ecb4236aacaryclark@google.com            double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
187159823f7f3ba43c7c6bc1fa8c600b093ecb4236aacaryclark@google.com            SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
18723350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            while (approximately_negative(otherTMatchStart - oSpan->fT)
18733350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com                    && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
187403f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        #ifdef SK_DEBUG
187559823f7f3ba43c7c6bc1fa8c600b093ecb4236aacaryclark@google.com                SkASSERT(originalWindValue == oSpan->fWindValue);
187603f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        #endif
18778dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                if (decrement) {
1878200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com                    other.decrementSpan(oSpan);
1879200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com                } else if (track && oSpan->fT < 1 && testT < 1) {
1880200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com                    TrackOutside(oOutsideTs, oSpan->fT, testT);
18818dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                }
18828dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                if (!oIndex) {
18838dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                    break;
18848dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                }
1885200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com                oSpan = &other.fTs[--oIndex];
1886d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            }
1887200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com            test = span;
1888200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com            oTest = oSpan;
18893350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        } while (!approximately_negative(endT - test->fT));
18903350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
189118063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com        // FIXME: determine if canceled edges need outside ts added
1892cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        if (!done() && outsideTs.count()) {
18932ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com            double tStart = outsideTs[0];
18942ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com            double oStart = outsideTs[1];
18952ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com            addCancelOutsides(tStart, oStart, other, oEndT);
18962ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com            int count = outsideTs.count();
18972ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com            if (count > 2) {
18982ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com                double tStart = outsideTs[count - 2];
18992ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com                double oStart = outsideTs[count - 1];
19002ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com                addCancelOutsides(tStart, oStart, other, oEndT);
19012ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com            }
190218063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com        }
1903cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        if (!other.done() && oOutsideTs.count()) {
19042ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com            double tStart = oOutsideTs[0];
19052ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com            double oStart = oOutsideTs[1];
19062ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com            other.addCancelOutsides(tStart, oStart, *this, endT);
190718063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com        }
19088dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
1909631cdcb4a6b926b6447f328b81911a4499fb3698skia.committer@gmail.com
19104aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com    int addSelfT(Segment* other, const SkPoint& pt, double& newT) {
19114aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com        int result = addT(other, pt, newT);
19124aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com        Span* span = &fTs[result];
19134aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com        span->fLoop = true;
19144aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com        return result;
19154aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com    }
191615dd300ac6d7695b4d2aca81d8f3648eae704451skia.committer@gmail.com
19177ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com    int addUnsortableT(Segment* other, bool start, const SkPoint& pt, double& newT) {
19187ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com        int result = addT(other, pt, newT);
191973ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com        Span* span = &fTs[result];
192073ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com        if (start) {
192173ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com            if (result > 0) {
192273ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                span[result - 1].fUnsortableEnd = true;
192373ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com            }
192473ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com            span[result].fUnsortableStart = true;
192573ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com        } else {
192673ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com            span[result].fUnsortableEnd = true;
192773ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com            if (result + 1 < fTs.count()) {
192873ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                span[result + 1].fUnsortableStart = true;
192973ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com            }
193073ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com        }
193173ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com        return result;
193273ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    }
1933b3b6a60d35c8ee521252367200148561c628ee42skia.committer@gmail.com
19344eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    int bumpCoincidentThis(const Span* oTest, bool opp, int index,
19354eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            SkTDArray<double>& outsideTs) {
19364eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        int oWindValue = oTest->fWindValue;
19374eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        int oOppValue = oTest->fOppValue;
19384eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        if (opp) {
19394eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            SkTSwap<int>(oWindValue, oOppValue);
19404eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        }
194157cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        Span* const test = &fTs[index];
194257cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        Span* end = test;
194357cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        const double oStartT = oTest->fT;
194457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        do {
19454eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            if (bumpSpan(end, oWindValue, oOppValue)) {
19464eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                TrackOutside(outsideTs, end->fT, oStartT);
194757cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com            }
194857cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com            end = &fTs[++index];
194957cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        } while (approximately_negative(end->fT - test->fT));
195057cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        return index;
195157cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    }
195257cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com
195357cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    // because of the order in which coincidences are resolved, this and other
195457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    // may not have the same intermediate points. Compute the corresponding
195557cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    // intermediate T values (using this as the master, other as the follower)
195657cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    // and walk other conditionally -- hoping that it catches up in the end
19574eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
19584eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            SkTDArray<double>& oOutsideTs) {
195957cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        Span* const oTest = &fTs[oIndex];
196057cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        Span* oEnd = oTest;
196157cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        const double startT = test->fT;
196257cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        const double oStartT = oTest->fT;
196357cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        while (!approximately_negative(oEndT - oEnd->fT)
19644eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                && approximately_negative(oEnd->fT - oStartT)) {
19654eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            zeroSpan(oEnd);
19664eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            TrackOutside(oOutsideTs, oEnd->fT, startT);
196757cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com            oEnd = &fTs[++oIndex];
196857cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        }
196957cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        return oIndex;
197057cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    }
197157cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com
197257cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    // FIXME: need to test this case:
197357cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    // contourA has two segments that are coincident
197457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    // contourB has two segments that are coincident in the same place
197557cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    // each ends up with +2/0 pairs for winding count
197657cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    // since logic below doesn't transfer count (only increments/decrements) can this be
197757cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    // resolved to +4/0 ?
19788dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
19798dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // set spans from start to end to increment the greater by one and decrement
19808dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // the lesser
19814eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
19823350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        SkASSERT(!approximately_negative(endT - startT));
19833350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        SkASSERT(!approximately_negative(oEndT - oStartT));
198457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        bool opp = fOperand ^ other.fOperand;
19858dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        int index = 0;
19863350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        while (!approximately_negative(startT - fTs[index].fT)) {
19878dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            ++index;
19888dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
19898dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        int oIndex = 0;
19903350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
19918dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            ++oIndex;
19928dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
19938dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        Span* test = &fTs[index];
19948dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        Span* oTest = &other.fTs[oIndex];
19958dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        SkTDArray<double> outsideTs;
19968dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        SkTDArray<double> oOutsideTs;
19978dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        do {
19984eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            // if either span has an opposite value and the operands don't match, resolve first
1999e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com     //       SkASSERT(!test->fDone || !oTest->fDone);
20000d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com            if (test->fDone || oTest->fDone) {
20010d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com                index = advanceCoincidentThis(oTest, opp, index);
20020d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com                oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
20030d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com            } else {
20040d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com                index = bumpCoincidentThis(oTest, opp, index, outsideTs);
20050d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com                oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
20060d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com            }
200757cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com            test = &fTs[index];
200857cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com            oTest = &other.fTs[oIndex];
20093350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        } while (!approximately_negative(endT - test->fT));
20103350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        SkASSERT(approximately_negative(oTest->fT - oEndT));
20113350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        SkASSERT(approximately_negative(oEndT - oTest->fT));
20124eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        if (!done() && outsideTs.count()) {
20134eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            addCoinOutsides(outsideTs, other, oEndT);
20148dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
20158dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        if (!other.done() && oOutsideTs.count()) {
2016cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            other.addCoinOutsides(oOutsideTs, *this, endT);
20178dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
20188dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
2019d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
2020cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com    // FIXME: this doesn't prevent the same span from being added twice
2021aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com    // fix in caller, SkASSERT here?
202245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    void addTPair(double t, Segment& other, double otherT, bool borrowWind, const SkPoint& pt) {
202347580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com        int tCount = fTs.count();
2024cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        for (int tIndex = 0; tIndex < tCount; ++tIndex) {
2025cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            const Span& span = fTs[tIndex];
20263350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            if (!approximately_negative(span.fT - t)) {
202747580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com                break;
20288dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            }
20296aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            if (approximately_negative(span.fT - t) && span.fOther == &other
20306aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                    && approximately_equal(span.fOtherT, otherT)) {
2031cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com#if DEBUG_ADD_T_PAIR
2032cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
2033cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                        __FUNCTION__, fID, t, other.fID, otherT);
2034cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com#endif
2035cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                return;
203647580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            }
2037cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        }
203847580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com#if DEBUG_ADD_T_PAIR
203947580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com        SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
204047580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com                __FUNCTION__, fID, t, other.fID, otherT);
204147580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com#endif
20427ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com        int insertedAt = addT(&other, pt, t);
20437ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com        int otherInsertedAt = other.addT(this, pt, otherT);
20448dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        addOtherT(insertedAt, otherT, otherInsertedAt);
2045b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com        other.addOtherT(otherInsertedAt, t, insertedAt);
20462ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com        matchWindingValue(insertedAt, t, borrowWind);
20472ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com        other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
20488dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
2049d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
20508dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
2051b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        // add edge leading into junction
20524eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        int min = SkMin32(end, start);
20534eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
20548dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            addAngle(angles, end, start);
20558dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
2056b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        // add edge leading away from junction
2057495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com        int step = SkSign32(end - start);
2058a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        int tIndex = nextExactSpan(end, step);
20594eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        min = SkMin32(end, tIndex);
20604eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
2061a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com            addAngle(angles, end, tIndex);
2062b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        }
2063b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    }
2064d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
20650d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com    int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
20660d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com        Span* const test = &fTs[index];
20670d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com        Span* end = test;
20680d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com        do {
20690d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com            end = &fTs[++index];
20700d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com        } while (approximately_negative(end->fT - test->fT));
20710d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com        return index;
20720d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com    }
20730d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com
20740d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com    int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
20750d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com        Span* const oTest = &fTs[oIndex];
20760d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com        Span* oEnd = oTest;
20770d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com        const double oStartT = oTest->fT;
20780d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com        while (!approximately_negative(oEndT - oEnd->fT)
20790d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com                && approximately_negative(oEnd->fT - oStartT)) {
20800d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com            oEnd = &fTs[++oIndex];
20810d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com        }
20820d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com        return oIndex;
20830d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com    }
2084b89a03c890668f98d9f8b269b6ad00824409435bskia.committer@gmail.com
2085db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    bool betweenTs(int lesser, double testT, int greater) {
2086db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (lesser > greater) {
2087db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            SkTSwap<int>(lesser, greater);
2088db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
2089db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
2090db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
20910d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com
2092fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    const Bounds& bounds() const {
2093fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return fBounds;
2094fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
2095a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
209631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
2097a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        double referenceT = fTs[index].fT;
2098a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        int lesser = index;
209931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
210031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                && precisely_negative(referenceT - fTs[lesser].fT)) {
2101a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com            buildAnglesInner(lesser, angles);
2102a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        }
2103b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        do {
2104a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com            buildAnglesInner(index, angles);
210531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
210631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                && precisely_negative(fTs[index].fT - referenceT));
2107b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    }
2108a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com
2109a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
21101ab0aac67247bf3ec1f23b220456d316d9a80b45caryclark@google.com        const Span* span = &fTs[index];
2111a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        Segment* other = span->fOther;
2112a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    // if there is only one live crossing, and no coincidence, continue
2113a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    // in the same direction
2114a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    // if there is coincidence, the only choice may be to reverse direction
2115a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        // find edge on either side of intersection
2116a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        int oIndex = span->fOtherIndex;
2117a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        // if done == -1, prior span has already been processed
2118a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        int step = 1;
2119a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        int next = other->nextExactSpan(oIndex, step);
2120a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com       if (next < 0) {
2121a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com            step = -step;
2122a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            next = other->nextExactSpan(oIndex, step);
2123a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        }
2124a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        // add candidate into and away from junction
2125a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        other->addTwoAngles(next, oIndex, angles);
21268dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
21278dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
21287fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    int computeSum(int startIndex, int endIndex, bool binary) {
2129534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        SkTDArray<Angle> angles;
2130534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        addTwoAngles(startIndex, endIndex, angles);
213131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        buildAngles(endIndex, angles, false);
2132d1688744d537d928699b6069f99c4470a0f6e772caryclark@google.com        // OPTIMIZATION: check all angles to see if any have computed wind sum
2133d1688744d537d928699b6069f99c4470a0f6e772caryclark@google.com        // before sorting (early exit if none)
2134534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        SkTDArray<Angle*> sorted;
2135c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        bool sortable = SortAngles(angles, sorted);
213603f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com#if DEBUG_SORT
213731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
213803f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com#endif
2139c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        if (!sortable) {
2140c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            return SK_MinS32;
2141c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        }
2142534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        int angleCount = angles.count();
2143534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        const Angle* angle;
2144534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        const Segment* base;
2145534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        int winding;
21467ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        int oWinding;
2147534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        int firstIndex = 0;
2148534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        do {
2149534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            angle = sorted[firstIndex];
2150534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            base = angle->segment();
2151534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            winding = base->windSum(angle);
2152534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            if (winding != SK_MinS32) {
21537ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                oWinding = base->oppSum(angle);
2154534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com                break;
2155534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            }
2156534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            if (++firstIndex == angleCount) {
2157534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com                return SK_MinS32;
2158534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            }
2159534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        } while (true);
2160534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        // turn winding into contourWinding
21612ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com        int spanWinding = base->spanSign(angle);
21622ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com        bool inner = useInnerWinding(winding + spanWinding, winding);
21632ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com    #if DEBUG_WINDING
216424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
216559823f7f3ba43c7c6bc1fa8c600b093ecb4236aacaryclark@google.com            spanWinding, winding, angle->sign(), inner,
21662ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com            inner ? winding + spanWinding : winding);
21672ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com    #endif
21682ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com        if (inner) {
2169534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            winding += spanWinding;
2170534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        }
2171534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com    #if DEBUG_SORT
21727ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
2173534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com    #endif
2174534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        int nextIndex = firstIndex + 1;
2175534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
21762ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com        winding -= base->spanSign(angle);
21777ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        oWinding -= base->oppSign(angle);
2178534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        do {
2179534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            if (nextIndex == angleCount) {
2180534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com                nextIndex = 0;
2181534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            }
2182534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            angle = sorted[nextIndex];
2183534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            Segment* segment = angle->segment();
21847ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            bool opp = base->fOperand ^ segment->fOperand;
21857ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            int maxWinding, oMaxWinding;
21867ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            int spanSign = segment->spanSign(angle);
21877ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            int oppoSign = segment->oppSign(angle);
21887ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            if (opp) {
21897ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                oMaxWinding = oWinding;
21907ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                oWinding -= spanSign;
2191729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com                maxWinding = winding;
21927ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                if (oppoSign) {
21937ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                    winding -= oppoSign;
21947ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                }
21957ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            } else {
21967ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                maxWinding = winding;
21977ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                winding -= spanSign;
2198729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com                oMaxWinding = oWinding;
21997ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                if (oppoSign) {
22007ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                    oWinding -= oppoSign;
22017ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                }
22027ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            }
22037ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            if (segment->windSum(angle) == SK_MinS32) {
22047ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                if (opp) {
22057ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                    if (useInnerWinding(oMaxWinding, oWinding)) {
22067ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                        oMaxWinding = oWinding;
22077ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                    }
22087ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                    if (oppoSign && useInnerWinding(maxWinding, winding)) {
22097ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                        maxWinding = winding;
22107ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                    }
22114eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                    (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
22127ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                } else {
22137ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                    if (useInnerWinding(maxWinding, winding)) {
22147ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                        maxWinding = winding;
22157ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                    }
22167ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                    if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
22177ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                        oMaxWinding = oWinding;
22187ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                    }
2219e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                    (void) segment->markAndChaseWinding(angle, maxWinding,
2220e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                            binary ? oMaxWinding : 0);
2221534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com                }
2222534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            }
2223534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        } while (++nextIndex != lastIndex);
22246ec1526680bcc05b8b8b2c7ad9f78ba247e123b7caryclark@google.com        int minIndex = SkMin32(startIndex, endIndex);
22256ec1526680bcc05b8b8b2c7ad9f78ba247e123b7caryclark@google.com        return windSum(minIndex);
2226534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com    }
2227b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com
22283586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
222910227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            double mid, bool opp, bool current) const {
2230db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        SkScalar bottom = fBounds.fBottom;
223110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        int bestTIndex = -1;
2232db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (bottom <= bestY) {
223310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            return bestTIndex;
2234db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
2235db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        SkScalar top = fBounds.fTop;
2236db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (top >= basePt.fY) {
223710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            return bestTIndex;
2238db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
2239db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (fBounds.fLeft > basePt.fX) {
224010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            return bestTIndex;
2241db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
2242db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (fBounds.fRight < basePt.fX) {
224310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            return bestTIndex;
2244db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
2245db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (fBounds.fLeft == fBounds.fRight) {
22468f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            // if vertical, and directly above test point, wait for another one
22476d0032a8ec680221c2a704cac2391f2a2d77546fcaryclark@google.com            return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
2248db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
224910227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        // intersect ray starting at basePt with edge
225010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        Intersections intersections;
225110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        // OPTIMIZE: use specialty function that intersects ray with curve,
225210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        // returning t values only for curve (we don't care about t on ray)
225310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
225410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        if (pts == 0 || (current && pts == 1)) {
225510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            return bestTIndex;
225610227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        }
225710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        if (current) {
225810227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            SkASSERT(pts > 1);
225910227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            int closestIdx = 0;
226010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            double closest = fabs(intersections.fT[0][0] - mid);
226110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            for (int idx = 1; idx < pts; ++idx) {
226210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                double test = fabs(intersections.fT[0][idx] - mid);
226310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                if (closest > test) {
226410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                    closestIdx = idx;
226510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                    closest = test;
226610227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                }
226710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            }
226810227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            if (closestIdx < pts - 1) {
226910227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
227010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            }
227110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            --pts;
227210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        }
227310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        double bestT = -1;
227410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        for (int index = 0; index < pts; ++index) {
227510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            double foundT = intersections.fT[0][index];
22768f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (approximately_less_than_zero(foundT)
22778f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                        || approximately_greater_than_one(foundT)) {
22788f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                continue;
22798f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            }
228010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
228110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            if (approximately_negative(testY - bestY)
228210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                    || approximately_negative(basePt.fY - testY)) {
228347580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com                continue;
228447580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            }
228510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            if (pts > 1 && fVerb == SkPath::kLine_Verb) {
22868f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                return SK_MinS32; // if the intersection is edge on, wait for another one
228710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            }
22888f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (fVerb > SkPath::kLine_Verb) {
228910227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
229010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                if (approximately_zero(dx)) {
22918f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    return SK_MinS32; // hit vertical, wait for another one
2292235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                }
22938dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            }
229410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            bestY = testY;
229510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            bestT = foundT;
22963586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        }
229710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        if (bestT < 0) {
229810227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            return bestTIndex;
22993586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        }
230010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        SkASSERT(bestT >= 0);
230110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        SkASSERT(bestT <= 1);
230210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        int start;
230310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        int end = 0;
230410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        do {
230510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            start = end;
230610227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            end = nextSpan(start, 1);
230710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        } while (fTs[end].fT < bestT);
230810227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        // FIXME: see next candidate for a better pattern to find the next start/end pair
230910227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        while (start + 1 < end && fTs[start].fDone) {
231010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            ++start;
231110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        }
23128f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        if (!isCanceled(start)) {
231310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            hitT = bestT;
23148f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            bestTIndex = start;
231510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            hitSomething = true;
23163586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        }
231710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        return bestTIndex;
2318495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com    }
231918063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com
23204eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    void decrementSpan(Span* span) {
232118063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com        SkASSERT(span->fWindValue > 0);
232218063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com        if (--(span->fWindValue) == 0) {
23234eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            if (!span->fOppValue && !span->fDone) {
2324f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                span->fDone = true;
2325f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                ++fDoneSpans;
2326f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            }
23274eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        }
23284eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    }
23294eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com
23304eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    bool bumpSpan(Span* span, int windDelta, int oppDelta) {
23314eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        SkASSERT(!span->fDone);
23324eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        span->fWindValue += windDelta;
23334eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        SkASSERT(span->fWindValue >= 0);
23344eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        span->fOppValue += oppDelta;
23354eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        SkASSERT(span->fOppValue >= 0);
23364eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        if (fXor) {
23374eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            span->fWindValue &= 1;
23384eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        }
23394eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        if (fOppXor) {
23404eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            span->fOppValue &= 1;
23414eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        }
23424eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        if (!span->fWindValue && !span->fOppValue) {
23434eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            span->fDone = true;
23444eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            ++fDoneSpans;
234518063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com            return true;
234618063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com        }
234718063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com        return false;
234818063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com    }
2349c7b4be7f110bc7b487c3c3f28d82877584e74c2fskia.committer@gmail.com
23500d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com    // OPTIMIZE
23510d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com    // when the edges are initially walked, they don't automatically get the prior and next
23520d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com    // edges assigned to positions t=0 and t=1. Doing that would remove the need for this check,
2353c7b4be7f110bc7b487c3c3f28d82877584e74c2fskia.committer@gmail.com    // and would additionally remove the need for similar checks in condition edges. It would
23540d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com    // also allow intersection code to assume end of segment intersections (maybe?)
23550d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com    bool complete() const {
23560d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com        int count = fTs.count();
23570d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com        return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
23580d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com    }
235918063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com
236015fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com    bool done() const {
2361af46cff4ee6099cebf3aa395805748af7d193a31caryclark@google.com        SkASSERT(fDoneSpans <= fTs.count());
2362af46cff4ee6099cebf3aa395805748af7d193a31caryclark@google.com        return fDoneSpans == fTs.count();
2363a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com    }
2364549c93ef979aeb4dcb65b3d0fca4b58e8ab62227skia.committer@gmail.com
2365f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    bool done(int min) const {
2366f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        return fTs[min].fDone;
2367f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
2368a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
23697fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    bool done(const Angle* angle) const {
23707fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        return done(SkMin32(angle->start(), angle->end()));
237147580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com    }
2372044679ef8c08e1f01afadf5bc08251fe8597df81skia.committer@gmail.com
23737ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com    SkVector dxdy(int index) const {
237445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        return (*SegmentDXDYAtT[fVerb])(fPts, fTs[index].fT);
237545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    }
237645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com
237745a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    SkScalar dy(int index) const {
237845a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        return (*SegmentDYAtT[fVerb])(fPts, fTs[index].fT);
237945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    }
238024c29d91caa4eaa31f9e77bad614627a252df35eskia.committer@gmail.com
2381db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    bool equalPoints(int greaterTIndex, int lesserTIndex) {
2382db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        SkASSERT(greaterTIndex >= lesserTIndex);
2383db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        double greaterT = fTs[greaterTIndex].fT;
2384db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        double lesserT = fTs[lesserTIndex].fT;
2385db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (greaterT == lesserT) {
2386db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            return true;
2387db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
2388db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (!approximately_negative(greaterT - lesserT)) {
2389db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            return false;
2390db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
2391db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2392db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
2393db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com
23947fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    /*
23957fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com     The M and S variable name parts stand for the operators.
23967fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com       Mi stands for Minuend (see wiki subtraction, analogous to difference)
23977fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com       Su stands for Subtrahend
23987fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com     The Opp variable name part designates that the value is for the Opposite operator.
23997fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com     Opposite values result from combining coincident spans.
24007fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com     */
2401c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com
24027fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
24037fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
2404235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        const int startIndex = nextStart;
2405c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        const int endIndex = nextEnd;
2406235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        SkASSERT(startIndex != endIndex);
24077fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        const int count = fTs.count();
24087fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
24097fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        const int step = SkSign32(endIndex - startIndex);
24107fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        const int end = nextExactSpan(startIndex, step);
2411235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        SkASSERT(end >= 0);
2412235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        Span* endSpan = &fTs[end];
2413235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        Segment* other;
2414235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        if (isSimple(end)) {
2415235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        // mark the smaller of startIndex, endIndex done, and all adjacent
2416235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        // spans with the same T value (but not 'other' spans)
2417235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    #if DEBUG_WINDING
2418235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            SkDebugf("%s simple\n", __FUNCTION__);
2419235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    #endif
2420e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            int min = SkMin32(startIndex, endIndex);
2421e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            if (fTs[min].fDone) {
2422e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                return NULL;
2423e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            }
2424e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            markDoneBinary(min);
2425235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            other = endSpan->fOther;
2426235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            nextStart = endSpan->fOtherIndex;
2427235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            double startT = other->fTs[nextStart].fT;
2428235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            nextEnd = nextStart;
2429235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            do {
2430235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                nextEnd += step;
2431a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            }
2432a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            while (precisely_zero(startT - other->fTs[nextEnd].fT));
2433235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2434235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            return other;
2435235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        }
2436235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        // more than one viable candidate -- measure angles to find best
2437235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        SkTDArray<Angle> angles;
2438235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        SkASSERT(startIndex - endIndex != 0);
2439235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2440235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        addTwoAngles(startIndex, end, angles);
244131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        buildAngles(end, angles, true);
2442235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        SkTDArray<Angle*> sorted;
2443c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        bool sortable = SortAngles(angles, sorted);
2444235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        int angleCount = angles.count();
2445235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        int firstIndex = findStartingEdge(sorted, startIndex, end);
2446235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        SkASSERT(firstIndex >= 0);
2447235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    #if DEBUG_SORT
24487fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        debugShowSort(__FUNCTION__, sorted, firstIndex);
2449235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    #endif
2450c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        if (!sortable) {
2451c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            unsortable = true;
2452c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            return NULL;
2453c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        }
2454235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        SkASSERT(sorted[firstIndex]->segment() == this);
2455235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    #if DEBUG_WINDING
245657cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
245757cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                sorted[firstIndex]->sign());
2458235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    #endif
24597fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int sumMiWinding = updateWinding(endIndex, startIndex);
24607fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int sumSuWinding = updateOppWinding(endIndex, startIndex);
24617fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        if (operand()) {
24627fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            SkTSwap<int>(sumMiWinding, sumSuWinding);
2463235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        }
2464235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        int nextIndex = firstIndex + 1;
2465235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2466235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        const Angle* foundAngle = NULL;
2467235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        bool foundDone = false;
2468235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        // iterate through the angle, and compute everyone's winding
2469235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        Segment* nextSegment;
24704aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com        int activeCount = 0;
2471235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        do {
24727fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            SkASSERT(nextIndex != firstIndex);
2473235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            if (nextIndex == angleCount) {
2474235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                nextIndex = 0;
2475235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
2476235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            const Angle* nextAngle = sorted[nextIndex];
2477235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            nextSegment = nextAngle->segment();
24787fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
24797fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
24807fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    nextAngle->end(), op, sumMiWinding, sumSuWinding,
24817fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
24824aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com            if (activeAngle) {
24834aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com                ++activeCount;
24844aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com                if (!foundAngle || (foundDone && activeCount & 1)) {
24854aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com                    if (nextSegment->tiny(nextAngle)) {
24864aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com                        unsortable = true;
24874aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com                        return NULL;
24884aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com                    }
24894aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com                    foundAngle = nextAngle;
24904aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com                    foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
24914aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com                }
2492235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
2493235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            if (nextSegment->done()) {
2494235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                continue;
2495235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
24967fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            if (nextSegment->windSum(nextAngle) != SK_MinS32) {
24977fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                continue;
24987fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            }
24997fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
25007fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    oppSumWinding, activeAngle, nextAngle);
25017fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            if (last) {
25027fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                *chase.append() = last;
25037fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com#if DEBUG_WINDING
25047fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
25057fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        last->fOther->fTs[last->fOtherIndex].fOther->debugID());
25067fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com#endif
2507235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
2508235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        } while (++nextIndex != lastIndex);
25097fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        markDoneBinary(SkMin32(startIndex, endIndex));
2510235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        if (!foundAngle) {
2511235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            return NULL;
2512235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        }
2513235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        nextStart = foundAngle->start();
2514235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        nextEnd = foundAngle->end();
2515235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        nextSegment = foundAngle->segment();
251657cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com
2517235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    #if DEBUG_WINDING
25187fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
25197fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2520235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com     #endif
2521235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        return nextSegment;
2522235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    }
252347580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com
2524d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2525d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            bool& unsortable) {
2526d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        const int startIndex = nextStart;
2527d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        const int endIndex = nextEnd;
2528d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkASSERT(startIndex != endIndex);
2529d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        const int count = fTs.count();
2530d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2531d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        const int step = SkSign32(endIndex - startIndex);
2532d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        const int end = nextExactSpan(startIndex, step);
2533d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkASSERT(end >= 0);
2534d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        Span* endSpan = &fTs[end];
2535d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        Segment* other;
2536d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        if (isSimple(end)) {
2537d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        // mark the smaller of startIndex, endIndex done, and all adjacent
2538d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        // spans with the same T value (but not 'other' spans)
2539d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    #if DEBUG_WINDING
2540d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            SkDebugf("%s simple\n", __FUNCTION__);
2541d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    #endif
2542d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            int min = SkMin32(startIndex, endIndex);
2543d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            if (fTs[min].fDone) {
2544d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                return NULL;
2545d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            }
2546d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            markDoneUnary(min);
2547d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            other = endSpan->fOther;
2548d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            nextStart = endSpan->fOtherIndex;
2549d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            double startT = other->fTs[nextStart].fT;
2550d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            nextEnd = nextStart;
2551d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            do {
2552d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                nextEnd += step;
2553d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            }
2554d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            while (precisely_zero(startT - other->fTs[nextEnd].fT));
2555d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2556d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            return other;
2557d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
2558d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        // more than one viable candidate -- measure angles to find best
2559d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkTDArray<Angle> angles;
2560d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkASSERT(startIndex - endIndex != 0);
2561d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2562d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        addTwoAngles(startIndex, end, angles);
2563d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        buildAngles(end, angles, true);
2564d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkTDArray<Angle*> sorted;
2565d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        bool sortable = SortAngles(angles, sorted);
2566d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int angleCount = angles.count();
2567d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int firstIndex = findStartingEdge(sorted, startIndex, end);
2568d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkASSERT(firstIndex >= 0);
2569d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    #if DEBUG_SORT
2570d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        debugShowSort(__FUNCTION__, sorted, firstIndex);
2571d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    #endif
2572d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        if (!sortable) {
2573d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            unsortable = true;
2574d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            return NULL;
2575d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
2576d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkASSERT(sorted[firstIndex]->segment() == this);
2577d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    #if DEBUG_WINDING
2578d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2579d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                sorted[firstIndex]->sign());
2580d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    #endif
2581d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int sumWinding = updateWinding(endIndex, startIndex);
2582d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int nextIndex = firstIndex + 1;
2583d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2584d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        const Angle* foundAngle = NULL;
2585d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        bool foundDone = false;
2586d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        // iterate through the angle, and compute everyone's winding
2587d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        Segment* nextSegment;
2588db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        int activeCount = 0;
2589d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        do {
2590d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            SkASSERT(nextIndex != firstIndex);
2591d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            if (nextIndex == angleCount) {
2592d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                nextIndex = 0;
2593d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            }
2594d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            const Angle* nextAngle = sorted[nextIndex];
2595d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            nextSegment = nextAngle->segment();
2596d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            int maxWinding;
25977a03d86a3d9adcb13432fbd82039725149487c97skia.committer@gmail.com            bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
2598d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    maxWinding, sumWinding);
2599db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            if (activeAngle) {
2600db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                ++activeCount;
2601db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                if (!foundAngle || (foundDone && activeCount & 1)) {
2602db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                    if (nextSegment->tiny(nextAngle)) {
2603db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                        unsortable = true;
2604db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                        return NULL;
2605db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                    }
2606db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                    foundAngle = nextAngle;
2607db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                    foundDone = nextSegment->done(nextAngle);
2608db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                }
2609d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            }
2610d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            if (nextSegment->done()) {
2611d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                continue;
2612d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            }
2613d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2614d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                continue;
2615d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            }
2616d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2617d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            if (last) {
2618d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                *chase.append() = last;
2619d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com#if DEBUG_WINDING
2620d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2621d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                        last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2622d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com#endif
2623d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            }
2624d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        } while (++nextIndex != lastIndex);
2625d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        markDoneUnary(SkMin32(startIndex, endIndex));
2626d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        if (!foundAngle) {
2627d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            return NULL;
2628d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
2629d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        nextStart = foundAngle->start();
2630d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        nextEnd = foundAngle->end();
2631d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        nextSegment = foundAngle->segment();
2632d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    #if DEBUG_WINDING
2633d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2634d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2635d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com     #endif
2636d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        return nextSegment;
2637d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    }
2638d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
2639c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
264024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        const int startIndex = nextStart;
264124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        const int endIndex = nextEnd;
264224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkASSERT(startIndex != endIndex);
264324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        int count = fTs.count();
264424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkASSERT(startIndex < endIndex ? startIndex < count - 1
264524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                : startIndex > 0);
264624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        int step = SkSign32(endIndex - startIndex);
2647a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        int end = nextExactSpan(startIndex, step);
264824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkASSERT(end >= 0);
264924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        Span* endSpan = &fTs[end];
265024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        Segment* other;
265124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        if (isSimple(end)) {
265224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    #if DEBUG_WINDING
265324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            SkDebugf("%s simple\n", __FUNCTION__);
265424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    #endif
2655e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            int min = SkMin32(startIndex, endIndex);
2656e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            if (fTs[min].fDone) {
2657e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                return NULL;
2658e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            }
2659e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            markDone(min, 1);
266024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            other = endSpan->fOther;
266124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            nextStart = endSpan->fOtherIndex;
266224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            double startT = other->fTs[nextStart].fT;
26638f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        #if 01 // FIXME: I don't know why the logic here is difference from the winding case
266424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            SkDEBUGCODE(bool firstLoop = true;)
26653350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            if ((approximately_less_than_zero(startT) && step < 0)
26663350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com                    || (approximately_greater_than_one(startT) && step > 0)) {
266724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                step = -step;
266824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                SkDEBUGCODE(firstLoop = false;)
266924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            }
267024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            do {
26718f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        #endif
267224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                nextEnd = nextStart;
267324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                do {
267424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                    nextEnd += step;
2675a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com                }
2676a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com                 while (precisely_zero(startT - other->fTs[nextEnd].fT));
26778f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        #if 01
267824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
267924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                    break;
268024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                }
268103f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com #ifdef SK_DEBUG
268224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                SkASSERT(firstLoop);
268303f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com #endif
268424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                SkDEBUGCODE(firstLoop = false;)
268524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                step = -step;
268624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            } while (true);
26878f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        #endif
268824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
268924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            return other;
269024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
269124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkTDArray<Angle> angles;
269224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkASSERT(startIndex - endIndex != 0);
269324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
269424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        addTwoAngles(startIndex, end, angles);
269531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        buildAngles(end, angles, false);
269624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkTDArray<Angle*> sorted;
2697c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        bool sortable = SortAngles(angles, sorted);
2698e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (!sortable) {
2699e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            unsortable = true;
27008f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #if DEBUG_SORT
27018f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
27028f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #endif
2703e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            return NULL;
2704e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        }
270524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        int angleCount = angles.count();
270624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        int firstIndex = findStartingEdge(sorted, startIndex, end);
270724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkASSERT(firstIndex >= 0);
270824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    #if DEBUG_SORT
270931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
271024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    #endif
271124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkASSERT(sorted[firstIndex]->segment() == this);
271224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        int nextIndex = firstIndex + 1;
271324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
27148f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        const Angle* foundAngle = NULL;
27158f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        bool foundDone = false;
271624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        Segment* nextSegment;
27178f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        int activeCount = 0;
271824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        do {
27198f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            SkASSERT(nextIndex != firstIndex);
272024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            if (nextIndex == angleCount) {
272124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                nextIndex = 0;
272224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            }
27238f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            const Angle* nextAngle = sorted[nextIndex];
272424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            nextSegment = nextAngle->segment();
27258f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            ++activeCount;
27268f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (!foundAngle || (foundDone && activeCount & 1)) {
27278f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                if (nextSegment->tiny(nextAngle)) {
27288f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    unsortable = true;
27298f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    return NULL;
27308f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                }
27318f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                foundAngle = nextAngle;
27328f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                foundDone = nextSegment->done(nextAngle);
27338f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            }
27348f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (nextSegment->done()) {
27358f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                continue;
273624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            }
2737e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        } while (++nextIndex != lastIndex);
2738e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        markDone(SkMin32(startIndex, endIndex), 1);
2739e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (!foundAngle) {
27408f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            return NULL;
2741e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        }
27428f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        nextStart = foundAngle->start();
27438f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        nextEnd = foundAngle->end();
27448f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        nextSegment = foundAngle->segment();
27458f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #if DEBUG_WINDING
27468f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
27478f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
27488f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com     #endif
274924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        return nextSegment;
275024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    }
2751fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com
2752fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com    int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2753fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        int angleCount = sorted.count();
2754fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        int firstIndex = -1;
2755fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2756fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com            const Angle* angle = sorted[angleIndex];
2757fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com            if (angle->segment() == this && angle->start() == end &&
2758fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com                    angle->end() == start) {
2759fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com                firstIndex = angleIndex;
2760fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com                break;
2761fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com            }
2762fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        }
2763fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        return firstIndex;
2764fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com    }
2765fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com
27661577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com    // FIXME: this is tricky code; needs its own unit test
27678f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    // note that fOtherIndex isn't computed yet, so it can't be used here
27684eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    void findTooCloseToCall() {
276915fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        int count = fTs.count();
277015fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        if (count < 3) { // require t=0, x, 1 at minimum
277115fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            return;
277215fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        }
2773a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com        int matchIndex = 0;
277415fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        int moCount;
277515fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        Span* match;
277615fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        Segment* mOther;
277715fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        do {
277815fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            match = &fTs[matchIndex];
277915fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            mOther = match->fOther;
2780c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com            // FIXME: allow quads, cubics to be near coincident?
2781c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com            if (mOther->fVerb == SkPath::kLine_Verb) {
2782c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                moCount = mOther->fTs.count();
2783c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                if (moCount >= 3) {
2784c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                    break;
2785c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                }
27861577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            }
27871577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            if (++matchIndex >= count) {
27881577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                return;
27891577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            }
27901577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com        } while (true); // require t=0, x, 1 at minimum
279115fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        // OPTIMIZATION: defer matchPt until qualifying toCount is found?
2792a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        const SkPoint* matchPt = &xyAtT(match);
2793a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com        // look for a pair of nearby T values that map to the same (x,y) value
2794a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com        // if found, see if the pair of other segments share a common point. If
2795a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com        // so, the span from here to there is coincident.
279615fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        for (int index = matchIndex + 1; index < count; ++index) {
279715fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            Span* test = &fTs[index];
27988dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            if (test->fDone) {
2799495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com                continue;
2800495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com            }
280115fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            Segment* tOther = test->fOther;
2802c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com            if (tOther->fVerb != SkPath::kLine_Verb) {
2803c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                continue; // FIXME: allow quads, cubics to be near coincident?
2804c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com            }
280515fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            int toCount = tOther->fTs.count();
280615fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            if (toCount < 3) { // require t=0, x, 1 at minimum
2807a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com                continue;
2808a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com            }
2809a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com            const SkPoint* testPt = &xyAtT(test);
2810a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com            if (*matchPt != *testPt) {
2811a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com                matchIndex = index;
281215fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com                moCount = toCount;
281315fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com                match = test;
281415fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com                mOther = tOther;
2815a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com                matchPt = testPt;
2816a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com                continue;
2817a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com            }
28181577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            int moStart = -1;
28191577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            int moEnd = -1;
28201577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            double moStartT, moEndT;
2821a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com            for (int moIndex = 0; moIndex < moCount; ++moIndex) {
282215fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com                Span& moSpan = mOther->fTs[moIndex];
28238dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                if (moSpan.fDone) {
2824495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com                    continue;
2825495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com                }
282615fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com                if (moSpan.fOther == this) {
282715fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com                    if (moSpan.fOtherT == match->fT) {
282815fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com                        moStart = moIndex;
28291577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                        moStartT = moSpan.fT;
283015fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com                    }
283115fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com                    continue;
283215fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com                }
28331577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                if (moSpan.fOther == tOther) {
28348f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    if (tOther->windValueAt(moSpan.fOtherT) == 0) {
2835c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                        moStart = -1;
2836c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                        break;
2837c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                    }
28381577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                    SkASSERT(moEnd == -1);
28391577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                    moEnd = moIndex;
28401577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                    moEndT = moSpan.fT;
2841a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com                }
28421577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            }
28431577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            if (moStart < 0 || moEnd < 0) {
28441577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                continue;
28451577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            }
28461577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
28473350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            if (approximately_equal(moStartT, moEndT)) {
28481577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                continue;
28491577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            }
28501577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            int toStart = -1;
28511577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            int toEnd = -1;
28521577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            double toStartT, toEndT;
28531577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            for (int toIndex = 0; toIndex < toCount; ++toIndex) {
28541577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                Span& toSpan = tOther->fTs[toIndex];
2855c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                if (toSpan.fDone) {
2856c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                    continue;
2857c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                }
28581577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                if (toSpan.fOther == this) {
28591577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                    if (toSpan.fOtherT == test->fT) {
28601577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                        toStart = toIndex;
28611577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                        toStartT = toSpan.fT;
2862a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com                    }
286315fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com                    continue;
2864a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com                }
28651577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
28668f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    if (mOther->windValueAt(toSpan.fOtherT) == 0) {
2867c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                        moStart = -1;
2868c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                        break;
2869c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                    }
28701577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                    SkASSERT(toEnd == -1);
28711577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                    toEnd = toIndex;
28721577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                    toEndT = toSpan.fT;
2873a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com                }
2874a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com            }
28751577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
28761577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            if (toStart <= 0 || toEnd <= 0) {
2877fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                continue;
2878fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            }
28793350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            if (approximately_equal(toStartT, toEndT)) {
2880fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                continue;
2881fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            }
28821577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            // test to see if the segment between there and here is linear
28831577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com            if (!mOther->isLinear(moStart, moEnd)
28841577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                    || !tOther->isLinear(toStart, toEnd)) {
28851577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com                continue;
2886b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com            }
2887c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com            bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
28888dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            if (flipped) {
28893350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com                mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
28908dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            } else {
28914eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
28928dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            }
2893fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        }
2894fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
2895fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
289645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    // FIXME: either:
2897c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    // a) mark spans with either end unsortable as done, or
2898c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2899c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    //    when encountering an unsortable span
2900c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com
2901a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com    // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2902a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com    // and use more concise logic like the old edge walker code?
2903a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com    // FIXME: this needs to deal with coincident edges
2904e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
2905fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        // iterate through T intersections and return topmost
2906fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        // topmost tangent from y-min to first pt is closer to horizontal
290788f7d0cb09707355bc9079d4b0569537e8048fa9caryclark@google.com        SkASSERT(!done());
29089f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com        int firstT = -1;
2909d0a19eb9140ecb968357f798f06d2b052b51fd89caryclark@google.com        /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT);
2910996d78b7cf9863a5b574fc1b64b1715cad4d0a23caryclark@google.com        if (firstT < 0) {
2911996d78b7cf9863a5b574fc1b64b1715cad4d0a23caryclark@google.com            unsortable = true;
2912996d78b7cf9863a5b574fc1b64b1715cad4d0a23caryclark@google.com            firstT = 0;
2913996d78b7cf9863a5b574fc1b64b1715cad4d0a23caryclark@google.com            while (fTs[firstT].fDone) {
2914996d78b7cf9863a5b574fc1b64b1715cad4d0a23caryclark@google.com                SkASSERT(firstT < fTs.count());
2915996d78b7cf9863a5b574fc1b64b1715cad4d0a23caryclark@google.com                ++firstT;
2916996d78b7cf9863a5b574fc1b64b1715cad4d0a23caryclark@google.com            }
2917996d78b7cf9863a5b574fc1b64b1715cad4d0a23caryclark@google.com            tIndex = firstT;
2918996d78b7cf9863a5b574fc1b64b1715cad4d0a23caryclark@google.com            endIndex = nextExactSpan(firstT, 1);
2919996d78b7cf9863a5b574fc1b64b1715cad4d0a23caryclark@google.com            return this;
2920996d78b7cf9863a5b574fc1b64b1715cad4d0a23caryclark@google.com        }
2921b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        // sort the edges to find the leftmost
2922a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        int step = 1;
2923a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        int end = nextSpan(firstT, step);
2924b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        if (end == -1) {
2925a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com            step = -1;
2926a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com            end = nextSpan(firstT, step);
292765f9f0a1664a9cb38157ccfbcc3e0e936af0a58ecaryclark@google.com            SkASSERT(end != -1);
2928b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        }
2929fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        // if the topmost T is not on end, or is three-way or more, find left
2930a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com        // look for left-ness from tLeft to firstT (matching y of other)
2931b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        SkTDArray<Angle> angles;
2932b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        SkASSERT(firstT - end != 0);
29338dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        addTwoAngles(end, firstT, angles);
293431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        buildAngles(firstT, angles, true);
2935b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        SkTDArray<Angle*> sorted;
2936f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        bool sortable = SortAngles(angles, sorted);
29371304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        int first = SK_MaxS32;
29381304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        SkScalar top = SK_ScalarMax;
29391304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        int count = sorted.count();
29401304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        for (int index = 0; index < count; ++index) {
29411304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            const Angle* angle = sorted[index];
29421304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            Segment* next = angle->segment();
29431304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            Bounds bounds;
29441304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            next->subDivideBounds(angle->end(), angle->start(), bounds);
29451304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            if (approximately_greater(top, bounds.fTop)) {
29461304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                top = bounds.fTop;
29471304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                first = index;
29481304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            }
29491304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        }
29501304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        SkASSERT(first < SK_MaxS32);
29511304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    #if DEBUG_SORT // || DEBUG_SWAP_TOP
29521304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        sorted[first]->segment()->debugShowSort(__FUNCTION__, sorted, first, 0, 0);
295303f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    #endif
2954e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (onlySortable && !sortable) {
2955e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            unsortable = true;
2956f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            return NULL;
2957f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
295888f7d0cb09707355bc9079d4b0569537e8048fa9caryclark@google.com        // skip edges that have already been processed
29591304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        firstT = first - 1;
296088f7d0cb09707355bc9079d4b0569537e8048fa9caryclark@google.com        Segment* leftSegment;
296188f7d0cb09707355bc9079d4b0569537e8048fa9caryclark@google.com        do {
29621304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            if (++firstT == count) {
29631304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                firstT = 0;
29641304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            }
29651304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            const Angle* angle = sorted[firstT];
2966e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            SkASSERT(!onlySortable || !angle->unsortable());
296788f7d0cb09707355bc9079d4b0569537e8048fa9caryclark@google.com            leftSegment = angle->segment();
296888f7d0cb09707355bc9079d4b0569537e8048fa9caryclark@google.com            tIndex = angle->end();
296988f7d0cb09707355bc9079d4b0569537e8048fa9caryclark@google.com            endIndex = angle->start();
297088f7d0cb09707355bc9079d4b0569537e8048fa9caryclark@google.com        } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
297145a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        if (leftSegment->verb() >= SkPath::kQuad_Verb) {
29721304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            if (!leftSegment->clockwise(tIndex, endIndex)) {
29731304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                bool swap = leftSegment->verb() == SkPath::kQuad_Verb
29741304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                        || (!leftSegment->monotonic_in_y(tIndex, endIndex)
29751304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                        && !leftSegment->serpentine(tIndex, endIndex));
297647d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com        #if DEBUG_SWAP_TOP
29771304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                SkDebugf("%s swap=%d serpentine=%d controls_contained_by_ends=%d\n", __FUNCTION__,
29781304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                        swap,
29791304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                        leftSegment->serpentine(tIndex, endIndex),
29801304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                        leftSegment->controls_contained_by_ends(tIndex, endIndex),
29811304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                        leftSegment->monotonic_in_y(tIndex, endIndex));
298247d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com        #endif
29831304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                if (swap) {
29841304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first
29851304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        // sorted but merely the first not already processed (i.e., not done)
29861304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                    SkTSwap(tIndex, endIndex);
29871304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                }
298845a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            }
298945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        }
2990e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
2991b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        return leftSegment;
2992b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    }
2993d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
2994b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // FIXME: not crazy about this
2995b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // when the intersections are performed, the other index is into an
29961304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    // incomplete array. As the array grows, the indices become incorrect
2997b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // while the following fixes the indices up again, it isn't smart about
2998b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // skipping segments whose indices are already correct
2999b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // assuming we leave the code that wrote the index in the first place
3000b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    void fixOtherTIndex() {
3001b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        int iCount = fTs.count();
3002b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        for (int i = 0; i < iCount; ++i) {
3003b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com            Span& iSpan = fTs[i];
3004b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com            double oT = iSpan.fOtherT;
3005b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com            Segment* other = iSpan.fOther;
3006b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com            int oCount = other->fTs.count();
3007b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com            for (int o = 0; o < oCount; ++o) {
3008b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                Span& oSpan = other->fTs[o];
30091304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan.fT) {
3010b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                    iSpan.fOtherIndex = o;
30118dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                    break;
3012b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                }
3013fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            }
3014fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        }
3015b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    }
3016c7b4be7f110bc7b487c3c3f28d82877584e74c2fskia.committer@gmail.com
30174eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
3018235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        fDoneSpans = 0;
3019235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        fOperand = operand;
30204eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        fXor = evenOdd;
3021b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        fPts = pts;
3022b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        fVerb = verb;
3023fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
30248d83d0db6433e009c6c7f9adbd2580578b6f297eskia.committer@gmail.com
30253586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    void initWinding(int start, int end) {
30263586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        int local = spanSign(start, end);
30273586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        int oppLocal = oppSign(start, end);
30283586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        (void) markAndChaseWinding(start, end, local, oppLocal);
302973ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com        // OPTIMIZATION: the reverse mark and chase could skip the first marking
303073ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com        (void) markAndChaseWinding(end, start, local, oppLocal);
30313586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    }
3032fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
30333586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    void initWinding(int start, int end, int winding, int oppWinding) {
3034db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        int local = spanSign(start, end);
30353586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        if (local * winding >= 0) {
3036db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            winding += local;
3037db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
3038db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        int oppLocal = oppSign(start, end);
30393586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        if (oppLocal * oppWinding >= 0) {
3040db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            oppWinding += oppLocal;
3041db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
3042db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        (void) markAndChaseWinding(start, end, winding, oppWinding);
3043db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
3044db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com
30453586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com/*
30463586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.comwhen we start with a vertical intersect, we try to use the dx to determine if the edge is to
30473586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.comthe left or the right of vertical. This determines if we need to add the span's
30488d83d0db6433e009c6c7f9adbd2580578b6f297eskia.committer@gmail.comsign or not. However, this isn't enough.
30498d83d0db6433e009c6c7f9adbd2580578b6f297eskia.committer@gmail.comIf the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed.
30503586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.comIf there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
30513586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.comfrom has the same x direction as this span, the winding should change. If the dx is opposite, then
30528d83d0db6433e009c6c7f9adbd2580578b6f297eskia.committer@gmail.comthe same winding is shared by both.
30533586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com*/
30543586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
30553586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com            SkScalar hitOppDx) {
30563586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        SkASSERT(hitDx || !winding);
3057db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
3058db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        SkASSERT(dx);
30593586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        int windVal = windValue(SkMin32(start, end));
30608f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #if DEBUG_WINDING_AT_T
30618f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
30628f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
30638f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #endif
3064db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (!winding) {
30653586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com            winding = dx < 0 ? windVal : -windVal;
30668f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        } else if (winding * dx < 0) {
30673586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com            int sideWind = winding + (dx < 0 ? windVal : -windVal);
30683586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com            if (abs(winding) < abs(sideWind)) {
30693586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                winding = sideWind;
30703586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com            }
30717fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
30728f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #if DEBUG_WINDING_AT_T
30738f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        SkDebugf(" winding=%d\n", winding);
30748f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #endif
3075db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        int oppLocal = oppSign(start, end);
30763586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        SkASSERT(hitOppDx || !oppWind || !oppLocal);
30773586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        int oppWindVal = oppValue(SkMin32(start, end));
30783586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        if (!oppWind) {
30793586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com            oppWind = dx < 0 ? oppWindVal : -oppWindVal;
30803586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        } else if (hitOppDx * dx >= 0) {
30813586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com            int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
30823586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com            if (abs(oppWind) < abs(oppSideWind)) {
30833586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                oppWind = oppSideWind;
30843586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com            }
30857fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
30863586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        (void) markAndChaseWinding(start, end, winding, oppWind);
30877fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
30887fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
3089fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    bool intersected() const {
3090fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return fTs.count() > 0;
3091fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
30927db7c6bba9e9a61ad574a1d60b65bce4563beee5caryclark@google.com
309310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    bool isCanceled(int tIndex) const {
309410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
309510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    }
309610227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com
30977db7c6bba9e9a61ad574a1d60b65bce4563beee5caryclark@google.com    bool isConnected(int startIndex, int endIndex) const {
30987db7c6bba9e9a61ad574a1d60b65bce4563beee5caryclark@google.com        return fTs[startIndex].fWindSum != SK_MinS32
30997db7c6bba9e9a61ad574a1d60b65bce4563beee5caryclark@google.com                || fTs[endIndex].fWindSum != SK_MinS32;
31007db7c6bba9e9a61ad574a1d60b65bce4563beee5caryclark@google.com    }
31017db7c6bba9e9a61ad574a1d60b65bce4563beee5caryclark@google.com
3102235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    bool isHorizontal() const {
3103235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        return fBounds.fTop == fBounds.fBottom;
3104235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    }
3105235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
310615fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com    bool isLinear(int start, int end) const {
310715fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        if (fVerb == SkPath::kLine_Verb) {
310815fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            return true;
310915fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        }
311015fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        if (fVerb == SkPath::kQuad_Verb) {
311115fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            SkPoint qPart[3];
311215fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
311315fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            return QuadIsLinear(qPart);
311415fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        } else {
311515fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            SkASSERT(fVerb == SkPath::kCubic_Verb);
311615fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            SkPoint cPart[4];
311715fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
311815fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            return CubicIsLinear(cPart);
311915fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        }
312015fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com    }
3121b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com
3122b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com    // OPTIMIZE: successive calls could start were the last leaves off
3123b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com    // or calls could specialize to walk forwards or backwards
3124b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com    bool isMissing(double startT) const {
3125b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com        size_t tCount = fTs.count();
3126b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com        for (size_t index = 0; index < tCount; ++index) {
31273350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            if (approximately_zero(startT - fTs[index].fT)) {
3128b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com                return false;
3129b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com            }
3130b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com        }
3131b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com        return true;
3132b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com    }
3133b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com
31348dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    bool isSimple(int end) const {
3135a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        int count = fTs.count();
3136a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        if (count == 2) {
3137a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com            return true;
3138a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        }
31398dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        double t = fTs[end].fT;
31403350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        if (approximately_less_than_zero(t)) {
31413350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            return !approximately_less_than_zero(fTs[1].fT);
3142a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        }
31433350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        if (approximately_greater_than_one(t)) {
31443350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            return !approximately_greater_than_one(fTs[count - 2].fT);
3145a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        }
31468dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return false;
3147a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    }
3148fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
3149fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    bool isVertical() const {
3150fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return fBounds.fLeft == fBounds.fRight;
3151fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
3152b89a03c890668f98d9f8b269b6ad00824409435bskia.committer@gmail.com
3153db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    bool isVertical(int start, int end) const {
3154db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        return (*SegmentVertical[fVerb])(fPts, start, end);
3155db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
3156a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
3157fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkScalar leftMost(int start, int end) const {
3158fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
3159fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
3160d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
3161495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com    // this span is excluded by the winding rule -- chase the ends
3162495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com    // as long as they are unambiguous to mark connections as done
3163495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com    // and give them the same winding value
316459823f7f3ba43c7c6bc1fa8c600b093ecb4236aacaryclark@google.com    Span* markAndChaseDone(const Angle* angle, int winding) {
3165495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com        int index = angle->start();
3166495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com        int endIndex = angle->end();
316731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        return markAndChaseDone(index, endIndex, winding);
316831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    }
316931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com
317031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    Span* markAndChaseDone(int index, int endIndex, int winding) {
3171495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com        int step = SkSign32(endIndex - index);
31724eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        int min = SkMin32(index, endIndex);
31734eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        markDone(min, winding);
31744eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Span* last;
31754eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Segment* other = this;
31764eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        while ((other = other->nextChase(index, step, min, last))) {
31774eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            other->markDone(min, winding);
31784eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        }
3179fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        return last;
3180495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com    }
3181d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
31827fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
31837fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int index = angle->start();
31847fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int endIndex = angle->end();
318531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int step = SkSign32(endIndex - index);
31864eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        int min = SkMin32(index, endIndex);
31874eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        markDoneBinary(min, winding, oppWinding);
31884eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Span* last;
31894eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Segment* other = this;
31904eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        while ((other = other->nextChase(index, step, min, last))) {
31914eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            other->markDoneBinary(min, winding, oppWinding);
31924eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        }
31937fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        return last;
31947fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
3195c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com
31967fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    Span* markAndChaseDoneBinary(int index, int endIndex) {
31977fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int step = SkSign32(endIndex - index);
31984eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        int min = SkMin32(index, endIndex);
31994eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        markDoneBinary(min);
32004eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Span* last;
32014eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Segment* other = this;
32024eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        while ((other = other->nextChase(index, step, min, last))) {
3203e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            if (other->done()) {
3204e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                return NULL;
3205e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            }
32064eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            other->markDoneBinary(min);
32074eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        }
320831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        return last;
320931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    }
321031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com
3211db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    Span* markAndChaseDoneUnary(int index, int endIndex) {
3212db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        int step = SkSign32(endIndex - index);
3213db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        int min = SkMin32(index, endIndex);
3214db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        markDoneUnary(min);
3215db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        Span* last;
3216db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        Segment* other = this;
3217db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        while ((other = other->nextChase(index, step, min, last))) {
3218db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            if (other->done()) {
3219db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                return NULL;
3220db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            }
3221db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            other->markDoneUnary(min);
3222db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
3223db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        return last;
3224db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
3225db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com
3226d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
3227d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int index = angle->start();
3228d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int endIndex = angle->end();
3229d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        return markAndChaseDone(index, endIndex, winding);
3230d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    }
3231d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
32324eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    Span* markAndChaseWinding(const Angle* angle, const int winding) {
32338dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        int index = angle->start();
32348dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        int endIndex = angle->end();
3235c7b4be7f110bc7b487c3c3f28d82877584e74c2fskia.committer@gmail.com        int step = SkSign32(endIndex - index);
32368dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        int min = SkMin32(index, endIndex);
323759823f7f3ba43c7c6bc1fa8c600b093ecb4236aacaryclark@google.com        markWinding(min, winding);
32384eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Span* last;
32394eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Segment* other = this;
32404eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        while ((other = other->nextChase(index, step, min, last))) {
32414eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            if (other->fTs[min].fWindSum != SK_MinS32) {
32424eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                SkASSERT(other->fTs[min].fWindSum == winding);
32434eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                return NULL;
32444eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            }
32454eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            other->markWinding(min, winding);
32464eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        }
3247fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        return last;
32488dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
3249c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com
32507fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
325131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int min = SkMin32(index, endIndex);
325231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int step = SkSign32(endIndex - index);
325331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        markWinding(min, winding, oppWinding);
32544eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Span* last;
32554eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Segment* other = this;
32564eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        while ((other = other->nextChase(index, step, min, last))) {
32574eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            if (other->fTs[min].fWindSum != SK_MinS32) {
32584aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com                SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
32594eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                return NULL;
32604eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            }
32614eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            other->markWinding(min, winding, oppWinding);
32624eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        }
326331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        return last;
326431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    }
326531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com
32667fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
32677fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int start = angle->start();
32687fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int end = angle->end();
32697fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        return markAndChaseWinding(start, end, winding, oppWinding);
32707fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
32717fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
3272d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
3273d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkASSERT(angle->segment() == this);
3274d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        if (useInnerWinding(maxWinding, sumWinding)) {
3275d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            maxWinding = sumWinding;
3276d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
3277d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        Span* last;
3278d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        if (activeAngle) {
3279d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            last = markAndChaseWinding(angle, maxWinding);
3280d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        } else {
3281d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            last = markAndChaseDoneUnary(angle, maxWinding);
3282d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
3283d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        return last;
3284d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    }
3285d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
32867fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
32877fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            bool activeAngle, const Angle* angle) {
32887fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        SkASSERT(angle->segment() == this);
32897fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        if (useInnerWinding(maxWinding, sumWinding)) {
32907fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            maxWinding = sumWinding;
32917fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
32927fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
32937fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            oppMaxWinding = oppSumWinding;
32947fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
32957fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        Span* last;
32967fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        if (activeAngle) {
32977fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
32987fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        } else {
32997fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
33007fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
33017fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        return last;
33027fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
33037fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
3304495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com    // FIXME: this should also mark spans with equal (x,y)
33058dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // This may be called when the segment is already marked done. While this
33068dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // wastes time, it shouldn't do any more than spin through the T spans.
3307d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    // OPTIMIZATION: abort on first done found (assuming that this code is
33088dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // always called to mark segments done).
330959823f7f3ba43c7c6bc1fa8c600b093ecb4236aacaryclark@google.com    void markDone(int index, int winding) {
33108dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com      //  SkASSERT(!done());
331124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkASSERT(winding);
3312af46cff4ee6099cebf3aa395805748af7d193a31caryclark@google.com        double referenceT = fTs[index].fT;
3313af46cff4ee6099cebf3aa395805748af7d193a31caryclark@google.com        int lesser = index;
3314a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3315a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            markOneDone(__FUNCTION__, lesser, winding);
3316a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        }
3317a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        do {
3318a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            markOneDone(__FUNCTION__, index, winding);
3319a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
332031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    }
332131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com
33227fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    void markDoneBinary(int index, int winding, int oppWinding) {
332331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com      //  SkASSERT(!done());
33249f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com        SkASSERT(winding || oppWinding);
332531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        double referenceT = fTs[index].fT;
332631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int lesser = index;
332731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
33287fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
33297fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
33307fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        do {
33317fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
33327fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
33337fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
33347fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
33357fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    void markDoneBinary(int index) {
33367fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        double referenceT = fTs[index].fT;
33377fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int lesser = index;
33387fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
33397fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            markOneDoneBinary(__FUNCTION__, lesser);
3340af46cff4ee6099cebf3aa395805748af7d193a31caryclark@google.com        }
3341af46cff4ee6099cebf3aa395805748af7d193a31caryclark@google.com        do {
33427fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            markOneDoneBinary(__FUNCTION__, index);
334331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
33448dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
3345549c93ef979aeb4dcb65b3d0fca4b58e8ab62227skia.committer@gmail.com
3346d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    void markDoneUnary(int index, int winding) {
3347d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com      //  SkASSERT(!done());
3348d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkASSERT(winding);
3349d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        double referenceT = fTs[index].fT;
3350d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int lesser = index;
3351d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3352d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            markOneDoneUnary(__FUNCTION__, lesser, winding);
3353d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
3354d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        do {
3355d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            markOneDoneUnary(__FUNCTION__, index, winding);
3356d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3357d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    }
3358d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
3359d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    void markDoneUnary(int index) {
3360d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        double referenceT = fTs[index].fT;
3361d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int lesser = index;
3362d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3363d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            markOneDoneUnary(__FUNCTION__, lesser);
3364d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
3365d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        do {
3366d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            markOneDoneUnary(__FUNCTION__, index);
3367d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3368d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    }
3369d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
337024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    void markOneDone(const char* funName, int tIndex, int winding) {
337124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        Span* span = markOneWinding(funName, tIndex, winding);
337224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        if (!span) {
337324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            return;
337424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
337524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        span->fDone = true;
337624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        fDoneSpans++;
337724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    }
3378d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
33797fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    void markOneDoneBinary(const char* funName, int tIndex) {
33807fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        Span* span = verifyOneWinding(funName, tIndex);
33817fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        if (!span) {
33827fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            return;
33837fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
33847fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        span->fDone = true;
33857fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        fDoneSpans++;
33867fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
33877fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
33887fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
338931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
339031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        if (!span) {
339131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            return;
339231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        }
339331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        span->fDone = true;
339431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        fDoneSpans++;
339531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    }
339631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com
3397d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    void markOneDoneUnary(const char* funName, int tIndex) {
3398d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        Span* span = verifyOneWindingU(funName, tIndex);
3399d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        if (!span) {
3400d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            return;
3401d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
3402d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        span->fDone = true;
3403d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        fDoneSpans++;
3404d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    }
3405d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
3406d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3407d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        Span* span = markOneWinding(funName, tIndex, winding);
3408d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        if (!span) {
3409d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            return;
3410d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
3411d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        span->fDone = true;
3412d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        fDoneSpans++;
3413d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    }
3414d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
341524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    Span* markOneWinding(const char* funName, int tIndex, int winding) {
341624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        Span& span = fTs[tIndex];
341724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        if (span.fDone) {
341824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            return NULL;
341924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
342024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    #if DEBUG_MARK_DONE
342124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        debugShowNewWinding(funName, span, winding);
342224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    #endif
342324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
342403f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com   #ifdef SK_DEBUG
342524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkASSERT(abs(winding) <= gDebugMaxWindSum);
342603f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com   #endif
342724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        span.fWindSum = winding;
342824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        return &span;
342924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    }
343024c29d91caa4eaa31f9e77bad614627a252df35eskia.committer@gmail.com
343131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
343231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        Span& span = fTs[tIndex];
343331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        if (span.fDone) {
343431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            return NULL;
343531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        }
343631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    #if DEBUG_MARK_DONE
343731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        debugShowNewWinding(funName, span, winding, oppWinding);
343831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    #endif
343931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
344031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com   #ifdef SK_DEBUG
344131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        SkASSERT(abs(winding) <= gDebugMaxWindSum);
344231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com   #endif
344331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        span.fWindSum = winding;
344431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
344531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com   #ifdef SK_DEBUG
344631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
344731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com   #endif
344831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        span.fOppSum = oppWinding;
344931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        return &span;
345031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    }
345131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com
34521304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    bool controls_contained_by_ends(int tStart, int tEnd) const {
34531304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        if (fVerb != SkPath::kCubic_Verb) {
34541304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            return false;
34551304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        }
34561304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        MAKE_CONST_CUBIC(aCubic, fPts);
34571304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        Cubic dst;
34581304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        sub_divide(aCubic, fTs[tStart].fT, fTs[tEnd].fT, dst);
34591304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        return ::controls_contained_by_ends(dst);
34601304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    }
34611304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com
34621304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
34631304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    bool clockwise(int tStart, int tEnd) const {
34641304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        SkASSERT(fVerb != SkPath::kLine_Verb);
34655e0500fb5f17fe14db42fc3e0aad08e6b41ccc5fcaryclark@google.com        SkPoint edge[4];
3466c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        subDivide(tStart, tEnd, edge);
34671304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        double sum = (edge[0].fX - edge[fVerb].fX) * (edge[0].fY + edge[fVerb].fY);
34681304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        if (fVerb == SkPath::kCubic_Verb) {
34691304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            SkScalar lesser = SkTMin(edge[0].fY, edge[3].fY);
34701304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            if (edge[1].fY < lesser && edge[2].fY < lesser) {
34711304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                _Line tangent1 = { {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1].fY} };
34721304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                _Line tangent2 = { {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3].fY} };
34731304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                if (testIntersect(tangent1, tangent2)) {
34741304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                    SkPoint topPt = CubicTop(fPts, fTs[tStart].fT, fTs[tEnd].fT);
34751304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                    sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY);
34761304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                    sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY);
34771304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                    return sum <= 0;
34781304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com                }
34791304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            }
34805e0500fb5f17fe14db42fc3e0aad08e6b41ccc5fcaryclark@google.com        }
34811304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        for (int idx = 0; idx < fVerb; ++idx){
34821304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
34831304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        }
34841304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        return sum <= 0;
34851304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    }
348603682beb8c1c5dfe714933e9419e1412b33c932dskia.committer@gmail.com
34871304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    bool monotonic_in_y(int tStart, int tEnd) const {
34881304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        if (fVerb != SkPath::kCubic_Verb) {
34891304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            return false;
34901304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        }
34911304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        MAKE_CONST_CUBIC(aCubic, fPts);
34921304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        Cubic dst;
34931304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        sub_divide(aCubic, fTs[tStart].fT, fTs[tEnd].fT, dst);
34941304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        return ::monotonic_in_y(dst);
34951304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    }
34961304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com
34971304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    bool serpentine(int tStart, int tEnd) const {
34981304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        if (fVerb != SkPath::kCubic_Verb) {
34991304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            return false;
35001304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        }
35011304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        MAKE_CONST_CUBIC(aCubic, fPts);
35021304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        Cubic dst;
35031304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        sub_divide(aCubic, fTs[tStart].fT, fTs[tEnd].fT, dst);
35041304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        return ::serpentine(dst);
35055e0500fb5f17fe14db42fc3e0aad08e6b41ccc5fcaryclark@google.com    }
35065e0500fb5f17fe14db42fc3e0aad08e6b41ccc5fcaryclark@google.com
35077fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    Span* verifyOneWinding(const char* funName, int tIndex) {
35087fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        Span& span = fTs[tIndex];
35097fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        if (span.fDone) {
35107fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            return NULL;
35117fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
35127fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    #if DEBUG_MARK_DONE
35137fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
35147fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    #endif
35157fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        SkASSERT(span.fWindSum != SK_MinS32);
35167fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        SkASSERT(span.fOppSum != SK_MinS32);
35177fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        return &span;
35187fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
35197fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
3520d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    Span* verifyOneWindingU(const char* funName, int tIndex) {
3521d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        Span& span = fTs[tIndex];
3522d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        if (span.fDone) {
3523d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            return NULL;
3524d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
3525d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    #if DEBUG_MARK_DONE
3526d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        debugShowNewWinding(funName, span, span.fWindSum);
3527d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    #endif
3528d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkASSERT(span.fWindSum != SK_MinS32);
3529d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        return &span;
3530d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    }
3531d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
3532f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    // note that just because a span has one end that is unsortable, that's
3533f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    // not enough to mark it done. The other end may be sortable, allowing the
3534f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    // span to be added.
35358f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
3536fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    void markUnsortable(int start, int end) {
3537fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        Span* span = &fTs[start];
3538fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        if (start < end) {
35398f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#if DEBUG_UNSORTABLE
35401304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            debugShowNewWinding(__FUNCTION__, *span, 0);
3541d9f65e3df45c9b4994c70f6bf13d29985afd2f65skia.committer@gmail.com#endif
3542fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com            span->fUnsortableStart = true;
3543fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        } else {
3544fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com            --span;
35458f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#if DEBUG_UNSORTABLE
35461304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com            debugShowNewWinding(__FUNCTION__, *span, 0);
3547d9f65e3df45c9b4994c70f6bf13d29985afd2f65skia.committer@gmail.com#endif
3548fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com            span->fUnsortableEnd = true;
3549fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        }
3550f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
3551fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com            return;
3552fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        }
3553fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        span->fDone = true;
3554fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        fDoneSpans++;
3555fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
35568dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
355759823f7f3ba43c7c6bc1fa8c600b093ecb4236aacaryclark@google.com    void markWinding(int index, int winding) {
3558afe56de6361a81eef537ddd8f6d5626c8546d4c7caryclark@google.com    //    SkASSERT(!done());
355924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkASSERT(winding);
35608dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        double referenceT = fTs[index].fT;
35618dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        int lesser = index;
3562a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3563a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            markOneWinding(__FUNCTION__, lesser, winding);
3564a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        }
3565a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        do {
3566a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            markOneWinding(__FUNCTION__, index, winding);
3567a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com       } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
356831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    }
356931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com
357031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    void markWinding(int index, int winding, int oppWinding) {
357131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    //    SkASSERT(!done());
35724eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        SkASSERT(winding || oppWinding);
357331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        double referenceT = fTs[index].fT;
357431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int lesser = index;
357531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
357631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
35778dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
35788dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        do {
357931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            markOneWinding(__FUNCTION__, index, winding, oppWinding);
358031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com       } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3581af46cff4ee6099cebf3aa395805748af7d193a31caryclark@google.com    }
3582fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
35832ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com    void matchWindingValue(int tIndex, double t, bool borrowWind) {
35840c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        int nextDoorWind = SK_MaxS32;
35857ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        int nextOppWind = SK_MaxS32;
35860c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        if (tIndex > 0) {
35870c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com            const Span& below = fTs[tIndex - 1];
35883350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            if (approximately_negative(t - below.fT)) {
35890c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com                nextDoorWind = below.fWindValue;
35907ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                nextOppWind = below.fOppValue;
35910c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com            }
35920c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        }
35930c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
35940c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com            const Span& above = fTs[tIndex + 1];
35953350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            if (approximately_negative(above.fT - t)) {
35960c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com                nextDoorWind = above.fWindValue;
35977ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                nextOppWind = above.fOppValue;
35980c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com            }
35990c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        }
36002ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com        if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
36012ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com            const Span& below = fTs[tIndex - 1];
36022ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com            nextDoorWind = below.fWindValue;
36037ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            nextOppWind = below.fOppValue;
36042ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com        }
36050c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        if (nextDoorWind != SK_MaxS32) {
36060c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com            Span& newSpan = fTs[tIndex];
36070c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com            newSpan.fWindValue = nextDoorWind;
36087ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            newSpan.fOppValue = nextOppWind;
36094eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
36100c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com                newSpan.fDone = true;
36110c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com                ++fDoneSpans;
36120c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com            }
36130c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        }
36140c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com    }
36150c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com
3616db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3617db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        // find bounds
3618db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        Bounds bounds;
3619db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        bounds.setPoint(xyAtT(index));
3620db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        bounds.add(xyAtT(endIndex));
3621db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        SkScalar width = bounds.width();
3622db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        SkScalar height = bounds.height();
3623db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (width > height) {
3624db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            if (approximately_negative(width)) {
3625db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                unsortable = true; // edge is too small to resolve meaningfully
3626db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            }
3627db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            return false;
3628db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        } else {
3629db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            if (approximately_negative(height)) {
3630db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                unsortable = true; // edge is too small to resolve meaningfully
3631db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            }
3632db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            return true;
3633db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
3634db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
3635db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com
36369764cc6c109dba208592fe5f16447b8439375746caryclark@google.com    // return span if when chasing, two or more radiating spans are not done
36379764cc6c109dba208592fe5f16447b8439375746caryclark@google.com    // OPTIMIZATION: ? multiple spans is detected when there is only one valid
36389764cc6c109dba208592fe5f16447b8439375746caryclark@google.com    // candidate and the remaining spans have windValue == 0 (canceled by
36399764cc6c109dba208592fe5f16447b8439375746caryclark@google.com    // coincidence). The coincident edges could either be removed altogether,
36409764cc6c109dba208592fe5f16447b8439375746caryclark@google.com    // or this code could be more complicated in detecting this case. Worth it?
36419764cc6c109dba208592fe5f16447b8439375746caryclark@google.com    bool multipleSpans(int end) const {
36429764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        return end > 0 && end < fTs.count() - 1;
364388f7d0cb09707355bc9079d4b0569537e8048fa9caryclark@google.com    }
364488f7d0cb09707355bc9079d4b0569537e8048fa9caryclark@google.com
3645db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    bool nextCandidate(int& start, int& end) const {
364610227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        while (fTs[end].fDone) {
364710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            if (fTs[end].fT == 1) {
3648db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                return false;
3649db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            }
365010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            ++end;
365110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        }
365210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        start = end;
365310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        end = nextExactSpan(start, 1);
3654db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        return true;
3655db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
3656db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com
36571ab0aac67247bf3ec1f23b220456d316d9a80b45caryclark@google.com    Segment* nextChase(int& index, const int step, int& min, Span*& last) {
36584eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        int end = nextExactSpan(index, step);
36594eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        SkASSERT(end >= 0);
36604eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        if (multipleSpans(end)) {
36614eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            last = &fTs[end];
36624eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            return NULL;
36634eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        }
36644eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        const Span& endSpan = fTs[end];
36654eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Segment* other = endSpan.fOther;
36664eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        index = endSpan.fOtherIndex;
3667aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com        SkASSERT(index >= 0);
36684eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        int otherEnd = other->nextExactSpan(index, step);
3669aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com        SkASSERT(otherEnd >= 0);
36704eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        min = SkMin32(index, otherEnd);
36714eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        return other;
36724eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    }
36734eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com
3674a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    // This has callers for two different situations: one establishes the end
3675a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    // of the current span, and one establishes the beginning of the next span
3676a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    // (thus the name). When this is looking for the end of the current span,
3677a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    // coincidence is found when the beginning Ts contain -step and the end
3678a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    // contains step. When it is looking for the beginning of the next, the
3679a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    // first Ts found can be ignored and the last Ts should contain -step.
36808dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    // OPTIMIZATION: probably should split into two functions
3681a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    int nextSpan(int from, int step) const {
3682495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com        const Span& fromSpan = fTs[from];
3683495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com        int count = fTs.count();
3684495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com        int to = from;
3685495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com        while (step > 0 ? ++to < count : --to >= 0) {
3686495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com            const Span& span = fTs[to];
36873350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            if (approximately_zero(span.fT - fromSpan.fT)) {
3688495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com                continue;
3689495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com            }
3690495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com            return to;
3691495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com        }
3692495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com        return -1;
3693495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com    }
3694439cb51451ef6f55f65dab90eb7f91acf67ea8feskia.committer@gmail.com
36956aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    // FIXME
36966aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    // this returns at any difference in T, vs. a preset minimum. It may be
36976aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    // that all callers to nextSpan should use this instead.
3698fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    // OPTIMIZATION splitting this into separate loops for up/down steps
3699fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    // would allow using precisely_negative instead of precisely_zero
37006aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    int nextExactSpan(int from, int step) const {
37016aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        const Span& fromSpan = fTs[from];
37026aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        int count = fTs.count();
37036aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        int to = from;
37046aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        while (step > 0 ? ++to < count : --to >= 0) {
37056aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            const Span& span = fTs[to];
3706a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com            if (precisely_zero(span.fT - fromSpan.fT)) {
37076aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                continue;
37086aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            }
37096aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            return to;
37106aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        }
37116aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        return -1;
37126aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    }
3713055c7c299cb47eebd360b809ad58a0006e2e55f7skia.committer@gmail.com
3714235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    bool operand() const {
3715235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        return fOperand;
3716235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    }
3717235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
371857cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    int oppSign(const Angle* angle) const {
371957cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        SkASSERT(angle->segment() == this);
372057cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        return oppSign(angle->start(), angle->end());
372157cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    }
3722b3b6a60d35c8ee521252367200148561c628ee42skia.committer@gmail.com
372357cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    int oppSign(int startIndex, int endIndex) const {
372457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
372557cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                : fTs[endIndex].fOppValue;
372657cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com#if DEBUG_WIND_BUMP
372757cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
372857cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com#endif
372957cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        return result;
373057cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    }
373157cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com
373231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    int oppSum(int tIndex) const {
373331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        return fTs[tIndex].fOppSum;
373431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    }
373531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com
373631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    int oppSum(const Angle* angle) const {
373731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int lesser = SkMin32(angle->start(), angle->end());
373831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        return fTs[lesser].fOppSum;
3739235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    }
3740495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com
374157cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    int oppValue(int tIndex) const {
374257cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        return fTs[tIndex].fOppValue;
374357cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    }
374457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com
3745e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    int oppValue(const Angle* angle) const {
3746e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        int lesser = SkMin32(angle->start(), angle->end());
3747e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        return fTs[lesser].fOppValue;
3748e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    }
3749e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com
3750fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    const SkPoint* pts() const {
3751fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return fPts;
3752fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
3753a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
3754fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    void reset() {
37554eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        init(NULL, (SkPath::Verb) -1, false, false);
3756fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3757fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fTs.reset();
3758a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com    }
37591c9c0d37111e6ff7a74a2908bf62a0d3954f2bb5skia.committer@gmail.com
37604eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    void setOppXor(bool isOppXor) {
37614eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        fOppXor = isOppXor;
37624eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    }
376312eea2b10d6caaafe0a207d10b1e9322510983a2skia.committer@gmail.com
37647ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com    void setSpanT(int index, double t) {
37657ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com        Span& span = fTs[index];
37667ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com        span.fT = t;
37677ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com        span.fOther->fTs[span.fOtherIndex].fOtherT = t;
37687ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com    }
37694eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com
3770d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3771d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int deltaSum = spanSign(index, endIndex);
3772d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        maxWinding = sumWinding;
3773d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        sumWinding = sumWinding -= deltaSum;
3774d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    }
3775d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
37767fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
37777fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
37787fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int deltaSum = spanSign(index, endIndex);
37797fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int oppDeltaSum = oppSign(index, endIndex);
37807fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        if (operand()) {
37817fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            maxWinding = sumSuWinding;
37827fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            sumWinding = sumSuWinding -= deltaSum;
37837fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            oppMaxWinding = sumMiWinding;
37847fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            oppSumWinding = sumMiWinding -= oppDeltaSum;
37857fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        } else {
37867fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            maxWinding = sumMiWinding;
37877fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            sumWinding = sumMiWinding -= deltaSum;
37887fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            oppMaxWinding = sumSuWinding;
37897fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            oppSumWinding = sumSuWinding -= oppDeltaSum;
37907fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
37917fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
37927fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
3793f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    // This marks all spans unsortable so that this info is available for early
3794f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    // exclusion in find top and others. This could be optimized to only mark
3795f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    // adjacent spans that unsortable. However, this makes it difficult to later
3796f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    // determine starting points for edge detection in find top and the like.
3797c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
3798f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        bool sortable = true;
3799c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        int angleCount = angles.count();
3800c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        int angleIndex;
3801c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        angleList.setReserve(angleCount);
3802c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3803c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            Angle& angle = angles[angleIndex];
3804f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            *angleList.append() = &angle;
3805f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            sortable &= !angle.unsortable();
3806f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
3807f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (sortable) {
3808f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            QSort<Angle>(angleList.begin(), angleList.end() - 1);
3809f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3810f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                if (angles[angleIndex].unsortable()) {
3811f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                    sortable = false;
3812f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                    break;
3813f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                }
3814f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            }
3815f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
3816f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (!sortable) {
3817f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3818f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                Angle& angle = angles[angleIndex];
3819fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com                angle.segment()->markUnsortable(angle.start(), angle.end());
3820c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            }
3821c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        }
3822f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        return sortable;
3823c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    }
3824c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com
38251577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com    // OPTIMIZATION: mark as debugging only if used solely by tests
3826a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    const Span& span(int tIndex) const {
3827a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        return fTs[tIndex];
3828a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    }
3829d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
3830235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    int spanSign(const Angle* angle) const {
3831235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        SkASSERT(angle->segment() == this);
3832235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        return spanSign(angle->start(), angle->end());
3833235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    }
3834235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
38358dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    int spanSign(int startIndex, int endIndex) const {
383631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
383731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                : fTs[endIndex].fWindValue;
38382ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com#if DEBUG_WIND_BUMP
38392ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com        SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
38402ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com#endif
38412ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com        return result;
38422ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com    }
384358433de8627c54ac2d68c65d248d67f48a79179dskia.committer@gmail.com
3844c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    void subDivide(int start, int end, SkPoint edge[4]) const {
3845c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        edge[0] = fTs[start].fPt;
3846c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        edge[fVerb] = fTs[end].fPt;
3847c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        if (fVerb == SkPath::kQuad_Verb || fVerb == SkPath::kCubic_Verb) {
3848c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            _Point sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[fVerb].fX, edge[fVerb].fY }};
3849c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            if (fVerb == SkPath::kQuad_Verb) {
3850c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                MAKE_CONST_QUAD(aQuad, fPts);
3851c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                edge[1] = sub_divide(aQuad, sub[0], sub[1], fTs[start].fT, fTs[end].fT).asSkPoint();
3852c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            } else {
3853c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                MAKE_CONST_CUBIC(aCubic, fPts);
3854c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                sub_divide(aCubic, sub[0], sub[1], fTs[start].fT, fTs[end].fT, sub);
3855c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                edge[1] = sub[0].asSkPoint();
3856c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                edge[2] = sub[1].asSkPoint();
3857c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            }
3858c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        }
3859c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    }
386003682beb8c1c5dfe714933e9419e1412b33c932dskia.committer@gmail.com
38611304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    void subDivideBounds(int start, int end, Bounds& bounds) const {
38621304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        SkPoint edge[4];
38631304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        subDivide(start, end, edge);
38641304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com        (bounds.*setSegmentBounds[fVerb])(edge);
38651304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    }
38662ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com
3867a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    // OPTIMIZATION: mark as debugging only if used solely by tests
3868fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    double t(int tIndex) const {
3869fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return fTs[tIndex].fT;
3870fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
3871d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
387210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    double tAtMid(int start, int end, double mid) const {
387310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
387410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    }
387510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com
38767fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    bool tiny(const Angle* angle) const {
38777fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int start = angle->start();
38787fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int end = angle->end();
3879f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        const Span& mSpan = fTs[SkMin32(start, end)];
3880f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        return mSpan.fTiny;
3881f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
3882f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
388318063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com    static void TrackOutside(SkTDArray<double>& outsideTs, double end,
388418063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com            double start) {
388518063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com        int outCount = outsideTs.count();
38863350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
388718063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com            *outsideTs.append() = end;
388818063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com            *outsideTs.append() = start;
388918063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com        }
389018063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com    }
3891c7b4be7f110bc7b487c3c3f28d82877584e74c2fskia.committer@gmail.com
389224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    void undoneSpan(int& start, int& end) {
389324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        size_t tCount = fTs.count();
389424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        size_t index;
389524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        for (index = 0; index < tCount; ++index) {
389624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            if (!fTs[index].fDone) {
389724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                break;
389824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            }
389924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
390024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkASSERT(index < tCount - 1);
390124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        start = index;
390224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        double startT = fTs[index].fT;
39033350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        while (approximately_negative(fTs[++index].fT - startT))
390424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            SkASSERT(index < tCount);
390524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkASSERT(index < tCount);
390624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        end = index;
390724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    }
390818063441c23b334ab2ee7075c39ceeb8378e6fcfcaryclark@google.com
3909fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    bool unsortable(int index) const {
3910fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3911fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
3912fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com
3913b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    void updatePts(const SkPoint pts[]) {
3914b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        fPts = pts;
3915b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    }
3916a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
39177fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    int updateOppWinding(int index, int endIndex) const {
39187fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int lesser = SkMin32(index, endIndex);
39197fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int oppWinding = oppSum(lesser);
39207fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int oppSpanWinding = oppSign(index, endIndex);
39215e0500fb5f17fe14db42fc3e0aad08e6b41ccc5fcaryclark@google.com        if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)
39225e0500fb5f17fe14db42fc3e0aad08e6b41ccc5fcaryclark@google.com                && oppWinding != SK_MaxS32) {
39237fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            oppWinding -= oppSpanWinding;
39247fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
39257fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        return oppWinding;
39267fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
3927c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com
39287fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    int updateOppWinding(const Angle* angle) const {
39297fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int startIndex = angle->start();
39307fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int endIndex = angle->end();
39317fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        return updateOppWinding(endIndex, startIndex);
39327fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
39337fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
39347fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    int updateOppWindingReverse(const Angle* angle) const {
39357fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int startIndex = angle->start();
39367fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int endIndex = angle->end();
39377fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        return updateOppWinding(startIndex, endIndex);
39387fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
39397fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
39407fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    int updateWinding(int index, int endIndex) const {
39417fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int lesser = SkMin32(index, endIndex);
39427fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int winding = windSum(lesser);
39437fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int spanWinding = spanSign(index, endIndex);
39445e0500fb5f17fe14db42fc3e0aad08e6b41ccc5fcaryclark@google.com        if (winding && useInnerWinding(winding - spanWinding, winding) && winding != SK_MaxS32) {
39457fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            winding -= spanWinding;
39467fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
39477fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        return winding;
39487fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
39497fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
39507fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    int updateWinding(const Angle* angle) const {
39517fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int startIndex = angle->start();
39527fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int endIndex = angle->end();
39537fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        return updateWinding(endIndex, startIndex);
39547fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
39557fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
39567fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    int updateWindingReverse(const Angle* angle) const {
39577fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int startIndex = angle->start();
39587fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int endIndex = angle->end();
39597fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        return updateWinding(startIndex, endIndex);
39607fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
39617fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
3962fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkPath::Verb verb() const {
3963fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return fVerb;
3964fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
3965b89a03c890668f98d9f8b269b6ad00824409435bskia.committer@gmail.com
39668d83d0db6433e009c6c7f9adbd2580578b6f297eskia.committer@gmail.com    int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
3967d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3968d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            return SK_MinS32;
3969d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
3970d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3971d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkASSERT(winding != SK_MinS32);
3972d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
39738f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #if DEBUG_WINDING_AT_T
39748f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
3975d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    #endif
3976d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        // see if a + change in T results in a +/- change in X (compute x'(T))
39773586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
3978d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3979d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            dx = fPts[2].fX - fPts[1].fX - dx;
3980d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
3981db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (dx == 0) {
39828f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #if DEBUG_WINDING_AT_T
39838f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            SkDebugf(" dx=0 winding=SK_MinS32\n");
39848f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #endif
3985db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            return SK_MinS32;
3986db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
3987d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        if (winding * dx > 0) { // if same signs, result is negative
3988d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            winding += dx > 0 ? -windVal : windVal;
3989d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
39908f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #if DEBUG_WINDING_AT_T
39918f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding);
39928f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #endif
3993d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        return winding;
3994d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    }
3995d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
3996fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com    int windSum(int tIndex) const {
39978dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return fTs[tIndex].fWindSum;
39988dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
3999d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
4000fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com    int windSum(const Angle* angle) const {
4001495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com        int start = angle->start();
4002495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com        int end = angle->end();
4003495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com        int index = SkMin32(start, end);
4004fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        return windSum(index);
40058dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
40068dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
40078dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    int windValue(int tIndex) const {
40088dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return fTs[tIndex].fWindValue;
40098dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
4010d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
40118dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    int windValue(const Angle* angle) const {
40128dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        int start = angle->start();
40138dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        int end = angle->end();
40148dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        int index = SkMin32(start, end);
40158dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return windValue(index);
40168dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
4017453995e01d884d62ce2e808e0067e494c0c9c7faskia.committer@gmail.com
40188f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    int windValueAt(double t) const {
40198f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        int count = fTs.count();
40208f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        for (int index = 0; index < count; ++index) {
40218f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (fTs[index].fT == t) {
40228f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                return fTs[index].fWindValue;
40238f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            }
40248f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        }
40258f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        SkASSERT(0);
40268f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        return 0;
40278f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    }
40288f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com
40293586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    SkScalar xAtT(int index) const {
40303586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        return xAtT(&fTs[index]);
40313586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    }
40323586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com
40338dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    SkScalar xAtT(const Span* span) const {
40348dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return xyAtT(span).fX;
4035495f8e435b677f28913cd2adc8caa8d3d766dd17caryclark@google.com    }
4036055c7c299cb47eebd360b809ad58a0006e2e55f7skia.committer@gmail.com
40378dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    const SkPoint& xyAtT(int index) const {
40388dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return xyAtT(&fTs[index]);
4039fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
4040fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
4041a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com    const SkPoint& xyAtT(const Span* span) const {
404227c449af06cd1d05db441593d08b84f3530fba52caryclark@google.com        if (SkScalarIsNaN(span->fPt.fX)) {
4043c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            SkASSERT(0); // make sure this path is never used
4044a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com            if (span->fT == 0) {
404527c449af06cd1d05db441593d08b84f3530fba52caryclark@google.com                span->fPt = fPts[0];
4046a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com            } else if (span->fT == 1) {
404727c449af06cd1d05db441593d08b84f3530fba52caryclark@google.com                span->fPt = fPts[fVerb];
4048a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com            } else {
404927c449af06cd1d05db441593d08b84f3530fba52caryclark@google.com                (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
4050a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com            }
4051a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com        }
405227c449af06cd1d05db441593d08b84f3530fba52caryclark@google.com        return span->fPt;
4053fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
4054d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
4055db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    // used only by right angle winding finding
405610227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    void xyAtT(double mid, SkPoint& pt) const {
405710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        (*SegmentXYAtT[fVerb])(fPts, mid, &pt);
4058db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
4059db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com
40608dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    SkScalar yAtT(int index) const {
40618dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return yAtT(&fTs[index]);
40628dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
4063fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
40648dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    SkScalar yAtT(const Span* span) const {
40658dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return xyAtT(span).fY;
4066a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com    }
4067a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
40684eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    void zeroCoincidentOpp(Span* oTest, int index) {
40694eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Span* const test = &fTs[index];
40704eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Span* end = test;
40714eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        do {
40724eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            end->fOppValue = 0;
40734eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            end = &fTs[++index];
40744eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        } while (approximately_negative(end->fT - test->fT));
40754eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    }
40764eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com
40774eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
40784eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Span* const oTest = &fTs[oIndex];
40794eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Span* oEnd = oTest;
40804eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        const double startT = test->fT;
40814eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        const double oStartT = oTest->fT;
40824eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        double otherTMatch = (test->fT - startT) * tRatio + oStartT;
40834eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        while (!approximately_negative(oEndT - oEnd->fT)
40844eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                && approximately_negative(oEnd->fT - otherTMatch)) {
40854eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            oEnd->fOppValue = 0;
40864eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            oEnd = &fTs[++oIndex];
4087729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com        }
40884eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    }
40894eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com
40904eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    void zeroSpan(Span* span) {
40914eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
40924eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        span->fWindValue = 0;
4093729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com        span->fOppValue = 0;
40944eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        SkASSERT(!span->fDone);
40954eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        span->fDone = true;
40964eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        ++fDoneSpans;
40976ec1526680bcc05b8b8b2c7ad9f78ba247e123b7caryclark@google.com    }
40986ec1526680bcc05b8b8b2c7ad9f78ba247e123b7caryclark@google.com
4099fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#if DEBUG_DUMP
4100fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    void dump() const {
4101fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        const char className[] = "Segment";
4102fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        const int tab = 4;
4103fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        for (int i = 0; i < fTs.count(); ++i) {
4104fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            SkPoint out;
4105fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
4106fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
41078dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                    " otherT=%1.9g windSum=%d\n",
4108fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    tab + sizeof(className), className, fID,
4109fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
41108dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                    fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
4111fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        }
411215fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com        SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
4113fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                tab + sizeof(className), className, fID,
411415fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com                fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
4115fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
4116fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#endif
4117fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
411847580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com#if DEBUG_CONCIDENT
4119aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com    // SkASSERT if pair has not already been added
4120534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com     void debugAddTPair(double t, const Segment& other, double otherT) const {
4121cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        for (int i = 0; i < fTs.count(); ++i) {
4122cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
4123cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com                return;
4124cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com            }
4125cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        }
4126cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com        SkASSERT(0);
4127cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com     }
4128cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com#endif
4129cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com
4130534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com#if DEBUG_DUMP
4131534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com    int debugID() const {
4132534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        return fID;
4133534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com    }
4134534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com#endif
4135534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com
413624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com#if DEBUG_WINDING
413724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    void debugShowSums() const {
413824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
413924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
414024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        for (int i = 0; i < fTs.count(); ++i) {
414124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            const Span& span = fTs[i];
414224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
414324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            if (span.fWindSum == SK_MinS32) {
414424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                SkDebugf("?");
414524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            } else {
414624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                SkDebugf("%d", span.fWindSum);
414724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            }
414824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            SkDebugf("]");
414924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
415024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkDebugf("\n");
415124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    }
415224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com#endif
415324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com
4154cc90505674cd845fcbebd7e0654c3ff04a2e4f25caryclark@google.com#if DEBUG_CONCIDENT
4155534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com    void debugShowTs() const {
415624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        SkDebugf("%s id=%d", __FUNCTION__, fID);
41574eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        int lastWind = -1;
41584eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        int lastOpp = -1;
41594eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        double lastT = -1;
41604eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        int i;
41614eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        for (i = 0; i < fTs.count(); ++i) {
41624eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
41634eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                    || lastOpp != fTs[i].fOppValue;
41644eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            if (change && lastWind >= 0) {
41654eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
41664eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                        lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
41674eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            }
41684eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            if (change) {
41694eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                SkDebugf(" [o=%d", fTs[i].fOther->fID);
41704eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                lastWind = fTs[i].fWindValue;
41714eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                lastOpp = fTs[i].fOppValue;
41724eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                lastT = fTs[i].fT;
41734eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            } else {
41744eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                SkDebugf(",%d", fTs[i].fOther->fID);
41754eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            }
41764eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        }
41774eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        if (i <= 0) {
41784eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            return;
41794eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        }
41804eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
41814eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
41824eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        if (fOperand) {
41834eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            SkDebugf(" operand");
41844eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        }
41854eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        if (done()) {
41864eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            SkDebugf(" done");
418747580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com        }
418847580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com        SkDebugf("\n");
418947580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com    }
419047580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com#endif
419147580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com
4192027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com#if DEBUG_ACTIVE_SPANS
4193534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com    void debugShowActiveSpans() const {
4194027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com        if (done()) {
4195027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com            return;
4196027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com        }
41974eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com#if DEBUG_ACTIVE_SPANS_SHORT_FORM
41984eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        int lastId = -1;
41994eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        double lastT = -1;
42004eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com#endif
4201027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com        for (int i = 0; i < fTs.count(); ++i) {
42027ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            SkASSERT(&fTs[i] == &fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOther->
42037ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                    fTs[fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOtherIndex]);
4204027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com            if (fTs[i].fDone) {
4205027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com                continue;
4206027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com            }
42074eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com#if DEBUG_ACTIVE_SPANS_SHORT_FORM
42084eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            if (lastId == fID && lastT == fTs[i].fT) {
42094eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                continue;
42104eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            }
42114eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            lastId = fID;
42124eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            lastT = fTs[i].fT;
42134eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com#endif
4214534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            SkDebugf("%s id=%d", __FUNCTION__, fID);
4215027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com            SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4216027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com            for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4217027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com                SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4218027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com            }
4219027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com            const Span* span = &fTs[i];
4220d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
42210c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com                     xAtT(span), yAtT(span));
422247d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com            int iEnd = i + 1;
422347d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com            while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) {
422447d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com                ++iEnd;
422547d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com            }
422647d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com            SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT);
4227027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com            const Segment* other = fTs[i].fOther;
4228534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
4229534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com                    other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
4230534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            if (fTs[i].fWindSum == SK_MinS32) {
4231534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com                SkDebugf("?");
4232534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            } else {
4233534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com                SkDebugf("%d", fTs[i].fWindSum);
4234534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            }
42354eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
4236027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com        }
4237027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com    }
4238b0a327e9390da5865d4c56db5e5259adc3380d37skia.committer@gmail.com
42396aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    // This isn't useful yet -- but leaving it in for now in case i think of something
42406aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    // to use it for
42416aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    void validateActiveSpans() const {
42426aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        if (done()) {
42436aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            return;
42446aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        }
42456aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        int tCount = fTs.count();
42466aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        for (int index = 0; index < tCount; ++index) {
42476aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            if (fTs[index].fDone) {
42486aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                continue;
42496aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            }
42506aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            // count number of connections which are not done
42516aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            int first = index;
42526aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            double baseT = fTs[index].fT;
42536aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
42546aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                --first;
42556aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            }
42566aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            int last = index;
42576aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
42586aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                ++last;
42596aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            }
42606aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            int connections = 0;
42616aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            connections += first > 0 && !fTs[first - 1].fDone;
42626aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            for (int test = first; test <= last; ++test) {
42636aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                connections += !fTs[test].fDone;
42646aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                const Segment* other = fTs[test].fOther;
42656aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                int oIndex = fTs[test].fOtherIndex;
42666aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                connections += !other->fTs[oIndex].fDone;
42676aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
42686aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            }
42696aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com      //      SkASSERT(!(connections & 1));
42706aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        }
42716aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    }
4272027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com#endif
4273027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com
42741304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com#if DEBUG_MARK_DONE || DEBUG_UNSORTABLE
42750c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com    void debugShowNewWinding(const char* fun, const Span& span, int winding) {
42760c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        const SkPoint& pt = xyAtT(&span);
42770c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        SkDebugf("%s id=%d", fun, fID);
42780c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
42790c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
42800c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com            SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
42810c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        }
4282fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4283fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com                fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4284d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com        SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d windSum=",
428564334352cc3f29f52dfa07225d65eb218d2fd830skia.committer@gmail.com                span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
4286d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com                (&span)[1].fT, winding);
42870c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        if (span.fWindSum == SK_MinS32) {
42880c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com            SkDebugf("?");
42890c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        } else {
42900c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com            SkDebugf("%d", span.fWindSum);
42910c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        }
42920c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com        SkDebugf(" windValue=%d\n", span.fWindValue);
42930c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com    }
429431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com
429531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
429631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        const SkPoint& pt = xyAtT(&span);
429731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        SkDebugf("%s id=%d", fun, fID);
429831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
429931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
430031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
430131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        }
430231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
430331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4304d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com        SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d newOppSum=%d oppSum=",
430531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
4306d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com                (&span)[1].fT, winding, oppWinding);
430731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        if (span.fOppSum == SK_MinS32) {
430831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            SkDebugf("?");
430931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        } else {
431031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            SkDebugf("%d", span.fOppSum);
431131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        }
431231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        SkDebugf(" windSum=");
431331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        if (span.fWindSum == SK_MinS32) {
431431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            SkDebugf("?");
431531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        } else {
431631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            SkDebugf("%d", span.fWindSum);
431731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        }
431831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        SkDebugf(" windValue=%d\n", span.fWindValue);
431931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    }
43200c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com#endif
43210c803d048c826fadfeed51207488867e17e0cc10caryclark@google.com
43221304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com#if DEBUG_SORT || DEBUG_SWAP_TOP
432303f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
432431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            const int contourWinding, const int oppContourWinding) const {
4325c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        if (--gDebugSortCount < 0) {
4326c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            return;
4327c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        }
4328afe56de6361a81eef537ddd8f6d5626c8546d4c7caryclark@google.com        SkASSERT(angles[first]->segment() == this);
4329200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com        SkASSERT(angles.count() > 1);
4330534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        int lastSum = contourWinding;
433131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int oppLastSum = oppContourWinding;
433257cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        const Angle* firstAngle = angles[first];
433357cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        int windSum = lastSum - spanSign(firstAngle);
433457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        int oppoSign = oppSign(firstAngle);
433557cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        int oppWindSum = oppLastSum - oppoSign;
4336c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        #define WIND_AS_STRING(x) char x##Str[12]; if (!valid_wind(x)) strcpy(x##Str, "?"); \
4337c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            else snprintf(x##Str, sizeof(x##Str), "%d", x)
4338c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        WIND_AS_STRING(contourWinding);
4339c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        WIND_AS_STRING(oppContourWinding);
4340c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FUNCTION__,
4341c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                contourWindingStr, oppContourWindingStr, spanSign(angles[first]));
4342afe56de6361a81eef537ddd8f6d5626c8546d4c7caryclark@google.com        int index = first;
4343afe56de6361a81eef537ddd8f6d5626c8546d4c7caryclark@google.com        bool firstTime = true;
434447580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com        do {
434547580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            const Angle& angle = *angles[index];
434647580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            const Segment& segment = *angle.segment();
434747580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            int start = angle.start();
434847580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            int end = angle.end();
434947580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            const Span& sSpan = segment.fTs[start];
435047580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            const Span& eSpan = segment.fTs[end];
435147580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            const Span& mSpan = segment.fTs[SkMin32(start, end)];
435231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            bool opp = segment.fOperand ^ fOperand;
4353534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            if (!firstTime) {
435457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                oppoSign = segment.oppSign(&angle);
435531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                if (opp) {
435631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    oppLastSum = oppWindSum;
435731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    oppWindSum -= segment.spanSign(&angle);
435857cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                    if (oppoSign) {
435957cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                        lastSum = windSum;
436057cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                        windSum -= oppoSign;
436157cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                    }
436231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                } else {
436331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    lastSum = windSum;
436431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    windSum -= segment.spanSign(&angle);
436557cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                    if (oppoSign) {
436657cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                        oppLastSum = oppWindSum;
436757cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                        oppWindSum -= oppoSign;
436857cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                    }
436931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                }
4370afe56de6361a81eef537ddd8f6d5626c8546d4c7caryclark@google.com            }
437164334352cc3f29f52dfa07225d65eb218d2fd830skia.committer@gmail.com            SkDebugf("%s [%d] %s", __FUNCTION__, index,
4372d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com                    angle.unsortable() ? "*** UNSORTABLE *** " : "");
4373d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com        #if COMPACT_DEBUG_SORT
4374d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com            SkDebugf("id=%d %s start=%d (%1.9g,%,1.9g) end=%d (%1.9g,%,1.9g)",
4375c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com                    segment.fID, kLVerbStr[segment.fVerb],
4376fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com                    start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
4377d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com                    segment.xAtT(&eSpan), segment.yAtT(&eSpan));
4378d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com        #else
4379d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com            switch (segment.fVerb) {
4380d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com                case SkPath::kLine_Verb:
4381d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com                    SkDebugf(LINE_DEBUG_STR, LINE_DEBUG_DATA(segment.fPts));
4382d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com                    break;
4383d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com                case SkPath::kQuad_Verb:
4384d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com                    SkDebugf(QUAD_DEBUG_STR, QUAD_DEBUG_DATA(segment.fPts));
4385d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com                    break;
4386d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com                case SkPath::kCubic_Verb:
4387d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com                    SkDebugf(CUBIC_DEBUG_STR, CUBIC_DEBUG_DATA(segment.fPts));
4388d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com                    break;
43891ab0aac67247bf3ec1f23b220456d316d9a80b45caryclark@google.com                default:
43901ab0aac67247bf3ec1f23b220456d316d9a80b45caryclark@google.com                    SkASSERT(0);
4391d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com            }
4392d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com            SkDebugf(" tStart=%1.9g tEnd=%1.9g", sSpan.fT, eSpan.fT);
4393d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com        #endif
4394d4c8e1e035bc2edb6caf2c9eac71ef918e60b80bcaryclark@google.com            SkDebugf(" sign=%d windValue=%d windSum=", angle.sign(), mSpan.fWindValue);
4395c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            winding_printf(mSpan.fWindSum);
439631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            int last, wind;
439731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            if (opp) {
439831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                last = oppLastSum;
439931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                wind = oppWindSum;
440031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            } else {
440131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                last = lastSum;
440231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                wind = windSum;
440331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            }
4404c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            bool useInner = valid_wind(last) && valid_wind(wind) && useInnerWinding(last, wind);
4405c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            WIND_AS_STRING(last);
4406c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            WIND_AS_STRING(wind);
4407c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            WIND_AS_STRING(lastSum);
4408c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            WIND_AS_STRING(oppLastSum);
4409c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            WIND_AS_STRING(windSum);
4410c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            WIND_AS_STRING(oppWindSum);
4411c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            #undef WIND_AS_STRING
441257cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com            if (!oppoSign) {
4413c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr : lastStr);
441457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com            } else {
4415c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : oppLastSumStr,
4416c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                        opp ? windSumStr : oppWindSumStr);
441757cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com            }
441831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
44196aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com#if false && DEBUG_ANGLE
4420c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com            angle.debugShow(segment.xyAtT(&sSpan));
4421c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com#endif
442247580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            ++index;
442347580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            if (index == angles.count()) {
442447580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com                index = 0;
442547580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            }
4426534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            if (firstTime) {
4427534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com                firstTime = false;
4428534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            }
442947580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com        } while (index != first);
443047580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com    }
44317fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
44327fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
44337fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        const Angle* firstAngle = angles[first];
44347fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        const Segment* segment = firstAngle->segment();
44357fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int winding = segment->updateWinding(firstAngle);
44367fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int oppWinding = segment->updateOppWinding(firstAngle);
44377fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        debugShowSort(fun, angles, first, winding, oppWinding);
44387fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    }
44397fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com
444047580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com#endif
444147580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com
4442534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com#if DEBUG_WINDING
44437ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    static char as_digit(int value) {
44447ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
44457ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    }
4446729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com#endif
44477ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com
4448729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com#if DEBUG_SHOW_WINDING
44497ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    int debugShowWindingValues(int slotCount, int ofInterest) const {
44507ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        if (!(1 << fID & ofInterest)) {
44517ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            return 0;
44527ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        }
44537ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        int sum = 0;
44547ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        SkTDArray<char> slots;
44557ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        slots.setCount(slotCount * 2);
44567ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        memset(slots.begin(), ' ', slotCount * 2);
44577ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        for (int i = 0; i < fTs.count(); ++i) {
44587ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com       //     if (!(1 << fTs[i].fOther->fID & ofInterest)) {
44597ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com       //         continue;
44607ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com       //     }
44617ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            sum += fTs[i].fWindValue;
44627ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
44637ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            sum += fTs[i].fOppValue;
44647ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
44657ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        }
44667ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
44677ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                slots.begin() + slotCount);
44687ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        return sum;
44697ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    }
4470729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com#endif
44717ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com
4472fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comprivate:
4473fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    const SkPoint* fPts;
4474fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    Bounds fBounds;
447515fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com    SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
44764eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
447724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    int fDoneSpans; // quick check that segment is finished
44784eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    // OPTIMIZATION: force the following to be byte-sized
44794eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    SkPath::Verb fVerb;
4480235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    bool fOperand;
44814eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    bool fXor; // set if original contour had even-odd fill
44824eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    bool fOppXor; // set if opposite operand had even-odd fill
4483fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#if DEBUG_DUMP
4484fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    int fID;
4485fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#endif
4486fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com};
4487fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
4488b973801328ef25105f7f3255ab912a1b675da056caryclark@google.comclass Contour;
4489b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com
44908dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.comstruct Coincidence {
4491b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com    Contour* fContours[2];
4492b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com    int fSegments[2];
44938dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    double fTs[2][2];
449445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    SkPoint fPts[2];
44958dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com};
44968dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
4497fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comclass Contour {
4498fa0588ff672564af1c235a63589573829035a60bcaryclark@google.compublic:
4499fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    Contour() {
4500fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        reset();
4501fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#if DEBUG_DUMP
4502fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fID = ++gContourID;
4503fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#endif
4504fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
4505fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
4506fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    bool operator<(const Contour& rh) const {
4507fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return fBounds.fTop == rh.fBounds.fTop
4508fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                ? fBounds.fLeft < rh.fBounds.fLeft
4509fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                : fBounds.fTop < rh.fBounds.fTop;
4510fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
4511fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
45128dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    void addCoincident(int index, Contour* other, int otherIndex,
45138dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            const Intersections& ts, bool swap) {
45148dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        Coincidence& coincidence = *fCoincidences.append();
451557cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        coincidence.fContours[0] = this; // FIXME: no need to store
4516b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com        coincidence.fContours[1] = other;
4517b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com        coincidence.fSegments[0] = index;
4518b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com        coincidence.fSegments[1] = otherIndex;
451945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        coincidence.fTs[swap][0] = ts.fT[0][0];
452045a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        coincidence.fTs[swap][1] = ts.fT[0][1];
452145a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        coincidence.fTs[!swap][0] = ts.fT[1][0];
452245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        coincidence.fTs[!swap][1] = ts.fT[1][1];
452345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        coincidence.fPts[0] = ts.fPt[0].asSkPoint();
452445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        coincidence.fPts[1] = ts.fPt[1].asSkPoint();
45258dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
45268dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
45278dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    void addCross(const Contour* crosser) {
45288dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com#ifdef DEBUG_CROSS
45298dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        for (int index = 0; index < fCrosses.count(); ++index) {
45308dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            SkASSERT(fCrosses[index] != crosser);
45318dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
45328dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com#endif
45338dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        *fCrosses.append() = crosser;
45348dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
45358dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
4536fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    void addCubic(const SkPoint pts[4]) {
45374eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        fSegments.push_back().addCubic(pts, fOperand, fXor);
4538c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        fContainsCurves = fContainsCubics = true;
4539fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
4540a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
4541b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    int addLine(const SkPoint pts[2]) {
45424eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        fSegments.push_back().addLine(pts, fOperand, fXor);
4543b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        return fSegments.count();
4544fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
4545d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
45468dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
45478dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
45488dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
4549a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
4550b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    int addQuad(const SkPoint pts[3]) {
45514eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        fSegments.push_back().addQuad(pts, fOperand, fXor);
4552fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fContainsCurves = true;
4553b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        return fSegments.count();
4554fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
4555a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
45567ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com    int addT(int segIndex, Contour* other, int otherIndex, const SkPoint& pt, double& newT) {
4557c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        setContainsIntercepts();
45587ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com        return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT);
45598dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
45608dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
45614aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com    int addSelfT(int segIndex, Contour* other, int otherIndex, const SkPoint& pt, double& newT) {
45624aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com        setContainsIntercepts();
45634aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com        return fSegments[segIndex].addSelfT(&other->fSegments[otherIndex], pt, newT);
45644aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com    }
45654aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com
45667ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com    int addUnsortableT(int segIndex, Contour* other, int otherIndex, bool start,
45677ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com            const SkPoint& pt, double& newT) {
45687ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com        return fSegments[segIndex].addUnsortableT(&other->fSegments[otherIndex], start, pt, newT);
456973ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    }
457073ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com
4571a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com    const Bounds& bounds() const {
4572fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return fBounds;
4573fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
4574d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
4575fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    void complete() {
4576fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        setBounds();
4577fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fContainsIntercepts = false;
4578fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
457958433de8627c54ac2d68c65d248d67f48a79179dskia.committer@gmail.com
4580c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    bool containsCubics() const {
4581c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        return fContainsCubics;
4582fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
4583a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
45848dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    bool crosses(const Contour* crosser) const {
45858dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        for (int index = 0; index < fCrosses.count(); ++index) {
45868dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            if (fCrosses[index] == crosser) {
45878dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                return true;
45888dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            }
45898dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
45908dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return false;
45918dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
4592549c93ef979aeb4dcb65b3d0fca4b58e8ab62227skia.committer@gmail.com
4593db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    bool done() const {
4594db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        return fDone;
4595db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
4596db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com
4597f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    const SkPoint& end() const {
4598f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        const Segment& segment = fSegments.back();
4599f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        return segment.pts()[segment.verb()];
4600f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
46018dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
46024eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    void findTooCloseToCall() {
4603a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com        int segmentCount = fSegments.count();
4604a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com        for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
46054eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            fSegments[sIndex].findTooCloseToCall();
4606a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com        }
4607a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com    }
4608a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
4609b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    void fixOtherTIndex() {
4610b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        int segmentCount = fSegments.count();
4611b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4612b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com            fSegments[sIndex].fixOtherTIndex();
4613b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        }
4614b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    }
4615453995e01d884d62ce2e808e0067e494c0c9c7faskia.committer@gmail.com
4616db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    Segment* nonVerticalSegment(int& start, int& end) {
4617db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        int segmentCount = fSortedSegments.count();
4618db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        SkASSERT(segmentCount > 0);
4619db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4620db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            Segment* testSegment = fSortedSegments[sortedIndex];
4621db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            if (testSegment->done()) {
4622db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                continue;
4623db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            }
4624db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            start = end = 0;
4625db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            while (testSegment->nextCandidate(start, end)) {
4626db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                if (!testSegment->isVertical(start, end)) {
4627db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                    return testSegment;
4628db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                }
4629db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            }
4630db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
4631db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        return NULL;
4632db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
4633db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com
463431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    bool operand() const {
463531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        return fOperand;
463631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    }
4637b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com
4638fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    void reset() {
4639fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fSegments.reset();
4640fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
4641c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false;
4642fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
4643b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com
46447ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    void resolveCoincidence(SkTDArray<Contour*>& contourList) {
46458dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        int count = fCoincidences.count();
46468dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        for (int index = 0; index < count; ++index) {
46478dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            Coincidence& coincidence = fCoincidences[index];
46484eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            SkASSERT(coincidence.fContours[0] == this);
4649b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com            int thisIndex = coincidence.fSegments[0];
46504eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            Segment& thisOne = fSegments[thisIndex];
46514eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            Contour* otherContour = coincidence.fContours[1];
4652b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com            int otherIndex = coincidence.fSegments[1];
4653b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com            Segment& other = otherContour->fSegments[otherIndex];
46540d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com            if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
46554eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com                continue;
46564eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            }
465747580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com        #if DEBUG_CONCIDENT
465847580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            thisOne.debugShowTs();
465947580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            other.debugShowTs();
466047580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com        #endif
46618dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            double startT = coincidence.fTs[0][0];
46628dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            double endT = coincidence.fTs[0][1];
466357cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com            bool cancelers = false;
46648dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            if (startT > endT) {
46658dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                SkTSwap<double>(startT, endT);
466657cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                cancelers ^= true; // FIXME: just assign true
46678dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            }
46683350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            SkASSERT(!approximately_negative(endT - startT));
46698dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            double oStartT = coincidence.fTs[1][0];
46708dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            double oEndT = coincidence.fTs[1][1];
46718dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            if (oStartT > oEndT) {
46728dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                SkTSwap<double>(oStartT, oEndT);
467357cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                cancelers ^= true;
46748dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            }
46753350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com            SkASSERT(!approximately_negative(oEndT - oStartT));
46764eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            bool opp = fOperand ^ otherContour->fOperand;
467757cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com            if (cancelers && !opp) {
467857cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                // make sure startT and endT have t entries
46792ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com                if (startT > 0 || oEndT < 1
46802ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com                        || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
468145a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
4682b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com                }
46832ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com                if (oStartT > 0 || endT < 1
46842ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com                        || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
468545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
4686b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com                }
46870d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com                if (!thisOne.done() && !other.done()) {
46880d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com                    thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
46890d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com                }
46908dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            } else {
4691200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com                if (startT > 0 || oStartT > 0
4692200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com                        || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
469345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
4694b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com                }
4695200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com                if (endT < 1 || oEndT < 1
4696200c211d34b11a4a988fc2549df3c17ae6875899caryclark@google.com                        || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
469745a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
4698b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com                }
46990d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com                if (!thisOne.done() && !other.done()) {
47000d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com                    thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
47010d3d09e5d2fd17aaed035ae23d59804b56b994ffcaryclark@google.com                }
47028dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            }
470347580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com        #if DEBUG_CONCIDENT
470447580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            thisOne.debugShowTs();
470547580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com            other.debugShowTs();
470647580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com        #endif
4707729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com        #if DEBUG_SHOW_WINDING
47087ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            debugShowWindingValues(contourList);
47097ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        #endif
47108dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        }
47118dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
4712d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
47138f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    // first pass, add missing T values
47148f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    // second pass, determine winding values of overlaps
47158f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    void addCoincidentPoints() {
47168f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        int count = fCoincidences.count();
47178f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        for (int index = 0; index < count; ++index) {
47188f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            Coincidence& coincidence = fCoincidences[index];
47198f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            SkASSERT(coincidence.fContours[0] == this);
47208f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            int thisIndex = coincidence.fSegments[0];
47218f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            Segment& thisOne = fSegments[thisIndex];
47228f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            Contour* otherContour = coincidence.fContours[1];
47238f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            int otherIndex = coincidence.fSegments[1];
47248f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            Segment& other = otherContour->fSegments[otherIndex];
47258f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
47268f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                // OPTIMIZATION: remove from array
47278f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                continue;
47288f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            }
47298f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        #if DEBUG_CONCIDENT
47308f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            thisOne.debugShowTs();
47318f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            other.debugShowTs();
47328f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        #endif
47338f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            double startT = coincidence.fTs[0][0];
47348f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            double endT = coincidence.fTs[0][1];
47358f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            bool cancelers;
47368f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if ((cancelers = startT > endT)) {
47377ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                SkTSwap(startT, endT);
47387ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                SkTSwap(coincidence.fPts[0], coincidence.fPts[1]);
47398f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            }
47408f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            SkASSERT(!approximately_negative(endT - startT));
47418f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            double oStartT = coincidence.fTs[1][0];
47428f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            double oEndT = coincidence.fTs[1][1];
47438f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (oStartT > oEndT) {
47448f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                SkTSwap<double>(oStartT, oEndT);
47458f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                cancelers ^= true;
47468f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            }
47478f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            SkASSERT(!approximately_negative(oEndT - oStartT));
47488f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            bool opp = fOperand ^ otherContour->fOperand;
47498f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (cancelers && !opp) {
47508f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                // make sure startT and endT have t entries
47518f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                if (startT > 0 || oEndT < 1
47528f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                        || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
475345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
47548f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                }
47558f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                if (oStartT > 0 || endT < 1
47568f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                        || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
475745a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
47588f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                }
47598f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            } else {
47608f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                if (startT > 0 || oStartT > 0
47618f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                        || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
476245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
47638f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                }
47648f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                if (endT < 1 || oEndT < 1
47658f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                        || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
476645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
47678f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                }
47688f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            }
47698f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        #if DEBUG_CONCIDENT
47708f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            thisOne.debugShowTs();
47718f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            other.debugShowTs();
47728f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        #endif
47738f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        }
47748f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    }
4775d9f65e3df45c9b4994c70f6bf13d29985afd2f65skia.committer@gmail.com
47768f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    void calcCoincidentWinding() {
47778f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        int count = fCoincidences.count();
47788f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        for (int index = 0; index < count; ++index) {
47798f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            Coincidence& coincidence = fCoincidences[index];
47808f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            SkASSERT(coincidence.fContours[0] == this);
47818f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            int thisIndex = coincidence.fSegments[0];
47828f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            Segment& thisOne = fSegments[thisIndex];
47838f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (thisOne.done()) {
47848f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                continue;
47858f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            }
47868f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            Contour* otherContour = coincidence.fContours[1];
47878f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            int otherIndex = coincidence.fSegments[1];
47888f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            Segment& other = otherContour->fSegments[otherIndex];
47898f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (other.done()) {
47908f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                continue;
47918f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            }
47928f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            double startT = coincidence.fTs[0][0];
47938f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            double endT = coincidence.fTs[0][1];
47948f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            bool cancelers;
47958f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if ((cancelers = startT > endT)) {
47968f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                SkTSwap<double>(startT, endT);
47978f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            }
47988f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            SkASSERT(!approximately_negative(endT - startT));
47998f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            double oStartT = coincidence.fTs[1][0];
48008f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            double oEndT = coincidence.fTs[1][1];
48018f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (oStartT > oEndT) {
48028f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                SkTSwap<double>(oStartT, oEndT);
48038f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                cancelers ^= true;
48048f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            }
48058f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            SkASSERT(!approximately_negative(oEndT - oStartT));
48068f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            bool opp = fOperand ^ otherContour->fOperand;
48078f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (cancelers && !opp) {
48088f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                // make sure startT and endT have t entries
48098f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                if (!thisOne.done() && !other.done()) {
48108f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
48118f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                }
48128f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            } else {
48138f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                if (!thisOne.done() && !other.done()) {
48148f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
48158f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                }
48168f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            }
48178f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        #if DEBUG_CONCIDENT
48188f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            thisOne.debugShowTs();
48198f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            other.debugShowTs();
48208f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        #endif
48218f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        }
48228f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    }
48238f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com
4824db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    SkTArray<Segment>& segments() {
48258dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return fSegments;
48268dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
4827d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
4828c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    void setContainsIntercepts() {
4829c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        fContainsIntercepts = true;
4830c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    }
4831c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com
4832235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    void setOperand(bool isOp) {
4833235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        fOperand = isOp;
4834235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    }
4835c7b4be7f110bc7b487c3c3f28d82877584e74c2fskia.committer@gmail.com
48364eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    void setOppXor(bool isOppXor) {
48374eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        fOppXor = isOppXor;
48384eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        int segmentCount = fSegments.count();
48394eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        for (int test = 0; test < segmentCount; ++test) {
48404eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            fSegments[test].setOppXor(isOppXor);
48414eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        }
48424eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    }
4843055c7c299cb47eebd360b809ad58a0006e2e55f7skia.committer@gmail.com
4844235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    void setXor(bool isXor) {
4845235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        fXor = isXor;
4846235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    }
4847235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
4848fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    void sortSegments() {
4849fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        int segmentCount = fSegments.count();
4850fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        fSortedSegments.setReserve(segmentCount);
4851fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        for (int test = 0; test < segmentCount; ++test) {
4852fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com            *fSortedSegments.append() = &fSegments[test];
4853fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        }
4854fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4855fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        fFirstSorted = 0;
4856fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
4857fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com
4858f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    const SkPoint& start() const {
4859f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        return fSegments.front().pts()[0];
4860f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
4861f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
4862f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    void toPath(PathWrapper& path) const {
4863f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        int segmentCount = fSegments.count();
4864f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        const SkPoint& pt = fSegments.front().pts()[0];
4865f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        path.deferredMove(pt);
4866f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        for (int test = 0; test < segmentCount; ++test) {
4867f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            fSegments[test].addCurveTo(0, 1, path, true);
4868f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
4869f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        path.close();
4870f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
4871549c93ef979aeb4dcb65b3d0fca4b58e8ab62227skia.committer@gmail.com
4872f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    void toPartialBackward(PathWrapper& path) const {
4873f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        int segmentCount = fSegments.count();
4874f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        for (int test = segmentCount - 1; test >= 0; --test) {
4875f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            fSegments[test].addCurveTo(1, 0, path, true);
4876f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
4877f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
4878f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
4879f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    void toPartialForward(PathWrapper& path) const {
4880f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        int segmentCount = fSegments.count();
4881f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        for (int test = 0; test < segmentCount; ++test) {
4882f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            fSegments[test].addCurveTo(0, 1, path, true);
4883f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
4884f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
4885f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
4886db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
4887fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        int segmentCount = fSortedSegments.count();
4888fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        SkASSERT(segmentCount > 0);
4889f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        int sortedIndex = fFirstSorted;
4890db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        fDone = true; // may be cleared below
4891f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4892f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            Segment* testSegment = fSortedSegments[sortedIndex];
4893fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com            if (testSegment->done()) {
4894f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                if (sortedIndex == fFirstSorted) {
4895f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                    ++fFirstSorted;
4896f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                }
4897f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                continue;
4898f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            }
4899db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            fDone = false;
490045a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            SkPoint testXY = testSegment->activeLeftTop(true, NULL);
4901db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            if (topStart) {
4902db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                if (testXY.fY < topLeft.fY) {
4903db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                    continue;
4904db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                }
4905db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4906db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                    continue;
4907db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                }
4908db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                if (bestXY.fY < testXY.fY) {
4909db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                    continue;
4910db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                }
4911db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4912db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                    continue;
4913db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                }
4914fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com            }
4915db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            topStart = testSegment;
4916f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            bestXY = testXY;
4917fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        }
4918fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
4919fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com
492024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    Segment* undoneSegment(int& start, int& end) {
492124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        int segmentCount = fSegments.count();
492224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        for (int test = 0; test < segmentCount; ++test) {
492324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            Segment* testSegment = &fSegments[test];
492424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            if (testSegment->done()) {
492524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                continue;
492624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            }
492724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            testSegment->undoneSpan(start, end);
492824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            return testSegment;
492924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
493024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        return NULL;
493124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    }
493224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com
49338dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    int updateSegment(int index, const SkPoint* pts) {
49348dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        Segment& segment = fSegments[index];
49358dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        segment.updatePts(pts);
49368dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return segment.verb() + 1;
49378dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
49388dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
49398dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com#if DEBUG_TEST
49408dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    SkTArray<Segment>& debugSegments() {
49418dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return fSegments;
49428dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
49438dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com#endif
49448dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com
4945fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#if DEBUG_DUMP
4946fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    void dump() {
4947fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        int i;
4948fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        const char className[] = "Contour";
4949fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        const int tab = 4;
4950fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4951fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        for (i = 0; i < fSegments.count(); ++i) {
4952fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4953fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    className, i);
4954fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            fSegments[i].dump();
4955fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        }
4956fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4957fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                tab + sizeof(className), className,
4958fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                fBounds.fLeft, fBounds.fTop,
4959fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                fBounds.fRight, fBounds.fBottom);
4960fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4961fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                className, fContainsIntercepts);
4962fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4963fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                className, fContainsCurves);
4964fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
4965fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#endif
4966fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
4967027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com#if DEBUG_ACTIVE_SPANS
4968027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com    void debugShowActiveSpans() {
4969027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com        for (int index = 0; index < fSegments.count(); ++index) {
4970534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            fSegments[index].debugShowActiveSpans();
4971027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com        }
4972027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com    }
49736aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com
49746aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    void validateActiveSpans() {
49756aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        for (int index = 0; index < fSegments.count(); ++index) {
49766aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com            fSegments[index].validateActiveSpans();
49776aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        }
49786aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    }
4979027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com#endif
4980027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com
4981729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com#if DEBUG_SHOW_WINDING
49827ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    int debugShowWindingValues(int totalSegments, int ofInterest) {
49837ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        int count = fSegments.count();
49847ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        int sum = 0;
49857ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        for (int index = 0; index < count; ++index) {
49867ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
49877ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        }
49887ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com  //      SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
49897ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        return sum;
49907ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    }
49917ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com
49927ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
49937ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com   //     int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
49947ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    //    int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
49957ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        int ofInterest = 1 << 5 | 1 << 8;
49967ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        int total = 0;
49977ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        int index;
49987ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        for (index = 0; index < contourList.count(); ++index) {
49997ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            total += contourList[index]->segments().count();
50007ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        }
50017ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        int sum = 0;
50027ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        for (index = 0; index < contourList.count(); ++index) {
50037ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            sum += contourList[index]->debugShowWindingValues(total, ofInterest);
50047ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        }
50057ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com //       SkDebugf("%s total=%d\n", __FUNCTION__, sum);
50067ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    }
50077ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com#endif
50087ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com
5009fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comprotected:
5010fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    void setBounds() {
5011fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        int count = fSegments.count();
5012fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        if (count == 0) {
5013fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            SkDebugf("%s empty contour\n", __FUNCTION__);
5014fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            SkASSERT(0);
5015fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            // FIXME: delete empty contour?
5016fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            return;
5017fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        }
5018fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fBounds = fSegments.front().bounds();
5019fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        for (int index = 1; index < count; ++index) {
50208dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            fBounds.add(fSegments[index].bounds());
5021fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        }
5022fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5023a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
5024fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comprivate:
50258dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    SkTArray<Segment> fSegments;
5026fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    SkTDArray<Segment*> fSortedSegments;
5027fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    int fFirstSorted;
50288dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    SkTDArray<Coincidence> fCoincidences;
50298dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    SkTDArray<const Contour*> fCrosses;
5030fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    Bounds fBounds;
5031c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    bool fContainsIntercepts; // FIXME: is this used by anybody?
5032c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    bool fContainsCubics;
5033fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    bool fContainsCurves;
5034db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    bool fDone;
5035235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    bool fOperand; // true for the second argument to a binary operator
5036235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    bool fXor;
50374eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    bool fOppXor;
5038fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#if DEBUG_DUMP
5039fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    int fID;
5040fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#endif
5041fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com};
5042fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5043fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comclass EdgeBuilder {
5044fa0588ff672564af1c235a63589573829035a60bcaryclark@google.compublic:
5045fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5046f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.comEdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
5047f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    : fPath(path.nativePath())
5048f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    , fContours(contours)
5049f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com{
5050f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    init();
5051f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com}
5052f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
5053a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.comEdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
5054235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    : fPath(&path)
5055fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    , fContours(contours)
5056fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com{
5057f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    init();
5058f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com}
5059f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
5060f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.comvoid init() {
5061f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    fCurrentContour = NULL;
5062f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    fOperand = false;
5063729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com    fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
5064fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#if DEBUG_DUMP
5065fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    gContourID = 0;
5066fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    gSegmentID = 0;
5067fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#endif
5068235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    fSecondHalf = preFetch();
5069235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
5070235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
5071235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comvoid addOperand(const SkPath& path) {
507231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
507331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    fPathVerbs.pop();
5074235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    fPath = &path;
5075729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com    fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
5076235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    preFetch();
5077235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
5078235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
5079235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comvoid finish() {
5080fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    walk();
5081235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    complete();
5082235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    if (fCurrentContour && !fCurrentContour->segments().count()) {
5083235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        fContours.pop_back();
5084235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    }
5085235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // correct pointers in contours since fReducePts may have moved as it grew
5086235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    int cIndex = 0;
5087235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    int extraCount = fExtra.count();
5088235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    SkASSERT(extraCount == 0 || fExtra[0] == -1);
5089235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    int eIndex = 0;
5090235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    int rIndex = 0;
5091235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    while (++eIndex < extraCount) {
5092235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        int offset = fExtra[eIndex];
5093235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        if (offset < 0) {
5094235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            ++cIndex;
5095235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            continue;
5096235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        }
5097235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        fCurrentContour = &fContours[cIndex];
5098235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        rIndex += fCurrentContour->updateSegment(offset - 1,
5099235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                &fReducePts[rIndex]);
5100235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    }
5101235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    fExtra.reset(); // we're done with this
5102235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
5103235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
5104235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comShapeOpMask xorMask() const {
5105729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com    return fXorMask[fOperand];
5106fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
5107fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5108fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comprotected:
5109fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5110fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comvoid complete() {
51118dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    if (fCurrentContour && fCurrentContour->segments().count()) {
5112fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fCurrentContour->complete();
5113fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fCurrentContour = NULL;
5114fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5115fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
5116fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5117235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com// FIXME:remove once we can access path pts directly
5118235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comint preFetch() {
5119235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
5120fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkPoint pts[4];
5121fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkPath::Verb verb;
5122fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    do {
5123fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        verb = iter.next(pts);
5124fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        *fPathVerbs.append() = verb;
5125fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        if (verb == SkPath::kMove_Verb) {
5126fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            *fPathPts.append() = pts[0];
5127fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
5128fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            fPathPts.append(verb, &pts[1]);
5129fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        }
5130fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    } while (verb != SkPath::kDone_Verb);
513131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    return fPathVerbs.count() - 1;
5132235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
5133a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
5134235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comvoid walk() {
5135fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkPath::Verb reducedVerb;
5136fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    uint8_t* verbPtr = fPathVerbs.begin();
5137235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
5138fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    const SkPoint* pointsPtr = fPathPts.begin();
5139b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    const SkPoint* finalCurveStart = NULL;
5140b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    const SkPoint* finalCurveEnd = NULL;
5141235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    SkPath::Verb verb;
5142fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
5143fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        switch (verb) {
5144fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            case SkPath::kMove_Verb:
5145fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                complete();
5146b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                if (!fCurrentContour) {
5147b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                    fCurrentContour = fContours.push_back_n(1);
5148235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                    fCurrentContour->setOperand(fOperand);
5149729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com                    fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
5150b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                    *fExtra.append() = -1; // start new contour
5151b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                }
515259823f7f3ba43c7c6bc1fa8c600b093ecb4236aacaryclark@google.com                finalCurveEnd = pointsPtr++;
515331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                goto nextVerb;
5154fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            case SkPath::kLine_Verb:
5155fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                // skip degenerate points
5156fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                if (pointsPtr[-1].fX != pointsPtr[0].fX
5157fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        || pointsPtr[-1].fY != pointsPtr[0].fY) {
5158fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    fCurrentContour->addLine(&pointsPtr[-1]);
5159fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                }
5160fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                break;
5161fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            case SkPath::kQuad_Verb:
5162d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
5163fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
5164fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                if (reducedVerb == 0) {
5165fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    break; // skip degenerate points
5166fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                }
5167fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                if (reducedVerb == 1) {
5168d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com                    *fExtra.append() =
5169b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                            fCurrentContour->addLine(fReducePts.end() - 2);
5170fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    break;
5171fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                }
5172fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                fCurrentContour->addQuad(&pointsPtr[-1]);
5173fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                break;
5174fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            case SkPath::kCubic_Verb:
5175fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
5176fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                if (reducedVerb == 0) {
5177fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    break; // skip degenerate points
5178fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                }
5179fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                if (reducedVerb == 1) {
5180b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                    *fExtra.append() =
5181b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                            fCurrentContour->addLine(fReducePts.end() - 2);
5182fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    break;
5183fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                }
5184fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                if (reducedVerb == 2) {
5185b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                    *fExtra.append() =
5186b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                            fCurrentContour->addQuad(fReducePts.end() - 3);
5187fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    break;
5188fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                }
5189fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                fCurrentContour->addCubic(&pointsPtr[-1]);
5190fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                break;
5191fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            case SkPath::kClose_Verb:
5192fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                SkASSERT(fCurrentContour);
5193b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                if (finalCurveStart && finalCurveEnd
5194b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                        && *finalCurveStart != *finalCurveEnd) {
5195b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                    *fReducePts.append() = *finalCurveStart;
5196b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                    *fReducePts.append() = *finalCurveEnd;
5197b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                    *fExtra.append() =
5198b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                            fCurrentContour->addLine(fReducePts.end() - 2);
5199b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com                }
5200fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                complete();
520131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                goto nextVerb;
5202fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            default:
5203fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                SkDEBUGFAIL("bad verb");
5204fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                return;
5205fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        }
5206b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        finalCurveStart = &pointsPtr[verb - 1];
5207fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        pointsPtr += verb;
5208fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SkASSERT(fCurrentContour);
520931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    nextVerb:
5210235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        if (verbPtr == endOfFirstHalf) {
5211235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            fOperand = true;
5212055c7c299cb47eebd360b809ad58a0006e2e55f7skia.committer@gmail.com        }
5213fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5214fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
5215fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5216fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comprivate:
5217235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    const SkPath* fPath;
5218fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
5219a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com    SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
5220fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    Contour* fCurrentContour;
5221fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkTArray<Contour>& fContours;
5222fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkTDArray<SkPoint> fReducePts; // segments created on the fly
5223b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
5224729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com    ShapeOpMask fXorMask[2];
5225235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    int fSecondHalf;
5226235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    bool fOperand;
5227fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com};
5228fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5229fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comclass Work {
5230fa0588ff672564af1c235a63589573829035a60bcaryclark@google.compublic:
5231fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    enum SegmentType {
5232fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        kHorizontalLine_Segment = -1,
5233fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        kVerticalLine_Segment = 0,
5234fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        kLine_Segment = SkPath::kLine_Verb,
5235fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        kQuad_Segment = SkPath::kQuad_Verb,
5236fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        kCubic_Segment = SkPath::kCubic_Verb,
5237fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    };
5238d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
52398dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    void addCoincident(Work& other, const Intersections& ts, bool swap) {
52408dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
52418dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
5242a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
5243b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // FIXME: does it make sense to write otherIndex now if we're going to
5244b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    // fix it up later?
5245b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    void addOtherT(int index, double otherT, int otherIndex) {
52468dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        fContour->addOtherT(fIndex, index, otherT, otherIndex);
5247fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5248a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
5249fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    // Avoid collapsing t values that are close to the same since
5250fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    // we walk ts to describe consecutive intersections. Since a pair of ts can
5251fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    // be nearly equal, any problems caused by this should be taken care
5252fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    // of later.
5253fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    // On the edge or out of range values are negative; add 2 to get end
52547ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com    int addT(const Work& other, const SkPoint& pt, double& newT) {
52557ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com        return fContour->addT(fIndex, other.fContour, other.fIndex, pt, newT);
5256fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5257631cdcb4a6b926b6447f328b81911a4499fb3698skia.committer@gmail.com
52584aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com    int addSelfT(const Work& other, const SkPoint& pt, double& newT) {
52594aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com        return fContour->addSelfT(fIndex, other.fContour, other.fIndex, pt, newT);
52604aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com    }
5261a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
52627ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com    int addUnsortableT(const Work& other, bool start, const SkPoint& pt, double& newT) {
52637ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com        return fContour->addUnsortableT(fIndex, other.fContour, other.fIndex, start, pt, newT);
526473ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    }
526573ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com
5266fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    bool advance() {
5267fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return ++fIndex < fLast;
5268fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5269a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
5270fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkScalar bottom() const {
5271fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return bounds().fBottom;
5272fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5273a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
5274fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    const Bounds& bounds() const {
52758dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return fContour->segments()[fIndex].bounds();
5276fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5277d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
527873ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com#if !APPROXIMATE_CUBICS
5279fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    const SkPoint* cubic() const {
5280fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return fCubic;
5281fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
528273ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com#endif
5283fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5284fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    void init(Contour* contour) {
5285fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fContour = contour;
5286fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fIndex = 0;
52878dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        fLast = contour->segments().count();
5288fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5289d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
529066ca2fba44fe04f3382a3e22096fe73b60ce19d7caryclark@google.com    bool isAdjacent(const Work& next) {
529166ca2fba44fe04f3382a3e22096fe73b60ce19d7caryclark@google.com        return fContour == next.fContour && fIndex + 1 == next.fIndex;
529266ca2fba44fe04f3382a3e22096fe73b60ce19d7caryclark@google.com    }
529366ca2fba44fe04f3382a3e22096fe73b60ce19d7caryclark@google.com
529466ca2fba44fe04f3382a3e22096fe73b60ce19d7caryclark@google.com    bool isFirstLast(const Work& next) {
529566ca2fba44fe04f3382a3e22096fe73b60ce19d7caryclark@google.com        return fContour == next.fContour && fIndex == 0
529666ca2fba44fe04f3382a3e22096fe73b60ce19d7caryclark@google.com                && next.fIndex == fLast - 1;
529766ca2fba44fe04f3382a3e22096fe73b60ce19d7caryclark@google.com    }
5298fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5299fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkScalar left() const {
5300fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return bounds().fLeft;
5301fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5302a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
530373ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com#if !APPROXIMATE_CUBICS
5304fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    void promoteToCubic() {
5305fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fCubic[0] = pts()[0];
5306fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fCubic[2] = pts()[1];
5307fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fCubic[3] = pts()[2];
5308fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
5309fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
5310fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
5311fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
5312fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
531373ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com#endif
5314a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
5315fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    const SkPoint* pts() const {
53168dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return fContour->segments()[fIndex].pts();
5317fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5318fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5319fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkScalar right() const {
5320fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return bounds().fRight;
5321fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5322a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
5323fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    ptrdiff_t segmentIndex() const {
5324fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return fIndex;
5325fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5326a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
5327fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SegmentType segmentType() const {
53288dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        const Segment& segment = fContour->segments()[fIndex];
5329fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        SegmentType type = (SegmentType) segment.verb();
5330fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        if (type != kLine_Segment) {
5331fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            return type;
5332fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        }
5333fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        if (segment.isHorizontal()) {
5334fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            return kHorizontalLine_Segment;
5335fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        }
5336fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        if (segment.isVertical()) {
5337fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            return kVerticalLine_Segment;
5338fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        }
5339fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return kLine_Segment;
5340fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5341a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
5342fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    bool startAfter(const Work& after) {
5343fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        fIndex = after.fIndex;
5344fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return advance();
5345fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5346fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5347fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkScalar top() const {
5348fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return bounds().fTop;
5349fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5350a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
5351fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkPath::Verb verb() const {
53528dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return fContour->segments()[fIndex].verb();
5353fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5354a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
5355fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkScalar x() const {
5356fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return bounds().fLeft;
5357fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5358fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5359fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    bool xFlipped() const {
5360fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return x() != pts()[0].fX;
5361fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5362fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5363fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkScalar y() const {
5364fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return bounds().fTop;
5365fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5366fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5367fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    bool yFlipped() const {
53688dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        return y() != pts()[0].fY;
5369fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5370fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5371fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comprotected:
5372fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    Contour* fContour;
537373ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com#if !APPROXIMATE_CUBICS
5374fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkPoint fCubic[4];
537573ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com#endif
5376fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    int fIndex;
5377fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    int fLast;
5378fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com};
5379fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
538065f9f0a1664a9cb38157ccfbcc3e0e936af0a58ecaryclark@google.com#if DEBUG_ADD_INTERSECTING_TS
5381c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com
538245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.comstatic void debugShowLineIntersection(int pts, const Work& wt, const Work& wn,
538345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        const Intersections& i) {
538445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    SkASSERT(i.used() == pts);
5385fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    if (!pts) {
5386c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n",
5387c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
5388fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return;
5389fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5390c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " LINE_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5391c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            i.fT[0][0], LINE_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5392fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    if (pts == 2) {
5393c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf(" " T_DEBUG_STR(wtTs, 1) " " PT_DEBUG_STR, i.fT[0][1], PT_DEBUG_DATA(i, 1));
5394fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5395c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
5396fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    if (pts == 2) {
5397c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf(" " T_DEBUG_STR(wnTs, 1), i.fT[1][1]);
5398a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com    }
5399a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com    SkDebugf("\n");
5400a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com}
5401a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com
5402fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.comstatic void debugShowQuadLineIntersection(int pts, const Work& wt,
540345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        const Work& wn, const Intersections& i) {
540445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    SkASSERT(i.used() == pts);
5405fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    if (!pts) {
5406c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf("%s no intersect " QUAD_DEBUG_STR " " LINE_DEBUG_STR "\n",
5407c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
5408fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        return;
5409fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
5410c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5411c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            i.fT[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5412c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    for (int n = 1; n < pts; ++n) {
5413c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
5414fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
5415c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
5416c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    for (int n = 1; n < pts; ++n) {
5417c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
5418fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
5419fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    SkDebugf("\n");
5420fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com}
5421fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com
5422a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.comstatic void debugShowQuadIntersection(int pts, const Work& wt,
542345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        const Work& wn, const Intersections& i) {
542445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    SkASSERT(i.used() == pts);
5425a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com    if (!pts) {
5426c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf("%s no intersect " QUAD_DEBUG_STR " " QUAD_DEBUG_STR "\n",
5427c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
5428a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com        return;
5429a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com    }
5430c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5431c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            i.fT[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5432c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    for (int n = 1; n < pts; ++n) {
5433c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
5434a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com    }
5435c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i.fT[1][0], QUAD_DEBUG_DATA(wn.pts()));
5436c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    for (int n = 1; n < pts; ++n) {
5437c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
5438fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5439b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com    SkDebugf("\n");
5440b973801328ef25105f7f3255ab912a1b675da056caryclark@google.com}
544173ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com
544273ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.comstatic void debugShowCubicLineIntersection(int pts, const Work& wt,
544345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        const Work& wn, const Intersections& i) {
544445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    SkASSERT(i.used() == pts);
544573ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    if (!pts) {
5446c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " LINE_DEBUG_STR "\n",
5447c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
544873ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com        return;
544973ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    }
5450c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5451c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5452c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    for (int n = 1; n < pts; ++n) {
5453c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
545473ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    }
5455c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
5456c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    for (int n = 1; n < pts; ++n) {
5457c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
545873ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    }
545973ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    SkDebugf("\n");
546073ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com}
546173ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com
546273ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.comstatic void debugShowCubicQuadIntersection(int pts, const Work& wt,
546345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        const Work& wn, const Intersections& i) {
546445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    SkASSERT(i.used() == pts);
546573ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    if (!pts) {
5466c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " QUAD_DEBUG_STR "\n",
5467c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
546873ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com        return;
546973ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    }
5470c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5471c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5472c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    for (int n = 1; n < pts; ++n) {
5473c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
5474c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    }
5475c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i.fT[1][0], QUAD_DEBUG_DATA(wn.pts()));
5476c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    for (int n = 1; n < pts; ++n) {
5477c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
547873ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    }
547973ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    SkDebugf("\n");
548073ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com}
548173ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com
548273ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.comstatic void debugShowCubicIntersection(int pts, const Work& wt,
548345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        const Work& wn, const Intersections& i) {
548445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    SkASSERT(i.used() == pts);
548573ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    if (!pts) {
5486c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " CUBIC_DEBUG_STR "\n",
5487c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), CUBIC_DEBUG_DATA(wn.pts()));
548873ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com        return;
548973ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    }
5490c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5491c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5492c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    for (int n = 1; n < pts; ++n) {
5493c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
5494c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    }
5495c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i.fT[1][0], CUBIC_DEBUG_DATA(wn.pts()));
5496c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    for (int n = 1; n < pts; ++n) {
5497c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
5498c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    }
5499c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf("\n");
5500c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com}
5501c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com
5502c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.comstatic void debugShowCubicIntersection(int pts, const Work& wt, const Intersections& i) {
5503c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkASSERT(i.used() == pts);
5504c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    if (!pts) {
5505c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkDebugf("%s no self intersect " CUBIC_DEBUG_STR "\n", __FUNCTION__,
5506c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com                CUBIC_DEBUG_DATA(wt.pts()));
5507c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        return;
550873ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    }
5509c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5510c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5511c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    SkDebugf(" " T_DEBUG_STR(wtTs, 1), i.fT[1][0]);
551273ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    SkDebugf("\n");
551373ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com}
551485ec74ca543b13739db1ad55dedd7bdfae4ab1a6caryclark@google.com
551565f9f0a1664a9cb38157ccfbcc3e0e936af0a58ecaryclark@google.com#else
551645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.comstatic void debugShowLineIntersection(int , const Work& , const Work& , const Intersections& ) {
5517fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
5518a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com
551945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.comstatic void debugShowQuadLineIntersection(int , const Work& , const Work& , const Intersections& ) {
5520fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com}
5521fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com
552245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.comstatic void debugShowQuadIntersection(int , const Work& , const Work& , const Intersections& ) {
5523a461ff0866526bc51dbd4c4f9f066a727ec21510caryclark@google.com}
552473ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com
552545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.comstatic void debugShowCubicLineIntersection(int , const Work& , const Work& ,
552645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        const Intersections& ) {
552773ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com}
552873ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com
552945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.comstatic void debugShowCubicQuadIntersection(int , const Work& , const Work& ,
553045a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        const Intersections& ) {
553173ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com}
553273ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com
553345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.comstatic void debugShowCubicIntersection(int , const Work& , const Work& , const Intersections& ) {
553473ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com}
5535c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com
5536c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.comstatic void debugShowCubicIntersection(int , const Work& , const Intersections& ) {
5537c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com}
553873ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com#endif
5539fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
554065f9f0a1664a9cb38157ccfbcc3e0e936af0a58ecaryclark@google.comstatic bool addIntersectTs(Contour* test, Contour* next) {
5541b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com
5542fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    if (test != next) {
5543fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        if (test->bounds().fBottom < next->bounds().fTop) {
5544fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            return false;
5545fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        }
5546fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5547fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            return true;
5548fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        }
5549fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
5550b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    Work wt;
5551fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    wt.init(test);
55528dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    bool foundCommonContour = test == next;
5553fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    do {
5554b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        Work wn;
5555b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        wn.init(next);
5556fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        if (test == next && !wn.startAfter(wt)) {
5557fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            continue;
5558fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        }
5559fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        do {
5560fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5561fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                continue;
5562fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            }
5563fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            int pts;
5564fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            Intersections ts;
5565fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            bool swap = false;
5566fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            switch (wt.segmentType()) {
5567fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                case Work::kHorizontalLine_Segment:
5568fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    swap = true;
5569fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    switch (wn.segmentType()) {
5570fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kHorizontalLine_Segment:
5571fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kVerticalLine_Segment:
5572fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kLine_Segment: {
5573fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = HLineIntersect(wn.pts(), wt.left(),
5574fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                                    wt.right(), wt.y(), wt.xFlipped(), ts);
557545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowLineIntersection(pts, wt, wn, ts);
5576fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5577fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5578fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kQuad_Segment: {
5579fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = HQuadIntersect(wn.pts(), wt.left(),
5580fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                                    wt.right(), wt.y(), wt.xFlipped(), ts);
5581fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5582fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5583fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kCubic_Segment: {
5584fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = HCubicIntersect(wn.pts(), wt.left(),
5585fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                                    wt.right(), wt.y(), wt.xFlipped(), ts);
558645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowCubicLineIntersection(pts, wn, wt, ts);
5587fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5588fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5589fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        default:
5590fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            SkASSERT(0);
5591fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    }
5592fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    break;
5593fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                case Work::kVerticalLine_Segment:
5594fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    swap = true;
5595fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    switch (wn.segmentType()) {
5596fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kHorizontalLine_Segment:
5597fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kVerticalLine_Segment:
5598fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kLine_Segment: {
5599fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = VLineIntersect(wn.pts(), wt.top(),
5600fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                                    wt.bottom(), wt.x(), wt.yFlipped(), ts);
560145a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowLineIntersection(pts, wt, wn, ts);
5602fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5603fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5604fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kQuad_Segment: {
5605fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = VQuadIntersect(wn.pts(), wt.top(),
5606fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                                    wt.bottom(), wt.x(), wt.yFlipped(), ts);
5607fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5608fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5609fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kCubic_Segment: {
5610fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = VCubicIntersect(wn.pts(), wt.top(),
5611fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                                    wt.bottom(), wt.x(), wt.yFlipped(), ts);
561245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowCubicLineIntersection(pts, wn, wt, ts);
5613fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5614fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5615fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        default:
5616fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            SkASSERT(0);
5617fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    }
5618fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    break;
5619fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                case Work::kLine_Segment:
5620fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    switch (wn.segmentType()) {
5621fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kHorizontalLine_Segment:
5622fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = HLineIntersect(wt.pts(), wn.left(),
5623fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                                    wn.right(), wn.y(), wn.xFlipped(), ts);
562445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowLineIntersection(pts, wt, wn, ts);
5625fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5626fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kVerticalLine_Segment:
5627fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = VLineIntersect(wt.pts(), wn.top(),
5628fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                                    wn.bottom(), wn.x(), wn.yFlipped(), ts);
562945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowLineIntersection(pts, wt, wn, ts);
5630fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5631fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kLine_Segment: {
5632fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = LineIntersect(wt.pts(), wn.pts(), ts);
563345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowLineIntersection(pts, wt, wn, ts);
5634fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5635fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5636fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kQuad_Segment: {
5637fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            swap = true;
5638fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
563945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowQuadLineIntersection(pts, wn, wt, ts);
5640fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5641fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5642fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kCubic_Segment: {
5643fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            swap = true;
5644fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
564545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowCubicLineIntersection(pts, wn, wt,  ts);
5646fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5647fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5648fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        default:
5649fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            SkASSERT(0);
5650fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    }
5651fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    break;
5652fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                case Work::kQuad_Segment:
5653fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    switch (wn.segmentType()) {
5654fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kHorizontalLine_Segment:
5655fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = HQuadIntersect(wt.pts(), wn.left(),
5656fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                                    wn.right(), wn.y(), wn.xFlipped(), ts);
5657fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5658fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kVerticalLine_Segment:
5659fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = VQuadIntersect(wt.pts(), wn.top(),
5660fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                                    wn.bottom(), wn.x(), wn.yFlipped(), ts);
5661fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5662fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kLine_Segment: {
5663fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
566445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowQuadLineIntersection(pts, wt, wn, ts);
5665fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5666fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5667fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kQuad_Segment: {
5668fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = QuadIntersect(wt.pts(), wn.pts(), ts);
566945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowQuadIntersection(pts, wt, wn, ts);
5670fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5671fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5672fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kCubic_Segment: {
567373ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                    #if APPROXIMATE_CUBICS
567473ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                            swap = true;
567573ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                            pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts);
567645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowCubicQuadIntersection(pts, wn, wt, ts);
567773ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                    #else
5678fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            wt.promoteToCubic();
5679fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
568045a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowCubicIntersection(pts, wt, wn, ts);
568173ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                    #endif
5682fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5683fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5684fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        default:
5685fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            SkASSERT(0);
5686fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    }
5687fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    break;
5688fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                case Work::kCubic_Segment:
5689fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    switch (wn.segmentType()) {
5690fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kHorizontalLine_Segment:
5691fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = HCubicIntersect(wt.pts(), wn.left(),
5692fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                                    wn.right(), wn.y(), wn.xFlipped(), ts);
569345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowCubicLineIntersection(pts, wt, wn, ts);
5694fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5695fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kVerticalLine_Segment:
5696fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = VCubicIntersect(wt.pts(), wn.top(),
5697fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                                    wn.bottom(), wn.x(), wn.yFlipped(), ts);
569845a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowCubicLineIntersection(pts, wt, wn, ts);
5699fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5700fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kLine_Segment: {
5701fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
570245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowCubicLineIntersection(pts, wt, wn, ts);
5703fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5704fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5705fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kQuad_Segment: {
570673ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                    #if APPROXIMATE_CUBICS
570773ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                            pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts);
570845a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowCubicQuadIntersection(pts, wt, wn, ts);
570973ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                    #else
5710fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            wn.promoteToCubic();
5711fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
571245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowCubicIntersection(pts, wt, wn, ts);
571373ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                    #endif
5714fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5715fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5716fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        case Work::kCubic_Segment: {
571773ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                            pts = CubicIntersect(wt.pts(), wn.pts(), ts);
571845a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                            debugShowCubicIntersection(pts, wt, wn, ts);
5719fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            break;
5720fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        }
5721fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                        default:
5722fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                            SkASSERT(0);
5723fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    }
5724fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    break;
5725fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                default:
5726fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                    SkASSERT(0);
5727fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            }
57288dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            if (!foundCommonContour && pts > 0) {
57298dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                test->addCross(next);
57308dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                next->addCross(test);
57318dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com                foundCommonContour = true;
57328dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com            }
5733fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            // in addition to recording T values, record matching segment
573473ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com            if (ts.unsortable()) {
573573ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                bool start = true;
573673ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                for (int pt = 0; pt < ts.used(); ++pt) {
573773ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                    // FIXME: if unsortable, the other points to the original. This logic is
573873ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                    // untested downstream.
573945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    SkPoint point = ts.fPt[pt].asSkPoint();
57407ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                    int testTAt = wt.addUnsortableT(wt, start, point, ts.fT[swap][pt]);
574173ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                    wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt);
57427ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                    testTAt = wn.addUnsortableT(wn, start ^ ts.fFlip, point, ts.fT[!swap][pt]);
574373ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                    wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt);
574473ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                    start ^= true;
574573ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                }
574673ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com                continue;
574773ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com            }
574832546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com            if (pts == 2) {
574932546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com                if (wn.segmentType() <= Work::kLine_Segment
575032546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com                        && wt.segmentType() <= Work::kLine_Segment) {
575132546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com                    wt.addCoincident(wn, ts, swap);
575232546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com                    continue;
575332546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com                }
5754beda389e646d6be3cfef853584a78ca8ba39d0fccaryclark@google.com                if (wn.segmentType() >= Work::kQuad_Segment
5755beda389e646d6be3cfef853584a78ca8ba39d0fccaryclark@google.com                        && wt.segmentType() >= Work::kQuad_Segment
575645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                        && ts.fIsCoincident[0]) {
575745a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                    SkASSERT(ts.coincidentUsed() == 2);
575832546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com                    wt.addCoincident(wn, ts, swap);
575932546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com                    continue;
576032546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com                }
576132546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com
5762a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com            }
576315fa138f2276a77679530fb608463ff5b4133f7bcaryclark@google.com            for (int pt = 0; pt < pts; ++pt) {
5764fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5765fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
576645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                SkPoint point = ts.fPt[pt].asSkPoint();
57677ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                int testTAt = wt.addT(wn, point, ts.fT[swap][pt]);
57687ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com                int nextTAt = wn.addT(wt, point, ts.fT[!swap][pt]);
57696aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
57706aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com                wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
5771fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            }
5772fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        } while (wn.advance());
5773fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    } while (wt.advance());
5774fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return true;
5775fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
5776fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
5777c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.comstatic void addSelfIntersectTs(Contour* test) {
5778c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    Work wt;
5779c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    wt.init(test);
5780c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    do {
5781c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        if (wt.segmentType() != Work::kCubic_Segment) {
5782c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            continue;
5783c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        }
5784c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        Intersections ts;
5785c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        int pts = CubicIntersect(wt.pts(), ts);
5786c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        debugShowCubicIntersection(pts, wt, ts);
5787c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        if (!pts) {
5788c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            continue;
5789c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        }
5790c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkASSERT(pts == 1);
5791c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkASSERT(ts.fT[0][0] >= 0 && ts.fT[0][0] <= 1);
5792c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkASSERT(ts.fT[1][0] >= 0 && ts.fT[1][0] <= 1);
5793c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        SkPoint point = ts.fPt[0].asSkPoint();
57944aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com        int testTAt = wt.addSelfT(wt, point, ts.fT[0][0]);
57957ff5c841bf669826b4cbd708ae1a6b3527f15dcacaryclark@google.com        int nextTAt = wt.addT(wt, point, ts.fT[1][0]);
5796c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        wt.addOtherT(testTAt, ts.fT[1][0], nextTAt);
5797c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        wt.addOtherT(nextTAt, ts.fT[0][0], testTAt);
5798c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    } while (wt.advance());
5799c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com}
5800c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com
58018dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com// resolve any coincident pairs found while intersecting, and
5802a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com// see if coincidence is formed by clipping non-concident segments
58034eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.comstatic void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
5804a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com    int contourCount = contourList.count();
58058f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#if ONE_PASS_COINCIDENCE_CHECK
5806f25edfeac7c41aafc018c5de75185368838ab404caryclark@google.com    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5807a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com        Contour* contour = contourList[cIndex];
58087ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        contour->resolveCoincidence(contourList);
58098dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    }
58108f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#else
58118f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
58128f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        Contour* contour = contourList[cIndex];
58138f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        contour->addCoincidentPoints();
58148f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    }
58158f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
58168f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        Contour* contour = contourList[cIndex];
58178f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        contour->calcCoincidentWinding();
58188f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    }
58198f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com#endif
58208dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
58218dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com        Contour* contour = contourList[cIndex];
58224eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        contour->findTooCloseToCall();
5823a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com    }
5824a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com}
5825a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com
5826db0b3e099f888213535c4ad4c785b84544309033caryclark@google.comstatic int contourRangeCheckY(SkTDArray<Contour*>& contourList,  Segment*& current, int& index,
58273586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
5828db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    SkPoint basePt;
582910227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    double tAtMid = current->tAtMid(index, endIndex, mid);
583010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    current->xyAtT(tAtMid, basePt);
5831e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    int contourCount = contourList.count();
5832e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    SkScalar bestY = SK_ScalarMin;
5833db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    Segment* bestSeg = NULL;
5834db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    int bestTIndex;
5835db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    bool bestOpp;
58363586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    bool hitSomething = false;
5837e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    for (int cTest = 0; cTest < contourCount; ++cTest) {
5838e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        Contour* contour = contourList[cTest];
5839e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        bool testOpp = contour->operand() ^ current->operand() ^ opp;
5840e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (basePt.fY < contour->bounds().fTop) {
5841e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            continue;
5842e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        }
5843e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (bestY > contour->bounds().fBottom) {
5844e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            continue;
5845e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        }
5846db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        int segmentCount = contour->segments().count();
5847db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        for (int test = 0; test < segmentCount; ++test) {
5848db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            Segment* testSeg = &contour->segments()[test];
5849db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            SkScalar testY = bestY;
5850db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            double testHit;
585110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
585210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                    testOpp, testSeg == current);
5853db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            if (testTIndex < 0) {
58548f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                if (testTIndex == SK_MinS32) {
58558f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    hitSomething = true;
58568f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    bestSeg = NULL;
58578f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    goto abortContours; // vertical encountered, return and try different point
58588f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                }
5859db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                continue;
5860db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            }
5861db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
58623586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                double baseT = current->t(index);
58633586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                double endT = current->t(endIndex);
58643586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                double newMid = (testHit - baseT) / (endT - baseT);
58653586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com#if DEBUG_WINDING
58663586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                SkPoint midXY, newXY;
586710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                double midT = current->tAtMid(index, endIndex, mid);
586810227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                current->xyAtT(midT, midXY);
586910227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                double newMidT = current->tAtMid(index, endIndex, newMid);
587010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                current->xyAtT(newMidT, newXY);
58713586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
58723586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                        " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
58733586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                        current->debugID(), mid, newMid,
58743586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                        baseT, current->xAtT(index), current->yAtT(index),
58753586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                        baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
58763586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                        baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
58773586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                        endT, current->xAtT(endIndex), current->yAtT(endIndex));
58783586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com#endif
58793586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                mid = newMid * 2; // calling loop with divide by 2 before continuing
58803586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                return SK_MinS32;
5881db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            }
5882db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            bestSeg = testSeg;
5883db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            bestHit = testHit;
5884db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            bestOpp = testOpp;
5885db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            bestTIndex = testTIndex;
5886db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            bestY = testY;
5887e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        }
5888e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    }
58898f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.comabortContours:
589010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    int result;
5891db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    if (!bestSeg) {
589210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        result = hitSomething ? SK_MinS32 : 0;
589310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    } else {
589410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
589510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            current = bestSeg;
589610227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            index = bestTIndex;
589710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            endIndex = bestSeg->nextSpan(bestTIndex, 1);
589810227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
589910227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            tryAgain = true;
590010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            return 0;
590110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        }
590210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
590310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        SkASSERT(bestDx);
5904db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
59053586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    double baseT = current->t(index);
59063586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    double endT = current->t(endIndex);
59073586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    bestHit = baseT + mid * (endT - baseT);
5908db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    return result;
5909e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com}
5910e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com
591124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.comstatic Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
591224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    int contourCount = contourList.count();
591324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    Segment* result;
591424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
591524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        Contour* contour = contourList[cIndex];
591624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        result = contour->undoneSegment(start, end);
591724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        if (result) {
591824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            return result;
591924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
592024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    }
592124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    return NULL;
592224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com}
592324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com
5924db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com#define OLD_FIND_CHASE 1
592524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com
592631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.comstatic Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
5927fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com    while (chase.count()) {
59280b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        Span* span;
59290b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        chase.pop(&span);
5930fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        const Span& backPtr = span->fOther->span(span->fOtherIndex);
5931fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        Segment* segment = backPtr.fOther;
5932fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com        tIndex = backPtr.fOtherIndex;
59339764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        SkTDArray<Angle> angles;
59349764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        int done = 0;
59359764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        if (segment->activeAngle(tIndex, done, angles)) {
59369764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            Angle* last = angles.end() - 1;
59379764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            tIndex = last->start();
59389764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            endIndex = last->end();
59390b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com   #if TRY_ROTATE
59400b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            *chase.insert(0) = span;
59410b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com   #else
59420b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            *chase.append() = span;
59430b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com   #endif
59449764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            return last->segment();
59459764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        }
59469764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        if (done == angles.count()) {
59479764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            continue;
59489764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        }
59499764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        SkTDArray<Angle*> sorted;
5950c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        bool sortable = Segment::SortAngles(angles, sorted);
5951db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        int angleCount = sorted.count();
595203f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com#if DEBUG_SORT
595331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
595403f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com#endif
5955c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        if (!sortable) {
5956c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            continue;
5957c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com        }
59589764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        // find first angle, initialize winding to computed fWindSum
59599764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        int firstIndex = -1;
59609764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        const Angle* angle;
5961db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com#if OLD_FIND_CHASE
5962534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        int winding;
59639764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        do {
59649764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            angle = sorted[++firstIndex];
5965534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            segment = angle->segment();
5966534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            winding = segment->windSum(angle);
5967534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        } while (winding == SK_MinS32);
5968534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        int spanWinding = segment->spanSign(angle->start(), angle->end());
5969534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com    #if DEBUG_WINDING
597031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        SkDebugf("%s winding=%d spanWinding=%d\n",
597131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                __FUNCTION__, winding, spanWinding);
597247580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com    #endif
597331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        // turn span winding into contour winding
5974534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        if (spanWinding * winding < 0) {
5975534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            winding += spanWinding;
59769764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        }
5977534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com    #if DEBUG_SORT
597831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
5979534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com    #endif
59809764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        // we care about first sign and whether wind sum indicates this
59819764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        // edge is inside or outside. Maybe need to pass span winding
59829764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        // or first winding or something into this function?
59839764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        // advance to first undone angle, then return it and winding
59849764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        // (to set whether edges are active or not)
59859764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        int nextIndex = firstIndex + 1;
59869764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5987534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com        angle = sorted[firstIndex];
59882ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com        winding -= angle->segment()->spanSign(angle);
5989db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com#else
5990db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        do {
5991db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            angle = sorted[++firstIndex];
5992db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            segment = angle->segment();
5993db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        } while (segment->windSum(angle) == SK_MinS32);
5994db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    #if DEBUG_SORT
5995db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5996db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    #endif
5997db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        int sumWinding = segment->updateWindingReverse(angle);
5998db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        int nextIndex = firstIndex + 1;
5999db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
6000db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        Segment* first = NULL;
6001db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com#endif
60029764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        do {
60039764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            SkASSERT(nextIndex != firstIndex);
60049764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            if (nextIndex == angleCount) {
60059764cc6c109dba208592fe5f16447b8439375746caryclark@google.com                nextIndex = 0;
60069764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            }
6007534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            angle = sorted[nextIndex];
60089764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            segment = angle->segment();
6009db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com#if OLD_FIND_CHASE
6010534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com            int maxWinding = winding;
60112ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com            winding -= segment->spanSign(angle);
6012534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com    #if DEBUG_SORT
60132ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com            SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
60142ddff9388694263c7be9347de7eb768cd0847997caryclark@google.com                    segment->debugID(), maxWinding, winding, angle->sign());
6015534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com    #endif
60169764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            tIndex = angle->start();
60179764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            endIndex = angle->end();
60189764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            int lesser = SkMin32(tIndex, endIndex);
60199764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            const Span& nextSpan = segment->span(lesser);
60209764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            if (!nextSpan.fDone) {
6021534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com#if 1
6022db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            // FIXME: this be wrong? assign startWinding if edge is in
60239764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            // same direction. If the direction is opposite, winding to
60249764cc6c109dba208592fe5f16447b8439375746caryclark@google.com            // assign is flipped sign or +/- 1?
602559823f7f3ba43c7c6bc1fa8c600b093ecb4236aacaryclark@google.com                if (useInnerWinding(maxWinding, winding)) {
6026534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com                    maxWinding = winding;
6027fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com                }
6028db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                segment->markAndChaseWinding(angle, maxWinding, 0);
6029534aa5b9460639a09b9dc30d29e77782e44b8fffcaryclark@google.com#endif
60309764cc6c109dba208592fe5f16447b8439375746caryclark@google.com                break;
6031fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com            }
6032db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com#else
6033db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            int start = angle->start();
6034db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            int end = angle->end();
6035db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            int maxWinding;
6036db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            segment->setUpWinding(start, end, maxWinding, sumWinding);
6037db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            if (!segment->done(angle)) {
6038db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                if (!first) {
6039db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                    first = segment;
6040db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                    tIndex = start;
6041db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                    endIndex = end;
6042db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                }
6043db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                (void) segment->markAngle(maxWinding, sumWinding, true, angle);
6044db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            }
6045db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com#endif
60469764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        } while (++nextIndex != lastIndex);
60470b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com   #if TRY_ROTATE
60480b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        *chase.insert(0) = span;
60490b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com   #else
60500b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        *chase.append() = span;
60510b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com   #endif
60529764cc6c109dba208592fe5f16447b8439375746caryclark@google.com        return segment;
6053fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com    }
6054fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com    return NULL;
6055fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com}
6056fa4a6e964691ff9a88bc047418abe2d4324dfcaecaryclark@google.com
6057027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com#if DEBUG_ACTIVE_SPANS
6058027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.comstatic void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
60596aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    int index;
60606aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    for (index = 0; index < contourList.count(); ++ index) {
6061027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com        contourList[index]->debugShowActiveSpans();
6062027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com    }
60636aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    for (index = 0; index < contourList.count(); ++ index) {
60646aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        contourList[index]->validateActiveSpans();
60656aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    }
6066027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com}
6067027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com#endif
6068027de226c144d9e6b7a76acb2e904952b5620a5ecaryclark@google.com
6069fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.comstatic Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
6070db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
6071fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    Segment* result;
6072fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    do {
6073f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
6074fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        int contourCount = contourList.count();
6075f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        Segment* topStart = NULL;
6076db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        done = true;
6077f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
6078f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            Contour* contour = contourList[cIndex];
6079db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            if (contour->done()) {
6080db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                continue;
6081db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            }
6082f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            const Bounds& bounds = contour->bounds();
6083f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            if (bounds.fBottom < topLeft.fY) {
6084db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                done = false;
6085fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com                continue;
6086fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com            }
6087f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
6088db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                done = false;
6089fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com                continue;
6090fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com            }
6091db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            contour->topSortableSegment(topLeft, bestXY, topStart);
6092db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            if (!contour->done()) {
6093db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                done = false;
6094f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            }
6095f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
6096f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (!topStart) {
6097f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            return NULL;
6098fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        }
6099f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        topLeft = bestXY;
6100e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        result = topStart->findTop(index, endIndex, unsortable, onlySortable);
6101fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    } while (!result);
6102fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    return result;
6103fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com}
610431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com
6105db0b3e099f888213535c4ad4c785b84544309033caryclark@google.comstatic int rightAngleWinding(SkTDArray<Contour*>& contourList,
61063586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
6107db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        bool opp) {
6108d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    double test = 0.9;
6109d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    int contourWinding;
6110d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    do {
61113586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
61123586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com                tryAgain, test, opp);
6113db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (contourWinding != SK_MinS32 || tryAgain) {
6114d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            return contourWinding;
6115d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
6116d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        test /= 2;
6117d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    } while (!approximately_negative(test));
6118d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    SkASSERT(0); // should be OK to comment out, but interested when this hits
6119d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    return contourWinding;
6120d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com}
6121d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
6122db0b3e099f888213535c4ad4c785b84544309033caryclark@google.comstatic void skipVertical(SkTDArray<Contour*>& contourList,
6123db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        Segment*& current, int& index, int& endIndex) {
6124db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    if (!current->isVertical(index, endIndex)) {
6125db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        return;
6126db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
6127db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    int contourCount = contourList.count();
6128db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
6129db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        Contour* contour = contourList[cIndex];
6130db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (contour->done()) {
6131db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            continue;
6132db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
6133db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        current = contour->nonVerticalSegment(index, endIndex);
6134db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (current) {
6135db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            return;
6136db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        }
6137db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
6138db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com}
6139db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com
61403586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.comstatic Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
6141db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
6142db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
6143db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            true);
6144db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    if (!current) {
6145db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        return NULL;
6146db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
6147db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    if (firstContour) {
61483586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        current->initWinding(index, endIndex);
6149db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        firstContour = false;
6150db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        return current;
6151db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
6152db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    int minIndex = SkMin32(index, endIndex);
6153db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    int sumWinding = current->windSum(minIndex);
6154db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    if (sumWinding != SK_MinS32) {
6155db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        return current;
6156db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
6157db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    sumWinding = current->computeSum(index, endIndex, binary);
6158db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    if (sumWinding != SK_MinS32) {
6159db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        return current;
6160db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    }
6161db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    int contourWinding;
6162db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    int oppContourWinding = 0;
6163db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    // the simple upward projection of the unresolved points hit unsortable angles
6164db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    // shoot rays at right angles to the segment to find its winding, ignoring angle cases
6165db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    bool tryAgain;
6166db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    double tHit;
61673586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    SkScalar hitDx = 0;
61683586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    SkScalar hitOppDx = 0;
6169db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    do {
6170db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        // if current is vertical, find another candidate which is not
6171db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        // if only remaining candidates are vertical, then they can be marked done
617210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
6173db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        skipVertical(contourList, current, index, endIndex);
617410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
6175db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        tryAgain = false;
61763586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
6177db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                tryAgain, false);
6178db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (tryAgain) {
6179d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            continue;
6180d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
6181db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        if (!binary) {
6182d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            break;
6183d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
61843586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
6185db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                tryAgain, true);
6186db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com    } while (tryAgain);
61878d83d0db6433e009c6c7f9adbd2580578b6f297eskia.committer@gmail.com
61883586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
6189d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    return current;
6190d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com}
6191d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
6192d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com// rewrite that abandons keeping local track of winding
61933586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.comstatic bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
6194d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    bool firstContour = true;
6195d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    bool unsortable = false;
6196d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    bool topUnsortable = false;
6197d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
6198d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    do {
6199d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        int index, endIndex;
6200db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        bool topDone;
62013586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com        Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
6202db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                topUnsortable, topDone, false);
6203d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        if (!current) {
6204db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            if (topUnsortable || !topDone) {
6205d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                topUnsortable = false;
6206db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
6207d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                topLeft.fX = topLeft.fY = SK_ScalarMin;
6208d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                continue;
6209d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            }
6210d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            break;
6211d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        }
6212d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        SkTDArray<Span*> chaseArray;
6213d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        do {
6214d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            if (current->activeWinding(index, endIndex)) {
6215d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                do {
6216d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            #if DEBUG_ACTIVE_SPANS
6217d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    if (!unsortable && current->done()) {
6218d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                        debugShowActiveSpans(contourList);
6219d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    }
6220d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            #endif
6221d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    SkASSERT(unsortable || !current->done());
6222d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    int nextStart = index;
6223d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    int nextEnd = endIndex;
6224d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
6225d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                            unsortable);
6226d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    if (!next) {
6227d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                        if (!unsortable && simple.hasMove()
6228d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                                && current->verb() != SkPath::kLine_Verb
6229d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                                && !simple.isClosed()) {
6230d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                            current->addCurveTo(index, endIndex, simple, true);
6231d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                            SkASSERT(simple.isClosed());
6232d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                        }
6233d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                        break;
6234d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    }
62358f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        #if DEBUG_FLOW
62368f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
62378f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
62388f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                    current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
62398f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        #endif
6240d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    current->addCurveTo(index, endIndex, simple, true);
6241d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    current = next;
6242d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    index = nextStart;
6243d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    endIndex = nextEnd;
62448f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                } while (!simple.isClosed() && (!unsortable
624510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                        || !current->done(SkMin32(index, endIndex))));
6246d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
6247d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    SkASSERT(unsortable);
6248d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    int min = SkMin32(index, endIndex);
6249d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    if (!current->done(min)) {
6250d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                        current->addCurveTo(index, endIndex, simple, true);
6251d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                        current->markDoneUnary(min);
6252d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    }
6253d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                }
6254d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                simple.close();
6255d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            } else {
6256db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                Span* last = current->markAndChaseDoneUnary(index, endIndex);
62574aaaaeace7e617ddc473645756fb7c20790bc270caryclark@google.com                if (last && !last->fLoop) {
6258d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                    *chaseArray.append() = last;
6259d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                }
6260d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            }
6261d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            current = findChase(chaseArray, index, endIndex);
6262d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        #if DEBUG_ACTIVE_SPANS
6263d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            debugShowActiveSpans(contourList);
6264d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        #endif
6265d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            if (!current) {
6266d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com                break;
6267d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com            }
6268d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com        } while (true);
6269d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    } while (true);
6270d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com    return simple.someAssemblyRequired();
6271d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com}
6272d0deb4fa612a44adb941025af52c5179c5d11cd7caryclark@google.com
6273c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com// returns true if all edges were processed
6274f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.comstatic bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
627524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    Segment* current;
627624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    int start, end;
6277c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    bool unsortable = false;
6278e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    bool closable = true;
627924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    while ((current = findUndone(contourList, start, end))) {
628024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        do {
62818f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #if DEBUG_ACTIVE_SPANS
62828f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            if (!unsortable && current->done()) {
62838f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com                debugShowActiveSpans(contourList);
62848f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com            }
62858f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com    #endif
6286c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            SkASSERT(unsortable || !current->done());
628724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            int nextStart = start;
628824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            int nextEnd = end;
6289c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com            Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
629024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            if (!next) {
6291e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                if (!unsortable && simple.hasMove()
6292f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        && current->verb() != SkPath::kLine_Verb
6293f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        && !simple.isClosed()) {
6294f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                    current->addCurveTo(start, end, simple, true);
6295f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                    SkASSERT(simple.isClosed());
6296c899ad9c7fa28234d99479ab09afb6866bbd8dc3caryclark@google.com                }
629724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                break;
629824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            }
6299e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        #if DEBUG_FLOW
6300e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6301e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                    current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
6302e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                    current->xyAtT(end).fX, current->xyAtT(end).fY);
6303e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        #endif
6304f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            current->addCurveTo(start, end, simple, true);
630524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            current = next;
630624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            start = nextStart;
630724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            end = nextEnd;
63088f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1bcaryclark@google.com        } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
6309e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (!simple.isClosed()) {
6310e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            SkASSERT(unsortable);
6311e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            int min = SkMin32(start, end);
6312e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            if (!current->done(min)) {
6313e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                current->addCurveTo(start, end, simple, true);
6314e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                current->markDone(min, 1);
6315e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            }
6316e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            closable = false;
631724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
6318e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        simple.close();
63196aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    #if DEBUG_ACTIVE_SPANS
63206aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com        debugShowActiveSpans(contourList);
63216aea33f92c611d6fdc88bc2352c5c966168af83bcaryclark@google.com    #endif
6322d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    }
6323e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    return closable;
632424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com}
632524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com
6326b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.comstatic void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
6327b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    int contourCount = contourList.count();
6328b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    for (int cTest = 0; cTest < contourCount; ++cTest) {
6329b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        Contour* contour = contourList[cTest];
6330b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        contour->fixOtherTIndex();
6331b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com    }
6332b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com}
6333b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com
6334fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.comstatic void sortSegments(SkTDArray<Contour*>& contourList) {
6335fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    int contourCount = contourList.count();
6336fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    for (int cTest = 0; cTest < contourCount; ++cTest) {
6337fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        Contour* contour = contourList[cTest];
6338fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        contour->sortSegments();
6339fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
6340fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com}
6341fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com
63424eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.comstatic void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
63434eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        bool evenOdd, bool oppEvenOdd) {
6344a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com    int count = contours.count();
6345fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    if (count == 0) {
6346fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return;
6347fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
6348a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com    for (int index = 0; index < count; ++index) {
63494eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        Contour& contour = contours[index];
63504eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
63514eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com        *list.append() = &contour;
6352fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
6353fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    QSort<Contour>(list.begin(), list.end() - 1);
6354fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
6355fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
6356f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.comstatic bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
63570b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
6358f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com}
6359f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com
636010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.comstatic bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
636110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    return distances[one] < distances[two];
636210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com}
6363f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    /*
6364f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        check start and end of each contour
6365f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if not the same, record them
6366f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        match them up
6367f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        connect closest
6368f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        reassemble contour pieces into new path
6369f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    */
6370f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.comstatic void assemble(const PathWrapper& path, PathWrapper& simple) {
6371f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com#if DEBUG_PATH_CONSTRUCTION
6372f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    SkDebugf("%s\n", __FUNCTION__);
6373f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com#endif
6374f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    SkTArray<Contour> contours;
6375f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    EdgeBuilder builder(path, contours);
6376f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    builder.finish();
6377f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    int count = contours.count();
63780b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    int outer;
6379f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    SkTDArray<int> runs; // indices of partial contours
63800b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    for (outer = 0; outer < count; ++outer) {
63810b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        const Contour& eContour = contours[outer];
6382f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        const SkPoint& eStart = eContour.start();
6383f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        const SkPoint& eEnd = eContour.end();
6384e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#if DEBUG_ASSEMBLE
6385e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        SkDebugf("%s contour", __FUNCTION__);
6386e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (!approximatelyEqual(eStart, eEnd)) {
6387e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            SkDebugf("[%d]", runs.count());
6388e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        } else {
6389e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            SkDebugf("   ");
6390e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        }
639161b05dcc7ebe48663c3ba84b7bd7449d6c887ac1skia.committer@gmail.com        SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
6392e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
6393e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#endif
6394f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        if (approximatelyEqual(eStart, eEnd)) {
6395f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            eContour.toPath(simple);
6396f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            continue;
6397f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
63980b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        *runs.append() = outer;
6399f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
6400f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    count = runs.count();
64010b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    if (count == 0) {
64020b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        return;
64030b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    }
6404f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    SkTDArray<int> sLink, eLink;
6405f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    sLink.setCount(count);
6406f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    eLink.setCount(count);
640710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    int rIndex, iIndex;
6408f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    for (rIndex = 0; rIndex < count; ++rIndex) {
6409aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com        sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
641010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    }
641110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    SkTDArray<double> distances;
641210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    const int ends = count * 2; // all starts and ends
641310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
641410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    distances.setCount(entries);
641510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
641610227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        outer = runs[rIndex >> 1];
64170b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        const Contour& oContour = contours[outer];
641810227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
641910227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
642010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com                * ends - rIndex - 1;
642110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
642210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            int inner = runs[iIndex >> 1];
64230b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            const Contour& iContour = contours[inner];
642410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
642510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            double dx = iPt.fX - oPt.fX;
642610227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            double dy = iPt.fY - oPt.fY;
64270b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            double dist = dx * dx + dy * dy;
642810227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            distances[row + iIndex] = dist; // oStart distance from iStart
642910227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        }
643010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    }
643110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    SkTDArray<int> sortedDist;
643210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    sortedDist.setCount(entries);
643310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    for (rIndex = 0; rIndex < entries; ++rIndex) {
643410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        sortedDist[rIndex] = rIndex;
643510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    }
643610227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
643710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    int remaining = count; // number of start/end pairs
643810227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    for (rIndex = 0; rIndex < entries; ++rIndex) {
643910227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        int pair = sortedDist[rIndex];
644010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        int row = pair / ends;
644110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        int col = pair - row * ends;
644210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        int thingOne = row < col ? row : ends - row - 2;
644310227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        int ndxOne = thingOne >> 1;
644410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        bool endOne = thingOne & 1;
644510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        int* linkOne = endOne ? eLink.begin() : sLink.begin();
6446aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com        if (linkOne[ndxOne] != SK_MaxS32) {
644710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            continue;
644810227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        }
644910227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        int thingTwo = row < col ? col : ends - row + col - 1;
645010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        int ndxTwo = thingTwo >> 1;
645110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        bool endTwo = thingTwo & 1;
645210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
6453aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com        if (linkTwo[ndxTwo] != SK_MaxS32) {
645410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            continue;
645510227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        }
645610227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
645710227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        bool flip = endOne == endTwo;
645810227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
645910227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
646010227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        if (!--remaining) {
646110227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com            break;
646210227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com        }
6463f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
646410227bf4679cd0eccae337cb83de8f64dfa959ebcaryclark@google.com    SkASSERT(!remaining);
6465e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#if DEBUG_ASSEMBLE
6466e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    for (rIndex = 0; rIndex < count; ++rIndex) {
6467e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        int s = sLink[rIndex];
6468e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        int e = eLink[rIndex];
6469e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
6470e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
6471f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    }
6472e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#endif
6473e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    rIndex = 0;
6474f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    do {
6475e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        bool forward = true;
6476e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        bool first = true;
6477e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        int sIndex = sLink[rIndex];
6478aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com        SkASSERT(sIndex != SK_MaxS32);
6479aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com        sLink[rIndex] = SK_MaxS32;
6480e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        int eIndex;
6481e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (sIndex < 0) {
6482e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            eIndex = sLink[~sIndex];
6483aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com            sLink[~sIndex] = SK_MaxS32;
6484e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        } else {
6485e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            eIndex = eLink[sIndex];
6486aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com            eLink[sIndex] = SK_MaxS32;
6487e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        }
6488aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com        SkASSERT(eIndex != SK_MaxS32);
6489e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#if DEBUG_ASSEMBLE
6490e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
649161b05dcc7ebe48663c3ba84b7bd7449d6c887ac1skia.committer@gmail.com                    sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
649261b05dcc7ebe48663c3ba84b7bd7449d6c887ac1skia.committer@gmail.com                    eIndex < 0 ? ~eIndex : eIndex);
6493e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#endif
6494f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        do {
64950b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            outer = runs[rIndex];
64960b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            const Contour& contour = contours[outer];
6497f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            if (first) {
6498f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                first = false;
6499e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                const SkPoint* startPtr = &contour.start();
6500f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                simple.deferredMove(startPtr[0]);
6501f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            }
6502f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            if (forward) {
6503f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                contour.toPartialForward(simple);
6504f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            } else {
6505f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                contour.toPartialBackward(simple);
6506f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            }
6507e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#if DEBUG_ASSEMBLE
6508e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
650961b05dcc7ebe48663c3ba84b7bd7449d6c887ac1skia.committer@gmail.com                eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
6510e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
6511e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#endif
6512e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
6513f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                simple.close();
6514f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                break;
6515f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            }
6516f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            if (forward) {
65170b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com                eIndex = eLink[rIndex];
6518aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com                SkASSERT(eIndex != SK_MaxS32);
6519aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com                eLink[rIndex] = SK_MaxS32;
65200b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com                if (eIndex >= 0) {
65210b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com                    SkASSERT(sLink[eIndex] == rIndex);
6522aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com                    sLink[eIndex] = SK_MaxS32;
6523f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                } else {
65240b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com                    SkASSERT(eLink[~eIndex] == ~rIndex);
6525aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com                    eLink[~eIndex] = SK_MaxS32;
6526f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                }
6527f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            } else {
65280b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com                eIndex = sLink[rIndex];
6529aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com                SkASSERT(eIndex != SK_MaxS32);
6530aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com                sLink[rIndex] = SK_MaxS32;
65310b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com                if (eIndex >= 0) {
65320b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com                    SkASSERT(eLink[eIndex] == rIndex);
6533aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com                    eLink[eIndex] = SK_MaxS32;
6534f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                } else {
65350b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com                    SkASSERT(sLink[~eIndex] == ~rIndex);
6536aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com                    sLink[~eIndex] = SK_MaxS32;
6537f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                }
6538f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            }
65390b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            rIndex = eIndex;
6540f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            if (rIndex < 0) {
6541f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                forward ^= 1;
6542f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                rIndex = ~rIndex;
6543f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            }
6544f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        } while (true);
6545f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        for (rIndex = 0; rIndex < count; ++rIndex) {
6546aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com            if (sLink[rIndex] != SK_MaxS32) {
6547f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                break;
6548f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com            }
6549f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        }
6550f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    } while (rIndex < count);
6551e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#if DEBUG_ASSEMBLE
6552e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    for (rIndex = 0; rIndex < count; ++rIndex) {
6553aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com       SkASSERT(sLink[rIndex] == SK_MaxS32);
6554aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com       SkASSERT(eLink[rIndex] == SK_MaxS32);
6555e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    }
6556e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com#endif
6557c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com}
6558c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com
6559f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.comvoid simplifyx(const SkPath& path, SkPath& result) {
65601304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com#if DEBUG_SORT || DEBUG_SWAP_TOP
6561c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com    gDebugSortCount = gDebugSortCountDefault;
6562c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com#endif
6563fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
6564f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    result.reset();
6565f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    result.setFillType(SkPath::kEvenOdd_FillType);
6566f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    PathWrapper simple(result);
6567fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
6568fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    // turn path into list of segments
6569fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkTArray<Contour> contours;
6570fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    EdgeBuilder builder(path, contours);
6571235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    builder.finish();
6572fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    SkTDArray<Contour*> contourList;
65734eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    makeContourList(contours, contourList, false, false);
6574fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    Contour** currentPtr = contourList.begin();
6575fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    if (!currentPtr) {
6576fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return;
6577fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
65781577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com    Contour** listEnd = contourList.end();
6579fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    // find all intersections between segments
6580fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    do {
6581fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        Contour** nextPtr = currentPtr;
6582fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        Contour* current = *currentPtr++;
6583c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        if (current->containsCubics()) {
6584c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com            addSelfIntersectTs(current);
6585c83c70e911a38aea03db4af8dd9841d0d77bd129caryclark@google.com        }
6586fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        Contour* next;
6587fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        do {
6588fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com            next = *nextPtr++;
658965f9f0a1664a9cb38157ccfbcc3e0e936af0a58ecaryclark@google.com        } while (addIntersectTs(current, next) && nextPtr != listEnd);
65901577e8f9c5bc8436cc71d3438c6d0b9f02c38338caryclark@google.com    } while (currentPtr != listEnd);
6591a833b5c40d0516237e0889fce8af44880423fc20caryclark@google.com    // eat through coincident edges
65924eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    coincidenceCheck(contourList, 0);
659366ca2fba44fe04f3382a3e22096fe73b60ce19d7caryclark@google.com    fixOtherTIndex(contourList);
6594fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    sortSegments(contourList);
65950b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com#if DEBUG_ACTIVE_SPANS
65960b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    debugShowActiveSpans(contourList);
65970b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com#endif
6598fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    // construct closed contours
65993586ece1ddbb48cabb2e7a4792be9ff5d74e40d9caryclark@google.com    if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
660020c301bd1aa4578c6d0abb23ac2c72b5fbb436dbskia.committer@gmail.com                : !bridgeXor(contourList, simple))
6601c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com    { // if some edges could not be resolved, assemble remaining fragments
6602f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        SkPath temp;
6603f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        temp.setFillType(SkPath::kEvenOdd_FillType);
6604f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        PathWrapper assembled(temp);
6605f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        assemble(simple, assembled);
6606f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        result = *assembled.nativePath();
660724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    }
6608fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
6609