EdgeWalker.cpp revision fb173424e915e696a73067d616ce4f39a407261a
1c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
2c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com/*
3c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com * Copyright 2012 Google Inc.
4c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com *
5c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com * Use of this source code is governed by a BSD-style license that can be
6c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com * found in the LICENSE file.
7c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com */
8c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
96680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com#include "CurveIntersection.h"
10a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com#include "Intersections.h"
11c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com#include "LineIntersection.h"
12c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com#include "SkPath.h"
13c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com#include "SkRect.h"
14c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com#include "SkTArray.h"
15c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com#include "SkTDArray.h"
16d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com#include "ShapeOps.h"
17c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com#include "TSearch.h"
18c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
19fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if 01 // set to 1 for no debugging whatsoever
20d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.comconst bool gShowDebugf = false; // FIXME: remove once debugging is complete
212e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
222e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_DUMP 0
232e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ADD 0
242e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ADD_INTERSECTING_TS 0
252e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ADD_BOTTOM_TS 0
262e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ABOVE_BELOW 0
272e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ACTIVE_LESS_THAN 0
28fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#define DEBUG_ASSEMBLE 0
29fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#define DEBUG_BRIDGE 0
302e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_SORT_HORIZONTAL 0
312e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_OUT 0
322e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_OUT_LESS_THAN 0
332e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ADJUST_COINCIDENT 0
34752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com#define DEBUG_BOTTOM 0
35198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com#define DEBUG_SPLIT 0
36fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#define DEBUG_STITCH_EDGE 0
372e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#else
38d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.comconst bool gShowDebugf = true; // FIXME: remove once debugging is complete
392e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
402e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_DUMP 01
412e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ADD 01
422e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ADD_INTERSECTING_TS 0
432e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ADD_BOTTOM_TS 0
442e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ABOVE_BELOW 01
45a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com#define DEBUG_ACTIVE_LESS_THAN 0
46fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#define DEBUG_ASSEMBLE 1
47fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#define DEBUG_BRIDGE 1
482e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_SORT_HORIZONTAL 01
492e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_OUT 01
502e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_OUT_LESS_THAN 0
512e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ADJUST_COINCIDENT 1
52198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com#define DEBUG_BOTTOM 0
53198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com#define DEBUG_SPLIT 1
54fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#define DEBUG_STITCH_EDGE 1
55752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
562e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
572e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
58fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE || DEBUG_BRIDGE
59fb173424e915e696a73067d616ce4f39a407261acaryclark@google.comstatic const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
60fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
61fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_STITCH_EDGE
62fb173424e915e696a73067d616ce4f39a407261acaryclark@google.comstatic const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
63fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
64fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com
656680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.comstatic int LineIntersect(const SkPoint a[2], const SkPoint b[2],
66a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        Intersections& intersections) {
67a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
68a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line bLine = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}};
69a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    return intersect(aLine, bLine, intersections.fT[0], intersections.fT[1]);
70a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
71a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com
72a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
73a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        Intersections& intersections) {
74a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
75a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line bLine = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}};
76198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    intersect(aQuad, bLine, intersections);
77198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    return intersections.fUsed;
78a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
79a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com
80a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic int CubicLineIntersect(const SkPoint a[2], const SkPoint b[3],
81a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        Intersections& intersections) {
82a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
83a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            {a[3].fX, a[3].fY}};
84a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line bLine = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}};
85198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    return intersect(aCubic, bLine, intersections.fT[0], intersections.fT[1]);
86a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
87a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com
88a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
89a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        Intersections& intersections) {
90a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
91a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Quadratic bQuad = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}, {b[2].fX, b[2].fY}};
92198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    intersect(aQuad, bQuad, intersections);
93198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    return intersections.fUsed;
94a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
95a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com
96a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic int CubicIntersect(const SkPoint a[4], const SkPoint b[4],
97a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        Intersections& intersections) {
98a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
99a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            {a[3].fX, a[3].fY}};
100a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Cubic bCubic = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}, {b[2].fX, b[2].fY},
101a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            {b[3].fX, b[3].fY}};
102198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    intersect(aCubic, bCubic, intersections);
103198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    return intersections.fUsed;
104c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com}
105c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
1062e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.comstatic int LineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
1072e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkScalar y, double aRange[2]) {
108a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
1092e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    return horizontalLineIntersect(aLine, left, right, y, aRange);
110c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com}
111c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
112198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.comstatic int QuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
113198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        SkScalar y, double aRange[3]) {
114198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
115198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    return horizontalIntersect(aQuad, left, right, y, aRange);
116198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com}
117198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
118198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.comstatic int CubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
119198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        SkScalar y, double aRange[4]) {
120198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
121198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            {a[3].fX, a[3].fY}};
122198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    return horizontalIntersect(aCubic, left, right, y, aRange);
123198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com}
124198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
125cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.comstatic void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
126a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line line = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
127cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    double x, y;
128a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    xy_at_t(line, t, x, y);
129cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    out->fX = SkDoubleToScalar(x);
130cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    out->fY = SkDoubleToScalar(y);
131cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com}
132cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com
133a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
134a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Quadratic quad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
135a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    double x, y;
136a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    xy_at_t(quad, t, x, y);
137a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    out->fX = SkDoubleToScalar(x);
138a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    out->fY = SkDoubleToScalar(y);
1392e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com}
1402e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
141a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
142a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Cubic cubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
143a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            {a[3].fX, a[3].fY}};
144a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    double x, y;
145a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    xy_at_t(cubic, t, x, y);
146a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    out->fX = SkDoubleToScalar(x);
147a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    out->fY = SkDoubleToScalar(y);
1482e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com}
1492e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
1506680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.comstatic SkScalar LineYAtT(const SkPoint a[2], double t) {
151a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
1526680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    double y;
1536680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    xy_at_t(aLine, t, *(double*) 0, y);
1546680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    return SkDoubleToScalar(y);
1556680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com}
1566680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
157a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic SkScalar QuadYAtT(const SkPoint a[3], double t) {
158a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Quadratic quad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
159a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    double y;
160a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    xy_at_t(quad, t, *(double*) 0, y);
161a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    return SkDoubleToScalar(y);
162a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
163a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com
164a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic SkScalar CubicYAtT(const SkPoint a[4], double t) {
165a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Cubic cubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
166a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            {a[3].fX, a[3].fY}};
167a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    double y;
168a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    xy_at_t(cubic, t, *(double*) 0, y);
169a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    return SkDoubleToScalar(y);
170a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
171a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com
1726680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.comstatic void LineSubDivide(const SkPoint a[2], double startT, double endT,
1736680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        SkPoint sub[2]) {
174a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
1756680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    _Line dst;
1766680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    sub_divide(aLine, startT, endT, dst);
1776680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    sub[0].fX = SkDoubleToScalar(dst[0].x);
1786680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    sub[0].fY = SkDoubleToScalar(dst[0].y);
1796680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    sub[1].fX = SkDoubleToScalar(dst[1].x);
1806680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    sub[1].fY = SkDoubleToScalar(dst[1].y);
1816680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com}
1826680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
183a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic void QuadSubDivide(const SkPoint a[3], double startT, double endT,
184a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        SkPoint sub[3]) {
185a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
186a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    Quadratic dst;
187a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub_divide(aQuad, startT, endT, dst);
188a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[0].fX = SkDoubleToScalar(dst[0].x);
189a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[0].fY = SkDoubleToScalar(dst[0].y);
190a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[1].fX = SkDoubleToScalar(dst[1].x);
191a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[1].fY = SkDoubleToScalar(dst[1].y);
192a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[2].fX = SkDoubleToScalar(dst[2].x);
193a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[2].fY = SkDoubleToScalar(dst[2].y);
1942e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com}
1956680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
196a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic void CubicSubDivide(const SkPoint a[4], double startT, double endT,
197a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        SkPoint sub[4]) {
198a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
199a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            {a[3].fX, a[3].fY}};
200a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    Cubic dst;
201a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub_divide(aCubic, startT, endT, dst);
202a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[0].fX = SkDoubleToScalar(dst[0].x);
203a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[0].fY = SkDoubleToScalar(dst[0].y);
204a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[1].fX = SkDoubleToScalar(dst[1].x);
205a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[1].fY = SkDoubleToScalar(dst[1].y);
206a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[2].fX = SkDoubleToScalar(dst[2].x);
207a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[2].fY = SkDoubleToScalar(dst[2].y);
208a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[3].fX = SkDoubleToScalar(dst[3].x);
209a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[3].fY = SkDoubleToScalar(dst[3].y);
210a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
211fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com
212fb173424e915e696a73067d616ce4f39a407261acaryclark@google.comstatic void QuadSubBounds(const SkPoint a[3], double startT, double endT,
213fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkRect& bounds) {
214fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    SkPoint dst[3];
215fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    QuadSubDivide(a, startT, endT, dst);
216fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    bounds.fLeft = bounds.fRight = dst[0].fX;
217fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    bounds.fTop = bounds.fBottom = dst[0].fY;
218fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    for (int index = 1; index < 3; ++index) {
219fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        bounds.growToInclude(dst[index].fX, dst[index].fY);
220fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    }
221fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com}
222fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com
223fb173424e915e696a73067d616ce4f39a407261acaryclark@google.comstatic void CubicSubBounds(const SkPoint a[4], double startT, double endT,
224fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkRect& bounds) {
225fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    SkPoint dst[4];
226fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    CubicSubDivide(a, startT, endT, dst);
227fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    bounds.fLeft = bounds.fRight = dst[0].fX;
228fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    bounds.fTop = bounds.fBottom = dst[0].fY;
229fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    for (int index = 1; index < 4; ++index) {
230fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        bounds.growToInclude(dst[index].fX, dst[index].fY);
231fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    }
232fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com}
233fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com
234c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com/*
235c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comlist of edges
236c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.combounds for edge
237c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comsort
238c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comactive T
239c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
240c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comif a contour's bounds is outside of the active area, no need to create edges
241c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com*/
242c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
243c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com/* given one or more paths,
244c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com find the bounds of each contour, select the active contours
245c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com for each active contour, compute a set of edges
246c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com each edge corresponds to one or more lines and curves
247c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com leave edges unbroken as long as possible
248c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com when breaking edges, compute the t at the break but leave the control points alone
249c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
250c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com */
251c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
252c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comvoid contourBounds(const SkPath& path, SkTDArray<SkRect>& boundsArray) {
253c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkPath::Iter iter(path, false);
254c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkPoint pts[4];
255c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkPath::Verb verb;
256c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkRect bounds;
257c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    bounds.setEmpty();
258c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    int count = 0;
259c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
260c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        switch (verb) {
261c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            case SkPath::kMove_Verb:
262c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                if (!bounds.isEmpty()) {
263c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                    *boundsArray.append() = bounds;
264c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                }
265c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                bounds.set(pts[0].fX, pts[0].fY, pts[0].fX, pts[0].fY);
266c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                count = 0;
267c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                break;
268c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            case SkPath::kLine_Verb:
269c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                count = 1;
270c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                break;
271c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            case SkPath::kQuad_Verb:
272c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                count = 2;
273c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                break;
274c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            case SkPath::kCubic_Verb:
275c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                count = 3;
276c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                break;
277c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            case SkPath::kClose_Verb:
278c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                count = 0;
279c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                break;
280c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            default:
281c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                SkDEBUGFAIL("bad verb");
282c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                return;
283c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
284c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        for (int i = 1; i <= count; ++i) {
285c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            bounds.growToInclude(pts[i].fX, pts[i].fY);
286c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
287c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
288c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com}
289c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
290f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.comstatic bool extendLine(const SkPoint line[2], const SkPoint& add) {
291f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    // FIXME: allow this to extend lines that have slopes that are nearly equal
292f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    SkScalar dx1 = line[1].fX - line[0].fX;
293f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    SkScalar dy1 = line[1].fY - line[0].fY;
294f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    SkScalar dx2 = add.fX - line[0].fX;
295f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    SkScalar dy2 = add.fY - line[0].fY;
296f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    return dx1 * dy2 == dx2 * dy1;
297f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com}
2986680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
2992e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// OPTIMIZATION: this should point to a list of input data rather than duplicating
3002e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// the line data here. This would reduce the need to assemble the results.
301f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.comstruct OutEdge {
302f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    bool operator<(const OutEdge& rh) const {
303cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const SkPoint& first = fPts[0];
304cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const SkPoint& rhFirst = rh.fPts[0];
305f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        return first.fY == rhFirst.fY
306f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                ? first.fX < rhFirst.fX
307f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                : first.fY < rhFirst.fY;
308f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    }
309752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
310cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    SkPoint fPts[4];
3112e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    int fID; // id of edge generating data
312cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    uint8_t fVerb; // FIXME: not read from everywhere
3132e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    bool fCloseCall; // edge is trimmable if not originally coincident
314f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com};
315f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com
3166680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.comclass OutEdgeBuilder {
3176680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.compublic:
318f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    OutEdgeBuilder(bool fill)
319f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        : fFill(fill) {
320f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        }
321f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com
322a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    void addCurve(const SkPoint line[4], SkPath::Verb verb, int id,
323a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            bool closeCall) {
324c17972e7acc784553445adc18f608a8c4b1beac8caryclark@google.com        OutEdge& newEdge = fEdges.push_back();
325a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        memcpy(newEdge.fPts, line, (verb + 1) * sizeof(SkPoint));
326a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        newEdge.fVerb = verb;
3272e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        newEdge.fID = id;
3282e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        newEdge.fCloseCall = closeCall;
3292e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
330752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
3312e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    bool trimLine(SkScalar y, int id) {
3322e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        size_t count = fEdges.count();
3332e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        while (count-- != 0) {
3342e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            OutEdge& edge = fEdges[count];
3352e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (edge.fID != id) {
3362e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                continue;
3372e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            }
3382e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (edge.fCloseCall) {
3392e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                return false;
3402e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            }
3412e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkASSERT(edge.fPts[0].fY <= y);
3422e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (edge.fPts[1].fY <= y) {
3432e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                continue;
3442e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            }
3452e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            edge.fPts[1].fX = edge.fPts[0].fX + (y - edge.fPts[0].fY)
3462e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    * (edge.fPts[1].fX - edge.fPts[0].fX)
3472e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    / (edge.fPts[1].fY - edge.fPts[0].fY);
3482e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            edge.fPts[1].fY = y;
3492e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (gShowDebugf) {
3502e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                SkDebugf("%s edge=%d %1.9g,%1.9g\n", __FUNCTION__, id,
3512e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                        edge.fPts[1].fX, y);
3522e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            }
3532e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            return true;
3542e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
3552e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        return false;
356f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    }
357f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com
358f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    void assemble(SkPath& simple) {
3596008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        size_t listCount = fEdges.count();
3606008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        if (listCount == 0) {
3616008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            return;
3626008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        }
363f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        do {
3646008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            size_t listIndex = 0;
3656008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            int advance = 1;
3666008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            while (listIndex < listCount && fTops[listIndex] == 0) {
3676008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                ++listIndex;
368f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            }
3696008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            if (listIndex >= listCount) {
3706008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                break;
371f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            }
3724917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com            int closeEdgeIndex = -listIndex - 1;
373fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            // the curve is deferred and not added right away because the
374fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            // following edge may extend the first curve.
375a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            SkPoint firstPt, lastCurve[4];
376a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            uint8_t lastVerb;
377fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
378fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            int firstIndex, lastIndex;
379fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            const int tab = 8;
380fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
3816008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            bool doMove = true;
3826008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            int edgeIndex;
3836008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            do {
384cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                SkPoint* ptArray = fEdges[listIndex].fPts;
385cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                uint8_t verb = fEdges[listIndex].fVerb;
386fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                SkPoint* curve[4];
3876008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                if (advance < 0) {
388fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    curve[0] = &ptArray[verb];
389fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    if (verb == SkPath::kCubic_Verb) {
390fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        curve[1] = &ptArray[2];
391fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        curve[2] = &ptArray[1];
392fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    }
393fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    curve[verb] = &ptArray[0];
3946008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                } else {
395fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    curve[0] = &ptArray[0];
396fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    if (verb == SkPath::kCubic_Verb) {
397fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        curve[1] = &ptArray[1];
398fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        curve[2] = &ptArray[2];
399fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    }
400fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    curve[verb] = &ptArray[verb];
401fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                }
402fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                if (verb == SkPath::kQuad_Verb) {
403fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    curve[1] = &ptArray[1];
404f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                }
405a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                if (doMove) {
406fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    firstPt = *curve[0];
407fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    simple.moveTo(curve[0]->fX, curve[0]->fY);
408fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
409fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    SkDebugf("%s %d moveTo (%g,%g)\n", __FUNCTION__,
410fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            listIndex + 1, curve[0]->fX, curve[0]->fY);
411fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    firstIndex = listIndex;
412fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
413fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    for (int index = 0; index <= verb; ++index) {
414fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        lastCurve[index] = *curve[index];
415a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    }
416a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    doMove = false;
417a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                } else {
418fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    bool gap = lastCurve[lastVerb] != *curve[0];
419fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    if (gap || lastVerb != SkPath::kLine_Verb) { // output the accumulated curve before the gap
420a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        // FIXME: see comment in bridge -- this probably
421a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        // conceals errors
422fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        SkASSERT(fFill && UlpsDiff(lastCurve[lastVerb].fY,
423fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                curve[0]->fY) <= 10);
424a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        switch (lastVerb) {
425a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kLine_Verb:
426a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                simple.lineTo(lastCurve[1].fX, lastCurve[1].fY);
427a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
428a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kQuad_Verb:
429a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                simple.quadTo(lastCurve[1].fX, lastCurve[1].fY,
430a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                        lastCurve[2].fX, lastCurve[2].fY);
431a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
432a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kCubic_Verb:
433a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                simple.cubicTo(lastCurve[1].fX, lastCurve[1].fY,
434a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                        lastCurve[2].fX, lastCurve[2].fY,
435a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                        lastCurve[3].fX, lastCurve[3].fY);
436a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
437cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                        }
438fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
439fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        SkDebugf("%*s %d %sTo (%g,%g)\n", tab, "", lastIndex + 1,
440fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                kLVerbStr[lastVerb], lastCurve[lastVerb].fX,
441fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                lastCurve[lastVerb].fY);
442fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
443a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    }
444fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    int firstCopy = 1;
445fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    if (gap || (lastVerb == SkPath::kLine_Verb &&
446fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            !extendLine(lastCurve, *curve[verb]))) {
447a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        // FIXME: see comment in bridge -- this probably
448a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        // conceals errors
449fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        SkASSERT(lastCurve[lastVerb] == *curve[0] ||
450fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                (fFill && UlpsDiff(lastCurve[lastVerb].fY,
451fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                curve[0]->fY) <= 10));
452fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        simple.lineTo(curve[0]->fX, curve[0]->fY);
453fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
454fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        SkDebugf("%*s %d gap lineTo (%g,%g)\n", tab, "",
455fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                lastIndex + 1, curve[0]->fX, curve[0]->fY);
456fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
457fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        firstCopy = 0;
458fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    } else if (lastVerb != SkPath::kLine_Verb) {
459fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        firstCopy = 0;
460a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    }
461fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    for (int index = firstCopy; index <= verb; ++index) {
462fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        lastCurve[index] = *curve[index];
463a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    }
4646008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                }
465fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                lastVerb = verb;
466fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
467fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                lastIndex = listIndex;
468fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
4696008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                if (advance < 0) {
4706008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    edgeIndex = fTops[listIndex];
4716008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    fTops[listIndex] = 0;
472fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                } else {
4736008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    edgeIndex = fBottoms[listIndex];
4746008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    fBottoms[listIndex] = 0;
4756008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                }
4764917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                if (edgeIndex) {
4774917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                    listIndex = abs(edgeIndex) - 1;
4784917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                    if (edgeIndex < 0) {
4794917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                        fTops[listIndex] = 0;
4804917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                    } else {
4814917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                        fBottoms[listIndex] = 0;
4824917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                    }
4834917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                }
4844917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                if (edgeIndex == closeEdgeIndex || edgeIndex == 0) {
485fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    switch (lastVerb) {
486fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        case SkPath::kLine_Verb:
487fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            simple.lineTo(lastCurve[1].fX, lastCurve[1].fY);
488fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            break;
489fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        case SkPath::kQuad_Verb:
490fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            simple.quadTo(lastCurve[1].fX, lastCurve[1].fY,
491fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                    lastCurve[2].fX, lastCurve[2].fY);
492fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            break;
493fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        case SkPath::kCubic_Verb:
494fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            simple.cubicTo(lastCurve[1].fX, lastCurve[1].fY,
495fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                    lastCurve[2].fX, lastCurve[2].fY,
496fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                    lastCurve[3].fX, lastCurve[3].fY);
497fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            break;
498fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    }
499fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
500fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    SkDebugf("%*s %d %sTo last (%g, %g)\n", tab, "",
501fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            lastIndex + 1, kLVerbStr[lastVerb],
502fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            lastCurve[lastVerb].fX, lastCurve[lastVerb].fY);
503fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
504a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    if (lastCurve[lastVerb] != firstPt) {
505fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        simple.lineTo(firstPt.fX, firstPt.fY);
506fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
507fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        SkDebugf("%*s %d final line (%g, %g)\n", tab, "",
508fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                firstIndex + 1, firstPt.fX, firstPt.fY);
509fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
5104917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                    }
511cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                    simple.close();
512fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
513fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    SkDebugf("%*s   close\n", tab, "");
514fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
515cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                    break;
516cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                }
517fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                // if this and next edge go different directions
518fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
519fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                SkDebugf("%*s   advance=%d edgeIndex=%d flip=%s\n", tab, "",
520fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        advance, edgeIndex, advance > 0 ^ edgeIndex < 0 ?
521fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        "true" : "false");
522fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
5236008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                if (advance > 0 ^ edgeIndex < 0) {
5246008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    advance = -advance;
5256008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                }
5264917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com            } while (edgeIndex);
5276008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        } while (true);
528f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    }
529752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
530cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    // sort points by y, then x
531cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    // if x/y is identical, sort bottoms before tops
532cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    // if identical and both tops/bottoms, sort by angle
533cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    static bool lessThan(SkTArray<OutEdge>& edges, const int one,
534cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            const int two) {
535cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const OutEdge& oneEdge = edges[abs(one) - 1];
536cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        int oneIndex = one < 0 ? 0 : oneEdge.fVerb;
537cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const SkPoint& startPt1 = oneEdge.fPts[oneIndex];
538cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const OutEdge& twoEdge = edges[abs(two) - 1];
539cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        int twoIndex = two < 0 ? 0 : twoEdge.fVerb;
540cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const SkPoint& startPt2 = twoEdge.fPts[twoIndex];
541cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        if (startPt1.fY != startPt2.fY) {
5422e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #if DEBUG_OUT_LESS_THAN
5432e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkDebugf("%s %d<%d (%g,%g) %s startPt1.fY < startPt2.fY\n", __FUNCTION__,
5442e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    one, two, startPt1.fY, startPt2.fY,
5452e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    startPt1.fY < startPt2.fY ? "true" : "false");
5462e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #endif
547cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            return startPt1.fY < startPt2.fY;
548cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        }
549cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        if (startPt1.fX != startPt2.fX) {
5502e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #if DEBUG_OUT_LESS_THAN
5512e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkDebugf("%s %d<%d (%g,%g) %s startPt1.fX < startPt2.fX\n", __FUNCTION__,
5522e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    one, two, startPt1.fX, startPt2.fX,
5532e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    startPt1.fX < startPt2.fX ? "true" : "false");
5542e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #endif
555cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            return startPt1.fX < startPt2.fX;
556cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        }
557cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const SkPoint& endPt1 = oneEdge.fPts[oneIndex ^ oneEdge.fVerb];
558cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const SkPoint& endPt2 = twoEdge.fPts[twoIndex ^ twoEdge.fVerb];
559cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        SkScalar dy1 = startPt1.fY - endPt1.fY;
560cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        SkScalar dy2 = startPt2.fY - endPt2.fY;
561cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        SkScalar dy1y2 = dy1 * dy2;
562cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        if (dy1y2 < 0) { // different signs
5632e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #if DEBUG_OUT_LESS_THAN
564cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                SkDebugf("%s %d<%d %s dy1 > 0\n", __FUNCTION__, one, two,
565cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                        dy1 > 0 ? "true" : "false");
5662e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #endif
567cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            return dy1 > 0; // one < two if one goes up and two goes down
568cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        }
569cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        if (dy1y2 == 0) {
5702e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #if DEBUG_OUT_LESS_THAN
5712e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkDebugf("%s %d<%d %s endPt1.fX < endPt2.fX\n", __FUNCTION__,
5722e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    one, two, endPt1.fX < endPt2.fX ? "true" : "false");
5732e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #endif
574cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            return endPt1.fX < endPt2.fX;
575cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        }
576cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        SkScalar dx1y2 = (startPt1.fX - endPt1.fX) * dy2;
577cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        SkScalar dx2y1 = (startPt2.fX - endPt2.fX) * dy1;
5782e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #if DEBUG_OUT_LESS_THAN
5792e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkDebugf("%s %d<%d %s dy2 < 0 ^ dx1y2 < dx2y1\n", __FUNCTION__,
5802e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                one, two, dy2 < 0 ^ dx1y2 < dx2y1 ? "true" : "false");
5812e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #endif
582cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        return dy2 > 0 ^ dx1y2 < dx2y1;
583f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    }
584f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com
5856008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    // Sort the indices of paired points and then create more indices so
5866008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    // assemble() can find the next edge and connect the top or bottom
587f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    void bridge() {
588f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        size_t index;
589f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        size_t count = fEdges.count();
590f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        if (!count) {
591f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            return;
592f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        }
593cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        SkASSERT(!fFill || count > 1);
594f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        fTops.setCount(count);
595f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        sk_bzero(fTops.begin(), sizeof(fTops[0]) * count);
596f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        fBottoms.setCount(count);
597f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        sk_bzero(fBottoms.begin(), sizeof(fBottoms[0]) * count);
5986008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        SkTDArray<int> order;
5996008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        for (index = 1; index <= count; ++index) {
6006008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            *order.append() = -index;
601f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        }
602cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        for (index = 1; index <= count; ++index) {
603cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            *order.append() = index;
604cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        }
605cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        QSort<SkTArray<OutEdge>, int>(fEdges, order.begin(), order.end() - 1, lessThan);
6066008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        int* lastPtr = order.end() - 1;
6076008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        int* leftPtr = order.begin();
6086008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        while (leftPtr < lastPtr) {
6096008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            int leftIndex = *leftPtr;
6106008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            int leftOutIndex = abs(leftIndex) - 1;
6116008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            const OutEdge& left = fEdges[leftOutIndex];
612f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            int* rightPtr = leftPtr + 1;
6136008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            int rightIndex = *rightPtr;
6146008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            int rightOutIndex = abs(rightIndex) - 1;
6156008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            const OutEdge& right = fEdges[rightOutIndex];
616cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            bool pairUp = fFill;
617cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            if (!pairUp) {
618cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                const SkPoint& leftMatch =
619cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                        left.fPts[leftIndex < 0 ? 0 : left.fVerb];
620cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                const SkPoint& rightMatch =
621cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                        right.fPts[rightIndex < 0 ? 0 : right.fVerb];
622cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                pairUp = leftMatch == rightMatch;
623cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            } else {
6242e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        #if DEBUG_OUT
625d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        // FIXME : not happy that error in low bit is allowed
626d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        // this probably conceals error elsewhere
627d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                if (UlpsDiff(left.fPts[leftIndex < 0 ? 0 : left.fVerb].fY,
628d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                        right.fPts[rightIndex < 0 ? 0 : right.fVerb].fY) > 1) {
6292e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    *fMismatches.append() = leftIndex;
6302e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    if (rightPtr == lastPtr) {
6312e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                        *fMismatches.append() = rightIndex;
6322e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    }
6332e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    pairUp = false;
6342e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                }
6352e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        #else
636d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                SkASSERT(UlpsDiff(left.fPts[leftIndex < 0 ? 0 : left.fVerb].fY,
637d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                        right.fPts[rightIndex < 0 ? 0 : right.fVerb].fY) <= 10);
6382e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        #endif
639cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            }
640cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            if (pairUp) {
6416008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                if (leftIndex < 0) {
6426008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    fTops[leftOutIndex] = rightIndex;
6436008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                } else {
6446008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    fBottoms[leftOutIndex] = rightIndex;
6456008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                }
6466008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                if (rightIndex < 0) {
6476008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    fTops[rightOutIndex] = leftIndex;
6486008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                } else {
6496008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    fBottoms[rightOutIndex] = leftIndex;
650f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                }
6516008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                ++rightPtr;
652f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            }
653f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            leftPtr = rightPtr;
6546680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        }
6552e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_OUT
6562e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        int* mismatch = fMismatches.begin();
6572e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        while (mismatch != fMismatches.end()) {
6582e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            int leftIndex = *mismatch++;
6592e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            int leftOutIndex = abs(leftIndex) - 1;
6602e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            const OutEdge& left = fEdges[leftOutIndex];
6612e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            const SkPoint& leftPt = left.fPts[leftIndex < 0 ? 0 : left.fVerb];
6622e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkDebugf("%s left=%d %s (%1.9g,%1.9g)\n",
6632e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    __FUNCTION__, left.fID, leftIndex < 0 ? "top" : "bot",
6642e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    leftPt.fX, leftPt.fY);
6652e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
6662e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkASSERT(fMismatches.count() == 0);
6672e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
668fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_BRIDGE
669fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    for (index = 0; index < count; ++index) {
670fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        const OutEdge& edge = fEdges[index];
671fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        uint8_t verb = edge.fVerb;
672fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkDebugf("%s %d edge=%d %s (%1.9g,%1.9g) (%1.9g,%1.9g)\n",
673fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                index == 0 ? __FUNCTION__ : "      ",
674fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                index + 1, edge.fID, kLVerbStr[verb], edge.fPts[0].fX,
675fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                edge.fPts[0].fY, edge.fPts[verb].fX, edge.fPts[verb].fY);
676fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    }
677fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    for (index = 0; index < count; ++index) {
678fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkDebugf("       top    of % 2d connects to %s of % 2d\n", index + 1,
679fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                fTops[index] < 0 ? "top   " : "bottom", abs(fTops[index]));
680fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkDebugf("       bottom of % 2d connects to %s of % 2d\n", index + 1,
681fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                fBottoms[index] < 0 ? "top   " : "bottom", abs(fBottoms[index]));
682fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    }
683fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
6846680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    }
6856680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
6866008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.comprotected:
6876680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    SkTArray<OutEdge> fEdges;
6886008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    SkTDArray<int> fTops;
6896008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    SkTDArray<int> fBottoms;
690f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    bool fFill;
6912e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_OUT
6922e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkTDArray<int> fMismatches;
6932e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
6946680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com};
6956680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
696c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com// Bounds, unlike Rect, does not consider a vertical line to be empty.
697c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comstruct Bounds : public SkRect {
698c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    static bool Intersects(const Bounds& a, const Bounds& b) {
699c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
700c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                a.fTop <= b.fBottom && b.fTop <= a.fBottom;
701c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
702752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
7036008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    bool isEmpty() {
7046008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        return fLeft > fRight || fTop > fBottom
7056008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                || fLeft == fRight && fTop == fBottom
7066008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                || isnan(fLeft) || isnan(fRight)
7076008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                || isnan(fTop) || isnan(fBottom);
7086008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    }
709c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com};
710c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
7114917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.comclass Intercepts {
7124917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.compublic:
7134917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com    Intercepts()
7144917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com        : fTopIntercepts(0)
715198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        , fBottomIntercepts(0)
716198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        , fExplicit(false) {
717198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
718198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
719198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    Intercepts& operator=(const Intercepts& src) {
720198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fTs = src.fTs;
721198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fTopIntercepts = src.fTopIntercepts;
722198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fBottomIntercepts = src.fBottomIntercepts;
723198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
724198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
725198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    // OPTIMIZATION: remove this function if it's never called
726198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    double t(int tIndex) const {
727198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        if (tIndex == 0) {
728198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            return 0;
729198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
730198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        if (tIndex > fTs.count()) {
731198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            return 1;
732198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
733198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        return fTs[tIndex - 1];
7344917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com    }
735752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
7362e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_DUMP
737a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    void dump(const SkPoint* pts, SkPath::Verb verb) {
7382e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        const char className[] = "Intercepts";
7392e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        const int tab = 8;
7402e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        for (int i = 0; i < fTs.count(); ++i) {
7412e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkPoint out;
742a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            switch (verb) {
743a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                case SkPath::kLine_Verb:
744a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    LineXYAtT(pts, fTs[i], &out);
745a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    break;
746a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                case SkPath::kQuad_Verb:
747a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    QuadXYAtT(pts, fTs[i], &out);
748a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    break;
749a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                case SkPath::kCubic_Verb:
750a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    CubicXYAtT(pts, fTs[i], &out);
751a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    break;
752a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                default:
753a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    SkASSERT(0);
754a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            }
755752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            SkDebugf("%*s.fTs[%d]=%1.9g (%1.9g,%1.9g)\n", tab + sizeof(className),
7562e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    className, i, fTs[i], out.fX, out.fY);
7572e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
758198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        SkDebugf("%*s.fTopIntercepts=%u\n", tab + sizeof(className),
7592e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                className, fTopIntercepts);
760198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        SkDebugf("%*s.fBottomIntercepts=%u\n", tab + sizeof(className),
7612e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                className, fBottomIntercepts);
762fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkDebugf("%*s.fExplicit=%d\n", tab + sizeof(className),
763fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                className, fExplicit);
7642e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
7652e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
7662e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
767c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkTDArray<double> fTs;
768198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    unsigned char fTopIntercepts; // 0=init state 1=1 edge >1=multiple edges
769198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    unsigned char fBottomIntercepts;
770198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    bool fExplicit; // if set, suppress 0 and 1
771198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
772c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com};
773c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
7742e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.comstruct HorizontalEdge {
7752e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    bool operator<(const HorizontalEdge& rh) const {
7762e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        return fY == rh.fY ? fLeft == rh.fLeft ? fRight < rh.fRight
7772e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                : fLeft < rh.fLeft : fY < rh.fY;
7782e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
7792e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
7802e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_DUMP
7812e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    void dump() {
7822e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        const char className[] = "HorizontalEdge";
7832e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        const int tab = 4;
784752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        SkDebugf("%*s.fLeft=%1.9g\n", tab + sizeof(className), className, fLeft);
785752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        SkDebugf("%*s.fRight=%1.9g\n", tab + sizeof(className), className, fRight);
786752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        SkDebugf("%*s.fY=%1.9g\n", tab + sizeof(className), className, fY);
7872e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
7882e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
7892e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
7902e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkScalar fLeft;
7912e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkScalar fRight;
7922e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkScalar fY;
7932e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com};
7942e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
7956680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.comstruct InEdge {
7966680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    bool operator<(const InEdge& rh) const {
797c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        return fBounds.fTop == rh.fBounds.fTop
798c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                ? fBounds.fLeft < rh.fBounds.fLeft
799c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                : fBounds.fTop < rh.fBounds.fTop;
800c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
801c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
8022e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // Avoid collapsing t values that are close to the same since
8032e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // we walk ts to describe consecutive intersections. Since a pair of ts can
8042e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // be nearly equal, any problems caused by this should be taken care
8052e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // of later.
8062e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    int add(double* ts, size_t count, ptrdiff_t verbIndex) {
807c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        // FIXME: in the pathological case where there is a ton of intercepts, binary search?
8086008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        bool foundIntercept = false;
8092e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        int insertedAt = -1;
8106008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        Intercepts& intercepts = fIntercepts[verbIndex];
811c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        for (size_t index = 0; index < count; ++index) {
812c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            double t = ts[index];
8134917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com            if (t <= 0) {
814198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                intercepts.fTopIntercepts <<= 1;
8154917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                fContainsIntercepts |= ++intercepts.fTopIntercepts > 1;
8164917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                continue;
8174917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com            }
8184917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com            if (t >= 1) {
819198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                intercepts.fBottomIntercepts <<= 1;
8204917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                fContainsIntercepts |= ++intercepts.fBottomIntercepts > 1;
8216008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                continue;
8226008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            }
823198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            fIntersected = true;
8246008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            foundIntercept = true;
825c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            size_t tCount = intercepts.fTs.count();
8262e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            double delta;
827c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            for (size_t idx2 = 0; idx2 < tCount; ++idx2) {
828c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                if (t <= intercepts.fTs[idx2]) {
8292e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    // FIXME: ?  if (t < intercepts.fTs[idx2]) // failed
8302e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    delta = intercepts.fTs[idx2] - t;
831cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                    if (delta > 0) {
8322e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                        insertedAt = idx2;
833c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                        *intercepts.fTs.insert(idx2) = t;
834c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                    }
8352e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    goto nextPt;
836c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                }
837c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            }
8382e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (tCount == 0 || (delta = t - intercepts.fTs[tCount - 1]) > 0) {
8392e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                insertedAt = tCount;
840c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                *intercepts.fTs.append() = t;
841c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            }
8422e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    nextPt:
8432e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            ;
844c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
8454917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com        fContainsIntercepts |= foundIntercept;
8462e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        return insertedAt;
847c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
848198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
849fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    void addPartial(SkTArray<InEdge>& edges, int ptStart, int ptEnd,
850198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            int verbStart, int verbEnd) {
851198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        InEdge* edge = edges.push_back_n(1);
852198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        int verbCount = verbEnd - verbStart;
853198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fIntercepts.push_back_n(verbCount);
854198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        uint8_t* verbs = &fVerbs[verbStart];
855198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        for (int ceptIdx = 0; ceptIdx < verbCount; ++ceptIdx) {
856198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            edge->fIntercepts[ceptIdx] = fIntercepts[verbStart + ceptIdx];
857198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
858198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fPts.append(ptEnd - ptStart, &fPts[ptStart]);
859198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fVerbs.append(verbCount, &fVerbs[verbStart]);
860198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->setBounds();
861198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fWinding = fWinding;
862198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fContainsIntercepts = fContainsIntercepts; // FIXME: may not be correct -- but do we need to know?
863198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
864198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
865fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    void addSplit(SkTArray<InEdge>& edges, SkPoint* pts, uint8_t verb,
866fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            Intercepts& intercepts, int firstT, int lastT, bool flipped) {
867198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        InEdge* edge = edges.push_back_n(1);
868198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fIntercepts.push_back_n(1);
869fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        if (firstT == 0) {
870fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            *edge->fIntercepts[0].fTs.append() = 0;
871fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        } else {
872fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            *edge->fIntercepts[0].fTs.append() = intercepts.fTs[firstT - 1];
873fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        }
874fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        bool add1 = lastT == intercepts.fTs.count();
875fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        edge->fIntercepts[0].fTs.append(lastT - firstT, &intercepts.fTs[firstT]);
876fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        if (add1) {
877fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            *edge->fIntercepts[0].fTs.append() = 1;
878fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        }
879198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fIntercepts[0].fExplicit = true;
880fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        edge->fPts.append(verb + 1, pts);
881198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fVerbs.append(1, &verb);
882fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        // FIXME: bounds could be better for partial Ts
883fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        edge->setSubBounds();
884198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fContainsIntercepts = fContainsIntercepts; // FIXME: may not be correct -- but do we need to know?
885198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        if (flipped) {
886fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            edge->flipTs();
887fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            edge->fWinding = -fWinding;
888fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        } else {
889fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            edge->fWinding = fWinding;
890198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
891198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
892c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
8936680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    bool cached(const InEdge* edge) {
894c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        // FIXME: in the pathological case where there is a ton of edges, binary search?
895c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        size_t count = fCached.count();
896c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        for (size_t index = 0; index < count; ++index) {
897c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            if (edge == fCached[index]) {
898c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                return true;
899c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            }
900c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            if (edge < fCached[index]) {
901c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                *fCached.insert(index) = edge;
902c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                return false;
903c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            }
904c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
905c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        *fCached.append() = edge;
906c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        return false;
907c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
908c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
909fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    void complete(signed char winding) {
910198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        setBounds();
911198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fIntercepts.push_back_n(fVerbs.count());
912198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        if ((fWinding = winding) < 0) { // reverse verbs, pts, if bottom to top
913198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            flip();
914198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
915198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fContainsIntercepts = fIntersected = false;
916198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
917198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
918fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    void flip() {
919198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        size_t index;
920198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        size_t last = fPts.count() - 1;
921198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        for (index = 0; index < last; ++index, --last) {
922198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            SkTSwap<SkPoint>(fPts[index], fPts[last]);
923198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
924198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        last = fVerbs.count() - 1;
925198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        for (index = 0; index < last; ++index, --last) {
926198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            SkTSwap<uint8_t>(fVerbs[index], fVerbs[last]);
927198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
928198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
929fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com
930fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    void flipTs() {
931fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkASSERT(fIntercepts.count() == 1);
932fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        Intercepts& intercepts = fIntercepts[0];
933fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkASSERT(intercepts.fExplicit);
934fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkTDArray<double>& ts = intercepts.fTs;
935fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        size_t index;
936fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        size_t last = ts.count() - 1;
937fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        for (index = 0; index < last; ++index, --last) {
938fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            SkTSwap<double>(ts[index], ts[last]);
939fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        }
940fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    }
941198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
942198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    void reset() {
943198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fCached.reset();
944198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fIntercepts.reset();
945198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fPts.reset();
946198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fVerbs.reset();
947198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
948198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fWinding = 0;
949198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fContainsIntercepts = false;
950198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fIntersected = false;
951198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
952198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
953198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    void setBounds() {
954c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        SkPoint* ptPtr = fPts.begin();
955c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        SkPoint* ptLast = fPts.end();
956c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        if (ptPtr == ptLast) {
957198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            SkDebugf("%s empty edge\n", __FUNCTION__);
958c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            SkASSERT(0);
959c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            // FIXME: delete empty edge?
960c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            return;
961c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
962c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        fBounds.set(ptPtr->fX, ptPtr->fY, ptPtr->fX, ptPtr->fY);
963c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        ++ptPtr;
964c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        while (ptPtr != ptLast) {
965c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            fBounds.growToInclude(ptPtr->fX, ptPtr->fY);
966c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            ++ptPtr;
967c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
968198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
969fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com
970fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    // recompute bounds based on subrange of T values
971fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    void setSubBounds() {
972fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkASSERT(fIntercepts.count() == 1);
973fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        Intercepts& intercepts = fIntercepts[0];
974fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkASSERT(intercepts.fExplicit);
975fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkASSERT(fVerbs.count() == 1);
976fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkTDArray<double>& ts = intercepts.fTs;
977fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        if (fVerbs[0] == SkPath::kQuad_Verb) {
978fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            SkASSERT(fPts.count() == 3);
979fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            QuadSubBounds(fPts.begin(), ts[0], ts[ts.count() - 1], fBounds);
980fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        } else {
981fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            SkASSERT(fVerbs[0] == SkPath::kCubic_Verb);
982fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            SkASSERT(fPts.count() == 4);
983fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            CubicSubBounds(fPts.begin(), ts[0], ts[ts.count() - 1], fBounds);
984fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        }
985fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    }
986198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
987fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    void splitInflectionPts(SkTArray<InEdge>& edges) {
988198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        if (!fIntersected) {
989198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            return;
990198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
991198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        uint8_t* verbs = fVerbs.begin();
992198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        SkPoint* pts = fPts.begin();
993198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        int lastVerb = 0;
994198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        int lastPt = 0;
995198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        uint8_t verb;
996198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        bool edgeSplit = false;
997198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        for (int ceptIdx = 0; ceptIdx < fIntercepts.count(); ++ceptIdx, pts += verb) {
998198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            Intercepts& intercepts = fIntercepts[ceptIdx];
999198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            verb = *verbs++;
1000198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            if (verb <= SkPath::kLine_Verb) {
1001198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                continue;
1002198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            }
1003198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            size_t tCount = intercepts.fTs.count();
1004198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            if (!tCount) {
1005198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                continue;
1006198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            }
1007198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            size_t tIndex = -1;
1008198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            SkScalar y = pts[0].fY;
1009198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            int lastSplit = 0;
1010198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            int firstSplit = -1;
1011198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            bool curveSplit = false;
1012198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            while (++tIndex < tCount) {
1013198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                double nextT = intercepts.fTs[tIndex];
1014198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                SkScalar nextY = verb == SkPath::kQuad_Verb
1015198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        ? QuadYAtT(pts, nextT) : CubicYAtT(pts, nextT);
1016198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                if (nextY < y) {
1017198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                    edgeSplit = curveSplit = true;
1018198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                    if (firstSplit < 0) {
1019198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        firstSplit = tIndex;
1020198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        int nextPt = pts - fPts.begin();
1021198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        int nextVerb = verbs - 1 - fVerbs.begin();
1022198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        if (lastVerb < nextVerb) {
1023fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            addPartial(edges, lastPt, nextPt, lastVerb, nextVerb);
1024198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            #if DEBUG_SPLIT
1025fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            SkDebugf("%s addPartial 1\n", __FUNCTION__);
1026198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            #endif
1027198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        }
1028198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        lastPt = nextPt;
1029198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        lastVerb = nextVerb;
1030198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                    }
1031198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                } else {
1032198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                    if (firstSplit >= 0) {
1033198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        if (lastSplit < firstSplit) {
1034fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            addSplit(edges, pts, verb, intercepts,
1035fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                    lastSplit, firstSplit, false);
1036198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            #if DEBUG_SPLIT
1037fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            SkDebugf("%s addSplit 1 tIndex=%d,%d\n",
1038fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                    __FUNCTION__, lastSplit, firstSplit);
1039198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            #endif
1040198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        }
1041fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        addSplit(edges, pts, verb, intercepts,
1042fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                firstSplit, tIndex, true);
1043198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            #if DEBUG_SPLIT
1044fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        SkDebugf("%s addSplit 2 tIndex=%d,%d flip\n",
1045fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                __FUNCTION__, firstSplit, tIndex);
1046198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            #endif
1047198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        lastSplit = tIndex;
1048198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        firstSplit = -1;
1049198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                    }
1050198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                }
1051198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                y = nextY;
1052198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            }
1053198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            if (curveSplit) {
1054198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                if (firstSplit < 0) {
1055198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                    firstSplit = lastSplit;
1056198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                } else {
1057fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    addSplit(edges, pts, verb, intercepts, lastSplit,
1058fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            firstSplit, false);
1059198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            #if DEBUG_SPLIT
1060fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    SkDebugf("%s addSplit 3 tIndex=%d,%d\n", __FUNCTION__,
1061fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            lastSplit, firstSplit);
1062198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            #endif
1063198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                }
1064fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                addSplit(edges, pts, verb, intercepts, firstSplit,
1065fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        tIndex, pts[verb].fY < y);
1066198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            #if DEBUG_SPLIT
1067fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                SkDebugf("%s addSplit 4 tIndex=%d,%d %s\n", __FUNCTION__,
1068fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        firstSplit, tIndex, pts[verb].fY < y ? "flip" : "");
1069198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            #endif
10706680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com            }
1071198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
1072198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        // collapse remainder -- if there's nothing left, clear it somehow?
1073198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        if (edgeSplit) {
1074198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            int nextVerb = verbs - 1 - fVerbs.begin();
1075198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            if (lastVerb < nextVerb) {
1076198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                int nextPt = pts - fPts.begin();
1077fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                addPartial(edges, lastPt, nextPt, lastVerb, nextVerb);
1078198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            #if DEBUG_SPLIT
1079fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                SkDebugf("%s addPartial 2\n", __FUNCTION__);
1080198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            #endif
10816680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com            }
1082198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            // OPTIMIZATION: reuse the edge instead of marking it empty
1083198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            reset();
10846680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        }
10852e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
10862e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
10872e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_DUMP
10882e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    void dump() {
10892e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        int i;
10902e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        const char className[] = "InEdge";
10912e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        const int tab = 4;
10922e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkDebugf("InEdge %p (edge=%d)\n", this, fID);
10932e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        for (i = 0; i < fCached.count(); ++i) {
10942e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkDebugf("%*s.fCached[%d]=0x%08x\n", tab + sizeof(className),
10952e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    className, i, fCached[i]);
10962e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
10972e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        uint8_t* verbs = fVerbs.begin();
10982e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkPoint* pts = fPts.begin();
10992e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        for (i = 0; i < fIntercepts.count(); ++i) {
11002e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkDebugf("%*s.fIntercepts[%d]:\n", tab + sizeof(className),
11012e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    className, i);
1102a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            fIntercepts[i].dump(pts, (SkPath::Verb) *verbs);
11032e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            pts += *verbs++;
11042e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
11052e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        for (i = 0; i < fPts.count(); ++i) {
1106752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            SkDebugf("%*s.fPts[%d]=(%1.9g,%1.9g)\n", tab + sizeof(className),
11072e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    className, i, fPts[i].fX, fPts[i].fY);
11082e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
11092e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        for (i = 0; i < fVerbs.count(); ++i) {
11102e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkDebugf("%*s.fVerbs[%d]=%d\n", tab + sizeof(className),
11112e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    className, i, fVerbs[i]);
11122e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
1113fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkDebugf("%*s.fBounds=(%1.9g, %1.9g, %1.9g, %1.9g)\n", tab + sizeof(className),
11142e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                className, fBounds.fLeft, fBounds.fTop,
11152e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                fBounds.fRight, fBounds.fBottom);
11162e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkDebugf("%*s.fWinding=%d\n", tab + sizeof(className), className,
11172e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                fWinding);
11182e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
11192e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                className, fContainsIntercepts);
1120198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        SkDebugf("%*s.fIntersected=%d\n", tab + sizeof(className),
1121198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                className, fIntersected);
1122c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
11232e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
1124c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
1125198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    // FIXME: temporary data : move this to a separate struct?
11266680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    SkTDArray<const InEdge*> fCached; // list of edges already intercepted
1127c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkTArray<Intercepts> fIntercepts; // one per verb
11284917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com
1129c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    // persistent data
1130c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkTDArray<SkPoint> fPts;
1131c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkTDArray<uint8_t> fVerbs;
1132c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    Bounds fBounds;
11332e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    int fID;
1134c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    signed char fWinding;
11356680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    bool fContainsIntercepts;
1136198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    bool fIntersected;
1137c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com};
1138c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
11396680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.comclass InEdgeBuilder {
1140c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.compublic:
1141c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
11422e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.comInEdgeBuilder(const SkPath& path, bool ignoreHorizontal, SkTArray<InEdge>& edges,
11432e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkTDArray<HorizontalEdge>& horizontalEdges)
1144c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    : fPath(path)
1145c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    , fCurrentEdge(NULL)
1146c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    , fEdges(edges)
11472e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    , fHorizontalEdges(horizontalEdges)
1148c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    , fIgnoreHorizontal(ignoreHorizontal)
1149198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    , fContainsCurves(false)
1150c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com{
1151c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    walk();
1152c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com}
1153c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
1154198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.combool containsCurves() const {
1155198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    return fContainsCurves;
1156198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com}
1157198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
1158c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comprotected:
1159c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
1160c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comvoid addEdge() {
1161f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    SkASSERT(fCurrentEdge);
1162c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    fCurrentEdge->fPts.append(fPtCount - fPtOffset, &fPts[fPtOffset]);
1163c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    fPtOffset = 1;
1164c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    *fCurrentEdge->fVerbs.append() = fVerb;
1165c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com}
1166c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
11676008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.combool complete() {
11686008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    if (fCurrentEdge && fCurrentEdge->fVerbs.count()) {
1169fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        fCurrentEdge->complete(fWinding);
11706008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        fCurrentEdge = NULL;
11716008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        return true;
11726008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    }
11736008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    return false;
11746008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com}
11756008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com
1176c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comint direction(int count) {
1177c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    fPtCount = count;
11782e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    if (fIgnoreHorizontal && isHorizontal()) {
1179c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        return 0;
1180c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
1181c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    int last = count - 1;
1182c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    return fPts[0].fY == fPts[last].fY
11836680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com            ? fPts[0].fX == fPts[last].fX ? 0 : fPts[0].fX < fPts[last].fX
11846680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com            ? 1 : -1 : fPts[0].fY < fPts[last].fY ? 1 : -1;
1185c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com}
1186c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
1187c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.combool isHorizontal() {
1188c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkScalar y = fPts[0].fY;
1189c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    for (int i = 1; i < fPtCount; ++i) {
1190c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        if (fPts[i].fY != y) {
1191c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            return false;
1192c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
1193c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
1194c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    return true;
1195c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com}
1196c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
1197c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comvoid startEdge() {
11986008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    if (!fCurrentEdge) {
11996008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        fCurrentEdge = fEdges.push_back_n(1);
12006008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    }
1201c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    fWinding = 0;
1202c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    fPtOffset = 0;
1203c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com}
1204c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
1205c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comvoid walk() {
1206c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkPath::Iter iter(fPath, true);
12072e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    int winding = 0;
1208c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    while ((fVerb = iter.next(fPts)) != SkPath::kDone_Verb) {
1209c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        switch (fVerb) {
1210c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            case SkPath::kMove_Verb:
1211c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                startEdge();
1212c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                continue;
1213c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            case SkPath::kLine_Verb:
1214c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                winding = direction(2);
1215c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                break;
1216c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            case SkPath::kQuad_Verb:
1217c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                winding = direction(3);
1218198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                fContainsCurves = true;
1219c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                break;
1220c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            case SkPath::kCubic_Verb:
1221c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                winding = direction(4);
1222198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                fContainsCurves = true;
1223c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                break;
1224c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            case SkPath::kClose_Verb:
1225f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                SkASSERT(fCurrentEdge);
12266008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                complete();
1227c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                continue;
1228c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            default:
1229c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                SkDEBUGFAIL("bad verb");
1230c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                return;
1231c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
12322e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if (winding == 0) {
12332e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            HorizontalEdge* horizontalEdge = fHorizontalEdges.append();
12342e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            // FIXME: for degenerate quads and cubics, compute x extremes
12352e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            horizontalEdge->fLeft = fPts[0].fX;
12362e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            horizontalEdge->fRight = fPts[fVerb].fX;
12372e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            horizontalEdge->fY = fPts[0].fY;
12382e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (horizontalEdge->fLeft > horizontalEdge->fRight) {
12392e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                SkTSwap<SkScalar>(horizontalEdge->fLeft, horizontalEdge->fRight);
12402e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            }
12416008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            if (complete()) {
12426008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                startEdge();
12436008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            }
1244c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            continue;
1245c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
1246c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        if (fWinding + winding == 0) {
1247c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            // FIXME: if prior verb or this verb is a horizontal line, reverse
1248c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            // it instead of starting a new edge
1249f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            SkASSERT(fCurrentEdge);
1250cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            if (complete()) {
1251cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                startEdge();
1252cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            }
1253c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
1254c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        fWinding = winding;
1255c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        addEdge();
1256c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
12576b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com    if (!complete()) {
12586b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com        if (fCurrentEdge) {
12596b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com            fEdges.pop_back();
12606b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com        }
12616b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com    }
1262c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com}
1263c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
1264c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comprivate:
1265c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    const SkPath& fPath;
12666680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    InEdge* fCurrentEdge;
12676680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    SkTArray<InEdge>& fEdges;
12682e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkTDArray<HorizontalEdge>& fHorizontalEdges;
1269c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkPoint fPts[4];
1270c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkPath::Verb fVerb;
1271c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    int fPtCount;
1272c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    int fPtOffset;
1273c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    int8_t fWinding;
1274c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    bool fIgnoreHorizontal;
1275198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    bool fContainsCurves;
1276c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com};
1277c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
12786680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.comstruct WorkEdge {
1279c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkScalar bottom() const {
12806680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        return fPts[verb()].fY;
1281c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
1282c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
12836680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    void init(const InEdge* edge) {
12846680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        fEdge = edge;
12856680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        fPts = edge->fPts.begin();
12866680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        fVerb = edge->fVerbs.begin();
1287c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
1288c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
1289cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    bool advance() {
12906680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        SkASSERT(fVerb < fEdge->fVerbs.end());
12916680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        fPts += *fVerb++;
12926680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        return fVerb != fEdge->fVerbs.end();
1293c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
1294752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
1295cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    SkPath::Verb lastVerb() const {
1296cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        SkASSERT(fVerb > fEdge->fVerbs.begin());
1297cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        return (SkPath::Verb) fVerb[-1];
1298cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    }
1299cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com
1300c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
1301c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkPath::Verb verb() const {
1302c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        return (SkPath::Verb) *fVerb;
1303c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
1304c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
13056008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    ptrdiff_t verbIndex() const {
13066680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        return fVerb - fEdge->fVerbs.begin();
13076680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    }
1308752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
13096680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    int winding() const {
13106680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        return fEdge->fWinding;
1311c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
1312c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
13136680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    const InEdge* fEdge;
1314c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    const SkPoint* fPts;
1315c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    const uint8_t* fVerb;
1316c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com};
1317c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
13186680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com// always constructed with SkTDArray because new edges are inserted
13196680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com// this may be a inappropriate optimization, suggesting that a separate array of
13206680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com// ActiveEdge* may be faster to insert and search
1321cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com
1322cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com// OPTIMIZATION: Brian suggests that global sorting should be unnecessary, since
1323cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com// as active edges are introduced, only local sorting should be required
13242e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.comclass ActiveEdge {
13252e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.compublic:
13266008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    bool operator<(const ActiveEdge& rh) const {
1327d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        double topD = fAbove.fX - rh.fAbove.fX;
1328d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        if (rh.fAbove.fY < fAbove.fY) {
1329d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            topD = (rh.fBelow.fY - rh.fAbove.fY) * topD
1330d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                    - (fAbove.fY - rh.fAbove.fY) * (rh.fBelow.fX - rh.fAbove.fX);
1331d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        } else if (rh.fAbove.fY > fAbove.fY) {
1332d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            topD = (fBelow.fY - fAbove.fY) * topD
1333d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                    + (rh.fAbove.fY - fAbove.fY) * (fBelow.fX - fAbove.fX);
1334d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        }
1335d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        double botD = fBelow.fX - rh.fBelow.fX;
1336d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        if (rh.fBelow.fY > fBelow.fY) {
1337d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            botD = (rh.fBelow.fY - rh.fAbove.fY) * botD
1338d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                    - (fBelow.fY - rh.fBelow.fY) * (rh.fBelow.fX - rh.fAbove.fX);
1339d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        } else if (rh.fBelow.fY < fBelow.fY) {
1340d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            botD = (fBelow.fY - fAbove.fY) * botD
1341d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                    + (rh.fBelow.fY - fBelow.fY) * (fBelow.fX - fAbove.fX);
1342d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        }
1343d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        // return sign of greater absolute value
1344d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        return (fabs(topD) > fabs(botD) ? topD : botD) < 0;
1345d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com    }
1346d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com
1347d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com    // OPTIMIZATION: fold return statements into one
1348d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com    bool operator_less_than(const ActiveEdge& rh) const {
1349cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        if (rh.fAbove.fY - fAbove.fY > fBelow.fY - rh.fAbove.fY
1350cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                && fBelow.fY < rh.fBelow.fY
1351cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                || fAbove.fY - rh.fAbove.fY < rh.fBelow.fY - fAbove.fY
1352cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                && rh.fBelow.fY < fBelow.fY) {
1353cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            // FIXME: need to compute distance, not check for points equal
1354cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            const SkPoint& check = rh.fBelow.fY <= fBelow.fY
1355cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                    && fBelow != rh.fBelow ? rh.fBelow :
1356cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                    rh.fAbove;
13572e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        #if DEBUG_ACTIVE_LESS_THAN
13582e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkDebugf("%s 1 %c %cthis (edge=%d) {%g,%g %g,%g}"
13592e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    " < rh (edge=%d) {%g,%g %g,%g} upls=(%d)\n", __FUNCTION__,
13602e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    rh.fBelow.fY <= fBelow.fY && fBelow != rh.fBelow ? 'B' : 'A',
13612e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    (check.fY - fAbove.fY) * (fBelow.fX - fAbove.fX)
13622e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    < (fBelow.fY - fAbove.fY) * (check.fX - fAbove.fX) ? ' '
13632e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    : '!', ID(), fAbove.fX, fAbove.fY, fBelow.fX, fBelow.fY,
13642e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    rh.ID(), rh.fAbove.fX, rh.fAbove.fY, rh.fBelow.fX, rh.fBelow.fY,
13652e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    UlpsDiff((check.fY - fAbove.fY) * (fBelow.fX - fAbove.fX),
13662e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                        (fBelow.fY - fAbove.fY) * (check.fX - fAbove.fX)));
13672e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        #endif
1368cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            return (check.fY - fAbove.fY) * (fBelow.fX - fAbove.fX)
1369cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                    < (fBelow.fY - fAbove.fY) * (check.fX - fAbove.fX);
1370cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        }
1371cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        // FIXME: need to compute distance, not check for points equal
1372cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        const SkPoint& check = fBelow.fY <= rh.fBelow.fY
1373cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                && fBelow != rh.fBelow ? fBelow : fAbove;
13742e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #if DEBUG_ACTIVE_LESS_THAN
13752e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkDebugf("%s 2 %c %cthis (edge=%d) {%g,%g %g,%g}"
1376752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                " < rh (edge=%d) {%g,%g %g,%g} upls=(%d) (%d,%d)\n", __FUNCTION__,
1377752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                fBelow.fY <= rh.fBelow.fY && fBelow != rh.fBelow ? 'B' : 'A',
13782e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                (rh.fBelow.fY - rh.fAbove.fY) * (check.fX - rh.fAbove.fX)
13792e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                < (check.fY - rh.fAbove.fY) * (rh.fBelow.fX - rh.fAbove.fX)
13802e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                ? ' ' : '!', ID(), fAbove.fX, fAbove.fY, fBelow.fX, fBelow.fY,
13812e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                rh.ID(), rh.fAbove.fX, rh.fAbove.fY, rh.fBelow.fX, rh.fBelow.fY,
13822e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                UlpsDiff((rh.fBelow.fY - rh.fAbove.fY) * (check.fX - rh.fAbove.fX),
1383752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                    (check.fY - rh.fAbove.fY) * (rh.fBelow.fX - rh.fAbove.fX)),
1384752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                UlpsDiff(fBelow.fX, rh.fBelow.fX), UlpsDiff(fBelow.fY, rh.fBelow.fY));
13852e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #endif
1386cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        return (rh.fBelow.fY - rh.fAbove.fY) * (check.fX - rh.fAbove.fX)
1387cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                < (check.fY - rh.fAbove.fY) * (rh.fBelow.fX - rh.fAbove.fX);
13886008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    }
1389752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
13902e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // If a pair of edges are nearly coincident for some span, add a T in the
13912e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // edge so it can be shortened to match the other edge. Note that another
13922e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // approach is to trim the edge after it is added to the OutBuilder list --
13932e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // FIXME: since this has no effect if the edge is already done (i.e.,
13942e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // fYBottom >= y) maybe this can only be done by calling trimLine later.
13952e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    void addTatYBelow(SkScalar y) {
13962e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if (fBelow.fY <= y || fYBottom >= y) {
13972e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            return;
13982e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
13992e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        addTatYInner(y);
14002e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        fFixBelow = true;
14012e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
1402752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
14032e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    void addTatYAbove(SkScalar y) {
14042e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if (fBelow.fY <= y) {
14052e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            return;
14062e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
14072e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        addTatYInner(y);
14082e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
14092e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
14102e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    void addTatYInner(SkScalar y) {
1411752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        if (fWorkEdge.fPts[0].fY > y) {
1412752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            backup(y);
1413752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        }
14142e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkScalar left = fWorkEdge.fPts[0].fX;
14152e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkScalar right = fWorkEdge.fPts[1].fX;
14162e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if (left > right) {
14172e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkTSwap(left, right);
14182e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
1419752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        double ts[2];
14202e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        int pts = LineIntersect(fWorkEdge.fPts, left, right, y, ts);
14212e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkASSERT(pts == 1);
14222e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        // An ActiveEdge or WorkEdge has no need to modify the T values computed
14232e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        // in the InEdge, except in the following case. If a pair of edges are
14242e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        // nearly coincident, this may not be detected when the edges are
14252e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        // intersected. Later, when sorted, and this near-coincidence is found,
14262e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        // an additional t value must be added, requiring the cast below.
14272e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        InEdge* writable = const_cast<InEdge*>(fWorkEdge.fEdge);
14282e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        int insertedAt = writable->add(ts, pts, fWorkEdge.verbIndex());
1429752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com    #if DEBUG_ADJUST_COINCIDENT
1430752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        SkDebugf("%s edge=%d y=%1.9g t=%1.9g\n", __FUNCTION__, ID(), y, ts[0]);
1431752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com    #endif
14322e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if (insertedAt >= 0) {
14332e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (insertedAt + 1 < fTIndex) {
14342e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                SkASSERT(insertedAt + 2 == fTIndex);
14352e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                --fTIndex;
14362e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            }
14372e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
14382e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
14396008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com
1440cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    bool advanceT() {
1441198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        SkASSERT(fTIndex <= fTs->count() - fExplicitTs);
1442198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        return ++fTIndex <= fTs->count() - fExplicitTs;
1443cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    }
14442e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
1445cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    bool advance() {
1446cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    // FIXME: flip sense of next
1447cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        bool result = fWorkEdge.advance();
1448cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        fDone = !result;
1449cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        initT();
1450cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        return result;
1451cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    }
1452752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
1453752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com    void backup(SkScalar y) {
1454752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        do {
1455752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            SkASSERT(fWorkEdge.fEdge->fVerbs.begin() < fWorkEdge.fVerb);
1456752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            fWorkEdge.fPts -= *--fWorkEdge.fVerb;
1457752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            SkASSERT(fWorkEdge.fEdge->fPts.begin() <= fWorkEdge.fPts);
1458752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        } while (fWorkEdge.fPts[0].fY >= y);
1459752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        initT();
1460198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        SkASSERT(!fExplicitTs);
1461752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        fTIndex = fTs->count() + 1;
1462752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com    }
1463752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
1464cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    void calcLeft(SkScalar y) {
1465cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        // OPTIMIZE: put a kDone_Verb at the end of the verb list?
14664917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com        if (fDone || fBelow.fY > y) {
1467cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            return; // nothing to do; use last
14684917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com        }
1469cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        calcLeft();
1470752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        if (fAbove.fY == fBelow.fY) {
1471752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            SkDebugf("%s edge=%d fAbove.fY != fBelow.fY %1.9g\n", __FUNCTION__,
1472752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                    ID(), fAbove.fY);
1473752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        }
1474cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    }
1475752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
1476cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    void calcLeft() {
1477a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        void (*xyAtTFunc)(const SkPoint a[], double t, SkPoint* out);
1478cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        switch (fWorkEdge.verb()) {
1479a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            case SkPath::kLine_Verb:
1480a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                xyAtTFunc = LineXYAtT;
1481a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                break;
1482a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            case SkPath::kQuad_Verb:
1483a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                xyAtTFunc = QuadXYAtT;
1484a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                break;
1485a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            case SkPath::kCubic_Verb:
1486a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                xyAtTFunc = CubicXYAtT;
1487cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                break;
1488cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            default:
1489cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                SkASSERT(0);
1490cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        }
1491a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        // OPTIMIZATION: if fXAbove, fXBelow have already been computed
1492a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        //  for the fTIndex, don't do it again
1493a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        // For identical x, this lets us know which edge is first.
1494a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        // If both edges have T values < 1, check x at next T (fXBelow).
1495198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        int add = (fTIndex <= fTs->count() - fExplicitTs) - 1;
1496a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        double tAbove = t(fTIndex + add);
1497a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        (*xyAtTFunc)(fWorkEdge.fPts, tAbove, &fAbove);
1498a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        double tBelow = t(fTIndex - ~add);
1499a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        (*xyAtTFunc)(fWorkEdge.fPts, tBelow, &fBelow);
1500a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        SkASSERT(tAbove != tBelow);
1501a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        // FIXME: this can loop forever
1502a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        // need a break if we hit the end
1503198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        // FIXME: in unit test, figure out how explicit Ts work as well
1504a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        while (fAbove.fY == fBelow.fY) {
1505a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            if (add < 0 || fTIndex == fTs->count()) {
1506a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                add -= 1;
1507a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                SkASSERT(fTIndex + add >= 0);
1508a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                tAbove = t(fTIndex + add);
1509a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                (*xyAtTFunc)(fWorkEdge.fPts, tAbove, &fAbove);
1510a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            } else {
1511a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                add += 1;
1512a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                SkASSERT(fTIndex - ~add <= fTs->count() + 1);
1513a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                tBelow = t(fTIndex - ~add);
1514a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                (*xyAtTFunc)(fWorkEdge.fPts, tBelow, &fBelow);
1515a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            }
1516a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        }
1517a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    #if DEBUG_ABOVE_BELOW
1518a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        fTAbove = tAbove;
1519a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        fTBelow = tBelow;
1520a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    #endif
15216008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    }
15226008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com
1523752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com    bool done(SkScalar bottom) const {
1524752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        return fDone || fYBottom >= bottom;
1525cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    }
1526752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
15272e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    void fixBelow() {
15282e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if (fFixBelow) {
1529a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            switch (fWorkEdge.verb()) {
1530a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                case SkPath::kLine_Verb:
1531a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    LineXYAtT(fWorkEdge.fPts, nextT(), &fBelow);
1532a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    break;
1533a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                case SkPath::kQuad_Verb:
1534a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    QuadXYAtT(fWorkEdge.fPts, nextT(), &fBelow);
1535a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    break;
1536a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                case SkPath::kCubic_Verb:
1537a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    CubicXYAtT(fWorkEdge.fPts, nextT(), &fBelow);
1538a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    break;
1539a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                default:
1540a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    SkASSERT(0);
1541a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            }
15422e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            fFixBelow = false;
15432e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
15442e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
15452e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
15466680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    void init(const InEdge* edge) {
15476680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        fWorkEdge.init(edge);
15486680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        initT();
15494917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com        fBelow.fY = SK_ScalarMin;
1550cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        fDone = false;
1551cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        fYBottom = SK_ScalarMin;
15526680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    }
1553752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
15546680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    void initT() {
15556008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        const Intercepts& intercepts = fWorkEdge.fEdge->fIntercepts.front();
15566008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        SkASSERT(fWorkEdge.verbIndex() <= fWorkEdge.fEdge->fIntercepts.count());
15576008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        const Intercepts* interceptPtr = &intercepts + fWorkEdge.verbIndex();
1558198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fTs = &interceptPtr->fTs;
1559198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fExplicitTs = interceptPtr->fExplicit;
15606008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com  //  the above is conceptually the same as
15616008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com  //    fTs = &fWorkEdge.fEdge->fIntercepts[fWorkEdge.verbIndex()].fTs;
15626008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com  //  but templated arrays don't allow returning a pointer to the end() element
15636680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        fTIndex = 0;
15646680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    }
1565752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
1566cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    // OPTIMIZATION: record if two edges are coincident when the are intersected
1567cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    // It's unclear how to do this -- seems more complicated than recording the
1568cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    // t values, since the same t values could exist intersecting non-coincident
1569cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    // edges.
1570cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    bool isCoincidentWith(const ActiveEdge* edge, SkScalar y) const {
1571d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        if (fAbove != edge->fAbove || fBelow != edge->fBelow) {
1572d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            return false;
1573d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        }
1574cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        uint8_t verb = fDone ? fWorkEdge.lastVerb() : fWorkEdge.verb();
1575cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        uint8_t edgeVerb = edge->fDone ? edge->fWorkEdge.lastVerb()
1576cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                : edge->fWorkEdge.verb();
1577cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        if (verb != edgeVerb) {
1578cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            return false;
1579cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        }
1580cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        switch (verb) {
1581cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            case SkPath::kLine_Verb: {
15824917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                return true;
1583cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            }
1584cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            default:
1585cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                // FIXME: add support for all curve types
1586cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                SkASSERT(0);
1587cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        }
1588cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        return false;
1589cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    }
1590752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
15912e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // The shortest close call edge should be moved into a position where
15922e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // it contributes if the winding is transitioning to or from zero.
15932e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    bool swapClose(const ActiveEdge* next, int prev, int wind, int mask) const {
1594d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com#if DEBUG_ADJUST_COINCIDENT
1595d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        SkDebugf("%s edge=%d (%g) next=%d (%g) prev=%d wind=%d nextWind=%d\n",
1596d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                __FUNCTION__, ID(), fBelow.fY, next->ID(), next->fBelow.fY,
1597d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                prev, wind, wind + next->fWorkEdge.winding());
1598d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com#endif
15992e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if ((prev & mask) == 0 || (wind & mask) == 0) {
16002e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            return next->fBelow.fY < fBelow.fY;
16012e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
16022e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        int nextWinding = wind + next->fWorkEdge.winding();
16032e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if ((nextWinding & mask) == 0) {
16042e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            return fBelow.fY < next->fBelow.fY;
16052e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
16062e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        return false;
16072e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
1608752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
1609cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    bool swapCoincident(const ActiveEdge* edge, SkScalar bottom) const {
1610cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        if (fBelow.fY >= bottom || fDone || edge->fDone) {
1611cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            return false;
1612cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        }
1613cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        ActiveEdge thisWork = *this;
1614cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        ActiveEdge edgeWork = *edge;
1615cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        while ((thisWork.advanceT() || thisWork.advance())
1616cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                && (edgeWork.advanceT() || edgeWork.advance())) {
1617cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            thisWork.calcLeft();
1618cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            edgeWork.calcLeft();
1619cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            if (thisWork < edgeWork) {
1620cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                return false;
1621cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            }
1622cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            if (edgeWork < thisWork) {
1623cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                return true;
1624cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            }
1625cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        }
1626cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com        return false;
1627cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    }
1628752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
16292e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    bool tooCloseToCall(const ActiveEdge* edge) const {
16302e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        int ulps;
1631d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com    // FIXME: the first variation works better (or at least causes fewer tests
1632d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com    // to fail than the second, although the second's logic better matches the
1633d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com    // current sort criteria. Need to track down the cause of the crash, and
1634d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com    // see if the second case isn't somehow buggy.
1635d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com#if 01
16362e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        // FIXME: don't compare points for equality
16372e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        // OPTIMIZATION: refactor to make one call to UlpsDiff
16382e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if (edge->fAbove.fY - fAbove.fY > fBelow.fY - edge->fAbove.fY
16392e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                && fBelow.fY < edge->fBelow.fY
16402e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                || fAbove.fY - edge->fAbove.fY < edge->fBelow.fY - fAbove.fY
16412e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                && edge->fBelow.fY < fBelow.fY) {
16422e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            const SkPoint& check = edge->fBelow.fY <= fBelow.fY
16432e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    && fBelow != edge->fBelow ? edge->fBelow :
16442e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    edge->fAbove;
16452e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            ulps = UlpsDiff((check.fY - fAbove.fY) * (fBelow.fX - fAbove.fX),
16462e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    (fBelow.fY - fAbove.fY) * (check.fX - fAbove.fX));
16472e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        } else {
16482e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            const SkPoint& check = fBelow.fY <= edge->fBelow.fY
16492e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    && fBelow != edge->fBelow ? fBelow : fAbove;
16502e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            ulps = UlpsDiff((edge->fBelow.fY - edge->fAbove.fY)
16512e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    * (check.fX - edge->fAbove.fX),
16522e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    (check.fY - edge->fAbove.fY)
16532e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    * (edge->fBelow.fX - edge->fAbove.fX));
16542e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
1655d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com#else
1656d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        double t1, t2, b1, b2;
1657d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        if (edge->fAbove.fY < fAbove.fY) {
1658d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            t1 = (edge->fBelow.fY - edge->fAbove.fY) * (fAbove.fX - edge->fAbove.fX);
1659d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            t2 = (fAbove.fY - edge->fAbove.fY) * (edge->fBelow.fX - edge->fAbove.fX);
1660d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        } else if (edge->fAbove.fY > fAbove.fY) {
1661d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            t1 = (fBelow.fY - fAbove.fY) * (fAbove.fX - edge->fAbove.fX);
1662d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            t2 = (fAbove.fY - edge->fAbove.fY) * (fBelow.fX - fAbove.fX);
1663d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        } else {
1664d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            t1 = fAbove.fX;
1665d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            t2 = edge->fAbove.fX;
1666d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        }
1667d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        if (edge->fBelow.fY > fBelow.fY) {
1668d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            b1 = (edge->fBelow.fY - edge->fAbove.fY) * (fBelow.fX - edge->fBelow.fX);
1669d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            b2 = (fBelow.fY - edge->fBelow.fY) * (edge->fBelow.fX - edge->fAbove.fX);
1670d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        } else if (edge->fBelow.fY < fBelow.fY) {
1671d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            b1 = (fBelow.fY - fAbove.fY) * (fBelow.fX - edge->fBelow.fX);
1672d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            b2 = (fBelow.fY - edge->fBelow.fY) * (fBelow.fX - fAbove.fX);
1673d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        } else {
1674d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            b1 = fBelow.fX;
1675d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            b2 = edge->fBelow.fX;
1676d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        }
1677d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        if (fabs(t1 - t2) > fabs(b1 - b2)) {
1678d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            ulps = UlpsDiff(t1, t2);
1679d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        } else {
1680d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com            ulps = UlpsDiff(b1, b2);
1681d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        }
1682d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com#if DEBUG_ADJUST_COINCIDENT
1683d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        SkDebugf("%s this=%d edge=%d ulps=%d\n", __FUNCTION__, ID(), edge->ID(),
1684d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                ulps);
1685d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com#endif
1686d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com#endif
16872e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        return ulps >= 0 && ulps <= 32;
16882e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
1689198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
16902e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    double nextT() const {
1691198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        SkASSERT(fTIndex <= fTs->count() - fExplicitTs);
1692cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        return t(fTIndex + 1);
1693cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    }
1694c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
1695cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    double t() const {
1696198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        return t(fTIndex);
1697c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
1698c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
1699cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    double t(int tIndex) const {
1700198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        if (fExplicitTs) {
1701198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            SkASSERT(tIndex < fTs->count());
1702198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            return (*fTs)[tIndex];
1703198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
1704cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        if (tIndex == 0) {
1705cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            return 0;
1706cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        }
1707cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        if (tIndex > fTs->count()) {
1708cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            return 1;
1709cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        }
1710cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        return (*fTs)[tIndex - 1];
1711cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    }
1712cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com
17132e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // FIXME: debugging only
1714752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com    int ID() const {
17152e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        return fWorkEdge.fEdge->fID;
17162e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
17172e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
17182e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.compublic:
17196680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    WorkEdge fWorkEdge;
17206680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    const SkTDArray<double>* fTs;
1721cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    SkPoint fAbove;
1722cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    SkPoint fBelow;
17232e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_ABOVE_BELOW
17242e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    double fTAbove;
17252e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    double fTBelow;
17262e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
1727cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    SkScalar fYBottom;
17282e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    int fCoincident;
17296680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    int fTIndex;
17302e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    bool fSkip; // OPTIMIZATION: use bitfields?
17312e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    bool fCloseCall;
1732cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    bool fDone;
17332e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    bool fFixBelow;
1734198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    bool fExplicitTs;
1735c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com};
1736c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
17376680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.comstatic void addToActive(SkTDArray<ActiveEdge>& activeEdges, const InEdge* edge) {
17386680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    size_t count = activeEdges.count();
17396680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    for (size_t index = 0; index < count; ++index) {
17406680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        if (edge == activeEdges[index].fWorkEdge.fEdge) {
17416680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com            return;
17426680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        }
17436680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    }
17446680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    ActiveEdge* active = activeEdges.append();
17456680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    active->init(edge);
17466680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com}
17476680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
17484917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com// Find any intersections in the range of active edges. A pair of edges, on
17494917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com// either side of another edge, may change the winding contribution for part of
17504917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com// the edge.
17512e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// Keep horizontal edges just for
17524917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com// the purpose of computing when edges change their winding contribution, since
17534917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com// this is essentially computing the horizontal intersection.
17542e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.comstatic void addBottomT(InEdge** currentPtr, InEdge** lastPtr,
17552e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        HorizontalEdge** horizontal) {
17562e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    InEdge** testPtr = currentPtr - 1;
17572e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    HorizontalEdge* horzEdge = *horizontal;
17582e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkScalar left = horzEdge->fLeft;
17592e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkScalar bottom = horzEdge->fY;
17602e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    while (++testPtr != lastPtr) {
17612e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        InEdge* test = *testPtr;
17622e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if (test->fBounds.fBottom <= bottom || test->fBounds.fRight <= left) {
17632e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            continue;
17642e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
17652e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        WorkEdge wt;
17662e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        wt.init(test);
17672e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        do {
17682e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            HorizontalEdge** sorted = horizontal;
17692e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            horzEdge = *sorted;
1770f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            do {
1771198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                double wtTs[4];
1772198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                int pts;
1773198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                uint8_t verb = wt.verb();
1774198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                switch (verb) {
1775198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                    case SkPath::kLine_Verb:
1776198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        pts = LineIntersect(wt.fPts, horzEdge->fLeft,
1777198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                                horzEdge->fRight, horzEdge->fY, wtTs);
1778198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        break;
1779198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                    case SkPath::kQuad_Verb:
1780198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        pts = QuadIntersect(wt.fPts, horzEdge->fLeft,
1781198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                                horzEdge->fRight, horzEdge->fY, wtTs);
1782198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        break;
1783198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                    case SkPath::kCubic_Verb:
1784198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        pts = CubicIntersect(wt.fPts, horzEdge->fLeft,
1785198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                                horzEdge->fRight, horzEdge->fY, wtTs);
1786198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        break;
1787198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                }
1788198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                if (pts) {
17892e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_ADD_BOTTOM_TS
1790198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                    for (int x = 0; x < pts; ++x) {
1791198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        SkDebugf("%s y=%g wtTs[0]=%g (%g,%g", __FUNCTION__,
1792198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                                horzEdge->fY, wtTs[x], wt.fPts[0].fX, wt.fPts[0].fY);
1793198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        for (int y = 0; y < verb; ++y) {
1794198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                            SkDebugf(" %g,%g", wt.fPts[y + 1].fX, wt.fPts[y + 1].fY));
17952e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                        }
1796198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        SkDebugf(")\n");
1797f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                    }
1798198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                    if (pts > verb) {
1799198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        SkASSERT(0); // FIXME ? should this work?
1800198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        SkDebugf("%s wtTs[1]=%g\n", __FUNCTION__, wtTs[1]);
1801198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                    }
1802198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com#endif
1803198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                    test->add(wtTs, pts, wt.verbIndex());
1804f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                }
18052e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                horzEdge = *++sorted;
18062e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            } while (horzEdge->fY == bottom
18072e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    && horzEdge->fLeft <= test->fBounds.fRight);
18082e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        } while (wt.advance());
1809f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    }
1810f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com}
1811f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com
1812a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic void debugShowLineIntersection(int pts, const WorkEdge& wt,
1813a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        const WorkEdge& wn, const double wtTs[2], const double wnTs[2]) {
1814a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com#if DEBUG_ADD_INTERSECTING_TS
1815a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    if (!pts) {
1816a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        return;
1817a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    }
1818a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    SkPoint wtOutPt, wnOutPt;
1819a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    LineXYAtT(wt.fPts, wtTs[0], &wtOutPt);
1820a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    LineXYAtT(wn.fPts, wnTs[0], &wnOutPt);
1821fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    SkDebugf("%s wtTs[0]=%g (%g,%g, %g,%g) (%g,%g)\n",
1822a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            __FUNCTION__,
1823a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            wtTs[0], wt.fPts[0].fX, wt.fPts[0].fY,
1824fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            wt.fPts[1].fX, wt.fPts[1].fY, wtOutPt.fX, wtOutPt.fY);
1825a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    if (pts == 2) {
1826a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        SkDebugf("%s wtTs[1]=%g\n", __FUNCTION__, wtTs[1]);
1827a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    }
1828fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    SkDebugf("%s wnTs[0]=%g (%g,%g, %g,%g) (%g,%g)\n",
1829a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            __FUNCTION__,
1830a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            wnTs[0], wn.fPts[0].fX, wn.fPts[0].fY,
1831fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            wn.fPts[1].fX, wn.fPts[1].fY, wnOutPt.fX, wnOutPt.fY);
1832a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    if (pts == 2) {
1833a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        SkDebugf("%s wnTs[1]=%g\n", __FUNCTION__, wnTs[1]);
1834a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    }
1835a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com#endif
1836a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
1837a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com
1838f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.comstatic void addIntersectingTs(InEdge** currentPtr, InEdge** lastPtr) {
1839cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    InEdge** testPtr = currentPtr - 1;
1840752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com    // FIXME: lastPtr should be past the point of interest, so
1841752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com    // test below should be  lastPtr - 2
1842752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com    // that breaks testSimplifyTriangle22, so further investigation is needed
1843cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    while (++testPtr != lastPtr - 1) {
1844cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        InEdge* test = *testPtr;
1845cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        InEdge** nextPtr = testPtr;
1846cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        do {
1847cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            InEdge* next = *++nextPtr;
1848198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            // FIXME: this compares against the sentinel sometimes
1849198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            // OPTIMIZATION: this may never be needed since this gets called
1850198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            // in two passes now. Verify that double hits are appropriate.
1851cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            if (test->cached(next)) {
1852cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                continue;
1853cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            }
1854cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            if (!Bounds::Intersects(test->fBounds, next->fBounds)) {
1855cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                continue;
1856cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            }
1857f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            WorkEdge wt, wn;
1858f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            wt.init(test);
1859f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            wn.init(next);
1860f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            do {
1861a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                int pts;
1862a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                Intersections ts;
1863a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                bool swap = false;
1864a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                switch (wt.verb()) {
1865a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    case SkPath::kLine_Verb:
1866a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        switch (wn.verb()) {
1867a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kLine_Verb: {
1868a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                pts = LineIntersect(wt.fPts, wn.fPts, ts);
1869a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                debugShowLineIntersection(pts, wt, wn,
1870a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                        ts.fT[0], ts.fT[1]);
1871a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
1872a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            }
1873a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kQuad_Verb: {
1874a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                swap = true;
1875a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                pts = QuadLineIntersect(wn.fPts, wt.fPts, ts);
1876a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
1877a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            }
1878a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kCubic_Verb: {
1879a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                swap = true;
1880a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                pts = CubicLineIntersect(wn.fPts, wt.fPts, ts);
1881a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
1882a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            }
1883a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            default:
1884a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                SkASSERT(0);
18852e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                        }
1886a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        break;
1887a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    case SkPath::kQuad_Verb:
1888a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        switch (wn.verb()) {
1889a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kLine_Verb: {
1890a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                pts = QuadLineIntersect(wt.fPts, wn.fPts, ts);
1891a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
1892a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            }
1893a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kQuad_Verb: {
1894a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                pts = QuadIntersect(wt.fPts, wn.fPts, ts);
1895a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
1896a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            }
1897a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kCubic_Verb: {
1898a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                // FIXME: promote quad to cubic
1899a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                pts = CubicIntersect(wt.fPts, wn.fPts, ts);
1900a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
1901a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            }
1902a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            default:
1903a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                SkASSERT(0);
19042e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                        }
1905a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        break;
1906a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    case SkPath::kCubic_Verb:
1907a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        switch (wn.verb()) {
1908a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kLine_Verb: {
1909a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                pts = CubicLineIntersect(wt.fPts, wn.fPts, ts);
1910a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
1911a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            }
1912a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kQuad_Verb: {
1913a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                 // FIXME: promote quad to cubic
1914a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                pts = CubicIntersect(wt.fPts, wn.fPts, ts);
1915a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
1916a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            }
1917a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kCubic_Verb: {
1918a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                pts = CubicIntersect(wt.fPts, wn.fPts, ts);
1919a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
1920a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            }
1921a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            default:
1922a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                SkASSERT(0);
1923a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        }
1924a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        break;
1925a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    default:
1926a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        SkASSERT(0);
1927f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                }
1928a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                test->add(ts.fT[swap], pts, wt.verbIndex());
1929a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                next->add(ts.fT[!swap], pts, wn.verbIndex());
1930cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            } while (wt.bottom() <= wn.bottom() ? wt.advance() : wn.advance());
1931cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        } while (nextPtr != lastPtr);
1932f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    }
1933f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com}
1934f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com
19352e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.comstatic InEdge** advanceEdges(SkTDArray<ActiveEdge>* activeEdges,
19366008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        InEdge** currentPtr, InEdge** lastPtr,  SkScalar y) {
19376008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    InEdge** testPtr = currentPtr - 1;
19386008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    while (++testPtr != lastPtr) {
19396008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        if ((*testPtr)->fBounds.fBottom > y) {
19406008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            continue;
19416008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        }
19422e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if (activeEdges) {
19432e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            InEdge* test = *testPtr;
19442e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            ActiveEdge* activePtr = activeEdges->begin() - 1;
19452e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            ActiveEdge* lastActive = activeEdges->end();
19462e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            while (++activePtr != lastActive) {
19472e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                if (activePtr->fWorkEdge.fEdge == test) {
19482e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    activeEdges->remove(activePtr - activeEdges->begin());
19492e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    break;
19502e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                }
19516008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            }
19526008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        }
19536008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        if (testPtr == currentPtr) {
19546008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            ++currentPtr;
19556008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        }
19566008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    }
19576008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    return currentPtr;
19586008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com}
19596008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com
19602e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// OPTIMIZE: inline?
19612e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.comstatic HorizontalEdge** advanceHorizontal(HorizontalEdge** edge, SkScalar y) {
19622e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    while ((*edge)->fY < y) {
19632e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        ++edge;
19642e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
19652e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    return edge;
19662e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com}
19672e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
1968f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com// compute bottom taking into account any intersected edges
19692e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.comstatic SkScalar computeInterceptBottom(SkTDArray<ActiveEdge>& activeEdges,
19702e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkScalar y, SkScalar bottom) {
1971f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    ActiveEdge* activePtr = activeEdges.begin() - 1;
1972f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    ActiveEdge* lastActive = activeEdges.end();
1973f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    while (++activePtr != lastActive) {
1974f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        const InEdge* test = activePtr->fWorkEdge.fEdge;
1975f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        if (!test->fContainsIntercepts) {
1976f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            continue;
1977f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        }
1978f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        WorkEdge wt;
1979f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        wt.init(test);
1980f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        do {
1981f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            const Intercepts& intercepts = test->fIntercepts[wt.verbIndex()];
19824917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com            if (intercepts.fTopIntercepts > 1) {
19834917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                SkScalar yTop = wt.fPts[0].fY;
19844917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                if (yTop > y && bottom > yTop) {
19854917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                    bottom = yTop;
19864917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                }
19874917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com            }
19884917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com            if (intercepts.fBottomIntercepts > 1) {
19894917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                SkScalar yBottom = wt.fPts[wt.verb()].fY;
19904917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                if (yBottom > y && bottom > yBottom) {
19914917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                    bottom = yBottom;
19924917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                }
19934917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com            }
1994f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            const SkTDArray<double>& fTs = intercepts.fTs;
1995f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            size_t count = fTs.count();
1996f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            for (size_t index = 0; index < count; ++index) {
1997a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                SkScalar yIntercept;
1998a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                switch (wt.verb()) {
1999a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    case SkPath::kLine_Verb: {
2000a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        yIntercept = LineYAtT(wt.fPts, fTs[index]);
2001a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        break;
2002f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                    }
2003a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    case SkPath::kQuad_Verb: {
2004a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        yIntercept = QuadYAtT(wt.fPts, fTs[index]);
2005a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        break;
2006a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    }
2007a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    case SkPath::kCubic_Verb: {
2008a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        yIntercept = CubicYAtT(wt.fPts, fTs[index]);
2009a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        break;
2010a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    }
2011a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    default:
2012a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        SkASSERT(0); // should never get here
2013a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                }
2014a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                if (yIntercept > y && bottom > yIntercept) {
2015a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    bottom = yIntercept;
2016f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                }
2017f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            }
2018cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        } while (wt.advance());
2019f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    }
2020198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com#if DEBUG_BOTTOM
2021198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    SkDebugf("%s bottom=%1.9g\n", __FUNCTION__, bottom);
2022198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com#endif
20232e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    return bottom;
2024f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com}
2025f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com
2026f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.comstatic SkScalar findBottom(InEdge** currentPtr,
20272e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        InEdge** edgeListEnd, SkTDArray<ActiveEdge>* activeEdges, SkScalar y,
20286008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        bool asFill, InEdge**& testPtr) {
2029f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    InEdge* current = *currentPtr;
2030f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    SkScalar bottom = current->fBounds.fBottom;
2031752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
2032f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    // find the list of edges that cross y
20336008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    InEdge* test = *testPtr;
20346008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    while (testPtr != edgeListEnd) {
20356008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        SkScalar testTop = test->fBounds.fTop;
20366008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        if (bottom <= testTop) {
2037f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            break;
2038f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        }
20396008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        SkScalar testBottom = test->fBounds.fBottom;
2040f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        // OPTIMIZATION: Shortening the bottom is only interesting when filling
2041f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        // and when the edge is to the left of a longer edge. If it's a framing
2042f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        // edge, or part of the right, it won't effect the longer edges.
20436008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        if (testTop > y) {
20446008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            bottom = testTop;
20456008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            break;
20466008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        }
20476008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        if (y < testBottom) {
20486008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            if (bottom > testBottom) {
20496008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                bottom = testBottom;
2050f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            }
20512e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (activeEdges) {
20522e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                addToActive(*activeEdges, test);
20532e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            }
2054f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        }
20556008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        test = *++testPtr;
2056f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    }
2057198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com#if DEBUG_BOTTOM
2058198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    SkDebugf("%s %d bottom=%1.9g\n", __FUNCTION__, activeEdges ? 2 : 1, bottom);
2059198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com#endif
2060f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    return bottom;
2061f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com}
2062f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com
2063f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.comstatic void makeEdgeList(SkTArray<InEdge>& edges, InEdge& edgeSentinel,
2064f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        SkTDArray<InEdge*>& edgeList) {
2065c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    size_t edgeCount = edges.count();
2066c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    if (edgeCount == 0) {
2067c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        return;
2068c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
2069fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    int id = 0;
2070c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    for (size_t index = 0; index < edgeCount; ++index) {
2071fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        InEdge& edge = edges[index];
2072fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        if (!edge.fWinding) {
2073fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            continue;
2074fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        }
2075fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        edge.fID = ++id;
2076fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        *edgeList.append() = &edge;
2077c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
2078c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    *edgeList.append() = &edgeSentinel;
2079cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    QSort<InEdge>(edgeList.begin(), edgeList.end() - 1);
2080f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com}
2081f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com
20822e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.comstatic void makeHorizontalList(SkTDArray<HorizontalEdge>& edges,
20832e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        HorizontalEdge& edgeSentinel, SkTDArray<HorizontalEdge*>& edgeList) {
20842e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    size_t edgeCount = edges.count();
20852e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    if (edgeCount == 0) {
20862e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        return;
20872e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
20882e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    for (size_t index = 0; index < edgeCount; ++index) {
20892e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        *edgeList.append() = &edges[index];
20902e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
20912e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    edgeSentinel.fLeft = edgeSentinel.fRight = edgeSentinel.fY = SK_ScalarMax;
20922e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    *edgeList.append() = &edgeSentinel;
20932e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    QSort<HorizontalEdge>(edgeList.begin(), edgeList.end() - 1);
20942e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com}
20956b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com
20966b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.comstatic void skipCoincidence(int lastWinding, int winding, int windingMask,
20976b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com            ActiveEdge* activePtr, ActiveEdge* firstCoincident) {
20986b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com    if (((lastWinding & windingMask) == 0) ^ (winding & windingMask) != 0) {
20996b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com        return;
21006b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com    }
21012e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // FIXME: ? shouldn't this be if (lastWinding & windingMask) ?
21026b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com    if (lastWinding) {
2103752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com#if DEBUG_ADJUST_COINCIDENT
2104752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        SkDebugf("%s edge=%d 1 set skip=false\n", __FUNCTION__, activePtr->ID());
2105752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com#endif
21066b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com        activePtr->fSkip = false;
21076b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com    } else {
2108752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com#if DEBUG_ADJUST_COINCIDENT
2109752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        SkDebugf("%s edge=%d 2 set skip=false\n", __FUNCTION__, firstCoincident->ID());
2110752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com#endif
21116b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com        firstCoincident->fSkip = false;
21126b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com    }
21136b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com}
21146b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com
21156008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.comstatic void sortHorizontal(SkTDArray<ActiveEdge>& activeEdges,
21162e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkTDArray<ActiveEdge*>& edgeList, SkScalar y) {
21176008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    size_t edgeCount = activeEdges.count();
21186008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    if (edgeCount == 0) {
21196008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        return;
21206008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    }
21212e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_SORT_HORIZONTAL
2122d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com    const int tab = 3; // FIXME: debugging only
21232e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkDebugf("%s y=%1.9g\n", __FUNCTION__, y);
21242e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
21256008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    size_t index;
21266008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    for (index = 0; index < edgeCount; ++index) {
21276008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        ActiveEdge& activeEdge = activeEdges[index];
21282e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        do {
21292e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            activeEdge.calcLeft(y);
21302e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            // skip segments that don't span y
21312e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (activeEdge.fAbove != activeEdge.fBelow) {
21322e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                break;
21332e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            }
21342e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (activeEdge.fDone) {
21352e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_SORT_HORIZONTAL
21362e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                SkDebugf("%*s edge=%d done\n", tab, "", activeEdge.ID());
21372e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
21382e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                goto nextEdge;
21392e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            }
21402e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_SORT_HORIZONTAL
21412e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkDebugf("%*s edge=%d above==below\n", tab, "", activeEdge.ID());
21422e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
21432e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        } while (activeEdge.advanceT() || activeEdge.advance());
21442e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_SORT_HORIZONTAL
21452e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkDebugf("%*s edge=%d above=(%1.9g,%1.9g) (%1.9g) below=(%1.9g,%1.9g)"
21462e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                " (%1.9g)\n", tab, "", activeEdge.ID(),
21472e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                activeEdge.fAbove.fX, activeEdge.fAbove.fY, activeEdge.fTAbove,
21482e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                activeEdge.fBelow.fX, activeEdge.fBelow.fY, activeEdge.fTBelow);
21492e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
21502e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        activeEdge.fSkip = activeEdge.fCloseCall = activeEdge.fFixBelow = false;
21516008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        *edgeList.append() = &activeEdge;
21522e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.comnextEdge:
21532e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        ;
21546008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    }
2155cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    QSort<ActiveEdge>(edgeList.begin(), edgeList.end() - 1);
21562e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com}
21572e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
21582e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// remove coincident edges
21592e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// OPTIMIZE: remove edges? This is tricky because the current logic expects
21602e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// the winding count to be maintained while skipping coincident edges. In
21612e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// addition to removing the coincident edges, the remaining edges would need
21622e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// to have a different winding value, possibly different per intercept span.
21632e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.comstatic SkScalar adjustCoincident(SkTDArray<ActiveEdge*>& edgeList,
21642e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        int windingMask, SkScalar y, SkScalar bottom, OutEdgeBuilder& outBuilder)
21652e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com{
21662e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_ADJUST_COINCIDENT
21672e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkDebugf("%s y=%1.9g bottom=%1.9g\n", __FUNCTION__, y, bottom);
21682e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
21692e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    size_t edgeCount = edgeList.count();
21702e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    if (edgeCount == 0) {
21712e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        return bottom;
21722e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
21736008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    ActiveEdge* activePtr = edgeList[0];
21742e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    size_t index;
21752e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    bool foundCoincident = false;
21762e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    int firstIndex = 0;
21772e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    for (index = 1; index < edgeCount; ++index) {
21782e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        ActiveEdge* nextPtr = edgeList[index];
21792e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        bool closeCall = false;
21802e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        activePtr->fCoincident = firstIndex;
21812e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if (activePtr->isCoincidentWith(nextPtr, y)
21822e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                || (closeCall = activePtr->tooCloseToCall(nextPtr))) {
21832e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            activePtr->fSkip = nextPtr->fSkip = foundCoincident = true;
21842e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            activePtr->fCloseCall = nextPtr->fCloseCall = closeCall;
21852e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        } else {
21862e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            firstIndex = index;
21872e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
21882e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        activePtr = nextPtr;
21892e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
21902e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    activePtr->fCoincident = firstIndex;
21912e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    if (!foundCoincident) {
21922e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        return bottom;
21932e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
21946b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com    int winding = 0;
21952e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    activePtr = edgeList[0];
21966008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    for (index = 1; index < edgeCount; ++index) {
21972e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        int priorWinding = winding;
21986b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com        winding += activePtr->fWorkEdge.winding();
21996008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        ActiveEdge* nextPtr = edgeList[index];
22002e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if (activePtr->fCoincident == nextPtr->fCoincident) {
2201cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            // the coincident edges may not have been sorted above -- advance
2202cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            // the edges and resort if needed
2203cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            // OPTIMIZE: if sorting is done incrementally as new edges are added
2204cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            // and not all at once as is done here, fold this test into the
2205cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            // current less than test.
22062e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (activePtr->fCloseCall ? activePtr->swapClose(nextPtr,
22072e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    priorWinding, winding, windingMask)
22082e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    : activePtr->swapCoincident(nextPtr, bottom)) {
22094917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                winding -= activePtr->fWorkEdge.winding();
2210cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                SkTSwap<ActiveEdge*>(edgeList[index - 1], edgeList[index]);
2211cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                SkTSwap<ActiveEdge*>(activePtr, nextPtr);
22124917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                winding += activePtr->fWorkEdge.winding();
2213cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            }
22142e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
22152e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        activePtr = nextPtr;
22162e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
22172e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    int firstCoincidentWinding = 0;
22182e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    ActiveEdge* firstCoincident = NULL;
22192e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    winding = 0;
22202e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    activePtr = edgeList[0];
22212e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    for (index = 1; index < edgeCount; ++index) {
22222e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        int priorWinding = winding;
22232e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        winding += activePtr->fWorkEdge.winding();
22242e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        ActiveEdge* nextPtr = edgeList[index];
22252e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if (activePtr->fCoincident == nextPtr->fCoincident) {
22266b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com            if (!firstCoincident) {
22276b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com                firstCoincident = activePtr;
22282e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                firstCoincidentWinding = priorWinding;
22292e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            }
22302e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (activePtr->fCloseCall) {
22312e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // If one of the edges has already been added to out as a non
22322e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // coincident edge, trim it back to the top of this span
22332e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                if (outBuilder.trimLine(y, activePtr->ID())) {
22342e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    activePtr->addTatYAbove(y);
2235752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            #if DEBUG_ADJUST_COINCIDENT
2236752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                    SkDebugf("%s 1 edge=%d y=%1.9g (was fYBottom=%1.9g)\n",
2237752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                            __FUNCTION__, activePtr->ID(), y, activePtr->fYBottom);
2238752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            #endif
22392e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    activePtr->fYBottom = y;
22402e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                }
22412e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                if (outBuilder.trimLine(y, nextPtr->ID())) {
22422e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    nextPtr->addTatYAbove(y);
2243752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            #if DEBUG_ADJUST_COINCIDENT
2244752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                    SkDebugf("%s 2 edge=%d y=%1.9g (was fYBottom=%1.9g)\n",
2245752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                            __FUNCTION__, nextPtr->ID(), y, nextPtr->fYBottom);
2246752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            #endif
22472e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    nextPtr->fYBottom = y;
22482e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                }
22492e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // add missing t values so edges can be the same length
22502e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                SkScalar testY = activePtr->fBelow.fY;
22512e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                nextPtr->addTatYBelow(testY);
22522e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                if (bottom > testY && testY > y) {
2253752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            #if DEBUG_ADJUST_COINCIDENT
2254752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                    SkDebugf("%s 3 edge=%d bottom=%1.9g (was bottom=%1.9g)\n",
2255752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                            __FUNCTION__, activePtr->ID(), testY, bottom);
2256752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            #endif
22572e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    bottom = testY;
22582e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                }
22592e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                testY = nextPtr->fBelow.fY;
22602e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                activePtr->addTatYBelow(testY);
22612e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                if (bottom > testY && testY > y) {
2262752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            #if DEBUG_ADJUST_COINCIDENT
2263752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                    SkDebugf("%s 4 edge=%d bottom=%1.9g (was bottom=%1.9g)\n",
2264752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                            __FUNCTION__, nextPtr->ID(), testY, bottom);
2265752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            #endif
22662e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    bottom = testY;
22672e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                }
22686b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com            }
22692e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        } else if (firstCoincident) {
22702e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            skipCoincidence(firstCoincidentWinding, winding, windingMask,
22712e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    activePtr, firstCoincident);
22726b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com            firstCoincident = NULL;
22736b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com        }
22746008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        activePtr = nextPtr;
2275f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    }
22762e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    if (firstCoincident) {
22776b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com        winding += activePtr->fWorkEdge.winding();
22782e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        skipCoincidence(firstCoincidentWinding, winding, windingMask, activePtr,
22796b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com                firstCoincident);
22806b9cfb34a3ed256a56571ebe3e39f5df940a16fbcaryclark@google.com    }
22812e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // fix up the bottom for close call edges. OPTIMIZATION: maybe this could
22822e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // be in the loop above, but moved here since loop above reads fBelow and
22832e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // it felt unsafe to write it in that loop
22842e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    for (index = 0; index < edgeCount; ++index) {
22852e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        (edgeList[index])->fixBelow();
22862e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
22872e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    return bottom;
2288f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com}
22896680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
2290f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com// stitch edge and t range that satisfies operation
22916008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.comstatic void stitchEdge(SkTDArray<ActiveEdge*>& edgeList, SkScalar y,
2292752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        SkScalar bottom, int windingMask, bool fill, OutEdgeBuilder& outBuilder) {
2293f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    int winding = 0;
22946008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    ActiveEdge** activeHandle = edgeList.begin() - 1;
22956008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    ActiveEdge** lastActive = edgeList.end();
22962e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    const int tab = 7; // FIXME: debugging only
2297cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    if (gShowDebugf) {
22982e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkDebugf("%s y=%1.9g bottom=%1.9g\n", __FUNCTION__, y, bottom);
2299c17972e7acc784553445adc18f608a8c4b1beac8caryclark@google.com    }
23006008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    while (++activeHandle != lastActive) {
23016008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        ActiveEdge* activePtr = *activeHandle;
2302f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        const WorkEdge& wt = activePtr->fWorkEdge;
2303f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        int lastWinding = winding;
2304f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        winding += wt.winding();
23052e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if (gShowDebugf) {
23062e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkDebugf("%*s edge=%d lastWinding=%d winding=%d skip=%d close=%d"
23072e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_ABOVE_BELOW
23082e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    " above=%1.9g below=%1.9g"
23092e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
23102e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    "\n",
23112e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    tab-4, "", activePtr->ID(), lastWinding,
23122e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    winding, activePtr->fSkip, activePtr->fCloseCall
23132e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_ABOVE_BELOW
23142e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    , activePtr->fTAbove, activePtr->fTBelow
23152e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
23162e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    );
23172e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
2318752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        if (activePtr->done(bottom)) {
2319752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            if (gShowDebugf) {
2320752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                SkDebugf("%*s fDone=%d || fYBottom=%1.9g >= bottom\n", tab, "",
2321752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                        activePtr->fDone, activePtr->fYBottom);
2322cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com            }
2323752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            continue;
2324cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        }
2325c17972e7acc784553445adc18f608a8c4b1beac8caryclark@google.com        int opener = (lastWinding & windingMask) == 0;
2326c17972e7acc784553445adc18f608a8c4b1beac8caryclark@google.com        bool closer = (winding & windingMask) == 0;
2327c17972e7acc784553445adc18f608a8c4b1beac8caryclark@google.com        SkASSERT(!opener | !closer);
2328c17972e7acc784553445adc18f608a8c4b1beac8caryclark@google.com        bool inWinding = opener | closer;
2329a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        SkPoint clippedPts[4];
23304917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com        const SkPoint* clipped = NULL;
2331cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        uint8_t verb = wt.verb();
2332cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        bool moreToDo, aboveBottom;
2333f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        do {
2334f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            double currentT = activePtr->t();
2335f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            const SkPoint* points = wt.fPts;
2336cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            double nextT;
23376680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com            do {
2338cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                nextT = activePtr->nextT();
2339a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                // FIXME: obtuse: want efficient way to say
2340a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                // !currentT && currentT != 1 || !nextT && nextT != 1
2341a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                if (currentT * nextT != 0 || currentT + nextT != 1) {
2342a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    // OPTIMIZATION: if !inWinding, we only need
2343a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    // clipped[1].fY
2344a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    switch (verb) {
2345a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        case SkPath::kLine_Verb:
2346a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            LineSubDivide(points, currentT, nextT, clippedPts);
2347a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            break;
2348a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        case SkPath::kQuad_Verb:
2349a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            QuadSubDivide(points, currentT, nextT, clippedPts);
2350a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            break;
2351a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        case SkPath::kCubic_Verb:
2352a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            CubicSubDivide(points, currentT, nextT, clippedPts);
2353a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            break;
2354a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        default:
2355a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            SkASSERT(0);
2356a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            break;
23576680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com                    }
2358a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    clipped = clippedPts;
2359a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                } else {
2360a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    clipped = points;
2361a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                }
2362a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                if (inWinding && !activePtr->fSkip && (fill ? clipped[0].fY
2363a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        != clipped[verb].fY : clipped[0] != clipped[verb])) {
2364fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_STITCH_EDGE
2365fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    SkDebugf("%*s add%s %1.9g,%1.9g %1.9g,%1.9g edge=%d"
2366fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            " v=%d t=(%1.9g,%1.9g)\n", tab, "",
2367fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            kUVerbStr[verb], clipped[0].fX, clipped[0].fY,
2368fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            clipped[verb].fX, clipped[verb].fY,
2369fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            activePtr->ID(),
2370fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            activePtr->fWorkEdge.fVerb
2371fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            - activePtr->fWorkEdge.fEdge->fVerbs.begin(),
2372fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            currentT, nextT);
2373fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
2374a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    outBuilder.addCurve(clipped, (SkPath::Verb) verb,
2375a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            activePtr->fWorkEdge.fEdge->fID,
2376a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            activePtr->fCloseCall);
2377cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                } else {
2378fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_STITCH_EDGE
2379fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    SkDebugf("%*s skip%s %1.9g,%1.9g %1.9g,%1.9g"
2380fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            " edge=%d v=%d t=(%1.9g,%1.9g)\n", tab, "",
2381fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            kUVerbStr[verb], clipped[0].fX, clipped[0].fY,
2382fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            clipped[verb].fX, clipped[verb].fY,
2383fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            activePtr->ID(),
2384fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            activePtr->fWorkEdge.fVerb
2385fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            - activePtr->fWorkEdge.fEdge->fVerbs.begin(),
2386fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            currentT, nextT);
2387fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
2388a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                }
2389a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            // by advancing fAbove/fBelow, the next call to sortHorizontal
2390a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            // will use these values if they're still valid instead of
2391a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            // recomputing
2392a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                if (clipped[1].fY > activePtr->fBelow.fY
2393a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        && bottom >= activePtr->fBelow.fY ) {
2394a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    activePtr->fAbove = activePtr->fBelow;
2395a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    activePtr->fBelow = clipped[1];
2396a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            #if DEBUG_ABOVE_BELOW
2397a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    activePtr->fTAbove = activePtr->fTBelow;
2398a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    activePtr->fTBelow = nextT;
2399a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            #endif
2400f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                }
2401f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                currentT = nextT;
2402cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                moreToDo = activePtr->advanceT();
24032e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                activePtr->fYBottom = clipped[verb].fY; // was activePtr->fCloseCall ? bottom :
24042e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
24052e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // clearing the fSkip/fCloseCall bit here means that trailing edges
24062e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // fall out of sync, if one edge is long and another is a series of short pieces
24072e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // if fSkip/fCloseCall is set, need to recompute coincidence/too-close-to-call
24082e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // after advancing
24092e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // another approach would be to restrict bottom to smaller part of close call
24102e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // maybe this is already happening with coincidence when intersection is computed,
24112e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // and needs to be added to the close call computation as well
24122e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // this is hard to do because that the bottom is important is not known when
24132e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // the lines are intersected; only when the computation for edge sorting is done
24142e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // does the need for new bottoms become apparent.
24152e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // maybe this is good incentive to scrap the current sort and do an insertion
24162e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // sort that can take this into consideration when the x value is computed
24172e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
24182e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // FIXME: initialized in sortHorizontal, cleared here as well so
24192e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // that next edge is not skipped -- but should skipped edges ever
24202e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                // continue? (probably not)
2421752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                aboveBottom = clipped[verb].fY < bottom;
2422752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                if (clipped[0].fY != clipped[verb].fY) {
2423752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                    activePtr->fSkip = false;
2424752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                    activePtr->fCloseCall = false;
2425752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                    aboveBottom &= !activePtr->fCloseCall;
2426752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                } else {
2427752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                    if (activePtr->fSkip || activePtr->fCloseCall) {
2428198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                        if (gShowDebugf) SkDebugf("== %1.9g\n", clippedPts[0].fY);
2429752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                    }
2430752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com                }
2431cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            } while (moreToDo & aboveBottom);
2432cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        } while ((moreToDo || activePtr->advance()) & aboveBottom);
2433f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    }
2434f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com}
24356680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
2436198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.comstatic void dumpEdgeList(const SkTDArray<InEdge*>& edgeList,
2437198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        const InEdge& edgeSentinel) {
2438198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com#if DEBUG_DUMP
2439198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    InEdge** debugPtr = edgeList.begin();
2440198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    do {
2441198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        (*debugPtr++)->dump();
2442198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    } while (*debugPtr != &edgeSentinel);
2443198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com#endif
2444198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com}
2445198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
2446f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.comvoid simplify(const SkPath& path, bool asFill, SkPath& simple) {
2447f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
2448f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    int windingMask = (path.getFillType() & 1) ? 1 : -1;
2449f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    simple.reset();
2450f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    simple.setFillType(SkPath::kEvenOdd_FillType);
2451f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    // turn path into list of edges increasing in y
2452cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    // if an edge is a quad or a cubic with a y extrema, note it, but leave it
2453cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    // unbroken. Once we have a list, sort it, then walk the list (walk edges
2454cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    // twice that have y extrema's on top)  and detect crossings -- look for raw
2455cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    // bounds that cross over, then tight bounds that cross
2456f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    SkTArray<InEdge> edges;
24572e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkTDArray<HorizontalEdge> horizontalEdges;
24582e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    InEdgeBuilder builder(path, asFill, edges, horizontalEdges);
2459f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    SkTDArray<InEdge*> edgeList;
2460f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    InEdge edgeSentinel;
2461fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    edgeSentinel.reset();
2462f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    makeEdgeList(edges, edgeSentinel, edgeList);
24632e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkTDArray<HorizontalEdge*> horizontalList;
24642e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    HorizontalEdge horizontalSentinel;
24652e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    makeHorizontalList(horizontalEdges, horizontalSentinel, horizontalList);
2466f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    InEdge** currentPtr = edgeList.begin();
24674917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com    if (!currentPtr) {
24684917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com        return;
24694917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com    }
24702e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // find all intersections between edges
24712e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// beyond looking for horizontal intercepts, we need to know if any active edges
24722e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// intersect edges below 'bottom', but above the active edge segment.
24732e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// maybe it makes more sense to compute all intercepts before doing anything
24742e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// else, since the intercept list is long-lived, at least in the current design.
24752e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkScalar y = (*currentPtr)->fBounds.fTop;
24762e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    HorizontalEdge** currentHorizontal = horizontalList.begin();
24772e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    do {
24782e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        InEdge** lastPtr = currentPtr; // find the edge below the bottom of the first set
24792e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkScalar bottom = findBottom(currentPtr, edgeList.end(),
24802e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                NULL, y, asFill, lastPtr);
24812e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        if (lastPtr > currentPtr) {
24822e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (currentHorizontal) {
24832e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                if ((*currentHorizontal)->fY < SK_ScalarMax) {
24842e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    addBottomT(currentPtr, lastPtr, currentHorizontal);
24852e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                }
24862e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                currentHorizontal = advanceHorizontal(currentHorizontal, bottom);
24872e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            }
24882e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            addIntersectingTs(currentPtr, lastPtr);
24892e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
24902e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        y = bottom;
24912e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        currentPtr = advanceEdges(NULL, currentPtr, lastPtr, y);
24922e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    } while (*currentPtr != &edgeSentinel);
2493198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    // if a quadratic or cubic now has an intermediate T value, see if the Ts
2494198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    // on either side cause the Y values to monotonically increase. If not, split
2495198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    // the curve at the new T.
2496198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    if (builder.containsCurves()) {
2497198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        currentPtr = edgeList.begin();
2498198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        SkTArray<InEdge> splits;
2499198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        do {
2500fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            (*currentPtr)->splitInflectionPts(splits);
2501198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        } while (*++currentPtr != &edgeSentinel);
2502198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        if (splits.count()) {
2503198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            for (int index = 0; index < splits.count(); ++index) {
2504198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                edges.push_back(splits[index]);
2505198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            }
2506fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            edgeList.reset();
2507198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            makeEdgeList(edges, edgeSentinel, edgeList);
2508198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
2509198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
2510198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    dumpEdgeList(edgeList, edgeSentinel);
2511f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    // walk the sorted edges from top to bottom, computing accumulated winding
2512f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    SkTDArray<ActiveEdge> activeEdges;
2513f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    OutEdgeBuilder outBuilder(asFill);
25142e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    currentPtr = edgeList.begin();
25152e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    y = (*currentPtr)->fBounds.fTop;
2516f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    do {
2517f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        InEdge** lastPtr = currentPtr; // find the edge below the bottom of the first set
2518f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        SkScalar bottom = findBottom(currentPtr, edgeList.end(),
25192e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                &activeEdges, y, asFill, lastPtr);
2520c17972e7acc784553445adc18f608a8c4b1beac8caryclark@google.com        if (lastPtr > currentPtr) {
25212e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            bottom = computeInterceptBottom(activeEdges, y, bottom);
2522c17972e7acc784553445adc18f608a8c4b1beac8caryclark@google.com            SkTDArray<ActiveEdge*> activeEdgeList;
25232e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            sortHorizontal(activeEdges, activeEdgeList, y);
25242e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            bottom = adjustCoincident(activeEdgeList, windingMask, y, bottom,
25252e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                outBuilder);
2526752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            stitchEdge(activeEdgeList, y, bottom, windingMask, asFill, outBuilder);
2527c17972e7acc784553445adc18f608a8c4b1beac8caryclark@google.com        }
2528c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        y = bottom;
25292e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        // OPTIMIZATION: as edges expire, InEdge allocations could be released
25302e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        currentPtr = advanceEdges(&activeEdges, currentPtr, lastPtr, y);
2531c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    } while (*currentPtr != &edgeSentinel);
2532c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    // assemble output path from string of pts, verbs
2533f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    outBuilder.bridge();
2534f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    outBuilder.assemble(simple);
2535c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com}
2536