1c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com/*
2c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com * Copyright 2012 Google Inc.
3c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com *
4c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com * Use of this source code is governed by a BSD-style license that can be
5c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com * found in the LICENSE file.
6c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com */
7c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
88dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com#include "Simplify.h"
9c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
1078e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#undef SkASSERT
1178e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#define SkASSERT(cond) while (!(cond)) { sk_throw(); }
122e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
1378e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com// FIXME: remove once debugging is complete
14fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#if 01 // set to 1 for no debugging whatsoever
1578e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com
1647580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com//const bool gRunTestsInOneThread = false;
1778e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com
1878e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#define DEBUG_ACTIVE_LESS_THAN 0
192e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ADD 0
202e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ADD_BOTTOM_TS 0
2178e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#define DEBUG_ADD_INTERSECTING_TS 0
2278e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#define DEBUG_ADJUST_COINCIDENT 0
23fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#define DEBUG_ASSEMBLE 0
2478e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#define DEBUG_BOTTOM 0
25fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#define DEBUG_BRIDGE 0
2678e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#define DEBUG_DUMP 0
272e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_SORT_HORIZONTAL 0
282e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_OUT 0
292e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_OUT_LESS_THAN 0
30198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com#define DEBUG_SPLIT 0
31fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#define DEBUG_STITCH_EDGE 0
3278e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#define DEBUG_TRIM_LINE 0
3378e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com
342e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#else
352e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
3647580694fbe974a065caf7c39c3d2075708c2018caryclark@google.com//const bool gRunTestsInOneThread = true;
3778e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com
3878e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#define DEBUG_ACTIVE_LESS_THAN 0
392e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ADD 01
402e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_ADD_BOTTOM_TS 0
4178e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#define DEBUG_ADD_INTERSECTING_TS 0
4278e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#define DEBUG_ADJUST_COINCIDENT 1
43fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#define DEBUG_ASSEMBLE 1
4478e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#define DEBUG_BOTTOM 0
45fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#define DEBUG_BRIDGE 1
4678e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#define DEBUG_DUMP 1
472e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_SORT_HORIZONTAL 01
482e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_OUT 01
492e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#define DEBUG_OUT_LESS_THAN 0
50198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com#define DEBUG_SPLIT 1
51fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#define DEBUG_STITCH_EDGE 1
5278e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#define DEBUG_TRIM_LINE 1
53752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
542e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
552e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
56fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE || DEBUG_BRIDGE
57fb173424e915e696a73067d616ce4f39a407261acaryclark@google.comstatic const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
58fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
59fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_STITCH_EDGE
60fb173424e915e696a73067d616ce4f39a407261acaryclark@google.comstatic const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
61fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
62fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com
636680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.comstatic int LineIntersect(const SkPoint a[2], const SkPoint b[2],
64a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        Intersections& intersections) {
65a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
66a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line bLine = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}};
6745a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    return intersect(aLine, bLine, intersections);
68a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
69a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com
70a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
71a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        Intersections& intersections) {
72a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
73a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line bLine = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}};
74198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    intersect(aQuad, bLine, intersections);
75198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    return intersections.fUsed;
76a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
77a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com
78a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic int CubicLineIntersect(const SkPoint a[2], const SkPoint b[3],
79a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        Intersections& intersections) {
80a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
81a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            {a[3].fX, a[3].fY}};
82a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line bLine = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}};
8373ca6243b31e225e9fd5b75a96cbc82d62557de6caryclark@google.com    return intersect(aCubic, bLine, intersections);
84a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
85a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com
86a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
87a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        Intersections& intersections) {
88a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
89a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Quadratic bQuad = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}, {b[2].fX, b[2].fY}};
9045a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com    intersect2(aQuad, bQuad, intersections);
91198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    return intersections.fUsed;
92a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
93a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com
94a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic int CubicIntersect(const SkPoint a[4], const SkPoint b[4],
95a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        Intersections& intersections) {
96a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
97a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            {a[3].fX, a[3].fY}};
98a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Cubic bCubic = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}, {b[2].fX, b[2].fY},
99a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            {b[3].fX, b[3].fY}};
100198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    intersect(aCubic, bCubic, intersections);
101198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    return intersections.fUsed;
102c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com}
103c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
1042e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.comstatic int LineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
1052e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkScalar y, double aRange[2]) {
106a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
1072e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    return horizontalLineIntersect(aLine, left, right, y, aRange);
108c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com}
109c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
110198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.comstatic int QuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
111198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        SkScalar y, double aRange[3]) {
112198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
113198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    return horizontalIntersect(aQuad, left, right, y, aRange);
114198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com}
115198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
116198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.comstatic int CubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
117198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        SkScalar y, double aRange[4]) {
118198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
119198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            {a[3].fX, a[3].fY}};
120198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    return horizontalIntersect(aCubic, left, right, y, aRange);
121198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com}
122198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
123cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.comstatic void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
124a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line line = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
125cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    double x, y;
126a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    xy_at_t(line, t, x, y);
127cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    out->fX = SkDoubleToScalar(x);
128cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com    out->fY = SkDoubleToScalar(y);
129cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com}
130cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com
131a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
132a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Quadratic quad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
133a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    double x, y;
134a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    xy_at_t(quad, t, x, y);
135a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    out->fX = SkDoubleToScalar(x);
136a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    out->fY = SkDoubleToScalar(y);
1372e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com}
1382e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
139a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
140a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Cubic cubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
141a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            {a[3].fX, a[3].fY}};
142a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    double x, y;
143a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    xy_at_t(cubic, t, x, y);
144a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    out->fX = SkDoubleToScalar(x);
145a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    out->fY = SkDoubleToScalar(y);
1462e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com}
1472e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
1486680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.comstatic SkScalar LineYAtT(const SkPoint a[2], double t) {
149a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
1506680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    double y;
1516680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    xy_at_t(aLine, t, *(double*) 0, y);
1526680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    return SkDoubleToScalar(y);
1536680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com}
1546680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
155a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic SkScalar QuadYAtT(const SkPoint a[3], double t) {
156a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Quadratic quad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
157a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    double y;
158a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    xy_at_t(quad, t, *(double*) 0, y);
159a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    return SkDoubleToScalar(y);
160a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
161a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com
162a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic SkScalar CubicYAtT(const SkPoint a[4], double t) {
163a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const Cubic cubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
164a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            {a[3].fX, a[3].fY}};
165a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    double y;
166a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    xy_at_t(cubic, t, *(double*) 0, y);
167a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    return SkDoubleToScalar(y);
168a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
169a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com
1706680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.comstatic void LineSubDivide(const SkPoint a[2], double startT, double endT,
1716680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        SkPoint sub[2]) {
172a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
1736680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    _Line dst;
1746680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    sub_divide(aLine, startT, endT, dst);
1756680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    sub[0].fX = SkDoubleToScalar(dst[0].x);
1766680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    sub[0].fY = SkDoubleToScalar(dst[0].y);
1776680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    sub[1].fX = SkDoubleToScalar(dst[1].x);
1786680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    sub[1].fY = SkDoubleToScalar(dst[1].y);
1796680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com}
1806680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
181a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic void QuadSubDivide(const SkPoint a[3], double startT, double endT,
182a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        SkPoint sub[3]) {
18378e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY},
18478e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com            {a[2].fX, a[2].fY}};
185a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    Quadratic dst;
186a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub_divide(aQuad, startT, endT, dst);
187a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[0].fX = SkDoubleToScalar(dst[0].x);
188a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[0].fY = SkDoubleToScalar(dst[0].y);
189a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[1].fX = SkDoubleToScalar(dst[1].x);
190a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[1].fY = SkDoubleToScalar(dst[1].y);
191a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[2].fX = SkDoubleToScalar(dst[2].x);
192a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[2].fY = SkDoubleToScalar(dst[2].y);
1932e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com}
1946680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
195a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.comstatic void CubicSubDivide(const SkPoint a[4], double startT, double endT,
196a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        SkPoint sub[4]) {
19778e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY},
19878e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com            {a[2].fX, a[2].fY}, {a[3].fX, a[3].fY}};
199a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    Cubic dst;
200a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub_divide(aCubic, startT, endT, dst);
201a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[0].fX = SkDoubleToScalar(dst[0].x);
202a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[0].fY = SkDoubleToScalar(dst[0].y);
203a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[1].fX = SkDoubleToScalar(dst[1].x);
204a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[1].fY = SkDoubleToScalar(dst[1].y);
205a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[2].fX = SkDoubleToScalar(dst[2].x);
206a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[2].fY = SkDoubleToScalar(dst[2].y);
207a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[3].fX = SkDoubleToScalar(dst[3].x);
208a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    sub[3].fY = SkDoubleToScalar(dst[3].y);
209a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com}
210fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com
211fb173424e915e696a73067d616ce4f39a407261acaryclark@google.comstatic void QuadSubBounds(const SkPoint a[3], double startT, double endT,
212fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkRect& bounds) {
213fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    SkPoint dst[3];
214fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    QuadSubDivide(a, startT, endT, dst);
215fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    bounds.fLeft = bounds.fRight = dst[0].fX;
216fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    bounds.fTop = bounds.fBottom = dst[0].fY;
217fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    for (int index = 1; index < 3; ++index) {
218fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        bounds.growToInclude(dst[index].fX, dst[index].fY);
219fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    }
220fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com}
221fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com
222fb173424e915e696a73067d616ce4f39a407261acaryclark@google.comstatic void CubicSubBounds(const SkPoint a[4], double startT, double endT,
223fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkRect& bounds) {
224fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    SkPoint dst[4];
225fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    CubicSubDivide(a, startT, endT, dst);
226fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    bounds.fLeft = bounds.fRight = dst[0].fX;
227fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    bounds.fTop = bounds.fBottom = dst[0].fY;
228fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    for (int index = 1; index < 4; ++index) {
229fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        bounds.growToInclude(dst[index].fX, dst[index].fY);
230fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    }
231fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com}
232fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com
23378e17130f396d8b2157116c2504e357192f87ed1caryclark@google.comstatic SkPath::Verb QuadReduceOrder(SkPoint a[4]) {
23478e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    const Quadratic aQuad =  {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY},
23578e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com            {a[2].fX, a[2].fY}};
23678e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    Quadratic dst;
23747d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com    int order = reduceOrder(aQuad, dst, kReduceOrder_TreatAsFill);
23878e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    for (int index = 0; index < order; ++index) {
23978e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com        a[index].fX = SkDoubleToScalar(dst[index].x);
24078e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com        a[index].fY = SkDoubleToScalar(dst[index].y);
24178e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    }
24278e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    if (order == 1) { // FIXME: allow returning points, caller should discard
24378e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com        a[1] = a[0];
24478e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com        return (SkPath::Verb) order;
24578e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    }
24678e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    return (SkPath::Verb) (order - 1);
24778e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com}
24878e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com
24978e17130f396d8b2157116c2504e357192f87ed1caryclark@google.comstatic SkPath::Verb CubicReduceOrder(SkPoint a[4]) {
25078e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY},
25178e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com            {a[2].fX, a[2].fY}, {a[3].fX, a[3].fY}};
25278e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    Cubic dst;
25347d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com    int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed, kReduceOrder_TreatAsFill);
25478e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    for (int index = 0; index < order; ++index) {
25578e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com        a[index].fX = SkDoubleToScalar(dst[index].x);
25678e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com        a[index].fY = SkDoubleToScalar(dst[index].y);
25778e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    }
25878e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    if (order == 1) { // FIXME: allow returning points, caller should discard
25978e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com        a[1] = a[0];
26078e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com        return (SkPath::Verb) order;
26178e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    }
26278e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    return (SkPath::Verb) (order - 1);
26378e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com}
26478e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com
26578e17130f396d8b2157116c2504e357192f87ed1caryclark@google.comstatic bool IsCoincident(const SkPoint a[2], const SkPoint& above,
26678e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com        const SkPoint& below) {
26778e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
26878e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    const _Line bLine = {{above.fX, above.fY}, {below.fX, below.fY}};
26978e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com    return implicit_matches_ulps(aLine, bLine, 32);
27078e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com}
27178e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com
272c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com/*
273c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comlist of edges
274c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.combounds for edge
275c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comsort
276c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comactive T
277c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
278d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.comif a contour's bounds is outside of the active area, no need to create edges
279c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com*/
280c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
281d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com/* given one or more paths,
282c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com find the bounds of each contour, select the active contours
283c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com for each active contour, compute a set of edges
284c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com each edge corresponds to one or more lines and curves
285c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com leave edges unbroken as long as possible
286c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com when breaking edges, compute the t at the break but leave the control points alone
287c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
288c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com */
289c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
290c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comvoid contourBounds(const SkPath& path, SkTDArray<SkRect>& boundsArray) {
291c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkPath::Iter iter(path, false);
292c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkPoint pts[4];
293c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkPath::Verb verb;
294c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkRect bounds;
295c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    bounds.setEmpty();
296c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    int count = 0;
297c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
298c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        switch (verb) {
299c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            case SkPath::kMove_Verb:
300c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                if (!bounds.isEmpty()) {
301c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                    *boundsArray.append() = bounds;
302c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                }
303c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                bounds.set(pts[0].fX, pts[0].fY, pts[0].fX, pts[0].fY);
304c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                count = 0;
305c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                break;
306d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            case SkPath::kLine_Verb:
307c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                count = 1;
308c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                break;
309c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            case SkPath::kQuad_Verb:
310c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                count = 2;
311c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                break;
312c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            case SkPath::kCubic_Verb:
313c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                count = 3;
314c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                break;
315c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            case SkPath::kClose_Verb:
316c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                count = 0;
317c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                break;
318c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            default:
319c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                SkDEBUGFAIL("bad verb");
320c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                return;
321c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
322c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        for (int i = 1; i <= count; ++i) {
323c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            bounds.growToInclude(pts[i].fX, pts[i].fY);
324c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
325c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
326c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com}
327c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
328f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.comstatic bool extendLine(const SkPoint line[2], const SkPoint& add) {
329f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    // FIXME: allow this to extend lines that have slopes that are nearly equal
330f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    SkScalar dx1 = line[1].fX - line[0].fX;
331f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    SkScalar dy1 = line[1].fY - line[0].fY;
332f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    SkScalar dx2 = add.fX - line[0].fX;
333f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    SkScalar dy2 = add.fY - line[0].fY;
334f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    return dx1 * dy2 == dx2 * dy1;
335f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com}
3366680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
3372e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// OPTIMIZATION: this should point to a list of input data rather than duplicating
3382e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com// the line data here. This would reduce the need to assemble the results.
339f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.comstruct OutEdge {
340f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    bool operator<(const OutEdge& rh) const {
341cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const SkPoint& first = fPts[0];
342cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const SkPoint& rhFirst = rh.fPts[0];
343f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        return first.fY == rhFirst.fY
344f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                ? first.fX < rhFirst.fX
345f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                : first.fY < rhFirst.fY;
346f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    }
347752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
348cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    SkPoint fPts[4];
3492e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    int fID; // id of edge generating data
350cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    uint8_t fVerb; // FIXME: not read from everywhere
3512e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    bool fCloseCall; // edge is trimmable if not originally coincident
352f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com};
353f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com
3546680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.comclass OutEdgeBuilder {
3556680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.compublic:
356f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    OutEdgeBuilder(bool fill)
357f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        : fFill(fill) {
358f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        }
359f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com
360a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    void addCurve(const SkPoint line[4], SkPath::Verb verb, int id,
361a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            bool closeCall) {
362c17972e7acc784553445adc18f608a8c4b1beac8caryclark@google.com        OutEdge& newEdge = fEdges.push_back();
363a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        memcpy(newEdge.fPts, line, (verb + 1) * sizeof(SkPoint));
364a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com        newEdge.fVerb = verb;
3652e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        newEdge.fID = id;
3662e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        newEdge.fCloseCall = closeCall;
3672e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
368752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
3692e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    bool trimLine(SkScalar y, int id) {
3702e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        size_t count = fEdges.count();
3712e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        while (count-- != 0) {
3722e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            OutEdge& edge = fEdges[count];
3732e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (edge.fID != id) {
3742e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                continue;
3752e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            }
3762e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (edge.fCloseCall) {
3772e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                return false;
3782e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            }
3792e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkASSERT(edge.fPts[0].fY <= y);
3802e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (edge.fPts[1].fY <= y) {
3812e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                continue;
3822e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            }
3832e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            edge.fPts[1].fX = edge.fPts[0].fX + (y - edge.fPts[0].fY)
3842e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    * (edge.fPts[1].fX - edge.fPts[0].fX)
3852e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    / (edge.fPts[1].fY - edge.fPts[0].fY);
3862e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            edge.fPts[1].fY = y;
38778e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#if DEBUG_TRIM_LINE
38878e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com            SkDebugf("%s edge=%d %1.9g,%1.9g\n", __FUNCTION__, id,
38978e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com                    edge.fPts[1].fX, y);
39078e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com#endif
3912e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            return true;
3922e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
3932e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        return false;
394f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    }
395f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com
396f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    void assemble(SkPath& simple) {
3976008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        size_t listCount = fEdges.count();
3986008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        if (listCount == 0) {
3996008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            return;
4006008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        }
401f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        do {
4026008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            size_t listIndex = 0;
4036008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            int advance = 1;
4046008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            while (listIndex < listCount && fTops[listIndex] == 0) {
4056008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                ++listIndex;
406f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            }
4076008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            if (listIndex >= listCount) {
4086008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                break;
409f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            }
4104917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com            int closeEdgeIndex = -listIndex - 1;
411fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            // the curve is deferred and not added right away because the
412fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            // following edge may extend the first curve.
413a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            SkPoint firstPt, lastCurve[4];
414a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            uint8_t lastVerb;
415fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
416fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            int firstIndex, lastIndex;
417fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            const int tab = 8;
418fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
4196008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            bool doMove = true;
4206008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            int edgeIndex;
4216008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            do {
422cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                SkPoint* ptArray = fEdges[listIndex].fPts;
423cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                uint8_t verb = fEdges[listIndex].fVerb;
424fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                SkPoint* curve[4];
4256008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                if (advance < 0) {
426fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    curve[0] = &ptArray[verb];
427fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    if (verb == SkPath::kCubic_Verb) {
428fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        curve[1] = &ptArray[2];
429fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        curve[2] = &ptArray[1];
430fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    }
431fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    curve[verb] = &ptArray[0];
4326008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                } else {
433fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    curve[0] = &ptArray[0];
434fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    if (verb == SkPath::kCubic_Verb) {
435fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        curve[1] = &ptArray[1];
436fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        curve[2] = &ptArray[2];
437fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    }
438fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    curve[verb] = &ptArray[verb];
439fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                }
440fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                if (verb == SkPath::kQuad_Verb) {
441fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    curve[1] = &ptArray[1];
442f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                }
443a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                if (doMove) {
444fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    firstPt = *curve[0];
445fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    simple.moveTo(curve[0]->fX, curve[0]->fY);
446fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
447fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    SkDebugf("%s %d moveTo (%g,%g)\n", __FUNCTION__,
448fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            listIndex + 1, curve[0]->fX, curve[0]->fY);
449fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    firstIndex = listIndex;
450fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
451fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    for (int index = 0; index <= verb; ++index) {
452fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        lastCurve[index] = *curve[index];
453a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    }
454a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    doMove = false;
455a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                } else {
456fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    bool gap = lastCurve[lastVerb] != *curve[0];
457fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    if (gap || lastVerb != SkPath::kLine_Verb) { // output the accumulated curve before the gap
458a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        // FIXME: see comment in bridge -- this probably
459a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        // conceals errors
460fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        SkASSERT(fFill && UlpsDiff(lastCurve[lastVerb].fY,
461fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                curve[0]->fY) <= 10);
462a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        switch (lastVerb) {
463a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kLine_Verb:
464a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                simple.lineTo(lastCurve[1].fX, lastCurve[1].fY);
465a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
466a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kQuad_Verb:
467a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                simple.quadTo(lastCurve[1].fX, lastCurve[1].fY,
468a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                        lastCurve[2].fX, lastCurve[2].fY);
469a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
470a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                            case SkPath::kCubic_Verb:
471a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                simple.cubicTo(lastCurve[1].fX, lastCurve[1].fY,
472a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                        lastCurve[2].fX, lastCurve[2].fY,
473a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                        lastCurve[3].fX, lastCurve[3].fY);
474a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                                break;
475cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                        }
476fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
477fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        SkDebugf("%*s %d %sTo (%g,%g)\n", tab, "", lastIndex + 1,
478fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                kLVerbStr[lastVerb], lastCurve[lastVerb].fX,
479fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                lastCurve[lastVerb].fY);
480fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
481a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    }
482fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    int firstCopy = 1;
48378e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com                    if (gap || (lastVerb == SkPath::kLine_Verb
48478e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com                             && (verb != SkPath::kLine_Verb
48578e17130f396d8b2157116c2504e357192f87ed1caryclark@google.com                             || !extendLine(lastCurve, *curve[verb])))) {
486a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        // FIXME: see comment in bridge -- this probably
487a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                        // conceals errors
488fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        SkASSERT(lastCurve[lastVerb] == *curve[0] ||
489fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                (fFill && UlpsDiff(lastCurve[lastVerb].fY,
490fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                curve[0]->fY) <= 10));
491fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        simple.lineTo(curve[0]->fX, curve[0]->fY);
492fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
493fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        SkDebugf("%*s %d gap lineTo (%g,%g)\n", tab, "",
494fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                lastIndex + 1, curve[0]->fX, curve[0]->fY);
495fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
496fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        firstCopy = 0;
497fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    } else if (lastVerb != SkPath::kLine_Verb) {
498fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        firstCopy = 0;
499a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    }
500fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    for (int index = firstCopy; index <= verb; ++index) {
501fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        lastCurve[index] = *curve[index];
502a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    }
5036008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                }
504fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                lastVerb = verb;
505fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
506fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                lastIndex = listIndex;
507fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
5086008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                if (advance < 0) {
5096008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    edgeIndex = fTops[listIndex];
5106008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    fTops[listIndex] = 0;
511fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                } else {
5126008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    edgeIndex = fBottoms[listIndex];
5136008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    fBottoms[listIndex] = 0;
5146008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                }
5154917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                if (edgeIndex) {
5164917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                    listIndex = abs(edgeIndex) - 1;
5174917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                    if (edgeIndex < 0) {
5184917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                        fTops[listIndex] = 0;
5194917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                    } else {
5204917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                        fBottoms[listIndex] = 0;
5214917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                    }
5224917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                }
5234917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                if (edgeIndex == closeEdgeIndex || edgeIndex == 0) {
524fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    switch (lastVerb) {
525fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        case SkPath::kLine_Verb:
526fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            simple.lineTo(lastCurve[1].fX, lastCurve[1].fY);
527fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            break;
528fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        case SkPath::kQuad_Verb:
529fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            simple.quadTo(lastCurve[1].fX, lastCurve[1].fY,
530fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                    lastCurve[2].fX, lastCurve[2].fY);
531fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            break;
532fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        case SkPath::kCubic_Verb:
533fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            simple.cubicTo(lastCurve[1].fX, lastCurve[1].fY,
534fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                    lastCurve[2].fX, lastCurve[2].fY,
535fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                    lastCurve[3].fX, lastCurve[3].fY);
536fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            break;
537fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    }
538fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
539fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    SkDebugf("%*s %d %sTo last (%g, %g)\n", tab, "",
540fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            lastIndex + 1, kLVerbStr[lastVerb],
541fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                            lastCurve[lastVerb].fX, lastCurve[lastVerb].fY);
542fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
543a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    if (lastCurve[lastVerb] != firstPt) {
544fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        simple.lineTo(firstPt.fX, firstPt.fY);
545fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
546fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        SkDebugf("%*s %d final line (%g, %g)\n", tab, "",
547fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                                firstIndex + 1, firstPt.fX, firstPt.fY);
548fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
5494917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                    }
550cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                    simple.close();
551fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
552fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                    SkDebugf("%*s   close\n", tab, "");
553fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
554cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                    break;
555cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                }
556fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                // if this and next edge go different directions
557fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_ASSEMBLE
558fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                SkDebugf("%*s   advance=%d edgeIndex=%d flip=%s\n", tab, "",
559fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        advance, edgeIndex, advance > 0 ^ edgeIndex < 0 ?
560fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                        "true" : "false");
561fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
5626008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                if (advance > 0 ^ edgeIndex < 0) {
5636008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    advance = -advance;
5646008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                }
5654917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com            } while (edgeIndex);
5666008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        } while (true);
567f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    }
568752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
569cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    // sort points by y, then x
570cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    // if x/y is identical, sort bottoms before tops
571cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    // if identical and both tops/bottoms, sort by angle
572cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com    static bool lessThan(SkTArray<OutEdge>& edges, const int one,
573cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            const int two) {
574cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const OutEdge& oneEdge = edges[abs(one) - 1];
575cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        int oneIndex = one < 0 ? 0 : oneEdge.fVerb;
576cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const SkPoint& startPt1 = oneEdge.fPts[oneIndex];
577cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const OutEdge& twoEdge = edges[abs(two) - 1];
578cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        int twoIndex = two < 0 ? 0 : twoEdge.fVerb;
579cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const SkPoint& startPt2 = twoEdge.fPts[twoIndex];
580cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        if (startPt1.fY != startPt2.fY) {
5812e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #if DEBUG_OUT_LESS_THAN
5822e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkDebugf("%s %d<%d (%g,%g) %s startPt1.fY < startPt2.fY\n", __FUNCTION__,
5832e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    one, two, startPt1.fY, startPt2.fY,
5842e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    startPt1.fY < startPt2.fY ? "true" : "false");
5852e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #endif
586cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            return startPt1.fY < startPt2.fY;
587cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        }
588cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        if (startPt1.fX != startPt2.fX) {
5892e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #if DEBUG_OUT_LESS_THAN
5902e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkDebugf("%s %d<%d (%g,%g) %s startPt1.fX < startPt2.fX\n", __FUNCTION__,
5912e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    one, two, startPt1.fX, startPt2.fX,
5922e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    startPt1.fX < startPt2.fX ? "true" : "false");
5932e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #endif
594cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            return startPt1.fX < startPt2.fX;
595cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        }
596cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const SkPoint& endPt1 = oneEdge.fPts[oneIndex ^ oneEdge.fVerb];
597cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        const SkPoint& endPt2 = twoEdge.fPts[twoIndex ^ twoEdge.fVerb];
598cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        SkScalar dy1 = startPt1.fY - endPt1.fY;
599cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        SkScalar dy2 = startPt2.fY - endPt2.fY;
600cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        SkScalar dy1y2 = dy1 * dy2;
601cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        if (dy1y2 < 0) { // different signs
6022e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #if DEBUG_OUT_LESS_THAN
603cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                SkDebugf("%s %d<%d %s dy1 > 0\n", __FUNCTION__, one, two,
604cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                        dy1 > 0 ? "true" : "false");
6052e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #endif
606cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            return dy1 > 0; // one < two if one goes up and two goes down
607cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        }
608cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        if (dy1y2 == 0) {
6092e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #if DEBUG_OUT_LESS_THAN
6102e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkDebugf("%s %d<%d %s endPt1.fX < endPt2.fX\n", __FUNCTION__,
6112e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    one, two, endPt1.fX < endPt2.fX ? "true" : "false");
6122e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #endif
613cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            return endPt1.fX < endPt2.fX;
614d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        }
615cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        SkScalar dx1y2 = (startPt1.fX - endPt1.fX) * dy2;
616cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        SkScalar dx2y1 = (startPt2.fX - endPt2.fX) * dy1;
6172e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #if DEBUG_OUT_LESS_THAN
6182e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkDebugf("%s %d<%d %s dy2 < 0 ^ dx1y2 < dx2y1\n", __FUNCTION__,
6192e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                one, two, dy2 < 0 ^ dx1y2 < dx2y1 ? "true" : "false");
6202e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    #endif
621cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        return dy2 > 0 ^ dx1y2 < dx2y1;
622f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    }
623f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com
6246008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    // Sort the indices of paired points and then create more indices so
6256008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    // assemble() can find the next edge and connect the top or bottom
626f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    void bridge() {
627f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        size_t index;
628f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        size_t count = fEdges.count();
629f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        if (!count) {
630f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            return;
631f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        }
632cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        SkASSERT(!fFill || count > 1);
633f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        fTops.setCount(count);
634f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        sk_bzero(fTops.begin(), sizeof(fTops[0]) * count);
635f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        fBottoms.setCount(count);
636f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        sk_bzero(fBottoms.begin(), sizeof(fBottoms[0]) * count);
6376008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        SkTDArray<int> order;
6386008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        for (index = 1; index <= count; ++index) {
6396008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            *order.append() = -index;
640f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com        }
641cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        for (index = 1; index <= count; ++index) {
642cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            *order.append() = index;
643cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        }
644cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com        QSort<SkTArray<OutEdge>, int>(fEdges, order.begin(), order.end() - 1, lessThan);
6456008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        int* lastPtr = order.end() - 1;
6466008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        int* leftPtr = order.begin();
6476008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        while (leftPtr < lastPtr) {
6486008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            int leftIndex = *leftPtr;
6496008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            int leftOutIndex = abs(leftIndex) - 1;
6506008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            const OutEdge& left = fEdges[leftOutIndex];
651f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            int* rightPtr = leftPtr + 1;
6526008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            int rightIndex = *rightPtr;
6536008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            int rightOutIndex = abs(rightIndex) - 1;
6546008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            const OutEdge& right = fEdges[rightOutIndex];
655cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            bool pairUp = fFill;
656cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            if (!pairUp) {
657cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                const SkPoint& leftMatch =
658cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                        left.fPts[leftIndex < 0 ? 0 : left.fVerb];
659cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                const SkPoint& rightMatch =
660cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                        right.fPts[rightIndex < 0 ? 0 : right.fVerb];
661cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com                pairUp = leftMatch == rightMatch;
662cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            } else {
6632e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        #if DEBUG_OUT
664d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        // FIXME : not happy that error in low bit is allowed
665d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com        // this probably conceals error elsewhere
666d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                if (UlpsDiff(left.fPts[leftIndex < 0 ? 0 : left.fVerb].fY,
667d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                        right.fPts[rightIndex < 0 ? 0 : right.fVerb].fY) > 1) {
6682e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    *fMismatches.append() = leftIndex;
6692e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    if (rightPtr == lastPtr) {
6702e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                        *fMismatches.append() = rightIndex;
6712e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    }
6722e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    pairUp = false;
6732e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                }
6742e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        #else
675d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                SkASSERT(UlpsDiff(left.fPts[leftIndex < 0 ? 0 : left.fVerb].fY,
676d88e0894d0156f4d427b812fec69bfba3eec7a8dcaryclark@google.com                        right.fPts[rightIndex < 0 ? 0 : right.fVerb].fY) <= 10);
6772e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        #endif
678cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            }
679cef7e3fc4bc6223ab0e42ed754e2a09028479c0bcaryclark@google.com            if (pairUp) {
6806008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                if (leftIndex < 0) {
6816008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    fTops[leftOutIndex] = rightIndex;
6826008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                } else {
6836008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    fBottoms[leftOutIndex] = rightIndex;
6846008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                }
6856008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                if (rightIndex < 0) {
6866008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    fTops[rightOutIndex] = leftIndex;
6876008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                } else {
6886008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                    fBottoms[rightOutIndex] = leftIndex;
689f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com                }
6906008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                ++rightPtr;
691f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            }
692f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com            leftPtr = rightPtr;
6936680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com        }
6942e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_OUT
6952e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        int* mismatch = fMismatches.begin();
6962e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        while (mismatch != fMismatches.end()) {
6972e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            int leftIndex = *mismatch++;
6982e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            int leftOutIndex = abs(leftIndex) - 1;
6992e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            const OutEdge& left = fEdges[leftOutIndex];
7002e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            const SkPoint& leftPt = left.fPts[leftIndex < 0 ? 0 : left.fVerb];
7012e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkDebugf("%s left=%d %s (%1.9g,%1.9g)\n",
7022e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    __FUNCTION__, left.fID, leftIndex < 0 ? "top" : "bot",
7032e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    leftPt.fX, leftPt.fY);
7042e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
7052e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        SkASSERT(fMismatches.count() == 0);
7062e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
707fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#if DEBUG_BRIDGE
708fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    for (index = 0; index < count; ++index) {
709fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        const OutEdge& edge = fEdges[index];
710fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        uint8_t verb = edge.fVerb;
711d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        SkDebugf("%s %d edge=%d %s (%1.9g,%1.9g) (%1.9g,%1.9g)\n",
712fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                index == 0 ? __FUNCTION__ : "      ",
713fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                index + 1, edge.fID, kLVerbStr[verb], edge.fPts[0].fX,
714fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                edge.fPts[0].fY, edge.fPts[verb].fX, edge.fPts[verb].fY);
715fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    }
716fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    for (index = 0; index < count; ++index) {
717fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkDebugf("       top    of % 2d connects to %s of % 2d\n", index + 1,
718fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                fTops[index] < 0 ? "top   " : "bottom", abs(fTops[index]));
719fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkDebugf("       bottom of % 2d connects to %s of % 2d\n", index + 1,
720fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                fBottoms[index] < 0 ? "top   " : "bottom", abs(fBottoms[index]));
721fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    }
722fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com#endif
7236680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    }
7246680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
7256008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.comprotected:
7266680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    SkTArray<OutEdge> fEdges;
7276008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    SkTDArray<int> fTops;
7286008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    SkTDArray<int> fBottoms;
729f8b000d7ae32ac9bb67c8e33cae500cac7407d26caryclark@google.com    bool fFill;
7302e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_OUT
7312e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkTDArray<int> fMismatches;
7322e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
7336680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com};
7346680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com
735c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com// Bounds, unlike Rect, does not consider a vertical line to be empty.
736c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.comstruct Bounds : public SkRect {
737c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    static bool Intersects(const Bounds& a, const Bounds& b) {
738c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
739c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                a.fTop <= b.fBottom && b.fTop <= a.fBottom;
740c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
741752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
7426008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    bool isEmpty() {
7436008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        return fLeft > fRight || fTop > fBottom
7449f3e9a5a17a7546e1c5bfde1eb7e6e9c11870333caryclark@google.com                || (fLeft == fRight && fTop == fBottom)
7456008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                || isnan(fLeft) || isnan(fRight)
7466008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                || isnan(fTop) || isnan(fBottom);
7476008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com    }
748c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com};
749c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
7504917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.comclass Intercepts {
7514917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.compublic:
7524917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com    Intercepts()
7534917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com        : fTopIntercepts(0)
754198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        , fBottomIntercepts(0)
755198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        , fExplicit(false) {
756198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
757d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
758198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    Intercepts& operator=(const Intercepts& src) {
759198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fTs = src.fTs;
760198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fTopIntercepts = src.fTopIntercepts;
761198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fBottomIntercepts = src.fBottomIntercepts;
762b45a1b46ee25e9b19800b028bb1ca925212ac7b4caryclark@google.com        return *this;
763198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
764198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
765198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    // OPTIMIZATION: remove this function if it's never called
766198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    double t(int tIndex) const {
767198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        if (tIndex == 0) {
768198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            return 0;
769198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
770198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        if (tIndex > fTs.count()) {
771198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            return 1;
772198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
773198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        return fTs[tIndex - 1];
7744917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com    }
775752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com
7762e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_DUMP
777a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com    void dump(const SkPoint* pts, SkPath::Verb verb) {
7782e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        const char className[] = "Intercepts";
7792e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        const int tab = 8;
7802e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        for (int i = 0; i < fTs.count(); ++i) {
7812e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            SkPoint out;
782a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            switch (verb) {
783a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                case SkPath::kLine_Verb:
784a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    LineXYAtT(pts, fTs[i], &out);
785a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    break;
786a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                case SkPath::kQuad_Verb:
787a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    QuadXYAtT(pts, fTs[i], &out);
788a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    break;
789a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                case SkPath::kCubic_Verb:
790a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    CubicXYAtT(pts, fTs[i], &out);
791a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    break;
792a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                default:
793a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com                    SkASSERT(0);
794a5764233aa6b207c4169fff7fccae567a160a0fdcaryclark@google.com            }
795752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com            SkDebugf("%*s.fTs[%d]=%1.9g (%1.9g,%1.9g)\n", tab + sizeof(className),
7962e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    className, i, fTs[i], out.fX, out.fY);
7972e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        }
798198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        SkDebugf("%*s.fTopIntercepts=%u\n", tab + sizeof(className),
7992e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                className, fTopIntercepts);
800198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        SkDebugf("%*s.fBottomIntercepts=%u\n", tab + sizeof(className),
8012e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                className, fBottomIntercepts);
802fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkDebugf("%*s.fExplicit=%d\n", tab + sizeof(className),
803fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com                className, fExplicit);
8042e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
8052e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
8062e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
807c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    SkTDArray<double> fTs;
808198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    unsigned char fTopIntercepts; // 0=init state 1=1 edge >1=multiple edges
809198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    unsigned char fBottomIntercepts;
810198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    bool fExplicit; // if set, suppress 0 and 1
811d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
812c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com};
813c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
8142e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.comstruct HorizontalEdge {
8152e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    bool operator<(const HorizontalEdge& rh) const {
8162e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        return fY == rh.fY ? fLeft == rh.fLeft ? fRight < rh.fRight
8172e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                : fLeft < rh.fLeft : fY < rh.fY;
8182e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
8192e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
8202e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#if DEBUG_DUMP
8212e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    void dump() {
8222e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        const char className[] = "HorizontalEdge";
8232e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        const int tab = 4;
824752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        SkDebugf("%*s.fLeft=%1.9g\n", tab + sizeof(className), className, fLeft);
825752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        SkDebugf("%*s.fRight=%1.9g\n", tab + sizeof(className), className, fRight);
826752b60e633a349c5b9f7bcc6a28b8064fc77bb41caryclark@google.com        SkDebugf("%*s.fY=%1.9g\n", tab + sizeof(className), className, fY);
8272e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    }
8282e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com#endif
8292e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
8302e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkScalar fLeft;
8312e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkScalar fRight;
8322e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    SkScalar fY;
8332e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com};
8342e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com
8356680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.comstruct InEdge {
8366680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    bool operator<(const InEdge& rh) const {
837c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        return fBounds.fTop == rh.fBounds.fTop
838c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                ? fBounds.fLeft < rh.fBounds.fLeft
839c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                : fBounds.fTop < rh.fBounds.fTop;
840c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
841c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
8422e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // Avoid collapsing t values that are close to the same since
8432e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // we walk ts to describe consecutive intersections. Since a pair of ts can
8442e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    // be nearly equal, any problems caused by this should be taken care
845d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    // of later.
8462e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    int add(double* ts, size_t count, ptrdiff_t verbIndex) {
847c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        // FIXME: in the pathological case where there is a ton of intercepts, binary search?
8486008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        bool foundIntercept = false;
8492e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        int insertedAt = -1;
8506008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com        Intercepts& intercepts = fIntercepts[verbIndex];
851c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        for (size_t index = 0; index < count; ++index) {
852c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            double t = ts[index];
8534917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com            if (t <= 0) {
854198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                intercepts.fTopIntercepts <<= 1;
8554917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                fContainsIntercepts |= ++intercepts.fTopIntercepts > 1;
8564917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                continue;
8574917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com            }
8584917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com            if (t >= 1) {
859198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com                intercepts.fBottomIntercepts <<= 1;
8604917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com                fContainsIntercepts |= ++intercepts.fBottomIntercepts > 1;
8616008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com                continue;
8626008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            }
863198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            fIntersected = true;
8646008c656f90026a3b434938454fd2b67cf135e0acaryclark@google.com            foundIntercept = true;
865c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            size_t tCount = intercepts.fTs.count();
8662e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            double delta;
867c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            for (size_t idx2 = 0; idx2 < tCount; ++idx2) {
868c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                if (t <= intercepts.fTs[idx2]) {
8692e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    // FIXME: ?  if (t < intercepts.fTs[idx2]) // failed
8702e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    delta = intercepts.fTs[idx2] - t;
871cd4421df5012b75c792c6c8bf2c5ee0410921c15caryclark@google.com                    if (delta > 0) {
8722e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                        insertedAt = idx2;
873c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                        *intercepts.fTs.insert(idx2) = t;
874c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                    }
8752e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                    goto nextPt;
876c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                }
877c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            }
8782e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            if (tCount == 0 || (delta = t - intercepts.fTs[tCount - 1]) > 0) {
8792e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com                insertedAt = tCount;
880c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                *intercepts.fTs.append() = t;
881c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            }
8822e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com    nextPt:
8832e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com            ;
884c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
8854917f17bf6bd8bff7f4b03717dcb02561cf227c9caryclark@google.com        fContainsIntercepts |= foundIntercept;
8862e7f4c810dc717383df42d27bdba862514ab6d51caryclark@google.com        return insertedAt;
887c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
888d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
889fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    void addPartial(SkTArray<InEdge>& edges, int ptStart, int ptEnd,
890198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            int verbStart, int verbEnd) {
891198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        InEdge* edge = edges.push_back_n(1);
892198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        int verbCount = verbEnd - verbStart;
893198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fIntercepts.push_back_n(verbCount);
894a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com     //   uint8_t* verbs = &fVerbs[verbStart];
895198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        for (int ceptIdx = 0; ceptIdx < verbCount; ++ceptIdx) {
896198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            edge->fIntercepts[ceptIdx] = fIntercepts[verbStart + ceptIdx];
897198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
898198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fPts.append(ptEnd - ptStart, &fPts[ptStart]);
899198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fVerbs.append(verbCount, &fVerbs[verbStart]);
900198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->setBounds();
901198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fWinding = fWinding;
902198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fContainsIntercepts = fContainsIntercepts; // FIXME: may not be correct -- but do we need to know?
903198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
904198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
905fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    void addSplit(SkTArray<InEdge>& edges, SkPoint* pts, uint8_t verb,
906fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            Intercepts& intercepts, int firstT, int lastT, bool flipped) {
907198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        InEdge* edge = edges.push_back_n(1);
908198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fIntercepts.push_back_n(1);
909fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        if (firstT == 0) {
910fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            *edge->fIntercepts[0].fTs.append() = 0;
911fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        } else {
912fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            *edge->fIntercepts[0].fTs.append() = intercepts.fTs[firstT - 1];
913fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        }
914fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        bool add1 = lastT == intercepts.fTs.count();
915fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        edge->fIntercepts[0].fTs.append(lastT - firstT, &intercepts.fTs[firstT]);
916fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        if (add1) {
917fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            *edge->fIntercepts[0].fTs.append() = 1;
918fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        }
919198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fIntercepts[0].fExplicit = true;
920fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        edge->fPts.append(verb + 1, pts);
921198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fVerbs.append(1, &verb);
922fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        // FIXME: bounds could be better for partial Ts
923fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        edge->setSubBounds();
924198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        edge->fContainsIntercepts = fContainsIntercepts; // FIXME: may not be correct -- but do we need to know?
925198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        if (flipped) {
926fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            edge->flipTs();
927fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            edge->fWinding = -fWinding;
928fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        } else {
929fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            edge->fWinding = fWinding;
930198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
931198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
932c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
9336680fb1dc0ca55e5e3ddd41cb26dcd74fce28f6ecaryclark@google.com    bool cached(const InEdge* edge) {
934c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        // FIXME: in the pathological case where there is a ton of edges, binary search?
935c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        size_t count = fCached.count();
936c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        for (size_t index = 0; index < count; ++index) {
937c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            if (edge == fCached[index]) {
938c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                return true;
939c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            }
940c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            if (edge < fCached[index]) {
941c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                *fCached.insert(index) = edge;
942c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com                return false;
943c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            }
944c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
945c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        *fCached.append() = edge;
946c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        return false;
947c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com    }
948c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com
949fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    void complete(signed char winding) {
950198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        setBounds();
951198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fIntercepts.push_back_n(fVerbs.count());
952198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        if ((fWinding = winding) < 0) { // reverse verbs, pts, if bottom to top
953198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            flip();
954198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
955198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fContainsIntercepts = fIntersected = false;
956198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
957d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
958fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    void flip() {
959198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        size_t index;
960198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        size_t last = fPts.count() - 1;
961198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        for (index = 0; index < last; ++index, --last) {
962198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            SkTSwap<SkPoint>(fPts[index], fPts[last]);
963198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
964198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        last = fVerbs.count() - 1;
965198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        for (index = 0; index < last; ++index, --last) {
966198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            SkTSwap<uint8_t>(fVerbs[index], fVerbs[last]);
967198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
968198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
969d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
970fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    void flipTs() {
971fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkASSERT(fIntercepts.count() == 1);
972fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        Intercepts& intercepts = fIntercepts[0];
973fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkASSERT(intercepts.fExplicit);
974fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkTDArray<double>& ts = intercepts.fTs;
975fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        size_t index;
976fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        size_t last = ts.count() - 1;
977fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        for (index = 0; index < last; ++index, --last) {
978fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            SkTSwap<double>(ts[index], ts[last]);
979fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        }
980fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    }
981198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
982198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    void reset() {
983198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fCached.reset();
984198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fIntercepts.reset();
985198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fPts.reset();
986198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fVerbs.reset();
987198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
988198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fWinding = 0;
989198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fContainsIntercepts = false;
990198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        fIntersected = false;
991198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
992198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
993198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    void setBounds() {
994c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        SkPoint* ptPtr = fPts.begin();
995c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        SkPoint* ptLast = fPts.end();
996c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        if (ptPtr == ptLast) {
997198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            SkDebugf("%s empty edge\n", __FUNCTION__);
998c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            SkASSERT(0);
999c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            // FIXME: delete empty edge?
1000c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            return;
1001c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
1002c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        fBounds.set(ptPtr->fX, ptPtr->fY, ptPtr->fX, ptPtr->fY);
1003c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        ++ptPtr;
1004c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        while (ptPtr != ptLast) {
1005c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            fBounds.growToInclude(ptPtr->fX, ptPtr->fY);
1006c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com            ++ptPtr;
1007c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com        }
1008198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
1009d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
1010fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    // recompute bounds based on subrange of T values
1011fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    void setSubBounds() {
1012fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkASSERT(fIntercepts.count() == 1);
1013fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        Intercepts& intercepts = fIntercepts[0];
1014fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkASSERT(intercepts.fExplicit);
1015fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkASSERT(fVerbs.count() == 1);
1016fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        SkTDArray<double>& ts = intercepts.fTs;
1017fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        if (fVerbs[0] == SkPath::kQuad_Verb) {
1018fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            SkASSERT(fPts.count() == 3);
1019fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            QuadSubBounds(fPts.begin(), ts[0], ts[ts.count() - 1], fBounds);
1020fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        } else {
1021fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            SkASSERT(fVerbs[0] == SkPath::kCubic_Verb);
1022fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            SkASSERT(fPts.count() == 4);
1023fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com            CubicSubBounds(fPts.begin(), ts[0], ts[ts.count() - 1], fBounds);
1024fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com        }
1025fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    }
1026198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
1027fb173424e915e696a73067d616ce4f39a407261acaryclark@google.com    void splitInflectionPts(SkTArray<InEdge>& edges) {
1028198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        if (!fIntersected) {
1029198e054b33051a6cd5f606ccbc