blob: 6b2ca98a0a6eb81036d31ce59da1197489c9e04b [file] [log] [blame]
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
caryclark@google.comb45a1b42012-05-18 20:50:33 +00007#include "Simplify.h"
caryclark@google.comfa0588f2012-04-26 21:01:06 +00008
9#undef SkASSERT
10#define SkASSERT(cond) while (!(cond)) { sk_throw(); }
11
caryclark@google.com15fa1382012-05-07 20:49:36 +000012// Terminology:
13// A Path contains one of more Contours
14// A Contour is made up of Segment array
caryclark@google.comb45a1b42012-05-18 20:50:33 +000015// A Segment is described by a Verb and a Point array with 2, 3, or 4 points
16// A Verb is one of Line, Quad(ratic), or Cubic
caryclark@google.com15fa1382012-05-07 20:49:36 +000017// A Segment contains a Span array
18// A Span is describes a portion of a Segment using starting and ending T
19// T values range from 0 to 1, where 0 is the first Point in the Segment
caryclark@google.com47580692012-07-23 12:14:49 +000020// An Edge is a Segment generated from a Span
caryclark@google.com15fa1382012-05-07 20:49:36 +000021
caryclark@google.comfa0588f2012-04-26 21:01:06 +000022// FIXME: remove once debugging is complete
caryclark@google.com47580692012-07-23 12:14:49 +000023#ifdef SK_DEBUG
24int gDebugMaxWindSum = SK_MaxS32;
25int gDebugMaxWindValue = SK_MaxS32;
26#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +000027
caryclark@google.comf839c032012-10-26 21:03:50 +000028#define PIN_ADD_T 0
caryclark@google.com0b7da432012-10-31 19:00:20 +000029#define TRY_ROTATE 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000030#define ONE_PASS_COINCIDENCE_CHECK 0
caryclark@google.com73ca6242013-01-17 21:02:47 +000031#define APPROXIMATE_CUBICS 1
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +000032#define COMPACT_DEBUG_SORT 0
caryclark@google.coma461ff02012-10-11 12:54:23 +000033
caryclark@google.com47580692012-07-23 12:14:49 +000034#define DEBUG_UNUSED 0 // set to expose unused functions
caryclark@google.com45a8fc62013-02-14 15:29:11 +000035
caryclark@google.com31143cf2012-11-09 22:14:19 +000036#if FORCE_RELEASE || defined SK_RELEASE
caryclark@google.com47580692012-07-23 12:14:49 +000037
38const bool gRunTestsInOneThread = false;
39
caryclark@google.combeda3892013-02-07 13:13:41 +000040#define DEBUG_ACTIVE_OP 0
caryclark@google.com47580692012-07-23 12:14:49 +000041#define DEBUG_ACTIVE_SPANS 0
caryclark@google.com4eeda372012-12-06 21:47:48 +000042#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000043#define DEBUG_ADD_INTERSECTING_TS 0
caryclark@google.com47580692012-07-23 12:14:49 +000044#define DEBUG_ADD_T_PAIR 0
caryclark@google.comc899ad92012-08-23 15:24:42 +000045#define DEBUG_ANGLE 0
caryclark@google.com7ff5c842013-02-26 15:56:05 +000046#define DEBUG_AS_C_CODE 1
caryclark@google.come7bd5f42012-12-13 19:47:53 +000047#define DEBUG_ASSEMBLE 0
caryclark@google.com47580692012-07-23 12:14:49 +000048#define DEBUG_CONCIDENT 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000049#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000050#define DEBUG_FLOW 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000051#define DEBUG_MARK_DONE 0
caryclark@google.comf839c032012-10-26 21:03:50 +000052#define DEBUG_PATH_CONSTRUCTION 0
caryclark@google.com729e1c42012-11-21 21:36:34 +000053#define DEBUG_SHOW_WINDING 0
caryclark@google.comc83c70e2013-02-22 21:50:07 +000054#define DEBUG_SORT 0
caryclark@google.com5e0500f2013-02-20 12:51:37 +000055#define DEBUG_SWAP_TOP 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000056#define DEBUG_UNSORTABLE 0
caryclark@google.comafe56de2012-07-24 18:11:03 +000057#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000058#define DEBUG_WINDING 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000059#define DEBUG_WINDING_AT_T 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000060
61#else
62
caryclark@google.com47580692012-07-23 12:14:49 +000063const bool gRunTestsInOneThread = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +000064
caryclark@google.combeda3892013-02-07 13:13:41 +000065#define DEBUG_ACTIVE_OP 1
caryclark@google.comc91dfe42012-10-16 12:06:27 +000066#define DEBUG_ACTIVE_SPANS 1
caryclark@google.com1304bb22013-03-13 20:29:41 +000067#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0
caryclark@google.com6aea33f2012-10-09 14:11:58 +000068#define DEBUG_ADD_INTERSECTING_TS 1
69#define DEBUG_ADD_T_PAIR 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000070#define DEBUG_ANGLE 1
caryclark@google.com4aaaaea2013-02-28 16:12:39 +000071#define DEBUG_AS_C_CODE 1
caryclark@google.come7bd5f42012-12-13 19:47:53 +000072#define DEBUG_ASSEMBLE 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000073#define DEBUG_CONCIDENT 1
caryclark@google.com534aa5b2012-08-02 20:08:21 +000074#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000075#define DEBUG_FLOW 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000076#define DEBUG_MARK_DONE 1
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000077#define DEBUG_PATH_CONSTRUCTION 1
caryclark@google.com729e1c42012-11-21 21:36:34 +000078#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000079#define DEBUG_SORT 1
caryclark@google.com47d73da2013-02-17 01:41:25 +000080#define DEBUG_SWAP_TOP 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000081#define DEBUG_UNSORTABLE 1
caryclark@google.comafe56de2012-07-24 18:11:03 +000082#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000083#define DEBUG_WINDING 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000084#define DEBUG_WINDING_AT_T 1
caryclark@google.comfa0588f2012-04-26 21:01:06 +000085
86#endif
87
caryclark@google.combeda3892013-02-07 13:13:41 +000088#define DEBUG_DUMP (DEBUG_ACTIVE_OP | DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | \
89 DEBUG_PATH_CONSTRUCTION)
caryclark@google.com027de222012-07-12 12:52:50 +000090
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +000091#if DEBUG_AS_C_CODE
92#define CUBIC_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}}"
93#define QUAD_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}}"
94#define LINE_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}}"
95#define PT_DEBUG_STR "{{%1.17g,%1.17g}}"
96#else
97#define CUBIC_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
98#define QUAD_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
99#define LINE_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g)"
100#define PT_DEBUG_STR "(%1.9g,%1.9g)"
101#endif
102#define T_DEBUG_STR(t, n) #t "[" #n "]=%1.9g"
103#define TX_DEBUG_STR(t) #t "[%d]=%1.9g"
104#define CUBIC_DEBUG_DATA(c) c[0].fX, c[0].fY, c[1].fX, c[1].fY, c[2].fX, c[2].fY, c[3].fX, c[3].fY
105#define QUAD_DEBUG_DATA(q) q[0].fX, q[0].fY, q[1].fX, q[1].fY, q[2].fX, q[2].fY
106#define LINE_DEBUG_DATA(l) l[0].fX, l[0].fY, l[1].fX, l[1].fY
107#define PT_DEBUG_DATA(i, n) i.fPt[n].x, i.fPt[n].y
108
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000109#if DEBUG_DUMP
110static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000111// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000112static int gContourID;
113static int gSegmentID;
114#endif
115
caryclark@google.com1304bb22013-03-13 20:29:41 +0000116#if DEBUG_SORT || DEBUG_SWAP_TOP
caryclark@google.com4aaaaea2013-02-28 16:12:39 +0000117static int gDebugSortCountDefault = SK_MaxS32;
caryclark@google.comc83c70e2013-02-22 21:50:07 +0000118static int gDebugSortCount;
119#endif
120
caryclark@google.com5e0500f2013-02-20 12:51:37 +0000121#if DEBUG_ACTIVE_OP
122static const char* kShapeOpStr[] = {"diff", "sect", "union", "xor"};
123#endif
124
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000125#ifndef DEBUG_TEST
126#define DEBUG_TEST 0
127#endif
128
caryclark@google.com32546db2012-08-31 20:55:07 +0000129#define MAKE_CONST_LINE(line, pts) \
130 const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}
131#define MAKE_CONST_QUAD(quad, pts) \
132 const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
133 {pts[2].fX, pts[2].fY}}
134#define MAKE_CONST_CUBIC(cubic, pts) \
135 const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
136 {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}}
137
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000138static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
139 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000140 MAKE_CONST_LINE(aLine, a);
141 MAKE_CONST_LINE(bLine, b);
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000142 return intersect(aLine, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000143}
144
145static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
146 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000147 MAKE_CONST_QUAD(aQuad, a);
148 MAKE_CONST_LINE(bLine, b);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000149 return intersect(aQuad, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000150}
151
caryclark@google.com32546db2012-08-31 20:55:07 +0000152static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000153 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000154 MAKE_CONST_CUBIC(aCubic, a);
155 MAKE_CONST_LINE(bLine, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000156 return intersect(aCubic, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000157}
158
159static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
160 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000161 MAKE_CONST_QUAD(aQuad, a);
162 MAKE_CONST_QUAD(bQuad, b);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000163#define TRY_QUARTIC_SOLUTION 1
164#if TRY_QUARTIC_SOLUTION
165 intersect2(aQuad, bQuad, intersections);
166#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000167 intersect(aQuad, bQuad, intersections);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000168#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000169 return intersections.fUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000170}
171
caryclark@google.com73ca6242013-01-17 21:02:47 +0000172#if APPROXIMATE_CUBICS
173static int CubicQuadIntersect(const SkPoint a[4], const SkPoint b[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000174 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000175 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000176 MAKE_CONST_QUAD(bQuad, b);
177 return intersect(aCubic, bQuad, intersections);
178}
179#endif
180
181static int CubicIntersect(const SkPoint a[4], const SkPoint b[4], Intersections& intersections) {
182 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com32546db2012-08-31 20:55:07 +0000183 MAKE_CONST_CUBIC(bCubic, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000184#if APPROXIMATE_CUBICS
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000185 intersect3(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000186#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000187 intersect(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000188#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000189 return intersections.fUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000190}
191
caryclark@google.comc83c70e2013-02-22 21:50:07 +0000192static int CubicIntersect(const SkPoint a[4], Intersections& intersections) {
193 MAKE_CONST_CUBIC(aCubic, a);
194 return intersect(aCubic, intersections);
195}
196
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000197static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
198 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000199 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000200 return horizontalIntersect(aLine, left, right, y, flipped, intersections);
201}
202
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000203static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
204 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000205 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000206 return horizontalIntersect(aQuad, left, right, y, flipped, intersections);
207}
208
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000209static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
210 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000211 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000212 return horizontalIntersect(aCubic, left, right, y, flipped, intersections);
213}
214
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000215static int (* const HSegmentIntersect[])(const SkPoint [], SkScalar ,
216 SkScalar , SkScalar , bool , Intersections& ) = {
217 NULL,
218 HLineIntersect,
219 HQuadIntersect,
220 HCubicIntersect
221};
222
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000223static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom,
224 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000225 MAKE_CONST_LINE(aLine, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000226 return verticalIntersect(aLine, top, bottom, x, flipped, intersections);
227}
228
229static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom,
230 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000231 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000232 return verticalIntersect(aQuad, top, bottom, x, flipped, intersections);
233}
234
235static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom,
236 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000237 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000238 return verticalIntersect(aCubic, top, bottom, x, flipped, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000239}
240
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000241static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar ,
242 SkScalar , SkScalar , bool , Intersections& ) = {
243 NULL,
244 VLineIntersect,
245 VQuadIntersect,
246 VCubicIntersect
247};
248
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000249static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000250 MAKE_CONST_LINE(line, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000251 double x, y;
252 xy_at_t(line, t, x, y);
253 out->fX = SkDoubleToScalar(x);
254 out->fY = SkDoubleToScalar(y);
255}
256
caryclark@google.comf9502d72013-02-04 14:06:49 +0000257static void LineXYAtT(const SkPoint a[2], double t, _Point* out) {
258 MAKE_CONST_LINE(line, a);
259 xy_at_t(line, t, out->x, out->y);
260}
261
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000262static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000263 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000264 double x, y;
265 xy_at_t(quad, t, x, y);
266 out->fX = SkDoubleToScalar(x);
267 out->fY = SkDoubleToScalar(y);
268}
269
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000270static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
271 MAKE_CONST_QUAD(quad, a);
272 xy_at_t(quad, t, out->x, out->y);
273}
274
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000275static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000276 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000277 double x, y;
278 xy_at_t(cubic, t, x, y);
279 out->fX = SkDoubleToScalar(x);
280 out->fY = SkDoubleToScalar(y);
281}
282
caryclark@google.comf9502d72013-02-04 14:06:49 +0000283static void CubicXYAtT(const SkPoint a[4], double t, _Point* out) {
284 MAKE_CONST_CUBIC(cubic, a);
285 xy_at_t(cubic, t, out->x, out->y);
286}
287
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000288static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
289 NULL,
290 LineXYAtT,
291 QuadXYAtT,
292 CubicXYAtT
293};
294
caryclark@google.comf9502d72013-02-04 14:06:49 +0000295static void (* const SegmentXYAtT2[])(const SkPoint [], double , _Point* ) = {
296 NULL,
297 LineXYAtT,
298 QuadXYAtT,
299 CubicXYAtT
300};
301
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000302static SkScalar LineXAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000303 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000304 double x;
305 xy_at_t(aLine, t, x, *(double*) 0);
306 return SkDoubleToScalar(x);
307}
308
309static SkScalar QuadXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000310 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000311 double x;
312 xy_at_t(quad, t, x, *(double*) 0);
313 return SkDoubleToScalar(x);
314}
315
316static SkScalar CubicXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000317 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000318 double x;
319 xy_at_t(cubic, t, x, *(double*) 0);
320 return SkDoubleToScalar(x);
321}
322
323static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
324 NULL,
325 LineXAtT,
326 QuadXAtT,
327 CubicXAtT
328};
329
330static SkScalar LineYAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000331 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000332 double y;
333 xy_at_t(aLine, t, *(double*) 0, y);
334 return SkDoubleToScalar(y);
335}
336
337static SkScalar QuadYAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000338 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000339 double y;
340 xy_at_t(quad, t, *(double*) 0, y);
341 return SkDoubleToScalar(y);
342}
343
344static SkScalar CubicYAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000345 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000346 double y;
347 xy_at_t(cubic, t, *(double*) 0, y);
348 return SkDoubleToScalar(y);
349}
350
351static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
352 NULL,
353 LineYAtT,
354 QuadYAtT,
355 CubicYAtT
356};
357
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000358static SkScalar LineDXAtT(const SkPoint a[2], double ) {
359 return a[1].fX - a[0].fX;
360}
361
362static SkScalar QuadDXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000363 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000364 double x = dx_at_t(quad, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000365 return SkDoubleToScalar(x);
366}
367
368static SkScalar CubicDXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000369 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000370 double x = dx_at_t(cubic, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000371 return SkDoubleToScalar(x);
372}
373
374static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
375 NULL,
376 LineDXAtT,
377 QuadDXAtT,
378 CubicDXAtT
379};
380
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000381static SkScalar LineDYAtT(const SkPoint a[2], double ) {
382 return a[1].fY - a[0].fY;
383}
384
385static SkScalar QuadDYAtT(const SkPoint a[3], double t) {
386 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000387 double y = dy_at_t(quad, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000388 return SkDoubleToScalar(y);
389}
390
391static SkScalar CubicDYAtT(const SkPoint a[4], double t) {
392 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000393 double y = dy_at_t(cubic, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000394 return SkDoubleToScalar(y);
395}
396
397static SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = {
398 NULL,
399 LineDYAtT,
400 QuadDYAtT,
401 CubicDYAtT
402};
403
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000404static SkVector LineDXDYAtT(const SkPoint a[2], double ) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000405 return a[1] - a[0];
406}
407
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000408static SkVector QuadDXDYAtT(const SkPoint a[3], double t) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000409 MAKE_CONST_QUAD(quad, a);
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000410 _Vector v = dxdy_at_t(quad, t);
411 return v.asSkVector();
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000412}
413
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000414static SkVector CubicDXDYAtT(const SkPoint a[4], double t) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000415 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000416 _Vector v = dxdy_at_t(cubic, t);
417 return v.asSkVector();
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000418}
419
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000420static SkVector (* const SegmentDXDYAtT[])(const SkPoint [], double ) = {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000421 NULL,
422 LineDXDYAtT,
423 QuadDXDYAtT,
424 CubicDXDYAtT
425};
426
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000427static void LineSubDivide(const SkPoint a[2], double startT, double endT,
428 SkPoint sub[2]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000429 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000430 _Line dst;
431 sub_divide(aLine, startT, endT, dst);
432 sub[0].fX = SkDoubleToScalar(dst[0].x);
433 sub[0].fY = SkDoubleToScalar(dst[0].y);
434 sub[1].fX = SkDoubleToScalar(dst[1].x);
435 sub[1].fY = SkDoubleToScalar(dst[1].y);
436}
437
438static void QuadSubDivide(const SkPoint a[3], double startT, double endT,
439 SkPoint sub[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000440 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000441 Quadratic dst;
442 sub_divide(aQuad, startT, endT, dst);
443 sub[0].fX = SkDoubleToScalar(dst[0].x);
444 sub[0].fY = SkDoubleToScalar(dst[0].y);
445 sub[1].fX = SkDoubleToScalar(dst[1].x);
446 sub[1].fY = SkDoubleToScalar(dst[1].y);
447 sub[2].fX = SkDoubleToScalar(dst[2].x);
448 sub[2].fY = SkDoubleToScalar(dst[2].y);
449}
450
451static void CubicSubDivide(const SkPoint a[4], double startT, double endT,
452 SkPoint sub[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000453 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000454 Cubic dst;
455 sub_divide(aCubic, startT, endT, dst);
456 sub[0].fX = SkDoubleToScalar(dst[0].x);
457 sub[0].fY = SkDoubleToScalar(dst[0].y);
458 sub[1].fX = SkDoubleToScalar(dst[1].x);
459 sub[1].fY = SkDoubleToScalar(dst[1].y);
460 sub[2].fX = SkDoubleToScalar(dst[2].x);
461 sub[2].fY = SkDoubleToScalar(dst[2].y);
462 sub[3].fX = SkDoubleToScalar(dst[3].x);
463 sub[3].fY = SkDoubleToScalar(dst[3].y);
464}
465
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000466static void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
467 SkPoint []) = {
468 NULL,
469 LineSubDivide,
470 QuadSubDivide,
471 CubicSubDivide
472};
473
caryclark@google.comaa358312013-01-29 20:28:49 +0000474static void LineSubDivideHD(const SkPoint a[2], double startT, double endT, _Line& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000475 MAKE_CONST_LINE(aLine, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000476 sub_divide(aLine, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000477}
478
caryclark@google.comaa358312013-01-29 20:28:49 +0000479static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT, Quadratic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000480 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000481 sub_divide(aQuad, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000482}
483
caryclark@google.comaa358312013-01-29 20:28:49 +0000484static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT, Cubic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000485 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000486 sub_divide(aCubic, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000487}
488
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000489static SkPoint QuadTop(const SkPoint a[3], double startT, double endT) {
490 MAKE_CONST_QUAD(quad, a);
491 _Point topPt = top(quad, startT, endT);
492 return topPt.asSkPoint();
493}
494
495static SkPoint CubicTop(const SkPoint a[3], double startT, double endT) {
496 MAKE_CONST_CUBIC(cubic, a);
497 _Point topPt = top(cubic, startT, endT);
498 return topPt.asSkPoint();
499}
500
501static SkPoint (* SegmentTop[])(const SkPoint[], double , double ) = {
502 NULL,
503 NULL,
504 QuadTop,
505 CubicTop
506};
507
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000508#if DEBUG_UNUSED
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000509static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
510 SkRect& bounds) {
511 SkPoint dst[3];
512 QuadSubDivide(a, startT, endT, dst);
513 bounds.fLeft = bounds.fRight = dst[0].fX;
514 bounds.fTop = bounds.fBottom = dst[0].fY;
515 for (int index = 1; index < 3; ++index) {
516 bounds.growToInclude(dst[index].fX, dst[index].fY);
517 }
518}
519
520static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
521 SkRect& bounds) {
522 SkPoint dst[4];
523 CubicSubDivide(a, startT, endT, dst);
524 bounds.fLeft = bounds.fRight = dst[0].fX;
525 bounds.fTop = bounds.fBottom = dst[0].fY;
526 for (int index = 1; index < 4; ++index) {
527 bounds.growToInclude(dst[index].fX, dst[index].fY);
528 }
529}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000530#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000531
caryclark@google.com15fa1382012-05-07 20:49:36 +0000532static SkPath::Verb QuadReduceOrder(const SkPoint a[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000533 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000534 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000535 Quadratic dst;
caryclark@google.com47d73da2013-02-17 01:41:25 +0000536 int order = reduceOrder(aQuad, dst, kReduceOrder_TreatAsFill);
caryclark@google.com24bec792012-08-20 12:43:57 +0000537 if (order == 2) { // quad became line
538 for (int index = 0; index < order; ++index) {
539 SkPoint* pt = reducePts.append();
540 pt->fX = SkDoubleToScalar(dst[index].x);
541 pt->fY = SkDoubleToScalar(dst[index].y);
542 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000543 }
544 return (SkPath::Verb) (order - 1);
545}
546
547static SkPath::Verb CubicReduceOrder(const SkPoint a[4],
548 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000549 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000550 Cubic dst;
caryclark@google.com47d73da2013-02-17 01:41:25 +0000551 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed, kReduceOrder_TreatAsFill);
caryclark@google.com24bec792012-08-20 12:43:57 +0000552 if (order == 2 || order == 3) { // cubic became line or quad
553 for (int index = 0; index < order; ++index) {
554 SkPoint* pt = reducePts.append();
555 pt->fX = SkDoubleToScalar(dst[index].x);
556 pt->fY = SkDoubleToScalar(dst[index].y);
557 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000558 }
559 return (SkPath::Verb) (order - 1);
560}
561
caryclark@google.com15fa1382012-05-07 20:49:36 +0000562static bool QuadIsLinear(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000563 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000564 return isLinear(aQuad, 0, 2);
565}
566
567static bool CubicIsLinear(const SkPoint a[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000568 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000569 return isLinear(aCubic, 0, 3);
570}
571
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000572static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000573 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000574 double x[2];
575 xy_at_t(aLine, startT, x[0], *(double*) 0);
caryclark@google.com495f8e42012-05-31 13:13:11 +0000576 xy_at_t(aLine, endT, x[1], *(double*) 0);
577 return SkMinScalar((float) x[0], (float) x[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000578}
579
580static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000581 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000582 return (float) leftMostT(aQuad, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000583}
584
585static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000586 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000587 return (float) leftMostT(aCubic, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000588}
589
590static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
591 NULL,
592 LineLeftMost,
593 QuadLeftMost,
594 CubicLeftMost
595};
596
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000597#if 0 // currently unused
caryclark@google.com235f56a2012-09-14 14:19:30 +0000598static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
599 Intersections& intersections) {
600 MAKE_CONST_QUAD(aQuad, a);
601 MAKE_CONST_LINE(bLine, b);
602 return intersectRay(aQuad, bLine, intersections);
603}
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000604#endif
605
caryclark@google.comf9502d72013-02-04 14:06:49 +0000606static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000607 MAKE_CONST_QUAD(aQuad, a);
608 return intersectRay(aQuad, bLine, intersections);
609}
caryclark@google.com235f56a2012-09-14 14:19:30 +0000610
caryclark@google.comf9502d72013-02-04 14:06:49 +0000611static int CubicRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
612 MAKE_CONST_CUBIC(aCubic, a);
613 return intersectRay(aCubic, bLine, intersections);
614}
615
616static int (* const SegmentRayIntersect[])(const SkPoint [], const _Line& , Intersections&) = {
617 NULL,
618 NULL,
619 QuadRayIntersect,
620 CubicRayIntersect
621};
622
623
624
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000625static bool LineVertical(const SkPoint a[2], double startT, double endT) {
626 MAKE_CONST_LINE(aLine, a);
627 double x[2];
628 xy_at_t(aLine, startT, x[0], *(double*) 0);
629 xy_at_t(aLine, endT, x[1], *(double*) 0);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000630 return AlmostEqualUlps((float) x[0], (float) x[1]);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000631}
632
633static bool QuadVertical(const SkPoint a[3], double startT, double endT) {
634 SkPoint dst[3];
635 QuadSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000636 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000637}
638
639static bool CubicVertical(const SkPoint a[4], double startT, double endT) {
640 SkPoint dst[4];
641 CubicSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000642 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX)
643 && AlmostEqualUlps(dst[2].fX, dst[3].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000644}
645
646static bool (* const SegmentVertical[])(const SkPoint [], double , double) = {
647 NULL,
648 LineVertical,
649 QuadVertical,
650 CubicVertical
651};
652
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000653class Segment;
654
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000655struct Span {
656 Segment* fOther;
657 mutable SkPoint fPt; // lazily computed as needed
658 double fT;
659 double fOtherT; // value at fOther[fOtherIndex].fT
660 int fOtherIndex; // can't be used during intersection
caryclark@google.com31143cf2012-11-09 22:14:19 +0000661 int fWindSum; // accumulated from contours surrounding this one.
662 int fOppSum; // for binary operators: the opposite winding sum
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000663 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
caryclark@google.com57cff8d2012-11-14 21:14:56 +0000664 int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000665 bool fDone; // if set, this span to next higher T has been processed
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000666 bool fUnsortableStart; // set when start is part of an unsortable pair
667 bool fUnsortableEnd; // set when end is part of an unsortable pair
caryclark@google.comf839c032012-10-26 21:03:50 +0000668 bool fTiny; // if set, span may still be considered once for edge following
caryclark@google.com4aaaaea2013-02-28 16:12:39 +0000669 bool fLoop; // set when a cubic loops back to this point
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000670};
671
caryclark@google.com15fa1382012-05-07 20:49:36 +0000672// sorting angles
673// given angles of {dx dy ddx ddy dddx dddy} sort them
674class Angle {
675public:
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000676 // FIXME: this is bogus for quads and cubics
677 // if the quads and cubics' line from end pt to ctrl pt are coincident,
678 // there's no obvious way to determine the curve ordering from the
679 // derivatives alone. In particular, if one quadratic's coincident tangent
680 // is longer than the other curve, the final control point can place the
681 // longer curve on either side of the shorter one.
682 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
683 // may provide some help, but nothing has been figured out yet.
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000684
caryclark@google.com32546db2012-08-31 20:55:07 +0000685 /*(
686 for quads and cubics, set up a parameterized line (e.g. LineParameters )
687 for points [0] to [1]. See if point [2] is on that line, or on one side
688 or the other. If it both quads' end points are on the same side, choose
689 the shorter tangent. If the tangents are equal, choose the better second
690 tangent angle
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000691
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000692 maybe I could set up LineParameters lazily
caryclark@google.com32546db2012-08-31 20:55:07 +0000693 */
caryclark@google.com15fa1382012-05-07 20:49:36 +0000694 bool operator<(const Angle& rh) const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000695 double y = dy();
696 double ry = rh.dy();
697 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
698 return y < 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000699 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000700 double x = dx();
701 double rx = rh.dx();
702 if (y == 0 && ry == 0 && x * rx < 0) {
703 return x < rx;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000704 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000705 double x_ry = x * ry;
706 double rx_y = rx * y;
707 double cmp = x_ry - rx_y;
caryclark@google.comc899ad92012-08-23 15:24:42 +0000708 if (!approximately_zero(cmp)) {
caryclark@google.com15fa1382012-05-07 20:49:36 +0000709 return cmp < 0;
710 }
caryclark@google.comd1688742012-09-18 20:08:37 +0000711 if (approximately_zero(x_ry) && approximately_zero(rx_y)
712 && !approximately_zero_squared(cmp)) {
713 return cmp < 0;
714 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000715 // at this point, the initial tangent line is coincident
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000716 // see if edges curl away from each other
caryclark@google.com31143cf2012-11-09 22:14:19 +0000717 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
718 || !approximately_zero(rh.fSide))) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000719 // FIXME: running demo will trigger this assertion
720 // (don't know if commenting out will trigger further assertion or not)
721 // commenting it out allows demo to run in release, though
722 // SkASSERT(fSide != rh.fSide);
723 return fSide < rh.fSide;
724 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000725 // see if either curve can be lengthened and try the tangent compare again
726 if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
727 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
728 Angle longer = *this;
729 Angle rhLonger = rh;
730 if (longer.lengthen() | rhLonger.lengthen()) {
731 return longer < rhLonger;
732 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000733 #if 0
caryclark@google.coma461ff02012-10-11 12:54:23 +0000734 // what if we extend in the other direction?
735 longer = *this;
736 rhLonger = rh;
737 if (longer.reverseLengthen() | rhLonger.reverseLengthen()) {
738 return longer < rhLonger;
739 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000740 #endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000741 }
caryclark@google.com185c7c42012-10-19 18:26:24 +0000742 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
caryclark@google.com31143cf2012-11-09 22:14:19 +0000743 || (rh.fVerb == SkPath::kLine_Verb
744 && approximately_zero(rx) && approximately_zero(ry))) {
caryclark@google.com185c7c42012-10-19 18:26:24 +0000745 // See general unsortable comment below. This case can happen when
746 // one line has a non-zero change in t but no change in x and y.
747 fUnsortable = true;
748 rh.fUnsortable = true;
749 return this < &rh; // even with no solution, return a stable sort
750 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000751 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
752 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
753 fUnsortable = true;
754 rh.fUnsortable = true;
755 return this < &rh; // even with no solution, return a stable sort
756 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000757 SkASSERT(fVerb >= SkPath::kQuad_Verb);
758 SkASSERT(rh.fVerb >= SkPath::kQuad_Verb);
skia.committer@gmail.comc1ad0222012-09-19 02:01:47 +0000759 // FIXME: until I can think of something better, project a ray from the
caryclark@google.comd1688742012-09-18 20:08:37 +0000760 // end of the shorter tangent to midway between the end points
761 // through both curves and use the resulting angle to sort
caryclark@google.com235f56a2012-09-14 14:19:30 +0000762 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
763 double len = fTangent1.normalSquared();
764 double rlen = rh.fTangent1.normalSquared();
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000765 _Line ray;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000766 Intersections i, ri;
caryclark@google.comd1688742012-09-18 20:08:37 +0000767 int roots, rroots;
768 bool flip = false;
769 do {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000770 bool useThis = (len < rlen) ^ flip;
771 const Cubic& part = useThis ? fCurvePart : rh.fCurvePart;
772 SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb;
773 ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ?
774 part[2] : part[1];
775 ray[1].x = (part[0].x + part[partVerb].x) / 2;
776 ray[1].y = (part[0].y + part[partVerb].y) / 2;
caryclark@google.comd1688742012-09-18 20:08:37 +0000777 SkASSERT(ray[0] != ray[1]);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000778 roots = (*SegmentRayIntersect[fVerb])(fPts, ray, i);
779 rroots = (*SegmentRayIntersect[rh.fVerb])(rh.fPts, ray, ri);
caryclark@google.comd1688742012-09-18 20:08:37 +0000780 } while ((roots == 0 || rroots == 0) && (flip ^= true));
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000781 if (roots == 0 || rroots == 0) {
782 // FIXME: we don't have a solution in this case. The interim solution
783 // is to mark the edges as unsortable, exclude them from this and
784 // future computations, and allow the returned path to be fragmented
785 fUnsortable = true;
786 rh.fUnsortable = true;
787 return this < &rh; // even with no solution, return a stable sort
788 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000789 _Point loc;
790 double best = SK_ScalarInfinity;
791 double dx, dy, dist;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000792 int index;
793 for (index = 0; index < roots; ++index) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000794 (*SegmentXYAtT2[fVerb])(fPts, i.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000795 dx = loc.x - ray[0].x;
796 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000797 dist = dx * dx + dy * dy;
798 if (best > dist) {
799 best = dist;
800 }
801 }
802 for (index = 0; index < rroots; ++index) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000803 (*SegmentXYAtT2[rh.fVerb])(rh.fPts, ri.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000804 dx = loc.x - ray[0].x;
805 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000806 dist = dx * dx + dy * dy;
807 if (best > dist) {
808 return fSide < 0;
809 }
810 }
811 return fSide > 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000812 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000813
caryclark@google.com47580692012-07-23 12:14:49 +0000814 double dx() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000815 return fTangent1.dx();
caryclark@google.com47580692012-07-23 12:14:49 +0000816 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000817
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000818 double dy() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000819 return fTangent1.dy();
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000820 }
821
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000822 int end() const {
823 return fEnd;
824 }
825
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000826 bool isHorizontal() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000827 return dy() == 0 && fVerb == SkPath::kLine_Verb;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000828 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000829
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000830 bool lengthen() {
831 int newEnd = fEnd;
832 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
833 fEnd = newEnd;
834 setSpans();
835 return true;
836 }
837 return false;
838 }
839
caryclark@google.coma461ff02012-10-11 12:54:23 +0000840 bool reverseLengthen() {
841 if (fReversed) {
842 return false;
843 }
844 int newEnd = fStart;
845 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
846 fEnd = newEnd;
847 fReversed = true;
848 setSpans();
849 return true;
850 }
851 return false;
852 }
853
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000854 void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000855 int start, int end, const SkTDArray<Span>& spans) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000856 fSegment = segment;
857 fStart = start;
858 fEnd = end;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000859 fPts = orig;
860 fVerb = verb;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000861 fSpans = &spans;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000862 fReversed = false;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000863 fUnsortable = false;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000864 setSpans();
865 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000866
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000867
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000868 void setSpans() {
869 double startT = (*fSpans)[fStart].fT;
870 double endT = (*fSpans)[fEnd].fT;
871 switch (fVerb) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000872 case SkPath::kLine_Verb:
873 _Line l;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000874 LineSubDivideHD(fPts, startT, endT, l);
caryclark@google.com32546db2012-08-31 20:55:07 +0000875 // OPTIMIZATION: for pure line compares, we never need fTangent1.c
876 fTangent1.lineEndPoints(l);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000877 fSide = 0;
caryclark@google.com32546db2012-08-31 20:55:07 +0000878 break;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000879 case SkPath::kQuad_Verb: {
880 Quadratic& quad = (Quadratic&)fCurvePart;
881 QuadSubDivideHD(fPts, startT, endT, quad);
882 fTangent1.quadEndPoints(quad, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000883 if (dx() == 0 && dy() == 0) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000884 fTangent1.quadEndPoints(quad);
caryclark@google.comaa358312013-01-29 20:28:49 +0000885 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000886 fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- compare sign only
887 } break;
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000888 case SkPath::kCubic_Verb: {
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000889 int nextC = 2;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000890 CubicSubDivideHD(fPts, startT, endT, fCurvePart);
891 fTangent1.cubicEndPoints(fCurvePart, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000892 if (dx() == 0 && dy() == 0) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000893 fTangent1.cubicEndPoints(fCurvePart, 0, 2);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000894 nextC = 3;
caryclark@google.comaa358312013-01-29 20:28:49 +0000895 if (dx() == 0 && dy() == 0) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000896 fTangent1.cubicEndPoints(fCurvePart, 0, 3);
caryclark@google.comaa358312013-01-29 20:28:49 +0000897 }
caryclark@google.comaa358312013-01-29 20:28:49 +0000898 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000899 fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign only
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000900 if (nextC == 2 && approximately_zero(fSide)) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000901 fSide = -fTangent1.pointDistance(fCurvePart[3]);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000902 }
903 } break;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000904 default:
905 SkASSERT(0);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000906 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000907 fUnsortable = dx() == 0 && dy() == 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000908 if (fUnsortable) {
909 return;
910 }
911 SkASSERT(fStart != fEnd);
912 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
913 for (int index = fStart; index != fEnd; index += step) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000914#if 1
915 const Span& thisSpan = (*fSpans)[index];
916 const Span& nextSpan = (*fSpans)[index + step];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000917 if (thisSpan.fTiny || precisely_equal(thisSpan.fT, nextSpan.fT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000918 continue;
caryclark@google.comf839c032012-10-26 21:03:50 +0000919 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000920 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
921#if DEBUG_UNSORTABLE
922 if (fUnsortable) {
923 SkPoint iPt, ePt;
924 (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt);
925 (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt);
926 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
927 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
928 }
929#endif
930 return;
931#else
932 if ((*fSpans)[index].fUnsortableStart) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000933 fUnsortable = true;
934 return;
935 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000936#endif
caryclark@google.comf839c032012-10-26 21:03:50 +0000937 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000938#if 1
939#if DEBUG_UNSORTABLE
940 SkPoint iPt, ePt;
941 (*SegmentXYAtT[fVerb])(fPts, startT, &iPt);
942 (*SegmentXYAtT[fVerb])(fPts, endT, &ePt);
943 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
944 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
945#endif
946 fUnsortable = true;
947#endif
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000948 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000949
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000950 Segment* segment() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000951 return const_cast<Segment*>(fSegment);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000952 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000953
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000954 int sign() const {
caryclark@google.com495f8e42012-05-31 13:13:11 +0000955 return SkSign32(fStart - fEnd);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000956 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000957
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000958 const SkTDArray<Span>* spans() const {
959 return fSpans;
960 }
961
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000962 int start() const {
963 return fStart;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000964 }
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +0000965
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000966 bool unsortable() const {
967 return fUnsortable;
968 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000969
caryclark@google.comc899ad92012-08-23 15:24:42 +0000970#if DEBUG_ANGLE
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000971 const SkPoint* pts() const {
972 return fPts;
973 }
974
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000975 SkPath::Verb verb() const {
976 return fVerb;
977 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000978
caryclark@google.comc899ad92012-08-23 15:24:42 +0000979 void debugShow(const SkPoint& a) const {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000980 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
caryclark@google.comc899ad92012-08-23 15:24:42 +0000981 }
982#endif
983
caryclark@google.com15fa1382012-05-07 20:49:36 +0000984private:
caryclark@google.com235f56a2012-09-14 14:19:30 +0000985 const SkPoint* fPts;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000986 Cubic fCurvePart;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000987 SkPath::Verb fVerb;
988 double fSide;
989 LineParameters fTangent1;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000990 const SkTDArray<Span>* fSpans;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000991 const Segment* fSegment;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000992 int fStart;
993 int fEnd;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000994 bool fReversed;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000995 mutable bool fUnsortable; // this alone is editable by the less than operator
caryclark@google.com15fa1382012-05-07 20:49:36 +0000996};
997
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000998// Bounds, unlike Rect, does not consider a line to be empty.
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000999struct Bounds : public SkRect {
1000 static bool Intersects(const Bounds& a, const Bounds& b) {
1001 return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
1002 a.fTop <= b.fBottom && b.fTop <= a.fBottom;
1003 }
1004
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001005 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
1006 if (left < fLeft) {
1007 fLeft = left;
1008 }
1009 if (top < fTop) {
1010 fTop = top;
1011 }
1012 if (right > fRight) {
1013 fRight = right;
1014 }
1015 if (bottom > fBottom) {
1016 fBottom = bottom;
1017 }
1018 }
1019
1020 void add(const Bounds& toAdd) {
1021 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
1022 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001023
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001024 void add(const SkPoint& pt) {
1025 if (pt.fX < fLeft) fLeft = pt.fX;
1026 if (pt.fY < fTop) fTop = pt.fY;
1027 if (pt.fX > fRight) fRight = pt.fX;
1028 if (pt.fY > fBottom) fBottom = pt.fY;
1029 }
1030
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001031 bool isEmpty() {
1032 return fLeft > fRight || fTop > fBottom
caryclark@google.com235f56a2012-09-14 14:19:30 +00001033 || (fLeft == fRight && fTop == fBottom)
caryclark@google.combeda3892013-02-07 13:13:41 +00001034 || sk_double_isnan(fLeft) || sk_double_isnan(fRight)
1035 || sk_double_isnan(fTop) || sk_double_isnan(fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001036 }
skia.committer@gmail.com03682be2013-03-14 07:02:51 +00001037
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001038 void setCubicBounds(const SkPoint a[4]) {
1039 _Rect dRect;
caryclark@google.com32546db2012-08-31 20:55:07 +00001040 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001041 dRect.setBounds(cubic);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001042 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1043 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001044 }
1045
caryclark@google.com1304bb22013-03-13 20:29:41 +00001046 void setLineBounds(const SkPoint a[2]) {
1047 setPoint(a[0]);
1048 add(a[1]);
1049 }
1050
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001051 void setQuadBounds(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +00001052 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001053 _Rect dRect;
1054 dRect.setBounds(quad);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001055 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1056 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001057 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001058
1059 void setPoint(const SkPoint& pt) {
1060 fLeft = fRight = pt.fX;
1061 fTop = fBottom = pt.fY;
1062 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001063};
1064
caryclark@google.com1304bb22013-03-13 20:29:41 +00001065static void (Bounds::*setSegmentBounds[])(const SkPoint[]) = {
1066 NULL,
1067 &Bounds::setLineBounds,
1068 &Bounds::setQuadBounds,
1069 &Bounds::setCubicBounds
1070};
1071
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001072// OPTIMIZATION: does the following also work, and is it any faster?
1073// return outerWinding * innerWinding > 0
1074// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
caryclark@google.com2ddff932012-08-07 21:25:27 +00001075static bool useInnerWinding(int outerWinding, int innerWinding) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001076 SkASSERT(outerWinding != SK_MaxS32);
1077 SkASSERT(innerWinding != SK_MaxS32);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001078 int absOut = abs(outerWinding);
1079 int absIn = abs(innerWinding);
1080 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
caryclark@google.com5e0500f2013-02-20 12:51:37 +00001081#if 0 && DEBUG_WINDING
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001082 if (outerWinding * innerWinding < 0) {
caryclark@google.com24bec792012-08-20 12:43:57 +00001083 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
caryclark@google.com2ddff932012-08-07 21:25:27 +00001084 outerWinding, innerWinding, result ? "true" : "false");
caryclark@google.com2ddff932012-08-07 21:25:27 +00001085 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001086#endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001087 return result;
1088}
1089
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001090#define F (false) // discard the edge
1091#define T (true) // keep the edge
1092
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001093static const bool gUnaryActiveEdge[2][2] = {
1094// from=0 from=1
1095// to=0,1 to=0,1
1096 {F, T}, {T, F},
1097};
1098
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001099static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
1100// miFrom=0 miFrom=1
1101// miTo=0 miTo=1 miTo=0 miTo=1
1102// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
1103// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
1104 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
1105 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
1106 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
1107 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su
caryclark@google.com235f56a2012-09-14 14:19:30 +00001108};
1109
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001110#undef F
1111#undef T
caryclark@google.com235f56a2012-09-14 14:19:30 +00001112
caryclark@google.comf839c032012-10-26 21:03:50 +00001113// wrap path to keep track of whether the contour is initialized and non-empty
1114class PathWrapper {
1115public:
1116 PathWrapper(SkPath& path)
1117 : fPathPtr(&path)
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001118 , fCloses(0)
1119 , fMoves(0)
caryclark@google.comf839c032012-10-26 21:03:50 +00001120 {
1121 init();
1122 }
1123
1124 void close() {
1125 if (!fHasMove) {
1126 return;
1127 }
1128 bool callClose = isClosed();
1129 lineTo();
1130 if (fEmpty) {
1131 return;
1132 }
1133 if (callClose) {
1134 #if DEBUG_PATH_CONSTRUCTION
1135 SkDebugf("path.close();\n");
1136 #endif
1137 fPathPtr->close();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001138 fCloses++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001139 }
1140 init();
1141 }
1142
1143 void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
1144 lineTo();
1145 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001146 fDefer[1] = pt3;
1147 nudge();
1148 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001149#if DEBUG_PATH_CONSTRUCTION
1150 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001151 pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001152#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001153 fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001154 fEmpty = false;
1155 }
1156
1157 void deferredLine(const SkPoint& pt) {
1158 if (pt == fDefer[1]) {
1159 return;
1160 }
1161 if (changedSlopes(pt)) {
1162 lineTo();
1163 fDefer[0] = fDefer[1];
1164 }
1165 fDefer[1] = pt;
1166 }
1167
1168 void deferredMove(const SkPoint& pt) {
1169 fMoved = true;
1170 fHasMove = true;
1171 fEmpty = true;
1172 fDefer[0] = fDefer[1] = pt;
1173 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001174
caryclark@google.comf839c032012-10-26 21:03:50 +00001175 void deferredMoveLine(const SkPoint& pt) {
1176 if (!fHasMove) {
1177 deferredMove(pt);
1178 }
1179 deferredLine(pt);
1180 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001181
caryclark@google.comf839c032012-10-26 21:03:50 +00001182 bool hasMove() const {
1183 return fHasMove;
1184 }
1185
1186 void init() {
1187 fEmpty = true;
1188 fHasMove = false;
1189 fMoved = false;
1190 }
1191
1192 bool isClosed() const {
1193 return !fEmpty && fFirstPt == fDefer[1];
1194 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001195
caryclark@google.comf839c032012-10-26 21:03:50 +00001196 void lineTo() {
1197 if (fDefer[0] == fDefer[1]) {
1198 return;
1199 }
1200 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001201 nudge();
caryclark@google.comf839c032012-10-26 21:03:50 +00001202 fEmpty = false;
1203#if DEBUG_PATH_CONSTRUCTION
1204 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
1205#endif
1206 fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
1207 fDefer[0] = fDefer[1];
1208 }
1209
1210 const SkPath* nativePath() const {
1211 return fPathPtr;
1212 }
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +00001213
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001214 void nudge() {
1215 if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX)
1216 || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) {
1217 return;
1218 }
1219 fDefer[1] = fFirstPt;
1220 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001221
1222 void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
1223 lineTo();
1224 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001225 fDefer[1] = pt2;
1226 nudge();
1227 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001228#if DEBUG_PATH_CONSTRUCTION
1229 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001230 pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001231#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001232 fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001233 fEmpty = false;
1234 }
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00001235
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001236 bool someAssemblyRequired() const {
1237 return fCloses < fMoves;
1238 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001239
1240protected:
1241 bool changedSlopes(const SkPoint& pt) const {
1242 if (fDefer[0] == fDefer[1]) {
1243 return false;
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001244 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001245 SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
1246 SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
1247 SkScalar lineDx = pt.fX - fDefer[1].fX;
1248 SkScalar lineDy = pt.fY - fDefer[1].fY;
1249 return deferDx * lineDy != deferDy * lineDx;
1250 }
1251
1252 void moveTo() {
1253 if (!fMoved) {
1254 return;
1255 }
1256 fFirstPt = fDefer[0];
1257#if DEBUG_PATH_CONSTRUCTION
1258 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
1259#endif
1260 fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
1261 fMoved = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001262 fMoves++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001263 }
1264
1265private:
1266 SkPath* fPathPtr;
1267 SkPoint fDefer[2];
1268 SkPoint fFirstPt;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001269 int fCloses;
1270 int fMoves;
caryclark@google.comf839c032012-10-26 21:03:50 +00001271 bool fEmpty;
1272 bool fHasMove;
1273 bool fMoved;
1274};
1275
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001276class Segment {
1277public:
1278 Segment() {
1279#if DEBUG_DUMP
1280 fID = ++gSegmentID;
1281#endif
1282 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00001283
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001284 bool operator<(const Segment& rh) const {
1285 return fBounds.fTop < rh.fBounds.fTop;
1286 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001287
caryclark@google.com4eeda372012-12-06 21:47:48 +00001288 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001289 if (activeAngleInner(index, done, angles)) {
1290 return true;
1291 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001292 int lesser = index;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001293 while (--lesser >= 0 && equalPoints(index, lesser)) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001294 if (activeAngleOther(lesser, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001295 return true;
1296 }
1297 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001298 lesser = index;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001299 do {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001300 if (activeAngleOther(index, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001301 return true;
1302 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001303 } while (++index < fTs.count() && equalPoints(index, lesser));
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001304 return false;
1305 }
1306
caryclark@google.com4eeda372012-12-06 21:47:48 +00001307 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001308 Span* span = &fTs[index];
1309 Segment* other = span->fOther;
1310 int oIndex = span->fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001311 return other->activeAngleInner(oIndex, done, angles);
1312 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001313
caryclark@google.com4eeda372012-12-06 21:47:48 +00001314 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001315 int next = nextExactSpan(index, 1);
caryclark@google.com9764cc62012-07-12 19:29:45 +00001316 if (next > 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001317 Span& upSpan = fTs[index];
1318 if (upSpan.fWindValue || upSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001319 addAngle(angles, index, next);
caryclark@google.comf839c032012-10-26 21:03:50 +00001320 if (upSpan.fDone || upSpan.fUnsortableEnd) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001321 done++;
1322 } else if (upSpan.fWindSum != SK_MinS32) {
1323 return true;
1324 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001325 } else if (!upSpan.fDone) {
1326 upSpan.fDone = true;
1327 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001328 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001329 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001330 int prev = nextExactSpan(index, -1);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001331 // edge leading into junction
caryclark@google.com9764cc62012-07-12 19:29:45 +00001332 if (prev >= 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001333 Span& downSpan = fTs[prev];
1334 if (downSpan.fWindValue || downSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001335 addAngle(angles, index, prev);
1336 if (downSpan.fDone) {
1337 done++;
1338 } else if (downSpan.fWindSum != SK_MinS32) {
1339 return true;
1340 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001341 } else if (!downSpan.fDone) {
1342 downSpan.fDone = true;
1343 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001344 }
1345 }
1346 return false;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001347 }
1348
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001349 SkPoint activeLeftTop(bool onlySortable, int* firstT) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001350 SkASSERT(!done());
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001351 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001352 int count = fTs.count();
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001353 // see if either end is not done since we want smaller Y of the pair
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001354 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00001355 bool lastUnsortable = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001356 double lastT = -1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001357 for (int index = 0; index < count; ++index) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001358 const Span& span = fTs[index];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001359 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001360 goto next;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001361 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001362 if (span.fDone && lastDone) {
1363 goto next;
1364 }
1365 if (approximately_negative(span.fT - lastT)) {
1366 goto next;
1367 }
1368 {
1369 const SkPoint& xy = xyAtT(&span);
1370 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
1371 topPt = xy;
1372 if (firstT) {
1373 *firstT = index;
1374 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001375 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001376 if (fVerb != SkPath::kLine_Verb && !lastDone) {
1377 SkPoint curveTop = (*SegmentTop[fVerb])(fPts, lastT, span.fT);
1378 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
1379 && topPt.fX > curveTop.fX)) {
1380 topPt = curveTop;
1381 if (firstT) {
1382 *firstT = index;
1383 }
1384 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001385 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001386 lastT = span.fT;
caryclark@google.comf839c032012-10-26 21:03:50 +00001387 }
1388 next:
1389 lastDone = span.fDone;
1390 lastUnsortable = span.fUnsortableEnd;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001391 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001392 return topPt;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001393 }
1394
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001395 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
1396 int sumMiWinding = updateWinding(endIndex, index);
1397 int sumSuWinding = updateOppWinding(endIndex, index);
1398 if (fOperand) {
1399 SkTSwap<int>(sumMiWinding, sumSuWinding);
1400 }
1401 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1402 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001403 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001404 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001405
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001406 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00001407 int& sumMiWinding, int& sumSuWinding,
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001408 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
1409 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1410 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001411 bool miFrom;
1412 bool miTo;
1413 bool suFrom;
1414 bool suTo;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001415 if (operand()) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001416 miFrom = (oppMaxWinding & xorMiMask) != 0;
1417 miTo = (oppSumWinding & xorMiMask) != 0;
1418 suFrom = (maxWinding & xorSuMask) != 0;
1419 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001420 } else {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001421 miFrom = (maxWinding & xorMiMask) != 0;
1422 miTo = (sumWinding & xorMiMask) != 0;
1423 suFrom = (oppMaxWinding & xorSuMask) != 0;
1424 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001425 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001426 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
caryclark@google.combeda3892013-02-07 13:13:41 +00001427#if DEBUG_ACTIVE_OP
1428 SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__,
1429 kShapeOpStr[op], miFrom, miTo, suFrom, suTo, result);
1430#endif
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001431 SkASSERT(result != -1);
1432 return result;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001433 }
1434
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001435 bool activeWinding(int index, int endIndex) {
1436 int sumWinding = updateWinding(endIndex, index);
1437 int maxWinding;
1438 return activeWinding(index, endIndex, maxWinding, sumWinding);
1439 }
1440
1441 bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
1442 setUpWinding(index, endIndex, maxWinding, sumWinding);
1443 bool from = maxWinding != 0;
1444 bool to = sumWinding != 0;
1445 bool result = gUnaryActiveEdge[from][to];
1446 SkASSERT(result != -1);
1447 return result;
1448 }
1449
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001450 void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001451 SkASSERT(start != end);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001452 Angle* angle = angles.append();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001453#if DEBUG_ANGLE
caryclark@google.com31143cf2012-11-09 22:14:19 +00001454 if (angles.count() > 1 && !fTs[start].fTiny) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001455 SkPoint angle0Pt, newPt;
1456 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
1457 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
1458 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
caryclark@google.com6d0032a2013-01-04 19:41:13 +00001459 SkASSERT(AlmostEqualUlps(angle0Pt.fX, newPt.fX));
1460 SkASSERT(AlmostEqualUlps(angle0Pt.fY, newPt.fY));
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001461 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001462#endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001463 angle->set(fPts, fVerb, this, start, end, fTs);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001464 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001465
caryclark@google.com2ddff932012-08-07 21:25:27 +00001466 void addCancelOutsides(double tStart, double oStart, Segment& other,
caryclark@google.comcc905052012-07-25 20:59:42 +00001467 double oEnd) {
1468 int tIndex = -1;
1469 int tCount = fTs.count();
1470 int oIndex = -1;
1471 int oCount = other.fTs.count();
caryclark@google.comcc905052012-07-25 20:59:42 +00001472 do {
1473 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001474 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001475 int tIndexStart = tIndex;
1476 do {
1477 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001478 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001479 int oIndexStart = oIndex;
1480 double nextT;
1481 do {
1482 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001483 } while (nextT < 1 && approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001484 double oNextT;
1485 do {
1486 oNextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001487 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001488 // at this point, spans before and after are at:
1489 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1490 // if tIndexStart == 0, no prior span
1491 // if nextT == 1, no following span
rmistry@google.comd6176b02012-08-23 18:14:13 +00001492
caryclark@google.comcc905052012-07-25 20:59:42 +00001493 // advance the span with zero winding
1494 // if the following span exists (not past the end, non-zero winding)
1495 // connect the two edges
1496 if (!fTs[tIndexStart].fWindValue) {
1497 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1498 #if DEBUG_CONCIDENT
1499 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1500 __FUNCTION__, fID, other.fID, tIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001501 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
1502 xyAtT(tIndexStart).fY);
caryclark@google.comcc905052012-07-25 20:59:42 +00001503 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001504 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false,
1505 fTs[tIndexStart].fPt);
caryclark@google.comcc905052012-07-25 20:59:42 +00001506 }
1507 if (nextT < 1 && fTs[tIndex].fWindValue) {
1508 #if DEBUG_CONCIDENT
1509 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1510 __FUNCTION__, fID, other.fID, tIndex,
1511 fTs[tIndex].fT, xyAtT(tIndex).fX,
1512 xyAtT(tIndex).fY);
1513 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001514 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false, fTs[tIndex].fPt);
caryclark@google.comcc905052012-07-25 20:59:42 +00001515 }
1516 } else {
1517 SkASSERT(!other.fTs[oIndexStart].fWindValue);
1518 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1519 #if DEBUG_CONCIDENT
1520 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1521 __FUNCTION__, fID, other.fID, oIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001522 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
1523 other.xyAtT(oIndexStart).fY);
1524 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
caryclark@google.comcc905052012-07-25 20:59:42 +00001525 #endif
caryclark@google.comcc905052012-07-25 20:59:42 +00001526 }
1527 if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1528 #if DEBUG_CONCIDENT
1529 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1530 __FUNCTION__, fID, other.fID, oIndex,
1531 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1532 other.xyAtT(oIndex).fY);
1533 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1534 #endif
1535 }
1536 }
1537 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001538
caryclark@google.comcc905052012-07-25 20:59:42 +00001539 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1540 double oEnd) {
1541 // walk this to outsideTs[0]
1542 // walk other to outsideTs[1]
1543 // if either is > 0, add a pointer to the other, copying adjacent winding
1544 int tIndex = -1;
1545 int oIndex = -1;
1546 double tStart = outsideTs[0];
1547 double oStart = outsideTs[1];
1548 do {
1549 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001550 } while (!approximately_negative(tStart - fTs[tIndex].fT));
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001551 SkPoint ptStart = fTs[tIndex].fPt;
caryclark@google.comcc905052012-07-25 20:59:42 +00001552 do {
1553 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001554 } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001555 if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001556 addTPair(tStart, other, oStart, false, ptStart);
caryclark@google.comcc905052012-07-25 20:59:42 +00001557 }
1558 tStart = fTs[tIndex].fT;
1559 oStart = other.fTs[oIndex].fT;
1560 do {
1561 double nextT;
1562 do {
1563 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001564 } while (approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001565 tStart = nextT;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001566 ptStart = fTs[tIndex].fPt;
caryclark@google.comcc905052012-07-25 20:59:42 +00001567 do {
1568 nextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001569 } while (approximately_negative(nextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001570 oStart = nextT;
caryclark@google.com4eeda372012-12-06 21:47:48 +00001571 if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001572 break;
1573 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001574 addTPair(tStart, other, oStart, false, ptStart);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001575 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001576 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001577
caryclark@google.com4eeda372012-12-06 21:47:48 +00001578 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
1579 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001580 fBounds.setCubicBounds(pts);
1581 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001582
caryclark@google.comf839c032012-10-26 21:03:50 +00001583 /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001584 SkPoint edge[4];
caryclark@google.comf839c032012-10-26 21:03:50 +00001585 const SkPoint* ePtr;
1586 int lastT = fTs.count() - 1;
1587 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1588 ePtr = fPts;
1589 } else {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001590 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001591 subDivide(start, end, edge);
caryclark@google.comf839c032012-10-26 21:03:50 +00001592 ePtr = edge;
1593 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001594 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001595 bool reverse = ePtr == fPts && start != 0;
1596 if (reverse) {
1597 path.deferredMoveLine(ePtr[fVerb]);
1598 switch (fVerb) {
1599 case SkPath::kLine_Verb:
1600 path.deferredLine(ePtr[0]);
1601 break;
1602 case SkPath::kQuad_Verb:
1603 path.quadTo(ePtr[1], ePtr[0]);
1604 break;
1605 case SkPath::kCubic_Verb:
1606 path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1607 break;
1608 default:
1609 SkASSERT(0);
1610 }
1611 // return ePtr[0];
1612 } else {
1613 path.deferredMoveLine(ePtr[0]);
1614 switch (fVerb) {
1615 case SkPath::kLine_Verb:
1616 path.deferredLine(ePtr[1]);
1617 break;
1618 case SkPath::kQuad_Verb:
1619 path.quadTo(ePtr[1], ePtr[2]);
1620 break;
1621 case SkPath::kCubic_Verb:
1622 path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1623 break;
1624 default:
1625 SkASSERT(0);
1626 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001627 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001628 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001629 // return ePtr[fVerb];
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001630 }
1631
caryclark@google.com4eeda372012-12-06 21:47:48 +00001632 void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
1633 init(pts, SkPath::kLine_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001634 fBounds.set(pts, 2);
1635 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001636
caryclark@google.comf839c032012-10-26 21:03:50 +00001637#if 0
1638 const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001639 const SkPoint& pt = xyAtT(tIndex);
1640 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001641 path.deferredMove(pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001642 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00001643 return pt;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001644 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001645#endif
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001646
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001647 // add 2 to edge or out of range values to get T extremes
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001648 void addOtherT(int index, double otherT, int otherIndex) {
1649 Span& span = fTs[index];
caryclark@google.comf839c032012-10-26 21:03:50 +00001650 #if PIN_ADD_T
caryclark@google.com185c7c42012-10-19 18:26:24 +00001651 if (precisely_less_than_zero(otherT)) {
1652 otherT = 0;
1653 } else if (precisely_greater_than_one(otherT)) {
1654 otherT = 1;
1655 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001656 #endif
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001657 span.fOtherT = otherT;
1658 span.fOtherIndex = otherIndex;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001659 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001660
caryclark@google.com4eeda372012-12-06 21:47:48 +00001661 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
1662 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001663 fBounds.setQuadBounds(pts);
1664 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001665
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001666 // Defer all coincident edge processing until
1667 // after normal intersections have been computed
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001668
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001669// no need to be tricky; insert in normal T order
1670// resolve overlapping ts when considering coincidence later
1671
1672 // add non-coincident intersection. Resulting edges are sorted in T.
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001673 int addT(Segment* other, const SkPoint& pt, double& newT) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001674 // FIXME: in the pathological case where there is a ton of intercepts,
1675 // binary search?
1676 int insertedAt = -1;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001677 size_t tCount = fTs.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00001678 #if PIN_ADD_T
caryclark@google.comc899ad92012-08-23 15:24:42 +00001679 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
caryclark@google.com185c7c42012-10-19 18:26:24 +00001680 if (precisely_less_than_zero(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001681 newT = 0;
caryclark@google.com185c7c42012-10-19 18:26:24 +00001682 } else if (precisely_greater_than_one(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001683 newT = 1;
1684 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001685 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001686 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001687 // OPTIMIZATION: if there are three or more identical Ts, then
1688 // the fourth and following could be further insertion-sorted so
1689 // that all the edges are clockwise or counterclockwise.
1690 // This could later limit segment tests to the two adjacent
1691 // neighbors, although it doesn't help with determining which
1692 // circular direction to go in.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001693 if (newT < fTs[index].fT) {
1694 insertedAt = index;
1695 break;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001696 }
1697 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001698 Span* span;
1699 if (insertedAt >= 0) {
1700 span = fTs.insert(insertedAt);
1701 } else {
1702 insertedAt = tCount;
1703 span = fTs.append();
1704 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001705 span->fT = newT;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001706 span->fOther = other;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001707 span->fPt = pt;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001708 span->fWindSum = SK_MinS32;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001709 span->fOppSum = SK_MinS32;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001710 span->fWindValue = 1;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001711 span->fOppValue = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00001712 span->fTiny = false;
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00001713 span->fLoop = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001714 if ((span->fDone = newT == 1)) {
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00001715 ++fDoneSpans;
rmistry@google.comd6176b02012-08-23 18:14:13 +00001716 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001717 span->fUnsortableStart = false;
1718 span->fUnsortableEnd = false;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001719 int less = -1;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001720 while (&span[less + 1] - fTs.begin() > 0 && xyAtT(&span[less]) == xyAtT(span)) {
1721#if 1
1722 if (span[less].fDone) {
1723 break;
1724 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001725 double tInterval = newT - span[less].fT;
1726 if (precisely_negative(tInterval)) {
1727 break;
1728 }
1729 if (fVerb == SkPath::kCubic_Verb) {
1730 double tMid = newT - tInterval / 2;
1731 _Point midPt;
1732 CubicXYAtT(fPts, tMid, &midPt);
1733 if (!midPt.approximatelyEqual(xyAtT(span))) {
1734 break;
1735 }
1736 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001737 span[less].fTiny = true;
1738 span[less].fDone = true;
1739 if (approximately_negative(newT - span[less].fT)) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00001740 if (approximately_greater_than_one(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001741 span[less].fUnsortableStart = true;
1742 span[less - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001743 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001744 if (approximately_less_than_zero(span[less].fT)) {
1745 span[less + 1].fUnsortableStart = true;
1746 span[less].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001747 }
1748 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001749 ++fDoneSpans;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001750#else
1751 double tInterval = newT - span[less].fT;
1752 if (precisely_negative(tInterval)) {
1753 break;
1754 }
1755 if (fVerb == SkPath::kCubic_Verb) {
1756 double tMid = newT - tInterval / 2;
1757 _Point midPt;
1758 CubicXYAtT(fPts, tMid, &midPt);
1759 if (!midPt.approximatelyEqual(xyAtT(span))) {
1760 break;
1761 }
1762 }
1763 SkASSERT(span[less].fDone == span->fDone);
1764 if (span[less].fT == 0) {
1765 span->fT = newT = 0;
1766 } else {
1767 setSpanT(less, newT);
1768 }
1769#endif
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001770 --less;
caryclark@google.comf839c032012-10-26 21:03:50 +00001771 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001772 int more = 1;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001773 while (fTs.end() - &span[more - 1] > 1 && xyAtT(&span[more]) == xyAtT(span)) {
1774#if 1
1775 if (span[more - 1].fDone) {
1776 break;
1777 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001778 double tEndInterval = span[more].fT - newT;
1779 if (precisely_negative(tEndInterval)) {
1780 break;
1781 }
1782 if (fVerb == SkPath::kCubic_Verb) {
1783 double tMid = newT - tEndInterval / 2;
1784 _Point midEndPt;
1785 CubicXYAtT(fPts, tMid, &midEndPt);
1786 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
1787 break;
1788 }
1789 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001790 span[more - 1].fTiny = true;
1791 span[more - 1].fDone = true;
1792 if (approximately_negative(span[more].fT - newT)) {
1793 if (approximately_greater_than_one(span[more].fT)) {
1794 span[more + 1].fUnsortableStart = true;
1795 span[more].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001796 }
1797 if (approximately_less_than_zero(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001798 span[more].fUnsortableStart = true;
1799 span[more - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001800 }
1801 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001802 ++fDoneSpans;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001803#else
1804 double tEndInterval = span[more].fT - newT;
1805 if (precisely_negative(tEndInterval)) {
1806 break;
1807 }
1808 if (fVerb == SkPath::kCubic_Verb) {
1809 double tMid = newT - tEndInterval / 2;
1810 _Point midEndPt;
1811 CubicXYAtT(fPts, tMid, &midEndPt);
1812 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
1813 break;
1814 }
1815 }
1816 SkASSERT(span[more - 1].fDone == span[more].fDone);
1817 if (newT == 0) {
1818 setSpanT(more, 0);
1819 } else {
1820 span->fT = newT = span[more].fT;
1821 }
1822#endif
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001823 ++more;
caryclark@google.comf839c032012-10-26 21:03:50 +00001824 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001825 return insertedAt;
1826 }
1827
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001828 // set spans from start to end to decrement by one
1829 // note this walks other backwards
1830 // FIMXE: there's probably an edge case that can be constructed where
1831 // two span in one segment are separated by float epsilon on one span but
1832 // not the other, if one segment is very small. For this
1833 // case the counts asserted below may or may not be enough to separate the
caryclark@google.com2ddff932012-08-07 21:25:27 +00001834 // spans. Even if the counts work out, what if the spans aren't correctly
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001835 // sorted? It feels better in such a case to match the span's other span
1836 // pointer since both coincident segments must contain the same spans.
1837 void addTCancel(double startT, double endT, Segment& other,
1838 double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001839 SkASSERT(!approximately_negative(endT - startT));
1840 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00001841 bool binary = fOperand != other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001842 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001843 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001844 ++index;
1845 }
caryclark@google.comb9738012012-07-03 19:53:30 +00001846 int oIndex = other.fTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001847 while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001848 ;
caryclark@google.com59823f72012-08-09 18:17:47 +00001849 double tRatio = (oEndT - oStartT) / (endT - startT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001850 Span* test = &fTs[index];
1851 Span* oTest = &other.fTs[oIndex];
caryclark@google.com18063442012-07-25 12:05:18 +00001852 SkTDArray<double> outsideTs;
1853 SkTDArray<double> oOutsideTs;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001854 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001855 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
caryclark@google.comcc905052012-07-25 20:59:42 +00001856 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.com200c2112012-08-03 15:05:04 +00001857 double testT = test->fT;
1858 double oTestT = oTest->fT;
1859 Span* span = test;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001860 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001861 if (decrement) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001862 decrementSpan(span);
caryclark@google.com200c2112012-08-03 15:05:04 +00001863 } else if (track && span->fT < 1 && oTestT < 1) {
1864 TrackOutside(outsideTs, span->fT, oTestT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001865 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001866 span = &fTs[++index];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001867 } while (approximately_negative(span->fT - testT));
caryclark@google.com200c2112012-08-03 15:05:04 +00001868 Span* oSpan = oTest;
caryclark@google.com59823f72012-08-09 18:17:47 +00001869 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1870 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1871 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001872 while (approximately_negative(otherTMatchStart - oSpan->fT)
1873 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
caryclark@google.com03f97062012-08-21 13:13:52 +00001874 #ifdef SK_DEBUG
caryclark@google.com59823f72012-08-09 18:17:47 +00001875 SkASSERT(originalWindValue == oSpan->fWindValue);
caryclark@google.com03f97062012-08-21 13:13:52 +00001876 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001877 if (decrement) {
caryclark@google.com200c2112012-08-03 15:05:04 +00001878 other.decrementSpan(oSpan);
1879 } else if (track && oSpan->fT < 1 && testT < 1) {
1880 TrackOutside(oOutsideTs, oSpan->fT, testT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001881 }
1882 if (!oIndex) {
1883 break;
1884 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001885 oSpan = &other.fTs[--oIndex];
rmistry@google.comd6176b02012-08-23 18:14:13 +00001886 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001887 test = span;
1888 oTest = oSpan;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001889 } while (!approximately_negative(endT - test->fT));
1890 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
caryclark@google.com18063442012-07-25 12:05:18 +00001891 // FIXME: determine if canceled edges need outside ts added
caryclark@google.comcc905052012-07-25 20:59:42 +00001892 if (!done() && outsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001893 double tStart = outsideTs[0];
1894 double oStart = outsideTs[1];
1895 addCancelOutsides(tStart, oStart, other, oEndT);
1896 int count = outsideTs.count();
1897 if (count > 2) {
1898 double tStart = outsideTs[count - 2];
1899 double oStart = outsideTs[count - 1];
1900 addCancelOutsides(tStart, oStart, other, oEndT);
1901 }
caryclark@google.com18063442012-07-25 12:05:18 +00001902 }
caryclark@google.comcc905052012-07-25 20:59:42 +00001903 if (!other.done() && oOutsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001904 double tStart = oOutsideTs[0];
1905 double oStart = oOutsideTs[1];
1906 other.addCancelOutsides(tStart, oStart, *this, endT);
caryclark@google.com18063442012-07-25 12:05:18 +00001907 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001908 }
skia.committer@gmail.com631cdcb2013-03-01 12:12:55 +00001909
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00001910 int addSelfT(Segment* other, const SkPoint& pt, double& newT) {
1911 int result = addT(other, pt, newT);
1912 Span* span = &fTs[result];
1913 span->fLoop = true;
1914 return result;
1915 }
skia.committer@gmail.com15dd3002013-01-18 07:07:28 +00001916
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001917 int addUnsortableT(Segment* other, bool start, const SkPoint& pt, double& newT) {
1918 int result = addT(other, pt, newT);
caryclark@google.com73ca6242013-01-17 21:02:47 +00001919 Span* span = &fTs[result];
1920 if (start) {
1921 if (result > 0) {
1922 span[result - 1].fUnsortableEnd = true;
1923 }
1924 span[result].fUnsortableStart = true;
1925 } else {
1926 span[result].fUnsortableEnd = true;
1927 if (result + 1 < fTs.count()) {
1928 span[result + 1].fUnsortableStart = true;
1929 }
1930 }
1931 return result;
1932 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00001933
caryclark@google.com4eeda372012-12-06 21:47:48 +00001934 int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1935 SkTDArray<double>& outsideTs) {
1936 int oWindValue = oTest->fWindValue;
1937 int oOppValue = oTest->fOppValue;
1938 if (opp) {
1939 SkTSwap<int>(oWindValue, oOppValue);
1940 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001941 Span* const test = &fTs[index];
1942 Span* end = test;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001943 const double oStartT = oTest->fT;
1944 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001945 if (bumpSpan(end, oWindValue, oOppValue)) {
1946 TrackOutside(outsideTs, end->fT, oStartT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001947 }
1948 end = &fTs[++index];
1949 } while (approximately_negative(end->fT - test->fT));
1950 return index;
1951 }
1952
1953 // because of the order in which coincidences are resolved, this and other
1954 // may not have the same intermediate points. Compute the corresponding
1955 // intermediate T values (using this as the master, other as the follower)
1956 // and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com4eeda372012-12-06 21:47:48 +00001957 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1958 SkTDArray<double>& oOutsideTs) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001959 Span* const oTest = &fTs[oIndex];
1960 Span* oEnd = oTest;
1961 const double startT = test->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001962 const double oStartT = oTest->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001963 while (!approximately_negative(oEndT - oEnd->fT)
caryclark@google.com4eeda372012-12-06 21:47:48 +00001964 && approximately_negative(oEnd->fT - oStartT)) {
1965 zeroSpan(oEnd);
1966 TrackOutside(oOutsideTs, oEnd->fT, startT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001967 oEnd = &fTs[++oIndex];
1968 }
1969 return oIndex;
1970 }
1971
1972 // FIXME: need to test this case:
1973 // contourA has two segments that are coincident
1974 // contourB has two segments that are coincident in the same place
1975 // each ends up with +2/0 pairs for winding count
1976 // since logic below doesn't transfer count (only increments/decrements) can this be
1977 // resolved to +4/0 ?
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001978
1979 // set spans from start to end to increment the greater by one and decrement
1980 // the lesser
caryclark@google.com4eeda372012-12-06 21:47:48 +00001981 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001982 SkASSERT(!approximately_negative(endT - startT));
1983 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001984 bool opp = fOperand ^ other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001985 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001986 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001987 ++index;
1988 }
1989 int oIndex = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001990 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001991 ++oIndex;
1992 }
1993 Span* test = &fTs[index];
1994 Span* oTest = &other.fTs[oIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001995 SkTDArray<double> outsideTs;
1996 SkTDArray<double> oOutsideTs;
1997 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001998 // if either span has an opposite value and the operands don't match, resolve first
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001999 // SkASSERT(!test->fDone || !oTest->fDone);
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002000 if (test->fDone || oTest->fDone) {
2001 index = advanceCoincidentThis(oTest, opp, index);
2002 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
2003 } else {
2004 index = bumpCoincidentThis(oTest, opp, index, outsideTs);
2005 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
2006 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002007 test = &fTs[index];
2008 oTest = &other.fTs[oIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002009 } while (!approximately_negative(endT - test->fT));
2010 SkASSERT(approximately_negative(oTest->fT - oEndT));
2011 SkASSERT(approximately_negative(oEndT - oTest->fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00002012 if (!done() && outsideTs.count()) {
2013 addCoinOutsides(outsideTs, other, oEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002014 }
2015 if (!other.done() && oOutsideTs.count()) {
caryclark@google.comcc905052012-07-25 20:59:42 +00002016 other.addCoinOutsides(oOutsideTs, *this, endT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002017 }
2018 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002019
caryclark@google.comcc905052012-07-25 20:59:42 +00002020 // FIXME: this doesn't prevent the same span from being added twice
caryclark@google.comaa358312013-01-29 20:28:49 +00002021 // fix in caller, SkASSERT here?
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002022 void addTPair(double t, Segment& other, double otherT, bool borrowWind, const SkPoint& pt) {
caryclark@google.comcc905052012-07-25 20:59:42 +00002023 int tCount = fTs.count();
2024 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
2025 const Span& span = fTs[tIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002026 if (!approximately_negative(span.fT - t)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00002027 break;
2028 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00002029 if (approximately_negative(span.fT - t) && span.fOther == &other
2030 && approximately_equal(span.fOtherT, otherT)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00002031#if DEBUG_ADD_T_PAIR
2032 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
2033 __FUNCTION__, fID, t, other.fID, otherT);
2034#endif
2035 return;
2036 }
2037 }
caryclark@google.com47580692012-07-23 12:14:49 +00002038#if DEBUG_ADD_T_PAIR
2039 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
2040 __FUNCTION__, fID, t, other.fID, otherT);
2041#endif
caryclark@google.com7ff5c842013-02-26 15:56:05 +00002042 int insertedAt = addT(&other, pt, t);
2043 int otherInsertedAt = other.addT(this, pt, otherT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002044 addOtherT(insertedAt, otherT, otherInsertedAt);
caryclark@google.comb9738012012-07-03 19:53:30 +00002045 other.addOtherT(otherInsertedAt, t, insertedAt);
caryclark@google.com2ddff932012-08-07 21:25:27 +00002046 matchWindingValue(insertedAt, t, borrowWind);
2047 other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002048 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002049
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002050 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002051 // add edge leading into junction
caryclark@google.com4eeda372012-12-06 21:47:48 +00002052 int min = SkMin32(end, start);
2053 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002054 addAngle(angles, end, start);
2055 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002056 // add edge leading away from junction
caryclark@google.com495f8e42012-05-31 13:13:11 +00002057 int step = SkSign32(end - start);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002058 int tIndex = nextExactSpan(end, step);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002059 min = SkMin32(end, tIndex);
2060 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002061 addAngle(angles, end, tIndex);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002062 }
2063 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002064
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002065 int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
2066 Span* const test = &fTs[index];
2067 Span* end = test;
2068 do {
2069 end = &fTs[++index];
2070 } while (approximately_negative(end->fT - test->fT));
2071 return index;
2072 }
2073
2074 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
2075 Span* const oTest = &fTs[oIndex];
2076 Span* oEnd = oTest;
2077 const double oStartT = oTest->fT;
2078 while (!approximately_negative(oEndT - oEnd->fT)
2079 && approximately_negative(oEnd->fT - oStartT)) {
2080 oEnd = &fTs[++oIndex];
2081 }
2082 return oIndex;
2083 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00002084
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002085 bool betweenTs(int lesser, double testT, int greater) {
2086 if (lesser > greater) {
2087 SkTSwap<int>(lesser, greater);
2088 }
2089 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
2090 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002091
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002092 const Bounds& bounds() const {
2093 return fBounds;
2094 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002095
caryclark@google.com31143cf2012-11-09 22:14:19 +00002096 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002097 double referenceT = fTs[index].fT;
2098 int lesser = index;
caryclark@google.com31143cf2012-11-09 22:14:19 +00002099 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
2100 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00002101 buildAnglesInner(lesser, angles);
2102 }
2103 do {
2104 buildAnglesInner(index, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002105 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
2106 && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002107 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002108
2109 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
caryclark@google.com1ab0aac2013-03-13 20:41:48 +00002110 const Span* span = &fTs[index];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002111 Segment* other = span->fOther;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002112 // if there is only one live crossing, and no coincidence, continue
2113 // in the same direction
2114 // if there is coincidence, the only choice may be to reverse direction
2115 // find edge on either side of intersection
2116 int oIndex = span->fOtherIndex;
2117 // if done == -1, prior span has already been processed
2118 int step = 1;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002119 int next = other->nextExactSpan(oIndex, step);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002120 if (next < 0) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002121 step = -step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002122 next = other->nextExactSpan(oIndex, step);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002123 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002124 // add candidate into and away from junction
2125 other->addTwoAngles(next, oIndex, angles);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002126 }
2127
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002128 int computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002129 SkTDArray<Angle> angles;
2130 addTwoAngles(startIndex, endIndex, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002131 buildAngles(endIndex, angles, false);
caryclark@google.comd1688742012-09-18 20:08:37 +00002132 // OPTIMIZATION: check all angles to see if any have computed wind sum
2133 // before sorting (early exit if none)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002134 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002135 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002136#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002137 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002138#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002139 if (!sortable) {
2140 return SK_MinS32;
2141 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002142 int angleCount = angles.count();
2143 const Angle* angle;
2144 const Segment* base;
2145 int winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002146 int oWinding;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002147 int firstIndex = 0;
2148 do {
2149 angle = sorted[firstIndex];
2150 base = angle->segment();
2151 winding = base->windSum(angle);
2152 if (winding != SK_MinS32) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002153 oWinding = base->oppSum(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002154 break;
2155 }
2156 if (++firstIndex == angleCount) {
2157 return SK_MinS32;
2158 }
2159 } while (true);
2160 // turn winding into contourWinding
caryclark@google.com2ddff932012-08-07 21:25:27 +00002161 int spanWinding = base->spanSign(angle);
2162 bool inner = useInnerWinding(winding + spanWinding, winding);
2163 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00002164 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
caryclark@google.com59823f72012-08-09 18:17:47 +00002165 spanWinding, winding, angle->sign(), inner,
caryclark@google.com2ddff932012-08-07 21:25:27 +00002166 inner ? winding + spanWinding : winding);
2167 #endif
2168 if (inner) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002169 winding += spanWinding;
2170 }
2171 #if DEBUG_SORT
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002172 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002173 #endif
2174 int nextIndex = firstIndex + 1;
2175 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com2ddff932012-08-07 21:25:27 +00002176 winding -= base->spanSign(angle);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002177 oWinding -= base->oppSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002178 do {
2179 if (nextIndex == angleCount) {
2180 nextIndex = 0;
2181 }
2182 angle = sorted[nextIndex];
2183 Segment* segment = angle->segment();
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002184 bool opp = base->fOperand ^ segment->fOperand;
2185 int maxWinding, oMaxWinding;
2186 int spanSign = segment->spanSign(angle);
2187 int oppoSign = segment->oppSign(angle);
2188 if (opp) {
2189 oMaxWinding = oWinding;
2190 oWinding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002191 maxWinding = winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002192 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002193 winding -= oppoSign;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002194 }
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002195 } else {
2196 maxWinding = winding;
2197 winding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002198 oMaxWinding = oWinding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002199 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002200 oWinding -= oppoSign;
2201 }
2202 }
2203 if (segment->windSum(angle) == SK_MinS32) {
2204 if (opp) {
2205 if (useInnerWinding(oMaxWinding, oWinding)) {
2206 oMaxWinding = oWinding;
2207 }
2208 if (oppoSign && useInnerWinding(maxWinding, winding)) {
2209 maxWinding = winding;
2210 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002211 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002212 } else {
2213 if (useInnerWinding(maxWinding, winding)) {
2214 maxWinding = winding;
2215 }
2216 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
2217 oMaxWinding = oWinding;
2218 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002219 (void) segment->markAndChaseWinding(angle, maxWinding,
2220 binary ? oMaxWinding : 0);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002221 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002222 }
2223 } while (++nextIndex != lastIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002224 int minIndex = SkMin32(startIndex, endIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002225 return windSum(minIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002226 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002227
caryclark@google.com3586ece2012-12-27 18:46:58 +00002228 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
caryclark@google.com10227bf2012-12-28 22:10:41 +00002229 double mid, bool opp, bool current) const {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002230 SkScalar bottom = fBounds.fBottom;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002231 int bestTIndex = -1;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002232 if (bottom <= bestY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002233 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002234 }
2235 SkScalar top = fBounds.fTop;
2236 if (top >= basePt.fY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002237 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002238 }
2239 if (fBounds.fLeft > basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002240 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002241 }
2242 if (fBounds.fRight < basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002243 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002244 }
2245 if (fBounds.fLeft == fBounds.fRight) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002246 // if vertical, and directly above test point, wait for another one
caryclark@google.com6d0032a2013-01-04 19:41:13 +00002247 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002248 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002249 // intersect ray starting at basePt with edge
2250 Intersections intersections;
2251 // OPTIMIZE: use specialty function that intersects ray with curve,
2252 // returning t values only for curve (we don't care about t on ray)
2253 int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
2254 if (pts == 0 || (current && pts == 1)) {
2255 return bestTIndex;
2256 }
2257 if (current) {
2258 SkASSERT(pts > 1);
2259 int closestIdx = 0;
2260 double closest = fabs(intersections.fT[0][0] - mid);
2261 for (int idx = 1; idx < pts; ++idx) {
2262 double test = fabs(intersections.fT[0][idx] - mid);
2263 if (closest > test) {
2264 closestIdx = idx;
2265 closest = test;
2266 }
2267 }
2268 if (closestIdx < pts - 1) {
2269 intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
2270 }
2271 --pts;
2272 }
2273 double bestT = -1;
2274 for (int index = 0; index < pts; ++index) {
2275 double foundT = intersections.fT[0][index];
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002276 if (approximately_less_than_zero(foundT)
2277 || approximately_greater_than_one(foundT)) {
2278 continue;
2279 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002280 SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
2281 if (approximately_negative(testY - bestY)
2282 || approximately_negative(basePt.fY - testY)) {
caryclark@google.com47580692012-07-23 12:14:49 +00002283 continue;
2284 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002285 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002286 return SK_MinS32; // if the intersection is edge on, wait for another one
caryclark@google.com10227bf2012-12-28 22:10:41 +00002287 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002288 if (fVerb > SkPath::kLine_Verb) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002289 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
2290 if (approximately_zero(dx)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002291 return SK_MinS32; // hit vertical, wait for another one
caryclark@google.com3586ece2012-12-27 18:46:58 +00002292 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00002293 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002294 bestY = testY;
2295 bestT = foundT;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002296 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002297 if (bestT < 0) {
2298 return bestTIndex;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002299 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002300 SkASSERT(bestT >= 0);
2301 SkASSERT(bestT <= 1);
2302 int start;
2303 int end = 0;
2304 do {
2305 start = end;
2306 end = nextSpan(start, 1);
2307 } while (fTs[end].fT < bestT);
2308 // FIXME: see next candidate for a better pattern to find the next start/end pair
2309 while (start + 1 < end && fTs[start].fDone) {
2310 ++start;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002311 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002312 if (!isCanceled(start)) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002313 hitT = bestT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002314 bestTIndex = start;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002315 hitSomething = true;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002316 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002317 return bestTIndex;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002318 }
caryclark@google.com18063442012-07-25 12:05:18 +00002319
caryclark@google.com4eeda372012-12-06 21:47:48 +00002320 void decrementSpan(Span* span) {
caryclark@google.com18063442012-07-25 12:05:18 +00002321 SkASSERT(span->fWindValue > 0);
2322 if (--(span->fWindValue) == 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002323 if (!span->fOppValue && !span->fDone) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002324 span->fDone = true;
2325 ++fDoneSpans;
2326 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002327 }
2328 }
2329
2330 bool bumpSpan(Span* span, int windDelta, int oppDelta) {
2331 SkASSERT(!span->fDone);
2332 span->fWindValue += windDelta;
2333 SkASSERT(span->fWindValue >= 0);
2334 span->fOppValue += oppDelta;
2335 SkASSERT(span->fOppValue >= 0);
2336 if (fXor) {
2337 span->fWindValue &= 1;
2338 }
2339 if (fOppXor) {
2340 span->fOppValue &= 1;
2341 }
2342 if (!span->fWindValue && !span->fOppValue) {
2343 span->fDone = true;
2344 ++fDoneSpans;
caryclark@google.com18063442012-07-25 12:05:18 +00002345 return true;
2346 }
2347 return false;
2348 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002349
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002350 // OPTIMIZE
2351 // when the edges are initially walked, they don't automatically get the prior and next
2352 // edges assigned to positions t=0 and t=1. Doing that would remove the need for this check,
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002353 // and would additionally remove the need for similar checks in condition edges. It would
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002354 // also allow intersection code to assume end of segment intersections (maybe?)
2355 bool complete() const {
2356 int count = fTs.count();
2357 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
2358 }
caryclark@google.com18063442012-07-25 12:05:18 +00002359
caryclark@google.com15fa1382012-05-07 20:49:36 +00002360 bool done() const {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002361 SkASSERT(fDoneSpans <= fTs.count());
2362 return fDoneSpans == fTs.count();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002363 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002364
caryclark@google.comf839c032012-10-26 21:03:50 +00002365 bool done(int min) const {
2366 return fTs[min].fDone;
2367 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002368
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002369 bool done(const Angle* angle) const {
2370 return done(SkMin32(angle->start(), angle->end()));
caryclark@google.com47580692012-07-23 12:14:49 +00002371 }
skia.committer@gmail.com044679e2013-02-15 07:16:57 +00002372
caryclark@google.com7ff5c842013-02-26 15:56:05 +00002373 SkVector dxdy(int index) const {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002374 return (*SegmentDXDYAtT[fVerb])(fPts, fTs[index].fT);
2375 }
2376
2377 SkScalar dy(int index) const {
2378 return (*SegmentDYAtT[fVerb])(fPts, fTs[index].fT);
2379 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00002380
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002381 bool equalPoints(int greaterTIndex, int lesserTIndex) {
2382 SkASSERT(greaterTIndex >= lesserTIndex);
2383 double greaterT = fTs[greaterTIndex].fT;
2384 double lesserT = fTs[lesserTIndex].fT;
2385 if (greaterT == lesserT) {
2386 return true;
2387 }
2388 if (!approximately_negative(greaterT - lesserT)) {
2389 return false;
2390 }
2391 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2392 }
2393
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002394 /*
2395 The M and S variable name parts stand for the operators.
2396 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2397 Su stands for Subtrahend
2398 The Opp variable name part designates that the value is for the Opposite operator.
2399 Opposite values result from combining coincident spans.
2400 */
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002401
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002402 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2403 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002404 const int startIndex = nextStart;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002405 const int endIndex = nextEnd;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002406 SkASSERT(startIndex != endIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002407 const int count = fTs.count();
2408 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2409 const int step = SkSign32(endIndex - startIndex);
2410 const int end = nextExactSpan(startIndex, step);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002411 SkASSERT(end >= 0);
2412 Span* endSpan = &fTs[end];
2413 Segment* other;
2414 if (isSimple(end)) {
2415 // mark the smaller of startIndex, endIndex done, and all adjacent
2416 // spans with the same T value (but not 'other' spans)
2417 #if DEBUG_WINDING
2418 SkDebugf("%s simple\n", __FUNCTION__);
2419 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002420 int min = SkMin32(startIndex, endIndex);
2421 if (fTs[min].fDone) {
2422 return NULL;
2423 }
2424 markDoneBinary(min);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002425 other = endSpan->fOther;
2426 nextStart = endSpan->fOtherIndex;
2427 double startT = other->fTs[nextStart].fT;
2428 nextEnd = nextStart;
2429 do {
2430 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002431 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002432 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002433 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2434 return other;
2435 }
2436 // more than one viable candidate -- measure angles to find best
2437 SkTDArray<Angle> angles;
2438 SkASSERT(startIndex - endIndex != 0);
2439 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2440 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002441 buildAngles(end, angles, true);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002442 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002443 bool sortable = SortAngles(angles, sorted);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002444 int angleCount = angles.count();
2445 int firstIndex = findStartingEdge(sorted, startIndex, end);
2446 SkASSERT(firstIndex >= 0);
2447 #if DEBUG_SORT
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002448 debugShowSort(__FUNCTION__, sorted, firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002449 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002450 if (!sortable) {
2451 unsortable = true;
2452 return NULL;
2453 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002454 SkASSERT(sorted[firstIndex]->segment() == this);
2455 #if DEBUG_WINDING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002456 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2457 sorted[firstIndex]->sign());
caryclark@google.com235f56a2012-09-14 14:19:30 +00002458 #endif
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002459 int sumMiWinding = updateWinding(endIndex, startIndex);
2460 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2461 if (operand()) {
2462 SkTSwap<int>(sumMiWinding, sumSuWinding);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002463 }
2464 int nextIndex = firstIndex + 1;
2465 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2466 const Angle* foundAngle = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002467 bool foundDone = false;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002468 // iterate through the angle, and compute everyone's winding
caryclark@google.com235f56a2012-09-14 14:19:30 +00002469 Segment* nextSegment;
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00002470 int activeCount = 0;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002471 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002472 SkASSERT(nextIndex != firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002473 if (nextIndex == angleCount) {
2474 nextIndex = 0;
2475 }
2476 const Angle* nextAngle = sorted[nextIndex];
2477 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002478 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2479 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2480 nextAngle->end(), op, sumMiWinding, sumSuWinding,
2481 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00002482 if (activeAngle) {
2483 ++activeCount;
2484 if (!foundAngle || (foundDone && activeCount & 1)) {
2485 if (nextSegment->tiny(nextAngle)) {
2486 unsortable = true;
2487 return NULL;
2488 }
2489 foundAngle = nextAngle;
2490 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
2491 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002492 }
2493 if (nextSegment->done()) {
2494 continue;
2495 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002496 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2497 continue;
2498 }
2499 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2500 oppSumWinding, activeAngle, nextAngle);
2501 if (last) {
2502 *chase.append() = last;
2503#if DEBUG_WINDING
2504 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2505 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2506#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002507 }
2508 } while (++nextIndex != lastIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002509 markDoneBinary(SkMin32(startIndex, endIndex));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002510 if (!foundAngle) {
2511 return NULL;
2512 }
2513 nextStart = foundAngle->start();
2514 nextEnd = foundAngle->end();
2515 nextSegment = foundAngle->segment();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002516
caryclark@google.com235f56a2012-09-14 14:19:30 +00002517 #if DEBUG_WINDING
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002518 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2519 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002520 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002521 return nextSegment;
2522 }
caryclark@google.com47580692012-07-23 12:14:49 +00002523
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002524 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2525 bool& unsortable) {
2526 const int startIndex = nextStart;
2527 const int endIndex = nextEnd;
2528 SkASSERT(startIndex != endIndex);
2529 const int count = fTs.count();
2530 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2531 const int step = SkSign32(endIndex - startIndex);
2532 const int end = nextExactSpan(startIndex, step);
2533 SkASSERT(end >= 0);
2534 Span* endSpan = &fTs[end];
2535 Segment* other;
2536 if (isSimple(end)) {
2537 // mark the smaller of startIndex, endIndex done, and all adjacent
2538 // spans with the same T value (but not 'other' spans)
2539 #if DEBUG_WINDING
2540 SkDebugf("%s simple\n", __FUNCTION__);
2541 #endif
2542 int min = SkMin32(startIndex, endIndex);
2543 if (fTs[min].fDone) {
2544 return NULL;
2545 }
2546 markDoneUnary(min);
2547 other = endSpan->fOther;
2548 nextStart = endSpan->fOtherIndex;
2549 double startT = other->fTs[nextStart].fT;
2550 nextEnd = nextStart;
2551 do {
2552 nextEnd += step;
2553 }
2554 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2555 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2556 return other;
2557 }
2558 // more than one viable candidate -- measure angles to find best
2559 SkTDArray<Angle> angles;
2560 SkASSERT(startIndex - endIndex != 0);
2561 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2562 addTwoAngles(startIndex, end, angles);
2563 buildAngles(end, angles, true);
2564 SkTDArray<Angle*> sorted;
2565 bool sortable = SortAngles(angles, sorted);
2566 int angleCount = angles.count();
2567 int firstIndex = findStartingEdge(sorted, startIndex, end);
2568 SkASSERT(firstIndex >= 0);
2569 #if DEBUG_SORT
2570 debugShowSort(__FUNCTION__, sorted, firstIndex);
2571 #endif
2572 if (!sortable) {
2573 unsortable = true;
2574 return NULL;
2575 }
2576 SkASSERT(sorted[firstIndex]->segment() == this);
2577 #if DEBUG_WINDING
2578 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2579 sorted[firstIndex]->sign());
2580 #endif
2581 int sumWinding = updateWinding(endIndex, startIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002582 int nextIndex = firstIndex + 1;
2583 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2584 const Angle* foundAngle = NULL;
2585 bool foundDone = false;
2586 // iterate through the angle, and compute everyone's winding
2587 Segment* nextSegment;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002588 int activeCount = 0;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002589 do {
2590 SkASSERT(nextIndex != firstIndex);
2591 if (nextIndex == angleCount) {
2592 nextIndex = 0;
2593 }
2594 const Angle* nextAngle = sorted[nextIndex];
2595 nextSegment = nextAngle->segment();
2596 int maxWinding;
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00002597 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002598 maxWinding, sumWinding);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002599 if (activeAngle) {
2600 ++activeCount;
2601 if (!foundAngle || (foundDone && activeCount & 1)) {
2602 if (nextSegment->tiny(nextAngle)) {
2603 unsortable = true;
2604 return NULL;
2605 }
2606 foundAngle = nextAngle;
2607 foundDone = nextSegment->done(nextAngle);
2608 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002609 }
2610 if (nextSegment->done()) {
2611 continue;
2612 }
2613 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2614 continue;
2615 }
2616 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2617 if (last) {
2618 *chase.append() = last;
2619#if DEBUG_WINDING
2620 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2621 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2622#endif
2623 }
2624 } while (++nextIndex != lastIndex);
2625 markDoneUnary(SkMin32(startIndex, endIndex));
2626 if (!foundAngle) {
2627 return NULL;
2628 }
2629 nextStart = foundAngle->start();
2630 nextEnd = foundAngle->end();
2631 nextSegment = foundAngle->segment();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002632 #if DEBUG_WINDING
2633 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2634 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2635 #endif
2636 return nextSegment;
2637 }
2638
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002639 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002640 const int startIndex = nextStart;
2641 const int endIndex = nextEnd;
2642 SkASSERT(startIndex != endIndex);
2643 int count = fTs.count();
2644 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2645 : startIndex > 0);
2646 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002647 int end = nextExactSpan(startIndex, step);
caryclark@google.com24bec792012-08-20 12:43:57 +00002648 SkASSERT(end >= 0);
2649 Span* endSpan = &fTs[end];
2650 Segment* other;
caryclark@google.com24bec792012-08-20 12:43:57 +00002651 if (isSimple(end)) {
2652 #if DEBUG_WINDING
2653 SkDebugf("%s simple\n", __FUNCTION__);
2654 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002655 int min = SkMin32(startIndex, endIndex);
2656 if (fTs[min].fDone) {
2657 return NULL;
2658 }
2659 markDone(min, 1);
caryclark@google.com24bec792012-08-20 12:43:57 +00002660 other = endSpan->fOther;
2661 nextStart = endSpan->fOtherIndex;
2662 double startT = other->fTs[nextStart].fT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002663 #if 01 // FIXME: I don't know why the logic here is difference from the winding case
caryclark@google.com24bec792012-08-20 12:43:57 +00002664 SkDEBUGCODE(bool firstLoop = true;)
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002665 if ((approximately_less_than_zero(startT) && step < 0)
2666 || (approximately_greater_than_one(startT) && step > 0)) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002667 step = -step;
2668 SkDEBUGCODE(firstLoop = false;)
2669 }
2670 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002671 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002672 nextEnd = nextStart;
2673 do {
2674 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002675 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002676 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002677 #if 01
caryclark@google.com24bec792012-08-20 12:43:57 +00002678 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2679 break;
2680 }
caryclark@google.com03f97062012-08-21 13:13:52 +00002681 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00002682 SkASSERT(firstLoop);
caryclark@google.com03f97062012-08-21 13:13:52 +00002683 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002684 SkDEBUGCODE(firstLoop = false;)
2685 step = -step;
2686 } while (true);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002687 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002688 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2689 return other;
2690 }
2691 SkTDArray<Angle> angles;
2692 SkASSERT(startIndex - endIndex != 0);
2693 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2694 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002695 buildAngles(end, angles, false);
caryclark@google.com24bec792012-08-20 12:43:57 +00002696 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002697 bool sortable = SortAngles(angles, sorted);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002698 if (!sortable) {
2699 unsortable = true;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002700 #if DEBUG_SORT
2701 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
2702 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002703 return NULL;
2704 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002705 int angleCount = angles.count();
2706 int firstIndex = findStartingEdge(sorted, startIndex, end);
2707 SkASSERT(firstIndex >= 0);
2708 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002709 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
caryclark@google.com24bec792012-08-20 12:43:57 +00002710 #endif
2711 SkASSERT(sorted[firstIndex]->segment() == this);
2712 int nextIndex = firstIndex + 1;
2713 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002714 const Angle* foundAngle = NULL;
2715 bool foundDone = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002716 Segment* nextSegment;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002717 int activeCount = 0;
caryclark@google.com24bec792012-08-20 12:43:57 +00002718 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002719 SkASSERT(nextIndex != firstIndex);
caryclark@google.com24bec792012-08-20 12:43:57 +00002720 if (nextIndex == angleCount) {
2721 nextIndex = 0;
2722 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002723 const Angle* nextAngle = sorted[nextIndex];
caryclark@google.com24bec792012-08-20 12:43:57 +00002724 nextSegment = nextAngle->segment();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002725 ++activeCount;
2726 if (!foundAngle || (foundDone && activeCount & 1)) {
2727 if (nextSegment->tiny(nextAngle)) {
2728 unsortable = true;
2729 return NULL;
2730 }
2731 foundAngle = nextAngle;
2732 foundDone = nextSegment->done(nextAngle);
2733 }
2734 if (nextSegment->done()) {
2735 continue;
caryclark@google.com24bec792012-08-20 12:43:57 +00002736 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002737 } while (++nextIndex != lastIndex);
2738 markDone(SkMin32(startIndex, endIndex), 1);
2739 if (!foundAngle) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002740 return NULL;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002741 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002742 nextStart = foundAngle->start();
2743 nextEnd = foundAngle->end();
2744 nextSegment = foundAngle->segment();
2745 #if DEBUG_WINDING
2746 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2747 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2748 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002749 return nextSegment;
2750 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002751
2752 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2753 int angleCount = sorted.count();
2754 int firstIndex = -1;
2755 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2756 const Angle* angle = sorted[angleIndex];
2757 if (angle->segment() == this && angle->start() == end &&
2758 angle->end() == start) {
2759 firstIndex = angleIndex;
2760 break;
2761 }
2762 }
2763 return firstIndex;
2764 }
2765
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002766 // FIXME: this is tricky code; needs its own unit test
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002767 // note that fOtherIndex isn't computed yet, so it can't be used here
caryclark@google.com4eeda372012-12-06 21:47:48 +00002768 void findTooCloseToCall() {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002769 int count = fTs.count();
2770 if (count < 3) { // require t=0, x, 1 at minimum
2771 return;
2772 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002773 int matchIndex = 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002774 int moCount;
2775 Span* match;
2776 Segment* mOther;
2777 do {
2778 match = &fTs[matchIndex];
2779 mOther = match->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002780 // FIXME: allow quads, cubics to be near coincident?
2781 if (mOther->fVerb == SkPath::kLine_Verb) {
2782 moCount = mOther->fTs.count();
2783 if (moCount >= 3) {
2784 break;
2785 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002786 }
2787 if (++matchIndex >= count) {
2788 return;
2789 }
2790 } while (true); // require t=0, x, 1 at minimum
caryclark@google.com15fa1382012-05-07 20:49:36 +00002791 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002792 const SkPoint* matchPt = &xyAtT(match);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002793 // look for a pair of nearby T values that map to the same (x,y) value
2794 // if found, see if the pair of other segments share a common point. If
2795 // so, the span from here to there is coincident.
caryclark@google.com15fa1382012-05-07 20:49:36 +00002796 for (int index = matchIndex + 1; index < count; ++index) {
2797 Span* test = &fTs[index];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002798 if (test->fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002799 continue;
2800 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002801 Segment* tOther = test->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002802 if (tOther->fVerb != SkPath::kLine_Verb) {
2803 continue; // FIXME: allow quads, cubics to be near coincident?
2804 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002805 int toCount = tOther->fTs.count();
2806 if (toCount < 3) { // require t=0, x, 1 at minimum
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002807 continue;
2808 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002809 const SkPoint* testPt = &xyAtT(test);
2810 if (*matchPt != *testPt) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002811 matchIndex = index;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002812 moCount = toCount;
2813 match = test;
2814 mOther = tOther;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002815 matchPt = testPt;
2816 continue;
2817 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002818 int moStart = -1;
2819 int moEnd = -1;
2820 double moStartT, moEndT;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002821 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002822 Span& moSpan = mOther->fTs[moIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002823 if (moSpan.fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002824 continue;
2825 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002826 if (moSpan.fOther == this) {
2827 if (moSpan.fOtherT == match->fT) {
2828 moStart = moIndex;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002829 moStartT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002830 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002831 continue;
2832 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002833 if (moSpan.fOther == tOther) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002834 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002835 moStart = -1;
2836 break;
2837 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002838 SkASSERT(moEnd == -1);
2839 moEnd = moIndex;
2840 moEndT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002841 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002842 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002843 if (moStart < 0 || moEnd < 0) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002844 continue;
2845 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002846 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002847 if (approximately_equal(moStartT, moEndT)) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002848 continue;
2849 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002850 int toStart = -1;
2851 int toEnd = -1;
2852 double toStartT, toEndT;
2853 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2854 Span& toSpan = tOther->fTs[toIndex];
caryclark@google.comc899ad92012-08-23 15:24:42 +00002855 if (toSpan.fDone) {
2856 continue;
2857 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002858 if (toSpan.fOther == this) {
2859 if (toSpan.fOtherT == test->fT) {
2860 toStart = toIndex;
2861 toStartT = toSpan.fT;
2862 }
2863 continue;
2864 }
2865 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002866 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002867 moStart = -1;
2868 break;
2869 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002870 SkASSERT(toEnd == -1);
2871 toEnd = toIndex;
2872 toEndT = toSpan.fT;
2873 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002874 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002875 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2876 if (toStart <= 0 || toEnd <= 0) {
2877 continue;
2878 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002879 if (approximately_equal(toStartT, toEndT)) {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002880 continue;
2881 }
2882 // test to see if the segment between there and here is linear
2883 if (!mOther->isLinear(moStart, moEnd)
2884 || !tOther->isLinear(toStart, toEnd)) {
2885 continue;
2886 }
caryclark@google.comc899ad92012-08-23 15:24:42 +00002887 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002888 if (flipped) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002889 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002890 } else {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002891 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002892 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002893 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002894 }
2895
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002896 // FIXME: either:
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002897 // a) mark spans with either end unsortable as done, or
2898 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2899 // when encountering an unsortable span
2900
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002901 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2902 // and use more concise logic like the old edge walker code?
2903 // FIXME: this needs to deal with coincident edges
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002904 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002905 // iterate through T intersections and return topmost
2906 // topmost tangent from y-min to first pt is closer to horizontal
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002907 SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002908 int firstT = -1;
caryclark@google.comd0a19eb2013-02-19 12:49:33 +00002909 /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002910 SkASSERT(firstT >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002911 // sort the edges to find the leftmost
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002912 int step = 1;
2913 int end = nextSpan(firstT, step);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002914 if (end == -1) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002915 step = -1;
2916 end = nextSpan(firstT, step);
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00002917 SkASSERT(end != -1);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002918 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002919 // if the topmost T is not on end, or is three-way or more, find left
2920 // look for left-ness from tLeft to firstT (matching y of other)
2921 SkTDArray<Angle> angles;
2922 SkASSERT(firstT - end != 0);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002923 addTwoAngles(end, firstT, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002924 buildAngles(firstT, angles, true);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002925 SkTDArray<Angle*> sorted;
caryclark@google.comf839c032012-10-26 21:03:50 +00002926 bool sortable = SortAngles(angles, sorted);
caryclark@google.com1304bb22013-03-13 20:29:41 +00002927 int first = SK_MaxS32;
2928 SkScalar top = SK_ScalarMax;
2929 int count = sorted.count();
2930 for (int index = 0; index < count; ++index) {
2931 const Angle* angle = sorted[index];
2932 Segment* next = angle->segment();
2933 Bounds bounds;
2934 next->subDivideBounds(angle->end(), angle->start(), bounds);
2935 if (approximately_greater(top, bounds.fTop)) {
2936 top = bounds.fTop;
2937 first = index;
2938 }
2939 }
2940 SkASSERT(first < SK_MaxS32);
2941 #if DEBUG_SORT // || DEBUG_SWAP_TOP
2942 sorted[first]->segment()->debugShowSort(__FUNCTION__, sorted, first, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002943 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002944 if (onlySortable && !sortable) {
2945 unsortable = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002946 return NULL;
2947 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002948 // skip edges that have already been processed
caryclark@google.com1304bb22013-03-13 20:29:41 +00002949 firstT = first - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002950 Segment* leftSegment;
2951 do {
caryclark@google.com1304bb22013-03-13 20:29:41 +00002952 if (++firstT == count) {
2953 firstT = 0;
2954 }
2955 const Angle* angle = sorted[firstT];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002956 SkASSERT(!onlySortable || !angle->unsortable());
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002957 leftSegment = angle->segment();
2958 tIndex = angle->end();
2959 endIndex = angle->start();
2960 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002961 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
caryclark@google.com1304bb22013-03-13 20:29:41 +00002962 if (!leftSegment->clockwise(tIndex, endIndex)) {
2963 bool swap = leftSegment->verb() == SkPath::kQuad_Verb
2964 || (!leftSegment->monotonic_in_y(tIndex, endIndex)
2965 && !leftSegment->serpentine(tIndex, endIndex));
caryclark@google.com47d73da2013-02-17 01:41:25 +00002966 #if DEBUG_SWAP_TOP
caryclark@google.com1304bb22013-03-13 20:29:41 +00002967 SkDebugf("%s swap=%d serpentine=%d controls_contained_by_ends=%d\n", __FUNCTION__,
2968 swap,
2969 leftSegment->serpentine(tIndex, endIndex),
2970 leftSegment->controls_contained_by_ends(tIndex, endIndex),
2971 leftSegment->monotonic_in_y(tIndex, endIndex));
caryclark@google.comc83c70e2013-02-22 21:50:07 +00002972 #endif
caryclark@google.com1304bb22013-03-13 20:29:41 +00002973 if (swap) {
2974 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first
2975 // sorted but merely the first not already processed (i.e., not done)
2976 SkTSwap(tIndex, endIndex);
2977 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002978 }
2979 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002980 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002981 return leftSegment;
2982 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002983
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002984 // FIXME: not crazy about this
2985 // when the intersections are performed, the other index is into an
caryclark@google.com1304bb22013-03-13 20:29:41 +00002986 // incomplete array. As the array grows, the indices become incorrect
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002987 // while the following fixes the indices up again, it isn't smart about
2988 // skipping segments whose indices are already correct
2989 // assuming we leave the code that wrote the index in the first place
2990 void fixOtherTIndex() {
2991 int iCount = fTs.count();
2992 for (int i = 0; i < iCount; ++i) {
2993 Span& iSpan = fTs[i];
2994 double oT = iSpan.fOtherT;
2995 Segment* other = iSpan.fOther;
2996 int oCount = other->fTs.count();
2997 for (int o = 0; o < oCount; ++o) {
2998 Span& oSpan = other->fTs[o];
caryclark@google.com1304bb22013-03-13 20:29:41 +00002999 if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan.fT) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003000 iSpan.fOtherIndex = o;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003001 break;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003002 }
3003 }
3004 }
3005 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003006
caryclark@google.com4eeda372012-12-06 21:47:48 +00003007 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00003008 fDoneSpans = 0;
3009 fOperand = operand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003010 fXor = evenOdd;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003011 fPts = pts;
3012 fVerb = verb;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003013 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003014
caryclark@google.com3586ece2012-12-27 18:46:58 +00003015 void initWinding(int start, int end) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003016 int local = spanSign(start, end);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003017 int oppLocal = oppSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00003018 (void) markAndChaseWinding(start, end, local, oppLocal);
caryclark@google.com73ca6242013-01-17 21:02:47 +00003019 // OPTIMIZATION: the reverse mark and chase could skip the first marking
3020 (void) markAndChaseWinding(end, start, local, oppLocal);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003021 }
3022
caryclark@google.com3586ece2012-12-27 18:46:58 +00003023 void initWinding(int start, int end, int winding, int oppWinding) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003024 int local = spanSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00003025 if (local * winding >= 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003026 winding += local;
3027 }
3028 int oppLocal = oppSign(start, end);
3029 if (oppLocal * oppWinding >= 0) {
3030 oppWinding += oppLocal;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003031 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003032 (void) markAndChaseWinding(start, end, winding, oppWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003033 }
3034
caryclark@google.com3586ece2012-12-27 18:46:58 +00003035/*
3036when we start with a vertical intersect, we try to use the dx to determine if the edge is to
3037the left or the right of vertical. This determines if we need to add the span's
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003038sign or not. However, this isn't enough.
3039If the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed.
caryclark@google.com3586ece2012-12-27 18:46:58 +00003040If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
3041from has the same x direction as this span, the winding should change. If the dx is opposite, then
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003042the same winding is shared by both.
caryclark@google.com3586ece2012-12-27 18:46:58 +00003043*/
3044 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
3045 SkScalar hitOppDx) {
3046 SkASSERT(hitDx || !winding);
3047 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
3048 SkASSERT(dx);
3049 int windVal = windValue(SkMin32(start, end));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003050 #if DEBUG_WINDING_AT_T
3051 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
3052 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
3053 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00003054 if (!winding) {
3055 winding = dx < 0 ? windVal : -windVal;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003056 } else if (winding * dx < 0) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00003057 int sideWind = winding + (dx < 0 ? windVal : -windVal);
3058 if (abs(winding) < abs(sideWind)) {
3059 winding = sideWind;
3060 }
3061 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003062 #if DEBUG_WINDING_AT_T
3063 SkDebugf(" winding=%d\n", winding);
3064 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00003065 int oppLocal = oppSign(start, end);
3066 SkASSERT(hitOppDx || !oppWind || !oppLocal);
3067 int oppWindVal = oppValue(SkMin32(start, end));
3068 if (!oppWind) {
3069 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
3070 } else if (hitOppDx * dx >= 0) {
3071 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
3072 if (abs(oppWind) < abs(oppSideWind)) {
3073 oppWind = oppSideWind;
3074 }
3075 }
3076 (void) markAndChaseWinding(start, end, winding, oppWind);
3077 }
3078
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003079 bool intersected() const {
3080 return fTs.count() > 0;
3081 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00003082
caryclark@google.com10227bf2012-12-28 22:10:41 +00003083 bool isCanceled(int tIndex) const {
3084 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
3085 }
3086
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00003087 bool isConnected(int startIndex, int endIndex) const {
3088 return fTs[startIndex].fWindSum != SK_MinS32
3089 || fTs[endIndex].fWindSum != SK_MinS32;
3090 }
3091
caryclark@google.com235f56a2012-09-14 14:19:30 +00003092 bool isHorizontal() const {
3093 return fBounds.fTop == fBounds.fBottom;
3094 }
3095
caryclark@google.com15fa1382012-05-07 20:49:36 +00003096 bool isLinear(int start, int end) const {
3097 if (fVerb == SkPath::kLine_Verb) {
3098 return true;
3099 }
3100 if (fVerb == SkPath::kQuad_Verb) {
3101 SkPoint qPart[3];
3102 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
3103 return QuadIsLinear(qPart);
3104 } else {
3105 SkASSERT(fVerb == SkPath::kCubic_Verb);
3106 SkPoint cPart[4];
3107 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
3108 return CubicIsLinear(cPart);
3109 }
3110 }
caryclark@google.comb9738012012-07-03 19:53:30 +00003111
3112 // OPTIMIZE: successive calls could start were the last leaves off
3113 // or calls could specialize to walk forwards or backwards
3114 bool isMissing(double startT) const {
3115 size_t tCount = fTs.count();
3116 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003117 if (approximately_zero(startT - fTs[index].fT)) {
caryclark@google.comb9738012012-07-03 19:53:30 +00003118 return false;
3119 }
3120 }
3121 return true;
3122 }
3123
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003124 bool isSimple(int end) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003125 int count = fTs.count();
3126 if (count == 2) {
3127 return true;
3128 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003129 double t = fTs[end].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003130 if (approximately_less_than_zero(t)) {
3131 return !approximately_less_than_zero(fTs[1].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003132 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003133 if (approximately_greater_than_one(t)) {
3134 return !approximately_greater_than_one(fTs[count - 2].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003135 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003136 return false;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003137 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003138
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003139 bool isVertical() const {
3140 return fBounds.fLeft == fBounds.fRight;
3141 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003142
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003143 bool isVertical(int start, int end) const {
3144 return (*SegmentVertical[fVerb])(fPts, start, end);
3145 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003146
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003147 SkScalar leftMost(int start, int end) const {
3148 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
3149 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003150
caryclark@google.com495f8e42012-05-31 13:13:11 +00003151 // this span is excluded by the winding rule -- chase the ends
3152 // as long as they are unambiguous to mark connections as done
3153 // and give them the same winding value
caryclark@google.com59823f72012-08-09 18:17:47 +00003154 Span* markAndChaseDone(const Angle* angle, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003155 int index = angle->start();
3156 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003157 return markAndChaseDone(index, endIndex, winding);
3158 }
3159
caryclark@google.com31143cf2012-11-09 22:14:19 +00003160 Span* markAndChaseDone(int index, int endIndex, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003161 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003162 int min = SkMin32(index, endIndex);
3163 markDone(min, winding);
3164 Span* last;
3165 Segment* other = this;
3166 while ((other = other->nextChase(index, step, min, last))) {
3167 other->markDone(min, winding);
3168 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003169 return last;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003170 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003171
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003172 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
3173 int index = angle->start();
3174 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003175 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003176 int min = SkMin32(index, endIndex);
3177 markDoneBinary(min, winding, oppWinding);
3178 Span* last;
3179 Segment* other = this;
3180 while ((other = other->nextChase(index, step, min, last))) {
3181 other->markDoneBinary(min, winding, oppWinding);
3182 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003183 return last;
3184 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003185
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003186 Span* markAndChaseDoneBinary(int index, int endIndex) {
3187 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003188 int min = SkMin32(index, endIndex);
3189 markDoneBinary(min);
3190 Span* last;
3191 Segment* other = this;
3192 while ((other = other->nextChase(index, step, min, last))) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003193 if (other->done()) {
3194 return NULL;
3195 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003196 other->markDoneBinary(min);
3197 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003198 return last;
3199 }
3200
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003201 Span* markAndChaseDoneUnary(int index, int endIndex) {
3202 int step = SkSign32(endIndex - index);
3203 int min = SkMin32(index, endIndex);
3204 markDoneUnary(min);
3205 Span* last;
3206 Segment* other = this;
3207 while ((other = other->nextChase(index, step, min, last))) {
3208 if (other->done()) {
3209 return NULL;
3210 }
3211 other->markDoneUnary(min);
3212 }
3213 return last;
3214 }
3215
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003216 Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
3217 int index = angle->start();
3218 int endIndex = angle->end();
3219 return markAndChaseDone(index, endIndex, winding);
3220 }
3221
caryclark@google.com4eeda372012-12-06 21:47:48 +00003222 Span* markAndChaseWinding(const Angle* angle, const int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003223 int index = angle->start();
3224 int endIndex = angle->end();
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003225 int step = SkSign32(endIndex - index);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003226 int min = SkMin32(index, endIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00003227 markWinding(min, winding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003228 Span* last;
3229 Segment* other = this;
3230 while ((other = other->nextChase(index, step, min, last))) {
3231 if (other->fTs[min].fWindSum != SK_MinS32) {
3232 SkASSERT(other->fTs[min].fWindSum == winding);
3233 return NULL;
3234 }
3235 other->markWinding(min, winding);
3236 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003237 return last;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003238 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003239
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003240 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003241 int min = SkMin32(index, endIndex);
3242 int step = SkSign32(endIndex - index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003243 markWinding(min, winding, oppWinding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003244 Span* last;
3245 Segment* other = this;
3246 while ((other = other->nextChase(index, step, min, last))) {
3247 if (other->fTs[min].fWindSum != SK_MinS32) {
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00003248 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003249 return NULL;
3250 }
3251 other->markWinding(min, winding, oppWinding);
3252 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003253 return last;
3254 }
3255
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003256 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
3257 int start = angle->start();
3258 int end = angle->end();
3259 return markAndChaseWinding(start, end, winding, oppWinding);
3260 }
3261
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003262 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
3263 SkASSERT(angle->segment() == this);
3264 if (useInnerWinding(maxWinding, sumWinding)) {
3265 maxWinding = sumWinding;
3266 }
3267 Span* last;
3268 if (activeAngle) {
3269 last = markAndChaseWinding(angle, maxWinding);
3270 } else {
3271 last = markAndChaseDoneUnary(angle, maxWinding);
3272 }
3273 return last;
3274 }
3275
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003276 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
3277 bool activeAngle, const Angle* angle) {
3278 SkASSERT(angle->segment() == this);
3279 if (useInnerWinding(maxWinding, sumWinding)) {
3280 maxWinding = sumWinding;
3281 }
3282 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
3283 oppMaxWinding = oppSumWinding;
3284 }
3285 Span* last;
3286 if (activeAngle) {
3287 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3288 } else {
3289 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
3290 }
3291 return last;
3292 }
3293
caryclark@google.com495f8e42012-05-31 13:13:11 +00003294 // FIXME: this should also mark spans with equal (x,y)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003295 // This may be called when the segment is already marked done. While this
3296 // wastes time, it shouldn't do any more than spin through the T spans.
rmistry@google.comd6176b02012-08-23 18:14:13 +00003297 // OPTIMIZATION: abort on first done found (assuming that this code is
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003298 // always called to mark segments done).
caryclark@google.com59823f72012-08-09 18:17:47 +00003299 void markDone(int index, int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003300 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003301 SkASSERT(winding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003302 double referenceT = fTs[index].fT;
3303 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003304 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3305 markOneDone(__FUNCTION__, lesser, winding);
3306 }
3307 do {
3308 markOneDone(__FUNCTION__, index, winding);
3309 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003310 }
3311
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003312 void markDoneBinary(int index, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003313 // SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003314 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003315 double referenceT = fTs[index].fT;
3316 int lesser = index;
3317 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003318 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003319 }
3320 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003321 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
3322 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3323 }
3324
3325 void markDoneBinary(int index) {
3326 double referenceT = fTs[index].fT;
3327 int lesser = index;
3328 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3329 markOneDoneBinary(__FUNCTION__, lesser);
3330 }
3331 do {
3332 markOneDoneBinary(__FUNCTION__, index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003333 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003334 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00003335
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003336 void markDoneUnary(int index, int winding) {
3337 // SkASSERT(!done());
3338 SkASSERT(winding);
3339 double referenceT = fTs[index].fT;
3340 int lesser = index;
3341 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3342 markOneDoneUnary(__FUNCTION__, lesser, winding);
3343 }
3344 do {
3345 markOneDoneUnary(__FUNCTION__, index, winding);
3346 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3347 }
3348
3349 void markDoneUnary(int index) {
3350 double referenceT = fTs[index].fT;
3351 int lesser = index;
3352 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3353 markOneDoneUnary(__FUNCTION__, lesser);
3354 }
3355 do {
3356 markOneDoneUnary(__FUNCTION__, index);
3357 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3358 }
3359
caryclark@google.com24bec792012-08-20 12:43:57 +00003360 void markOneDone(const char* funName, int tIndex, int winding) {
3361 Span* span = markOneWinding(funName, tIndex, winding);
3362 if (!span) {
3363 return;
3364 }
3365 span->fDone = true;
3366 fDoneSpans++;
3367 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003368
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003369 void markOneDoneBinary(const char* funName, int tIndex) {
3370 Span* span = verifyOneWinding(funName, tIndex);
3371 if (!span) {
3372 return;
3373 }
3374 span->fDone = true;
3375 fDoneSpans++;
3376 }
3377
3378 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003379 Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
3380 if (!span) {
3381 return;
3382 }
3383 span->fDone = true;
3384 fDoneSpans++;
3385 }
3386
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003387 void markOneDoneUnary(const char* funName, int tIndex) {
3388 Span* span = verifyOneWindingU(funName, tIndex);
3389 if (!span) {
3390 return;
3391 }
3392 span->fDone = true;
3393 fDoneSpans++;
3394 }
3395
3396 void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3397 Span* span = markOneWinding(funName, tIndex, winding);
3398 if (!span) {
3399 return;
3400 }
3401 span->fDone = true;
3402 fDoneSpans++;
3403 }
3404
caryclark@google.com24bec792012-08-20 12:43:57 +00003405 Span* markOneWinding(const char* funName, int tIndex, int winding) {
3406 Span& span = fTs[tIndex];
3407 if (span.fDone) {
3408 return NULL;
3409 }
3410 #if DEBUG_MARK_DONE
3411 debugShowNewWinding(funName, span, winding);
3412 #endif
3413 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com03f97062012-08-21 13:13:52 +00003414 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00003415 SkASSERT(abs(winding) <= gDebugMaxWindSum);
caryclark@google.com03f97062012-08-21 13:13:52 +00003416 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00003417 span.fWindSum = winding;
3418 return &span;
3419 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003420
caryclark@google.com31143cf2012-11-09 22:14:19 +00003421 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
3422 Span& span = fTs[tIndex];
3423 if (span.fDone) {
3424 return NULL;
3425 }
3426 #if DEBUG_MARK_DONE
3427 debugShowNewWinding(funName, span, winding, oppWinding);
3428 #endif
3429 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3430 #ifdef SK_DEBUG
3431 SkASSERT(abs(winding) <= gDebugMaxWindSum);
3432 #endif
3433 span.fWindSum = winding;
3434 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3435 #ifdef SK_DEBUG
3436 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
3437 #endif
3438 span.fOppSum = oppWinding;
3439 return &span;
3440 }
3441
caryclark@google.com1304bb22013-03-13 20:29:41 +00003442 bool controls_contained_by_ends(int tStart, int tEnd) const {
3443 if (fVerb != SkPath::kCubic_Verb) {
3444 return false;
3445 }
3446 MAKE_CONST_CUBIC(aCubic, fPts);
3447 Cubic dst;
3448 sub_divide(aCubic, fTs[tStart].fT, fTs[tEnd].fT, dst);
3449 return ::controls_contained_by_ends(dst);
3450 }
3451
3452 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
3453 bool clockwise(int tStart, int tEnd) const {
3454 SkASSERT(fVerb != SkPath::kLine_Verb);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003455 SkPoint edge[4];
caryclark@google.comc83c70e2013-02-22 21:50:07 +00003456 subDivide(tStart, tEnd, edge);
caryclark@google.com1304bb22013-03-13 20:29:41 +00003457 double sum = (edge[0].fX - edge[fVerb].fX) * (edge[0].fY + edge[fVerb].fY);
3458 if (fVerb == SkPath::kCubic_Verb) {
3459 SkScalar lesser = SkTMin(edge[0].fY, edge[3].fY);
3460 if (edge[1].fY < lesser && edge[2].fY < lesser) {
3461 _Line tangent1 = { {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1].fY} };
3462 _Line tangent2 = { {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3].fY} };
3463 if (testIntersect(tangent1, tangent2)) {
3464 SkPoint topPt = CubicTop(fPts, fTs[tStart].fT, fTs[tEnd].fT);
3465 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY);
3466 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY);
3467 return sum <= 0;
3468 }
3469 }
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003470 }
caryclark@google.com1304bb22013-03-13 20:29:41 +00003471 for (int idx = 0; idx < fVerb; ++idx){
3472 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
3473 }
3474 return sum <= 0;
3475 }
skia.committer@gmail.com03682be2013-03-14 07:02:51 +00003476
caryclark@google.com1304bb22013-03-13 20:29:41 +00003477 bool monotonic_in_y(int tStart, int tEnd) const {
3478 if (fVerb != SkPath::kCubic_Verb) {
3479 return false;
3480 }
3481 MAKE_CONST_CUBIC(aCubic, fPts);
3482 Cubic dst;
3483 sub_divide(aCubic, fTs[tStart].fT, fTs[tEnd].fT, dst);
3484 return ::monotonic_in_y(dst);
3485 }
3486
3487 bool serpentine(int tStart, int tEnd) const {
3488 if (fVerb != SkPath::kCubic_Verb) {
3489 return false;
3490 }
3491 MAKE_CONST_CUBIC(aCubic, fPts);
3492 Cubic dst;
3493 sub_divide(aCubic, fTs[tStart].fT, fTs[tEnd].fT, dst);
3494 return ::serpentine(dst);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003495 }
3496
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003497 Span* verifyOneWinding(const char* funName, int tIndex) {
3498 Span& span = fTs[tIndex];
3499 if (span.fDone) {
3500 return NULL;
3501 }
3502 #if DEBUG_MARK_DONE
3503 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3504 #endif
3505 SkASSERT(span.fWindSum != SK_MinS32);
3506 SkASSERT(span.fOppSum != SK_MinS32);
3507 return &span;
3508 }
3509
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003510 Span* verifyOneWindingU(const char* funName, int tIndex) {
3511 Span& span = fTs[tIndex];
3512 if (span.fDone) {
3513 return NULL;
3514 }
3515 #if DEBUG_MARK_DONE
3516 debugShowNewWinding(funName, span, span.fWindSum);
3517 #endif
3518 SkASSERT(span.fWindSum != SK_MinS32);
3519 return &span;
3520 }
3521
caryclark@google.comf839c032012-10-26 21:03:50 +00003522 // note that just because a span has one end that is unsortable, that's
3523 // not enough to mark it done. The other end may be sortable, allowing the
3524 // span to be added.
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003525 // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003526 void markUnsortable(int start, int end) {
3527 Span* span = &fTs[start];
3528 if (start < end) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003529#if DEBUG_UNSORTABLE
caryclark@google.com1304bb22013-03-13 20:29:41 +00003530 debugShowNewWinding(__FUNCTION__, *span, 0);
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003531#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003532 span->fUnsortableStart = true;
3533 } else {
3534 --span;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003535#if DEBUG_UNSORTABLE
caryclark@google.com1304bb22013-03-13 20:29:41 +00003536 debugShowNewWinding(__FUNCTION__, *span, 0);
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003537#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003538 span->fUnsortableEnd = true;
3539 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003540 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003541 return;
3542 }
3543 span->fDone = true;
3544 fDoneSpans++;
3545 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003546
caryclark@google.com59823f72012-08-09 18:17:47 +00003547 void markWinding(int index, int winding) {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003548 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003549 SkASSERT(winding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003550 double referenceT = fTs[index].fT;
3551 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003552 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3553 markOneWinding(__FUNCTION__, lesser, winding);
3554 }
3555 do {
3556 markOneWinding(__FUNCTION__, index, winding);
3557 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003558 }
3559
3560 void markWinding(int index, int winding, int oppWinding) {
3561 // SkASSERT(!done());
caryclark@google.com4eeda372012-12-06 21:47:48 +00003562 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003563 double referenceT = fTs[index].fT;
3564 int lesser = index;
3565 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3566 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003567 }
3568 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003569 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3570 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003571 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003572
caryclark@google.com2ddff932012-08-07 21:25:27 +00003573 void matchWindingValue(int tIndex, double t, bool borrowWind) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003574 int nextDoorWind = SK_MaxS32;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003575 int nextOppWind = SK_MaxS32;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003576 if (tIndex > 0) {
3577 const Span& below = fTs[tIndex - 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003578 if (approximately_negative(t - below.fT)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003579 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003580 nextOppWind = below.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003581 }
3582 }
3583 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3584 const Span& above = fTs[tIndex + 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003585 if (approximately_negative(above.fT - t)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003586 nextDoorWind = above.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003587 nextOppWind = above.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003588 }
3589 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003590 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3591 const Span& below = fTs[tIndex - 1];
3592 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003593 nextOppWind = below.fOppValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003594 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003595 if (nextDoorWind != SK_MaxS32) {
3596 Span& newSpan = fTs[tIndex];
3597 newSpan.fWindValue = nextDoorWind;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003598 newSpan.fOppValue = nextOppWind;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003599 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003600 newSpan.fDone = true;
3601 ++fDoneSpans;
3602 }
3603 }
3604 }
3605
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003606 bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3607 // find bounds
3608 Bounds bounds;
3609 bounds.setPoint(xyAtT(index));
3610 bounds.add(xyAtT(endIndex));
3611 SkScalar width = bounds.width();
3612 SkScalar height = bounds.height();
3613 if (width > height) {
3614 if (approximately_negative(width)) {
3615 unsortable = true; // edge is too small to resolve meaningfully
3616 }
3617 return false;
3618 } else {
3619 if (approximately_negative(height)) {
3620 unsortable = true; // edge is too small to resolve meaningfully
3621 }
3622 return true;
3623 }
3624 }
3625
caryclark@google.com9764cc62012-07-12 19:29:45 +00003626 // return span if when chasing, two or more radiating spans are not done
3627 // OPTIMIZATION: ? multiple spans is detected when there is only one valid
3628 // candidate and the remaining spans have windValue == 0 (canceled by
3629 // coincidence). The coincident edges could either be removed altogether,
3630 // or this code could be more complicated in detecting this case. Worth it?
3631 bool multipleSpans(int end) const {
3632 return end > 0 && end < fTs.count() - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00003633 }
3634
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003635 bool nextCandidate(int& start, int& end) const {
caryclark@google.com10227bf2012-12-28 22:10:41 +00003636 while (fTs[end].fDone) {
3637 if (fTs[end].fT == 1) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003638 return false;
3639 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00003640 ++end;
3641 }
3642 start = end;
3643 end = nextExactSpan(start, 1);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003644 return true;
3645 }
3646
caryclark@google.com1ab0aac2013-03-13 20:41:48 +00003647 Segment* nextChase(int& index, const int step, int& min, Span*& last) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003648 int end = nextExactSpan(index, step);
3649 SkASSERT(end >= 0);
3650 if (multipleSpans(end)) {
3651 last = &fTs[end];
3652 return NULL;
3653 }
3654 const Span& endSpan = fTs[end];
3655 Segment* other = endSpan.fOther;
3656 index = endSpan.fOtherIndex;
caryclark@google.comaa358312013-01-29 20:28:49 +00003657 SkASSERT(index >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003658 int otherEnd = other->nextExactSpan(index, step);
caryclark@google.comaa358312013-01-29 20:28:49 +00003659 SkASSERT(otherEnd >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003660 min = SkMin32(index, otherEnd);
3661 return other;
3662 }
3663
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003664 // This has callers for two different situations: one establishes the end
3665 // of the current span, and one establishes the beginning of the next span
3666 // (thus the name). When this is looking for the end of the current span,
3667 // coincidence is found when the beginning Ts contain -step and the end
3668 // contains step. When it is looking for the beginning of the next, the
3669 // first Ts found can be ignored and the last Ts should contain -step.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003670 // OPTIMIZATION: probably should split into two functions
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003671 int nextSpan(int from, int step) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003672 const Span& fromSpan = fTs[from];
caryclark@google.com495f8e42012-05-31 13:13:11 +00003673 int count = fTs.count();
3674 int to = from;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003675 while (step > 0 ? ++to < count : --to >= 0) {
3676 const Span& span = fTs[to];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003677 if (approximately_zero(span.fT - fromSpan.fT)) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003678 continue;
3679 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003680 return to;
3681 }
3682 return -1;
3683 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +00003684
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003685 // FIXME
3686 // this returns at any difference in T, vs. a preset minimum. It may be
3687 // that all callers to nextSpan should use this instead.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003688 // OPTIMIZATION splitting this into separate loops for up/down steps
3689 // would allow using precisely_negative instead of precisely_zero
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003690 int nextExactSpan(int from, int step) const {
3691 const Span& fromSpan = fTs[from];
3692 int count = fTs.count();
3693 int to = from;
3694 while (step > 0 ? ++to < count : --to >= 0) {
3695 const Span& span = fTs[to];
caryclark@google.coma461ff02012-10-11 12:54:23 +00003696 if (precisely_zero(span.fT - fromSpan.fT)) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003697 continue;
3698 }
3699 return to;
3700 }
3701 return -1;
3702 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003703
caryclark@google.com235f56a2012-09-14 14:19:30 +00003704 bool operand() const {
3705 return fOperand;
3706 }
3707
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003708 int oppSign(const Angle* angle) const {
3709 SkASSERT(angle->segment() == this);
3710 return oppSign(angle->start(), angle->end());
3711 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003712
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003713 int oppSign(int startIndex, int endIndex) const {
3714 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3715 : fTs[endIndex].fOppValue;
3716#if DEBUG_WIND_BUMP
3717 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3718#endif
3719 return result;
3720 }
3721
caryclark@google.com31143cf2012-11-09 22:14:19 +00003722 int oppSum(int tIndex) const {
3723 return fTs[tIndex].fOppSum;
3724 }
3725
3726 int oppSum(const Angle* angle) const {
3727 int lesser = SkMin32(angle->start(), angle->end());
3728 return fTs[lesser].fOppSum;
caryclark@google.com235f56a2012-09-14 14:19:30 +00003729 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003730
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003731 int oppValue(int tIndex) const {
3732 return fTs[tIndex].fOppValue;
3733 }
3734
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003735 int oppValue(const Angle* angle) const {
3736 int lesser = SkMin32(angle->start(), angle->end());
3737 return fTs[lesser].fOppValue;
3738 }
3739
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003740 const SkPoint* pts() const {
3741 return fPts;
3742 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003743
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003744 void reset() {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003745 init(NULL, (SkPath::Verb) -1, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003746 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3747 fTs.reset();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003748 }
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +00003749
caryclark@google.com4eeda372012-12-06 21:47:48 +00003750 void setOppXor(bool isOppXor) {
3751 fOppXor = isOppXor;
3752 }
skia.committer@gmail.com12eea2b2013-02-27 07:10:10 +00003753
caryclark@google.com7ff5c842013-02-26 15:56:05 +00003754 void setSpanT(int index, double t) {
3755 Span& span = fTs[index];
3756 span.fT = t;
3757 span.fOther->fTs[span.fOtherIndex].fOtherT = t;
3758 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003759
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003760 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3761 int deltaSum = spanSign(index, endIndex);
3762 maxWinding = sumWinding;
3763 sumWinding = sumWinding -= deltaSum;
3764 }
3765
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003766 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3767 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3768 int deltaSum = spanSign(index, endIndex);
3769 int oppDeltaSum = oppSign(index, endIndex);
3770 if (operand()) {
3771 maxWinding = sumSuWinding;
3772 sumWinding = sumSuWinding -= deltaSum;
3773 oppMaxWinding = sumMiWinding;
3774 oppSumWinding = sumMiWinding -= oppDeltaSum;
3775 } else {
3776 maxWinding = sumMiWinding;
3777 sumWinding = sumMiWinding -= deltaSum;
3778 oppMaxWinding = sumSuWinding;
3779 oppSumWinding = sumSuWinding -= oppDeltaSum;
3780 }
3781 }
3782
caryclark@google.comf839c032012-10-26 21:03:50 +00003783 // This marks all spans unsortable so that this info is available for early
3784 // exclusion in find top and others. This could be optimized to only mark
3785 // adjacent spans that unsortable. However, this makes it difficult to later
3786 // determine starting points for edge detection in find top and the like.
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003787 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
caryclark@google.comf839c032012-10-26 21:03:50 +00003788 bool sortable = true;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003789 int angleCount = angles.count();
3790 int angleIndex;
3791 angleList.setReserve(angleCount);
3792 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003793 Angle& angle = angles[angleIndex];
caryclark@google.comf839c032012-10-26 21:03:50 +00003794 *angleList.append() = &angle;
3795 sortable &= !angle.unsortable();
3796 }
3797 if (sortable) {
3798 QSort<Angle>(angleList.begin(), angleList.end() - 1);
3799 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3800 if (angles[angleIndex].unsortable()) {
3801 sortable = false;
3802 break;
3803 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003804 }
3805 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003806 if (!sortable) {
3807 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3808 Angle& angle = angles[angleIndex];
3809 angle.segment()->markUnsortable(angle.start(), angle.end());
3810 }
3811 }
3812 return sortable;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003813 }
3814
caryclark@google.com1577e8f2012-05-22 17:01:14 +00003815 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003816 const Span& span(int tIndex) const {
3817 return fTs[tIndex];
3818 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003819
caryclark@google.com235f56a2012-09-14 14:19:30 +00003820 int spanSign(const Angle* angle) const {
3821 SkASSERT(angle->segment() == this);
3822 return spanSign(angle->start(), angle->end());
3823 }
3824
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003825 int spanSign(int startIndex, int endIndex) const {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003826 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3827 : fTs[endIndex].fWindValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003828#if DEBUG_WIND_BUMP
3829 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3830#endif
3831 return result;
3832 }
skia.committer@gmail.com58433de2013-02-23 07:02:45 +00003833
caryclark@google.comc83c70e2013-02-22 21:50:07 +00003834 void subDivide(int start, int end, SkPoint edge[4]) const {
3835 edge[0] = fTs[start].fPt;
3836 edge[fVerb] = fTs[end].fPt;
3837 if (fVerb == SkPath::kQuad_Verb || fVerb == SkPath::kCubic_Verb) {
3838 _Point sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[fVerb].fX, edge[fVerb].fY }};
3839 if (fVerb == SkPath::kQuad_Verb) {
3840 MAKE_CONST_QUAD(aQuad, fPts);
3841 edge[1] = sub_divide(aQuad, sub[0], sub[1], fTs[start].fT, fTs[end].fT).asSkPoint();
3842 } else {
3843 MAKE_CONST_CUBIC(aCubic, fPts);
3844 sub_divide(aCubic, sub[0], sub[1], fTs[start].fT, fTs[end].fT, sub);
3845 edge[1] = sub[0].asSkPoint();
3846 edge[2] = sub[1].asSkPoint();
3847 }
3848 }
3849 }
skia.committer@gmail.com03682be2013-03-14 07:02:51 +00003850
caryclark@google.com1304bb22013-03-13 20:29:41 +00003851 void subDivideBounds(int start, int end, Bounds& bounds) const {
3852 SkPoint edge[4];
3853 subDivide(start, end, edge);
3854 (bounds.*setSegmentBounds[fVerb])(edge);
3855 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003856
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003857 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003858 double t(int tIndex) const {
3859 return fTs[tIndex].fT;
3860 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003861
caryclark@google.com10227bf2012-12-28 22:10:41 +00003862 double tAtMid(int start, int end, double mid) const {
3863 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
3864 }
3865
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003866 bool tiny(const Angle* angle) const {
3867 int start = angle->start();
3868 int end = angle->end();
caryclark@google.comf839c032012-10-26 21:03:50 +00003869 const Span& mSpan = fTs[SkMin32(start, end)];
3870 return mSpan.fTiny;
3871 }
3872
caryclark@google.com18063442012-07-25 12:05:18 +00003873 static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3874 double start) {
3875 int outCount = outsideTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003876 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
caryclark@google.com18063442012-07-25 12:05:18 +00003877 *outsideTs.append() = end;
3878 *outsideTs.append() = start;
3879 }
3880 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003881
caryclark@google.com24bec792012-08-20 12:43:57 +00003882 void undoneSpan(int& start, int& end) {
3883 size_t tCount = fTs.count();
3884 size_t index;
3885 for (index = 0; index < tCount; ++index) {
3886 if (!fTs[index].fDone) {
3887 break;
3888 }
3889 }
3890 SkASSERT(index < tCount - 1);
3891 start = index;
3892 double startT = fTs[index].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003893 while (approximately_negative(fTs[++index].fT - startT))
caryclark@google.com24bec792012-08-20 12:43:57 +00003894 SkASSERT(index < tCount);
3895 SkASSERT(index < tCount);
3896 end = index;
3897 }
caryclark@google.com18063442012-07-25 12:05:18 +00003898
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003899 bool unsortable(int index) const {
3900 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3901 }
3902
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003903 void updatePts(const SkPoint pts[]) {
3904 fPts = pts;
3905 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003906
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003907 int updateOppWinding(int index, int endIndex) const {
3908 int lesser = SkMin32(index, endIndex);
3909 int oppWinding = oppSum(lesser);
3910 int oppSpanWinding = oppSign(index, endIndex);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003911 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)
3912 && oppWinding != SK_MaxS32) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003913 oppWinding -= oppSpanWinding;
3914 }
3915 return oppWinding;
3916 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003917
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003918 int updateOppWinding(const Angle* angle) const {
3919 int startIndex = angle->start();
3920 int endIndex = angle->end();
3921 return updateOppWinding(endIndex, startIndex);
3922 }
3923
3924 int updateOppWindingReverse(const Angle* angle) const {
3925 int startIndex = angle->start();
3926 int endIndex = angle->end();
3927 return updateOppWinding(startIndex, endIndex);
3928 }
3929
3930 int updateWinding(int index, int endIndex) const {
3931 int lesser = SkMin32(index, endIndex);
3932 int winding = windSum(lesser);
3933 int spanWinding = spanSign(index, endIndex);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003934 if (winding && useInnerWinding(winding - spanWinding, winding) && winding != SK_MaxS32) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003935 winding -= spanWinding;
3936 }
3937 return winding;
3938 }
3939
3940 int updateWinding(const Angle* angle) const {
3941 int startIndex = angle->start();
3942 int endIndex = angle->end();
3943 return updateWinding(endIndex, startIndex);
3944 }
3945
3946 int updateWindingReverse(const Angle* angle) const {
3947 int startIndex = angle->start();
3948 int endIndex = angle->end();
3949 return updateWinding(startIndex, endIndex);
3950 }
3951
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003952 SkPath::Verb verb() const {
3953 return fVerb;
3954 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003955
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003956 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003957 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3958 return SK_MinS32;
3959 }
3960 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3961 SkASSERT(winding != SK_MinS32);
3962 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003963 #if DEBUG_WINDING_AT_T
3964 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003965 #endif
3966 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark@google.com3586ece2012-12-27 18:46:58 +00003967 dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003968 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3969 dx = fPts[2].fX - fPts[1].fX - dx;
3970 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003971 if (dx == 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003972 #if DEBUG_WINDING_AT_T
3973 SkDebugf(" dx=0 winding=SK_MinS32\n");
3974 #endif
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003975 return SK_MinS32;
3976 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003977 if (winding * dx > 0) { // if same signs, result is negative
3978 winding += dx > 0 ? -windVal : windVal;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003979 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003980 #if DEBUG_WINDING_AT_T
3981 SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding);
3982 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003983 return winding;
3984 }
3985
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003986 int windSum(int tIndex) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003987 return fTs[tIndex].fWindSum;
3988 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003989
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003990 int windSum(const Angle* angle) const {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003991 int start = angle->start();
3992 int end = angle->end();
3993 int index = SkMin32(start, end);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003994 return windSum(index);
caryclark@google.com495f8e42012-05-31 13:13:11 +00003995 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003996
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003997 int windValue(int tIndex) const {
3998 return fTs[tIndex].fWindValue;
3999 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004000
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004001 int windValue(const Angle* angle) const {
4002 int start = angle->start();
4003 int end = angle->end();
4004 int index = SkMin32(start, end);
4005 return windValue(index);
4006 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004007
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004008 int windValueAt(double t) const {
4009 int count = fTs.count();
4010 for (int index = 0; index < count; ++index) {
4011 if (fTs[index].fT == t) {
4012 return fTs[index].fWindValue;
4013 }
4014 }
4015 SkASSERT(0);
4016 return 0;
4017 }
4018
caryclark@google.com3586ece2012-12-27 18:46:58 +00004019 SkScalar xAtT(int index) const {
4020 return xAtT(&fTs[index]);
4021 }
4022
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004023 SkScalar xAtT(const Span* span) const {
4024 return xyAtT(span).fX;
4025 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004026
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004027 const SkPoint& xyAtT(int index) const {
4028 return xyAtT(&fTs[index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004029 }
4030
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00004031 const SkPoint& xyAtT(const Span* span) const {
caryclark@google.com27c449a2012-07-27 18:26:38 +00004032 if (SkScalarIsNaN(span->fPt.fX)) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004033 SkASSERT(0); // make sure this path is never used
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00004034 if (span->fT == 0) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00004035 span->fPt = fPts[0];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00004036 } else if (span->fT == 1) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00004037 span->fPt = fPts[fVerb];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00004038 } else {
caryclark@google.com27c449a2012-07-27 18:26:38 +00004039 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00004040 }
4041 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00004042 return span->fPt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004043 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004044
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004045 // used only by right angle winding finding
caryclark@google.com10227bf2012-12-28 22:10:41 +00004046 void xyAtT(double mid, SkPoint& pt) const {
4047 (*SegmentXYAtT[fVerb])(fPts, mid, &pt);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004048 }
4049
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004050 SkScalar yAtT(int index) const {
4051 return yAtT(&fTs[index]);
4052 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004053
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004054 SkScalar yAtT(const Span* span) const {
4055 return xyAtT(span).fY;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004056 }
4057
caryclark@google.com4eeda372012-12-06 21:47:48 +00004058 void zeroCoincidentOpp(Span* oTest, int index) {
4059 Span* const test = &fTs[index];
4060 Span* end = test;
4061 do {
4062 end->fOppValue = 0;
4063 end = &fTs[++index];
4064 } while (approximately_negative(end->fT - test->fT));
4065 }
4066
4067 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
4068 Span* const oTest = &fTs[oIndex];
4069 Span* oEnd = oTest;
4070 const double startT = test->fT;
4071 const double oStartT = oTest->fT;
4072 double otherTMatch = (test->fT - startT) * tRatio + oStartT;
4073 while (!approximately_negative(oEndT - oEnd->fT)
4074 && approximately_negative(oEnd->fT - otherTMatch)) {
4075 oEnd->fOppValue = 0;
4076 oEnd = &fTs[++oIndex];
4077 }
4078 }
4079
4080 void zeroSpan(Span* span) {
4081 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
caryclark@google.com6ec15262012-11-16 20:16:50 +00004082 span->fWindValue = 0;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004083 span->fOppValue = 0;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004084 SkASSERT(!span->fDone);
4085 span->fDone = true;
4086 ++fDoneSpans;
caryclark@google.com6ec15262012-11-16 20:16:50 +00004087 }
4088
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004089#if DEBUG_DUMP
4090 void dump() const {
4091 const char className[] = "Segment";
4092 const int tab = 4;
4093 for (int i = 0; i < fTs.count(); ++i) {
4094 SkPoint out;
4095 (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
4096 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004097 " otherT=%1.9g windSum=%d\n",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004098 tab + sizeof(className), className, fID,
4099 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004100 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004101 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00004102 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004103 tab + sizeof(className), className, fID,
caryclark@google.com15fa1382012-05-07 20:49:36 +00004104 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004105 }
4106#endif
4107
caryclark@google.com47580692012-07-23 12:14:49 +00004108#if DEBUG_CONCIDENT
caryclark@google.comaa358312013-01-29 20:28:49 +00004109 // SkASSERT if pair has not already been added
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004110 void debugAddTPair(double t, const Segment& other, double otherT) const {
caryclark@google.comcc905052012-07-25 20:59:42 +00004111 for (int i = 0; i < fTs.count(); ++i) {
4112 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
4113 return;
4114 }
4115 }
4116 SkASSERT(0);
4117 }
4118#endif
4119
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004120#if DEBUG_DUMP
4121 int debugID() const {
4122 return fID;
4123 }
4124#endif
4125
caryclark@google.com24bec792012-08-20 12:43:57 +00004126#if DEBUG_WINDING
4127 void debugShowSums() const {
4128 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
4129 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
4130 for (int i = 0; i < fTs.count(); ++i) {
4131 const Span& span = fTs[i];
4132 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
4133 if (span.fWindSum == SK_MinS32) {
4134 SkDebugf("?");
4135 } else {
4136 SkDebugf("%d", span.fWindSum);
4137 }
4138 SkDebugf("]");
4139 }
4140 SkDebugf("\n");
4141 }
4142#endif
4143
caryclark@google.comcc905052012-07-25 20:59:42 +00004144#if DEBUG_CONCIDENT
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004145 void debugShowTs() const {
caryclark@google.com24bec792012-08-20 12:43:57 +00004146 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com4eeda372012-12-06 21:47:48 +00004147 int lastWind = -1;
4148 int lastOpp = -1;
4149 double lastT = -1;
4150 int i;
4151 for (i = 0; i < fTs.count(); ++i) {
4152 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
4153 || lastOpp != fTs[i].fOppValue;
4154 if (change && lastWind >= 0) {
4155 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
4156 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
4157 }
4158 if (change) {
4159 SkDebugf(" [o=%d", fTs[i].fOther->fID);
4160 lastWind = fTs[i].fWindValue;
4161 lastOpp = fTs[i].fOppValue;
4162 lastT = fTs[i].fT;
4163 } else {
4164 SkDebugf(",%d", fTs[i].fOther->fID);
4165 }
4166 }
4167 if (i <= 0) {
4168 return;
4169 }
4170 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
4171 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
4172 if (fOperand) {
4173 SkDebugf(" operand");
4174 }
4175 if (done()) {
4176 SkDebugf(" done");
caryclark@google.com47580692012-07-23 12:14:49 +00004177 }
4178 SkDebugf("\n");
4179 }
4180#endif
4181
caryclark@google.com027de222012-07-12 12:52:50 +00004182#if DEBUG_ACTIVE_SPANS
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004183 void debugShowActiveSpans() const {
caryclark@google.com027de222012-07-12 12:52:50 +00004184 if (done()) {
4185 return;
4186 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004187#if DEBUG_ACTIVE_SPANS_SHORT_FORM
4188 int lastId = -1;
4189 double lastT = -1;
4190#endif
caryclark@google.com027de222012-07-12 12:52:50 +00004191 for (int i = 0; i < fTs.count(); ++i) {
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004192 SkASSERT(&fTs[i] == &fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOther->
4193 fTs[fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOtherIndex]);
caryclark@google.com027de222012-07-12 12:52:50 +00004194 if (fTs[i].fDone) {
4195 continue;
4196 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004197#if DEBUG_ACTIVE_SPANS_SHORT_FORM
4198 if (lastId == fID && lastT == fTs[i].fT) {
4199 continue;
4200 }
4201 lastId = fID;
4202 lastT = fTs[i].fT;
4203#endif
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004204 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com027de222012-07-12 12:52:50 +00004205 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4206 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4207 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4208 }
4209 const Span* span = &fTs[i];
rmistry@google.comd6176b02012-08-23 18:14:13 +00004210 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
caryclark@google.com0c803d02012-08-06 11:15:47 +00004211 xAtT(span), yAtT(span));
caryclark@google.com47d73da2013-02-17 01:41:25 +00004212 int iEnd = i + 1;
4213 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) {
4214 ++iEnd;
4215 }
4216 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT);
caryclark@google.com027de222012-07-12 12:52:50 +00004217 const Segment* other = fTs[i].fOther;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004218 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
4219 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
4220 if (fTs[i].fWindSum == SK_MinS32) {
4221 SkDebugf("?");
4222 } else {
4223 SkDebugf("%d", fTs[i].fWindSum);
4224 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004225 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
caryclark@google.com027de222012-07-12 12:52:50 +00004226 }
4227 }
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +00004228
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004229 // This isn't useful yet -- but leaving it in for now in case i think of something
4230 // to use it for
4231 void validateActiveSpans() const {
4232 if (done()) {
4233 return;
4234 }
4235 int tCount = fTs.count();
4236 for (int index = 0; index < tCount; ++index) {
4237 if (fTs[index].fDone) {
4238 continue;
4239 }
4240 // count number of connections which are not done
4241 int first = index;
4242 double baseT = fTs[index].fT;
4243 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
4244 --first;
4245 }
4246 int last = index;
4247 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
4248 ++last;
4249 }
4250 int connections = 0;
4251 connections += first > 0 && !fTs[first - 1].fDone;
4252 for (int test = first; test <= last; ++test) {
4253 connections += !fTs[test].fDone;
4254 const Segment* other = fTs[test].fOther;
4255 int oIndex = fTs[test].fOtherIndex;
4256 connections += !other->fTs[oIndex].fDone;
4257 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
4258 }
4259 // SkASSERT(!(connections & 1));
4260 }
4261 }
caryclark@google.com027de222012-07-12 12:52:50 +00004262#endif
4263
caryclark@google.com1304bb22013-03-13 20:29:41 +00004264#if DEBUG_MARK_DONE || DEBUG_UNSORTABLE
caryclark@google.com0c803d02012-08-06 11:15:47 +00004265 void debugShowNewWinding(const char* fun, const Span& span, int winding) {
4266 const SkPoint& pt = xyAtT(&span);
4267 SkDebugf("%s id=%d", fun, fID);
4268 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4269 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4270 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4271 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004272 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4273 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +00004274 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d windSum=",
skia.committer@gmail.com64334352013-03-06 07:01:46 +00004275 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +00004276 (&span)[1].fT, winding);
caryclark@google.com0c803d02012-08-06 11:15:47 +00004277 if (span.fWindSum == SK_MinS32) {
4278 SkDebugf("?");
4279 } else {
4280 SkDebugf("%d", span.fWindSum);
4281 }
4282 SkDebugf(" windValue=%d\n", span.fWindValue);
4283 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004284
4285 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
4286 const SkPoint& pt = xyAtT(&span);
4287 SkDebugf("%s id=%d", fun, fID);
4288 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4289 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4290 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4291 }
4292 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4293 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +00004294 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d newOppSum=%d oppSum=",
caryclark@google.com31143cf2012-11-09 22:14:19 +00004295 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +00004296 (&span)[1].fT, winding, oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004297 if (span.fOppSum == SK_MinS32) {
4298 SkDebugf("?");
4299 } else {
4300 SkDebugf("%d", span.fOppSum);
4301 }
4302 SkDebugf(" windSum=");
4303 if (span.fWindSum == SK_MinS32) {
4304 SkDebugf("?");
4305 } else {
4306 SkDebugf("%d", span.fWindSum);
4307 }
4308 SkDebugf(" windValue=%d\n", span.fWindValue);
4309 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00004310#endif
4311
caryclark@google.com1304bb22013-03-13 20:29:41 +00004312#if DEBUG_SORT || DEBUG_SWAP_TOP
caryclark@google.com03f97062012-08-21 13:13:52 +00004313 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
caryclark@google.com31143cf2012-11-09 22:14:19 +00004314 const int contourWinding, const int oppContourWinding) const {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004315 if (--gDebugSortCount < 0) {
4316 return;
4317 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004318 SkASSERT(angles[first]->segment() == this);
caryclark@google.com200c2112012-08-03 15:05:04 +00004319 SkASSERT(angles.count() > 1);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004320 int lastSum = contourWinding;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004321 int oppLastSum = oppContourWinding;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004322 const Angle* firstAngle = angles[first];
4323 int windSum = lastSum - spanSign(firstAngle);
4324 int oppoSign = oppSign(firstAngle);
4325 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004326 #define WIND_AS_STRING(x) char x##Str[12]; if (!valid_wind(x)) strcpy(x##Str, "?"); \
4327 else snprintf(x##Str, sizeof(x##Str), "%d", x)
4328 WIND_AS_STRING(contourWinding);
4329 WIND_AS_STRING(oppContourWinding);
4330 SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FUNCTION__,
4331 contourWindingStr, oppContourWindingStr, spanSign(angles[first]));
caryclark@google.comafe56de2012-07-24 18:11:03 +00004332 int index = first;
4333 bool firstTime = true;
caryclark@google.com47580692012-07-23 12:14:49 +00004334 do {
4335 const Angle& angle = *angles[index];
4336 const Segment& segment = *angle.segment();
4337 int start = angle.start();
4338 int end = angle.end();
4339 const Span& sSpan = segment.fTs[start];
4340 const Span& eSpan = segment.fTs[end];
4341 const Span& mSpan = segment.fTs[SkMin32(start, end)];
caryclark@google.com31143cf2012-11-09 22:14:19 +00004342 bool opp = segment.fOperand ^ fOperand;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004343 if (!firstTime) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004344 oppoSign = segment.oppSign(&angle);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004345 if (opp) {
4346 oppLastSum = oppWindSum;
4347 oppWindSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004348 if (oppoSign) {
4349 lastSum = windSum;
4350 windSum -= oppoSign;
4351 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004352 } else {
4353 lastSum = windSum;
4354 windSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004355 if (oppoSign) {
4356 oppLastSum = oppWindSum;
4357 oppWindSum -= oppoSign;
4358 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004359 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004360 }
skia.committer@gmail.com64334352013-03-06 07:01:46 +00004361 SkDebugf("%s [%d] %s", __FUNCTION__, index,
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +00004362 angle.unsortable() ? "*** UNSORTABLE *** " : "");
4363 #if COMPACT_DEBUG_SORT
4364 SkDebugf("id=%d %s start=%d (%1.9g,%,1.9g) end=%d (%1.9g,%,1.9g)",
caryclark@google.comc91dfe42012-10-16 12:06:27 +00004365 segment.fID, kLVerbStr[segment.fVerb],
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004366 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +00004367 segment.xAtT(&eSpan), segment.yAtT(&eSpan));
4368 #else
4369 switch (segment.fVerb) {
4370 case SkPath::kLine_Verb:
4371 SkDebugf(LINE_DEBUG_STR, LINE_DEBUG_DATA(segment.fPts));
4372 break;
4373 case SkPath::kQuad_Verb:
4374 SkDebugf(QUAD_DEBUG_STR, QUAD_DEBUG_DATA(segment.fPts));
4375 break;
4376 case SkPath::kCubic_Verb:
4377 SkDebugf(CUBIC_DEBUG_STR, CUBIC_DEBUG_DATA(segment.fPts));
4378 break;
caryclark@google.com1ab0aac2013-03-13 20:41:48 +00004379 default:
4380 SkASSERT(0);
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +00004381 }
4382 SkDebugf(" tStart=%1.9g tEnd=%1.9g", sSpan.fT, eSpan.fT);
4383 #endif
4384 SkDebugf(" sign=%d windValue=%d windSum=", angle.sign(), mSpan.fWindValue);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004385 winding_printf(mSpan.fWindSum);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004386 int last, wind;
4387 if (opp) {
4388 last = oppLastSum;
4389 wind = oppWindSum;
4390 } else {
4391 last = lastSum;
4392 wind = windSum;
4393 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004394 bool useInner = valid_wind(last) && valid_wind(wind) && useInnerWinding(last, wind);
4395 WIND_AS_STRING(last);
4396 WIND_AS_STRING(wind);
4397 WIND_AS_STRING(lastSum);
4398 WIND_AS_STRING(oppLastSum);
4399 WIND_AS_STRING(windSum);
4400 WIND_AS_STRING(oppWindSum);
4401 #undef WIND_AS_STRING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004402 if (!oppoSign) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004403 SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr : lastStr);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004404 } else {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004405 SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : oppLastSumStr,
4406 opp ? windSumStr : oppWindSumStr);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004407 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004408 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004409#if false && DEBUG_ANGLE
caryclark@google.comc899ad92012-08-23 15:24:42 +00004410 angle.debugShow(segment.xyAtT(&sSpan));
4411#endif
caryclark@google.com47580692012-07-23 12:14:49 +00004412 ++index;
4413 if (index == angles.count()) {
4414 index = 0;
4415 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004416 if (firstTime) {
4417 firstTime = false;
4418 }
caryclark@google.com47580692012-07-23 12:14:49 +00004419 } while (index != first);
4420 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00004421
4422 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
4423 const Angle* firstAngle = angles[first];
4424 const Segment* segment = firstAngle->segment();
4425 int winding = segment->updateWinding(firstAngle);
4426 int oppWinding = segment->updateOppWinding(firstAngle);
4427 debugShowSort(fun, angles, first, winding, oppWinding);
4428 }
4429
caryclark@google.com47580692012-07-23 12:14:49 +00004430#endif
4431
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004432#if DEBUG_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004433 static char as_digit(int value) {
4434 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
4435 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004436#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004437
caryclark@google.com729e1c42012-11-21 21:36:34 +00004438#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004439 int debugShowWindingValues(int slotCount, int ofInterest) const {
4440 if (!(1 << fID & ofInterest)) {
4441 return 0;
4442 }
4443 int sum = 0;
4444 SkTDArray<char> slots;
4445 slots.setCount(slotCount * 2);
4446 memset(slots.begin(), ' ', slotCount * 2);
4447 for (int i = 0; i < fTs.count(); ++i) {
4448 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
4449 // continue;
4450 // }
4451 sum += fTs[i].fWindValue;
4452 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
4453 sum += fTs[i].fOppValue;
4454 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
4455 }
4456 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
4457 slots.begin() + slotCount);
4458 return sum;
4459 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004460#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004461
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004462private:
4463 const SkPoint* fPts;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004464 Bounds fBounds;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004465 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
caryclark@google.com4eeda372012-12-06 21:47:48 +00004466 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
caryclark@google.com24bec792012-08-20 12:43:57 +00004467 int fDoneSpans; // quick check that segment is finished
caryclark@google.com4eeda372012-12-06 21:47:48 +00004468 // OPTIMIZATION: force the following to be byte-sized
4469 SkPath::Verb fVerb;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004470 bool fOperand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004471 bool fXor; // set if original contour had even-odd fill
4472 bool fOppXor; // set if opposite operand had even-odd fill
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004473#if DEBUG_DUMP
4474 int fID;
4475#endif
4476};
4477
caryclark@google.comb9738012012-07-03 19:53:30 +00004478class Contour;
4479
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004480struct Coincidence {
caryclark@google.comb9738012012-07-03 19:53:30 +00004481 Contour* fContours[2];
4482 int fSegments[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004483 double fTs[2][2];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004484 SkPoint fPts[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004485};
4486
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004487class Contour {
4488public:
4489 Contour() {
4490 reset();
4491#if DEBUG_DUMP
4492 fID = ++gContourID;
4493#endif
4494 }
4495
4496 bool operator<(const Contour& rh) const {
4497 return fBounds.fTop == rh.fBounds.fTop
4498 ? fBounds.fLeft < rh.fBounds.fLeft
4499 : fBounds.fTop < rh.fBounds.fTop;
4500 }
4501
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004502 void addCoincident(int index, Contour* other, int otherIndex,
4503 const Intersections& ts, bool swap) {
4504 Coincidence& coincidence = *fCoincidences.append();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004505 coincidence.fContours[0] = this; // FIXME: no need to store
caryclark@google.comb9738012012-07-03 19:53:30 +00004506 coincidence.fContours[1] = other;
4507 coincidence.fSegments[0] = index;
4508 coincidence.fSegments[1] = otherIndex;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004509 coincidence.fTs[swap][0] = ts.fT[0][0];
4510 coincidence.fTs[swap][1] = ts.fT[0][1];
4511 coincidence.fTs[!swap][0] = ts.fT[1][0];
4512 coincidence.fTs[!swap][1] = ts.fT[1][1];
4513 coincidence.fPts[0] = ts.fPt[0].asSkPoint();
4514 coincidence.fPts[1] = ts.fPt[1].asSkPoint();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004515 }
4516
4517 void addCross(const Contour* crosser) {
4518#ifdef DEBUG_CROSS
4519 for (int index = 0; index < fCrosses.count(); ++index) {
4520 SkASSERT(fCrosses[index] != crosser);
4521 }
4522#endif
4523 *fCrosses.append() = crosser;
4524 }
4525
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004526 void addCubic(const SkPoint pts[4]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004527 fSegments.push_back().addCubic(pts, fOperand, fXor);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004528 fContainsCurves = fContainsCubics = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004529 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004530
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004531 int addLine(const SkPoint pts[2]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004532 fSegments.push_back().addLine(pts, fOperand, fXor);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004533 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004534 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004535
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004536 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
4537 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
4538 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004539
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004540 int addQuad(const SkPoint pts[3]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004541 fSegments.push_back().addQuad(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004542 fContainsCurves = true;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004543 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004544 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004545
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004546 int addT(int segIndex, Contour* other, int otherIndex, const SkPoint& pt, double& newT) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004547 setContainsIntercepts();
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004548 return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004549 }
4550
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00004551 int addSelfT(int segIndex, Contour* other, int otherIndex, const SkPoint& pt, double& newT) {
4552 setContainsIntercepts();
4553 return fSegments[segIndex].addSelfT(&other->fSegments[otherIndex], pt, newT);
4554 }
4555
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004556 int addUnsortableT(int segIndex, Contour* other, int otherIndex, bool start,
4557 const SkPoint& pt, double& newT) {
4558 return fSegments[segIndex].addUnsortableT(&other->fSegments[otherIndex], start, pt, newT);
caryclark@google.com73ca6242013-01-17 21:02:47 +00004559 }
4560
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004561 const Bounds& bounds() const {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004562 return fBounds;
4563 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004564
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004565 void complete() {
4566 setBounds();
4567 fContainsIntercepts = false;
4568 }
skia.committer@gmail.com58433de2013-02-23 07:02:45 +00004569
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004570 bool containsCubics() const {
4571 return fContainsCubics;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004572 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004573
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004574 bool crosses(const Contour* crosser) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004575 for (int index = 0; index < fCrosses.count(); ++index) {
4576 if (fCrosses[index] == crosser) {
4577 return true;
4578 }
4579 }
4580 return false;
4581 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004582
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004583 bool done() const {
4584 return fDone;
4585 }
4586
caryclark@google.comf839c032012-10-26 21:03:50 +00004587 const SkPoint& end() const {
4588 const Segment& segment = fSegments.back();
4589 return segment.pts()[segment.verb()];
4590 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004591
caryclark@google.com4eeda372012-12-06 21:47:48 +00004592 void findTooCloseToCall() {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004593 int segmentCount = fSegments.count();
4594 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004595 fSegments[sIndex].findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004596 }
4597 }
4598
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004599 void fixOtherTIndex() {
4600 int segmentCount = fSegments.count();
4601 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4602 fSegments[sIndex].fixOtherTIndex();
4603 }
4604 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004605
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004606 Segment* nonVerticalSegment(int& start, int& end) {
4607 int segmentCount = fSortedSegments.count();
4608 SkASSERT(segmentCount > 0);
4609 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4610 Segment* testSegment = fSortedSegments[sortedIndex];
4611 if (testSegment->done()) {
4612 continue;
4613 }
4614 start = end = 0;
4615 while (testSegment->nextCandidate(start, end)) {
4616 if (!testSegment->isVertical(start, end)) {
4617 return testSegment;
4618 }
4619 }
4620 }
4621 return NULL;
4622 }
4623
caryclark@google.com31143cf2012-11-09 22:14:19 +00004624 bool operand() const {
4625 return fOperand;
4626 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004627
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004628 void reset() {
4629 fSegments.reset();
4630 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004631 fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004632 }
caryclark@google.comb9738012012-07-03 19:53:30 +00004633
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004634 void resolveCoincidence(SkTDArray<Contour*>& contourList) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004635 int count = fCoincidences.count();
4636 for (int index = 0; index < count; ++index) {
4637 Coincidence& coincidence = fCoincidences[index];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004638 SkASSERT(coincidence.fContours[0] == this);
caryclark@google.comb9738012012-07-03 19:53:30 +00004639 int thisIndex = coincidence.fSegments[0];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004640 Segment& thisOne = fSegments[thisIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004641 Contour* otherContour = coincidence.fContours[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004642 int otherIndex = coincidence.fSegments[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004643 Segment& other = otherContour->fSegments[otherIndex];
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004644 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004645 continue;
4646 }
caryclark@google.com47580692012-07-23 12:14:49 +00004647 #if DEBUG_CONCIDENT
4648 thisOne.debugShowTs();
4649 other.debugShowTs();
4650 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004651 double startT = coincidence.fTs[0][0];
4652 double endT = coincidence.fTs[0][1];
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004653 bool cancelers = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004654 if (startT > endT) {
4655 SkTSwap<double>(startT, endT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004656 cancelers ^= true; // FIXME: just assign true
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004657 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004658 SkASSERT(!approximately_negative(endT - startT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004659 double oStartT = coincidence.fTs[1][0];
4660 double oEndT = coincidence.fTs[1][1];
4661 if (oStartT > oEndT) {
4662 SkTSwap<double>(oStartT, oEndT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004663 cancelers ^= true;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004664 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004665 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00004666 bool opp = fOperand ^ otherContour->fOperand;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004667 if (cancelers && !opp) {
4668 // make sure startT and endT have t entries
caryclark@google.com2ddff932012-08-07 21:25:27 +00004669 if (startT > 0 || oEndT < 1
4670 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004671 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004672 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00004673 if (oStartT > 0 || endT < 1
4674 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004675 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004676 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004677 if (!thisOne.done() && !other.done()) {
4678 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4679 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004680 } else {
caryclark@google.com200c2112012-08-03 15:05:04 +00004681 if (startT > 0 || oStartT > 0
4682 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004683 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004684 }
caryclark@google.com200c2112012-08-03 15:05:04 +00004685 if (endT < 1 || oEndT < 1
4686 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004687 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004688 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004689 if (!thisOne.done() && !other.done()) {
4690 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4691 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004692 }
caryclark@google.com47580692012-07-23 12:14:49 +00004693 #if DEBUG_CONCIDENT
4694 thisOne.debugShowTs();
4695 other.debugShowTs();
4696 #endif
caryclark@google.com729e1c42012-11-21 21:36:34 +00004697 #if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004698 debugShowWindingValues(contourList);
4699 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004700 }
4701 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004702
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004703 // first pass, add missing T values
4704 // second pass, determine winding values of overlaps
4705 void addCoincidentPoints() {
4706 int count = fCoincidences.count();
4707 for (int index = 0; index < count; ++index) {
4708 Coincidence& coincidence = fCoincidences[index];
4709 SkASSERT(coincidence.fContours[0] == this);
4710 int thisIndex = coincidence.fSegments[0];
4711 Segment& thisOne = fSegments[thisIndex];
4712 Contour* otherContour = coincidence.fContours[1];
4713 int otherIndex = coincidence.fSegments[1];
4714 Segment& other = otherContour->fSegments[otherIndex];
4715 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
4716 // OPTIMIZATION: remove from array
4717 continue;
4718 }
4719 #if DEBUG_CONCIDENT
4720 thisOne.debugShowTs();
4721 other.debugShowTs();
4722 #endif
4723 double startT = coincidence.fTs[0][0];
4724 double endT = coincidence.fTs[0][1];
4725 bool cancelers;
4726 if ((cancelers = startT > endT)) {
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004727 SkTSwap(startT, endT);
4728 SkTSwap(coincidence.fPts[0], coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004729 }
4730 SkASSERT(!approximately_negative(endT - startT));
4731 double oStartT = coincidence.fTs[1][0];
4732 double oEndT = coincidence.fTs[1][1];
4733 if (oStartT > oEndT) {
4734 SkTSwap<double>(oStartT, oEndT);
4735 cancelers ^= true;
4736 }
4737 SkASSERT(!approximately_negative(oEndT - oStartT));
4738 bool opp = fOperand ^ otherContour->fOperand;
4739 if (cancelers && !opp) {
4740 // make sure startT and endT have t entries
4741 if (startT > 0 || oEndT < 1
4742 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004743 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004744 }
4745 if (oStartT > 0 || endT < 1
4746 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004747 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004748 }
4749 } else {
4750 if (startT > 0 || oStartT > 0
4751 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004752 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004753 }
4754 if (endT < 1 || oEndT < 1
4755 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004756 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004757 }
4758 }
4759 #if DEBUG_CONCIDENT
4760 thisOne.debugShowTs();
4761 other.debugShowTs();
4762 #endif
4763 }
4764 }
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00004765
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004766 void calcCoincidentWinding() {
4767 int count = fCoincidences.count();
4768 for (int index = 0; index < count; ++index) {
4769 Coincidence& coincidence = fCoincidences[index];
4770 SkASSERT(coincidence.fContours[0] == this);
4771 int thisIndex = coincidence.fSegments[0];
4772 Segment& thisOne = fSegments[thisIndex];
4773 if (thisOne.done()) {
4774 continue;
4775 }
4776 Contour* otherContour = coincidence.fContours[1];
4777 int otherIndex = coincidence.fSegments[1];
4778 Segment& other = otherContour->fSegments[otherIndex];
4779 if (other.done()) {
4780 continue;
4781 }
4782 double startT = coincidence.fTs[0][0];
4783 double endT = coincidence.fTs[0][1];
4784 bool cancelers;
4785 if ((cancelers = startT > endT)) {
4786 SkTSwap<double>(startT, endT);
4787 }
4788 SkASSERT(!approximately_negative(endT - startT));
4789 double oStartT = coincidence.fTs[1][0];
4790 double oEndT = coincidence.fTs[1][1];
4791 if (oStartT > oEndT) {
4792 SkTSwap<double>(oStartT, oEndT);
4793 cancelers ^= true;
4794 }
4795 SkASSERT(!approximately_negative(oEndT - oStartT));
4796 bool opp = fOperand ^ otherContour->fOperand;
4797 if (cancelers && !opp) {
4798 // make sure startT and endT have t entries
4799 if (!thisOne.done() && !other.done()) {
4800 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4801 }
4802 } else {
4803 if (!thisOne.done() && !other.done()) {
4804 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4805 }
4806 }
4807 #if DEBUG_CONCIDENT
4808 thisOne.debugShowTs();
4809 other.debugShowTs();
4810 #endif
4811 }
4812 }
4813
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004814 SkTArray<Segment>& segments() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004815 return fSegments;
4816 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004817
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004818 void setContainsIntercepts() {
4819 fContainsIntercepts = true;
4820 }
4821
caryclark@google.com235f56a2012-09-14 14:19:30 +00004822 void setOperand(bool isOp) {
4823 fOperand = isOp;
4824 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00004825
caryclark@google.com4eeda372012-12-06 21:47:48 +00004826 void setOppXor(bool isOppXor) {
4827 fOppXor = isOppXor;
4828 int segmentCount = fSegments.count();
4829 for (int test = 0; test < segmentCount; ++test) {
4830 fSegments[test].setOppXor(isOppXor);
4831 }
4832 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004833
caryclark@google.com235f56a2012-09-14 14:19:30 +00004834 void setXor(bool isXor) {
4835 fXor = isXor;
4836 }
4837
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004838 void sortSegments() {
4839 int segmentCount = fSegments.count();
4840 fSortedSegments.setReserve(segmentCount);
4841 for (int test = 0; test < segmentCount; ++test) {
4842 *fSortedSegments.append() = &fSegments[test];
4843 }
4844 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4845 fFirstSorted = 0;
4846 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004847
caryclark@google.comf839c032012-10-26 21:03:50 +00004848 const SkPoint& start() const {
4849 return fSegments.front().pts()[0];
4850 }
4851
4852 void toPath(PathWrapper& path) const {
4853 int segmentCount = fSegments.count();
4854 const SkPoint& pt = fSegments.front().pts()[0];
4855 path.deferredMove(pt);
4856 for (int test = 0; test < segmentCount; ++test) {
4857 fSegments[test].addCurveTo(0, 1, path, true);
4858 }
4859 path.close();
4860 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004861
caryclark@google.comf839c032012-10-26 21:03:50 +00004862 void toPartialBackward(PathWrapper& path) const {
4863 int segmentCount = fSegments.count();
4864 for (int test = segmentCount - 1; test >= 0; --test) {
4865 fSegments[test].addCurveTo(1, 0, path, true);
4866 }
4867 }
4868
4869 void toPartialForward(PathWrapper& path) const {
4870 int segmentCount = fSegments.count();
4871 for (int test = 0; test < segmentCount; ++test) {
4872 fSegments[test].addCurveTo(0, 1, path, true);
4873 }
4874 }
4875
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004876 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004877 int segmentCount = fSortedSegments.count();
4878 SkASSERT(segmentCount > 0);
caryclark@google.comf839c032012-10-26 21:03:50 +00004879 int sortedIndex = fFirstSorted;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004880 fDone = true; // may be cleared below
caryclark@google.comf839c032012-10-26 21:03:50 +00004881 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4882 Segment* testSegment = fSortedSegments[sortedIndex];
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004883 if (testSegment->done()) {
caryclark@google.comf839c032012-10-26 21:03:50 +00004884 if (sortedIndex == fFirstSorted) {
4885 ++fFirstSorted;
4886 }
4887 continue;
4888 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004889 fDone = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004890 SkPoint testXY = testSegment->activeLeftTop(true, NULL);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004891 if (topStart) {
4892 if (testXY.fY < topLeft.fY) {
4893 continue;
4894 }
4895 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4896 continue;
4897 }
4898 if (bestXY.fY < testXY.fY) {
4899 continue;
4900 }
4901 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4902 continue;
4903 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004904 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004905 topStart = testSegment;
caryclark@google.comf839c032012-10-26 21:03:50 +00004906 bestXY = testXY;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004907 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004908 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004909
caryclark@google.com24bec792012-08-20 12:43:57 +00004910 Segment* undoneSegment(int& start, int& end) {
4911 int segmentCount = fSegments.count();
4912 for (int test = 0; test < segmentCount; ++test) {
4913 Segment* testSegment = &fSegments[test];
4914 if (testSegment->done()) {
4915 continue;
4916 }
4917 testSegment->undoneSpan(start, end);
4918 return testSegment;
4919 }
4920 return NULL;
4921 }
4922
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004923 int updateSegment(int index, const SkPoint* pts) {
4924 Segment& segment = fSegments[index];
4925 segment.updatePts(pts);
4926 return segment.verb() + 1;
4927 }
4928
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004929#if DEBUG_TEST
4930 SkTArray<Segment>& debugSegments() {
4931 return fSegments;
4932 }
4933#endif
4934
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004935#if DEBUG_DUMP
4936 void dump() {
4937 int i;
4938 const char className[] = "Contour";
4939 const int tab = 4;
4940 SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4941 for (i = 0; i < fSegments.count(); ++i) {
4942 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4943 className, i);
4944 fSegments[i].dump();
4945 }
4946 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4947 tab + sizeof(className), className,
4948 fBounds.fLeft, fBounds.fTop,
4949 fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004950 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4951 className, fContainsIntercepts);
4952 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4953 className, fContainsCurves);
4954 }
4955#endif
4956
caryclark@google.com027de222012-07-12 12:52:50 +00004957#if DEBUG_ACTIVE_SPANS
4958 void debugShowActiveSpans() {
4959 for (int index = 0; index < fSegments.count(); ++index) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004960 fSegments[index].debugShowActiveSpans();
caryclark@google.com027de222012-07-12 12:52:50 +00004961 }
4962 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004963
4964 void validateActiveSpans() {
4965 for (int index = 0; index < fSegments.count(); ++index) {
4966 fSegments[index].validateActiveSpans();
4967 }
4968 }
caryclark@google.com027de222012-07-12 12:52:50 +00004969#endif
4970
caryclark@google.com729e1c42012-11-21 21:36:34 +00004971#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004972 int debugShowWindingValues(int totalSegments, int ofInterest) {
4973 int count = fSegments.count();
4974 int sum = 0;
4975 for (int index = 0; index < count; ++index) {
4976 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4977 }
4978 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4979 return sum;
4980 }
4981
4982 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4983 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4984 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4985 int ofInterest = 1 << 5 | 1 << 8;
4986 int total = 0;
4987 int index;
4988 for (index = 0; index < contourList.count(); ++index) {
4989 total += contourList[index]->segments().count();
4990 }
4991 int sum = 0;
4992 for (index = 0; index < contourList.count(); ++index) {
4993 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4994 }
4995 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4996 }
4997#endif
4998
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004999protected:
5000 void setBounds() {
5001 int count = fSegments.count();
5002 if (count == 0) {
5003 SkDebugf("%s empty contour\n", __FUNCTION__);
5004 SkASSERT(0);
5005 // FIXME: delete empty contour?
5006 return;
5007 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005008 fBounds = fSegments.front().bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005009 for (int index = 1; index < count; ++index) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005010 fBounds.add(fSegments[index].bounds());
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005011 }
5012 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005013
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005014private:
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005015 SkTArray<Segment> fSegments;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005016 SkTDArray<Segment*> fSortedSegments;
5017 int fFirstSorted;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005018 SkTDArray<Coincidence> fCoincidences;
5019 SkTDArray<const Contour*> fCrosses;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005020 Bounds fBounds;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005021 bool fContainsIntercepts; // FIXME: is this used by anybody?
5022 bool fContainsCubics;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005023 bool fContainsCurves;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005024 bool fDone;
caryclark@google.com235f56a2012-09-14 14:19:30 +00005025 bool fOperand; // true for the second argument to a binary operator
5026 bool fXor;
caryclark@google.com4eeda372012-12-06 21:47:48 +00005027 bool fOppXor;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005028#if DEBUG_DUMP
5029 int fID;
5030#endif
5031};
5032
5033class EdgeBuilder {
5034public:
5035
caryclark@google.comf839c032012-10-26 21:03:50 +00005036EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
5037 : fPath(path.nativePath())
5038 , fContours(contours)
5039{
5040 init();
5041}
5042
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005043EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
caryclark@google.com235f56a2012-09-14 14:19:30 +00005044 : fPath(&path)
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005045 , fContours(contours)
5046{
caryclark@google.comf839c032012-10-26 21:03:50 +00005047 init();
5048}
5049
5050void init() {
5051 fCurrentContour = NULL;
5052 fOperand = false;
caryclark@google.com729e1c42012-11-21 21:36:34 +00005053 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005054#if DEBUG_DUMP
5055 gContourID = 0;
5056 gSegmentID = 0;
5057#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00005058 fSecondHalf = preFetch();
5059}
5060
5061void addOperand(const SkPath& path) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00005062 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
5063 fPathVerbs.pop();
caryclark@google.com235f56a2012-09-14 14:19:30 +00005064 fPath = &path;
caryclark@google.com729e1c42012-11-21 21:36:34 +00005065 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.com235f56a2012-09-14 14:19:30 +00005066 preFetch();
5067}
5068
5069void finish() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005070 walk();
caryclark@google.com235f56a2012-09-14 14:19:30 +00005071 complete();
5072 if (fCurrentContour && !fCurrentContour->segments().count()) {
5073 fContours.pop_back();
5074 }
5075 // correct pointers in contours since fReducePts may have moved as it grew
5076 int cIndex = 0;
5077 int extraCount = fExtra.count();
5078 SkASSERT(extraCount == 0 || fExtra[0] == -1);
5079 int eIndex = 0;
5080 int rIndex = 0;
5081 while (++eIndex < extraCount) {
5082 int offset = fExtra[eIndex];
5083 if (offset < 0) {
5084 ++cIndex;
5085 continue;
5086 }
5087 fCurrentContour = &fContours[cIndex];
5088 rIndex += fCurrentContour->updateSegment(offset - 1,
5089 &fReducePts[rIndex]);
5090 }
5091 fExtra.reset(); // we're done with this
5092}
5093
5094ShapeOpMask xorMask() const {
caryclark@google.com729e1c42012-11-21 21:36:34 +00005095 return fXorMask[fOperand];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005096}
5097
5098protected:
5099
5100void complete() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005101 if (fCurrentContour && fCurrentContour->segments().count()) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005102 fCurrentContour->complete();
5103 fCurrentContour = NULL;
5104 }
5105}
5106
caryclark@google.com235f56a2012-09-14 14:19:30 +00005107// FIXME:remove once we can access path pts directly
5108int preFetch() {
5109 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005110 SkPoint pts[4];
5111 SkPath::Verb verb;
5112 do {
5113 verb = iter.next(pts);
5114 *fPathVerbs.append() = verb;
5115 if (verb == SkPath::kMove_Verb) {
5116 *fPathPts.append() = pts[0];
5117 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
5118 fPathPts.append(verb, &pts[1]);
5119 }
5120 } while (verb != SkPath::kDone_Verb);
caryclark@google.com31143cf2012-11-09 22:14:19 +00005121 return fPathVerbs.count() - 1;
caryclark@google.com235f56a2012-09-14 14:19:30 +00005122}
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005123
caryclark@google.com235f56a2012-09-14 14:19:30 +00005124void walk() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005125 SkPath::Verb reducedVerb;
5126 uint8_t* verbPtr = fPathVerbs.begin();
caryclark@google.com235f56a2012-09-14 14:19:30 +00005127 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005128 const SkPoint* pointsPtr = fPathPts.begin();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005129 const SkPoint* finalCurveStart = NULL;
5130 const SkPoint* finalCurveEnd = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00005131 SkPath::Verb verb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005132 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
5133 switch (verb) {
5134 case SkPath::kMove_Verb:
5135 complete();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005136 if (!fCurrentContour) {
5137 fCurrentContour = fContours.push_back_n(1);
caryclark@google.com235f56a2012-09-14 14:19:30 +00005138 fCurrentContour->setOperand(fOperand);
caryclark@google.com729e1c42012-11-21 21:36:34 +00005139 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005140 *fExtra.append() = -1; // start new contour
5141 }
caryclark@google.com59823f72012-08-09 18:17:47 +00005142 finalCurveEnd = pointsPtr++;
caryclark@google.com31143cf2012-11-09 22:14:19 +00005143 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005144 case SkPath::kLine_Verb:
5145 // skip degenerate points
5146 if (pointsPtr[-1].fX != pointsPtr[0].fX
5147 || pointsPtr[-1].fY != pointsPtr[0].fY) {
5148 fCurrentContour->addLine(&pointsPtr[-1]);
5149 }
5150 break;
5151 case SkPath::kQuad_Verb:
rmistry@google.comd6176b02012-08-23 18:14:13 +00005152
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005153 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
5154 if (reducedVerb == 0) {
5155 break; // skip degenerate points
5156 }
5157 if (reducedVerb == 1) {
rmistry@google.comd6176b02012-08-23 18:14:13 +00005158 *fExtra.append() =
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005159 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005160 break;
5161 }
5162 fCurrentContour->addQuad(&pointsPtr[-1]);
5163 break;
5164 case SkPath::kCubic_Verb:
5165 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
5166 if (reducedVerb == 0) {
5167 break; // skip degenerate points
5168 }
5169 if (reducedVerb == 1) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005170 *fExtra.append() =
5171 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005172 break;
5173 }
5174 if (reducedVerb == 2) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005175 *fExtra.append() =
5176 fCurrentContour->addQuad(fReducePts.end() - 3);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005177 break;
5178 }
5179 fCurrentContour->addCubic(&pointsPtr[-1]);
5180 break;
5181 case SkPath::kClose_Verb:
5182 SkASSERT(fCurrentContour);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005183 if (finalCurveStart && finalCurveEnd
5184 && *finalCurveStart != *finalCurveEnd) {
5185 *fReducePts.append() = *finalCurveStart;
5186 *fReducePts.append() = *finalCurveEnd;
5187 *fExtra.append() =
5188 fCurrentContour->addLine(fReducePts.end() - 2);
5189 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005190 complete();
caryclark@google.com31143cf2012-11-09 22:14:19 +00005191 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005192 default:
5193 SkDEBUGFAIL("bad verb");
5194 return;
5195 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005196 finalCurveStart = &pointsPtr[verb - 1];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005197 pointsPtr += verb;
5198 SkASSERT(fCurrentContour);
caryclark@google.com31143cf2012-11-09 22:14:19 +00005199 nextVerb:
caryclark@google.com235f56a2012-09-14 14:19:30 +00005200 if (verbPtr == endOfFirstHalf) {
5201 fOperand = true;
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00005202 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005203 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005204}
5205
5206private:
caryclark@google.com235f56a2012-09-14 14:19:30 +00005207 const SkPath* fPath;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005208 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005209 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005210 Contour* fCurrentContour;
5211 SkTArray<Contour>& fContours;
5212 SkTDArray<SkPoint> fReducePts; // segments created on the fly
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005213 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
caryclark@google.com729e1c42012-11-21 21:36:34 +00005214 ShapeOpMask fXorMask[2];
caryclark@google.com235f56a2012-09-14 14:19:30 +00005215 int fSecondHalf;
5216 bool fOperand;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005217};
5218
5219class Work {
5220public:
5221 enum SegmentType {
5222 kHorizontalLine_Segment = -1,
5223 kVerticalLine_Segment = 0,
5224 kLine_Segment = SkPath::kLine_Verb,
5225 kQuad_Segment = SkPath::kQuad_Verb,
5226 kCubic_Segment = SkPath::kCubic_Verb,
5227 };
rmistry@google.comd6176b02012-08-23 18:14:13 +00005228
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005229 void addCoincident(Work& other, const Intersections& ts, bool swap) {
5230 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
5231 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005232
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005233 // FIXME: does it make sense to write otherIndex now if we're going to
5234 // fix it up later?
5235 void addOtherT(int index, double otherT, int otherIndex) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005236 fContour->addOtherT(fIndex, index, otherT, otherIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005237 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005238
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005239 // Avoid collapsing t values that are close to the same since
5240 // we walk ts to describe consecutive intersections. Since a pair of ts can
5241 // be nearly equal, any problems caused by this should be taken care
5242 // of later.
5243 // On the edge or out of range values are negative; add 2 to get end
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005244 int addT(const Work& other, const SkPoint& pt, double& newT) {
5245 return fContour->addT(fIndex, other.fContour, other.fIndex, pt, newT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005246 }
skia.committer@gmail.com631cdcb2013-03-01 12:12:55 +00005247
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00005248 int addSelfT(const Work& other, const SkPoint& pt, double& newT) {
5249 return fContour->addSelfT(fIndex, other.fContour, other.fIndex, pt, newT);
5250 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005251
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005252 int addUnsortableT(const Work& other, bool start, const SkPoint& pt, double& newT) {
5253 return fContour->addUnsortableT(fIndex, other.fContour, other.fIndex, start, pt, newT);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005254 }
5255
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005256 bool advance() {
5257 return ++fIndex < fLast;
5258 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005259
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005260 SkScalar bottom() const {
5261 return bounds().fBottom;
5262 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005263
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005264 const Bounds& bounds() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005265 return fContour->segments()[fIndex].bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005266 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00005267
caryclark@google.com73ca6242013-01-17 21:02:47 +00005268#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005269 const SkPoint* cubic() const {
5270 return fCubic;
5271 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005272#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005273
5274 void init(Contour* contour) {
5275 fContour = contour;
5276 fIndex = 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005277 fLast = contour->segments().count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005278 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00005279
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00005280 bool isAdjacent(const Work& next) {
5281 return fContour == next.fContour && fIndex + 1 == next.fIndex;
5282 }
5283
5284 bool isFirstLast(const Work& next) {
5285 return fContour == next.fContour && fIndex == 0
5286 && next.fIndex == fLast - 1;
5287 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005288
5289 SkScalar left() const {
5290 return bounds().fLeft;
5291 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005292
caryclark@google.com73ca6242013-01-17 21:02:47 +00005293#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005294 void promoteToCubic() {
5295 fCubic[0] = pts()[0];
5296 fCubic[2] = pts()[1];
5297 fCubic[3] = pts()[2];
5298 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
5299 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
5300 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
5301 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
5302 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005303#endif
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005304
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005305 const SkPoint* pts() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005306 return fContour->segments()[fIndex].pts();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005307 }
5308
5309 SkScalar right() const {
5310 return bounds().fRight;
5311 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005312
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005313 ptrdiff_t segmentIndex() const {
5314 return fIndex;
5315 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005316
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005317 SegmentType segmentType() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005318 const Segment& segment = fContour->segments()[fIndex];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005319 SegmentType type = (SegmentType) segment.verb();
5320 if (type != kLine_Segment) {
5321 return type;
5322 }
5323 if (segment.isHorizontal()) {
5324 return kHorizontalLine_Segment;
5325 }
5326 if (segment.isVertical()) {
5327 return kVerticalLine_Segment;
5328 }
5329 return kLine_Segment;
5330 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005331
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005332 bool startAfter(const Work& after) {
5333 fIndex = after.fIndex;
5334 return advance();
5335 }
5336
5337 SkScalar top() const {
5338 return bounds().fTop;
5339 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005340
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005341 SkPath::Verb verb() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005342 return fContour->segments()[fIndex].verb();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005343 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005344
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005345 SkScalar x() const {
5346 return bounds().fLeft;
5347 }
5348
5349 bool xFlipped() const {
5350 return x() != pts()[0].fX;
5351 }
5352
5353 SkScalar y() const {
5354 return bounds().fTop;
5355 }
5356
5357 bool yFlipped() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005358 return y() != pts()[0].fY;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005359 }
5360
5361protected:
5362 Contour* fContour;
caryclark@google.com73ca6242013-01-17 21:02:47 +00005363#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005364 SkPoint fCubic[4];
caryclark@google.com73ca6242013-01-17 21:02:47 +00005365#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005366 int fIndex;
5367 int fLast;
5368};
5369
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005370#if DEBUG_ADD_INTERSECTING_TS
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005371
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005372static void debugShowLineIntersection(int pts, const Work& wt, const Work& wn,
5373 const Intersections& i) {
5374 SkASSERT(i.used() == pts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005375 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005376 SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n",
5377 __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005378 return;
5379 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005380 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " LINE_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5381 i.fT[0][0], LINE_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005382 if (pts == 2) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005383 SkDebugf(" " T_DEBUG_STR(wtTs, 1) " " PT_DEBUG_STR, i.fT[0][1], PT_DEBUG_DATA(i, 1));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005384 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005385 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005386 if (pts == 2) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005387 SkDebugf(" " T_DEBUG_STR(wnTs, 1), i.fT[1][1]);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005388 }
5389 SkDebugf("\n");
5390}
5391
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005392static void debugShowQuadLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005393 const Work& wn, const Intersections& i) {
5394 SkASSERT(i.used() == pts);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005395 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005396 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " LINE_DEBUG_STR "\n",
5397 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005398 return;
5399 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005400 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5401 i.fT[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5402 for (int n = 1; n < pts; ++n) {
5403 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005404 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005405 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
5406 for (int n = 1; n < pts; ++n) {
5407 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005408 }
5409 SkDebugf("\n");
5410}
5411
caryclark@google.coma461ff02012-10-11 12:54:23 +00005412static void debugShowQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005413 const Work& wn, const Intersections& i) {
5414 SkASSERT(i.used() == pts);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005415 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005416 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " QUAD_DEBUG_STR "\n",
5417 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
caryclark@google.coma461ff02012-10-11 12:54:23 +00005418 return;
5419 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005420 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5421 i.fT[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5422 for (int n = 1; n < pts; ++n) {
5423 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
caryclark@google.coma461ff02012-10-11 12:54:23 +00005424 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005425 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i.fT[1][0], QUAD_DEBUG_DATA(wn.pts()));
5426 for (int n = 1; n < pts; ++n) {
5427 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005428 }
caryclark@google.comb9738012012-07-03 19:53:30 +00005429 SkDebugf("\n");
5430}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005431
5432static void debugShowCubicLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005433 const Work& wn, const Intersections& i) {
5434 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005435 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005436 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " LINE_DEBUG_STR "\n",
5437 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005438 return;
5439 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005440 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5441 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5442 for (int n = 1; n < pts; ++n) {
5443 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005444 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005445 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
5446 for (int n = 1; n < pts; ++n) {
5447 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005448 }
5449 SkDebugf("\n");
5450}
5451
caryclark@google.com73ca6242013-01-17 21:02:47 +00005452static void debugShowCubicQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005453 const Work& wn, const Intersections& i) {
5454 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005455 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005456 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " QUAD_DEBUG_STR "\n",
5457 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005458 return;
5459 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005460 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5461 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5462 for (int n = 1; n < pts; ++n) {
5463 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005464 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005465 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i.fT[1][0], QUAD_DEBUG_DATA(wn.pts()));
5466 for (int n = 1; n < pts; ++n) {
5467 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005468 }
5469 SkDebugf("\n");
5470}
5471
caryclark@google.com73ca6242013-01-17 21:02:47 +00005472static void debugShowCubicIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005473 const Work& wn, const Intersections& i) {
5474 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005475 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005476 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " CUBIC_DEBUG_STR "\n",
5477 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), CUBIC_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005478 return;
5479 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005480 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5481 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5482 for (int n = 1; n < pts; ++n) {
5483 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005484 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005485 SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i.fT[1][0], CUBIC_DEBUG_DATA(wn.pts()));
5486 for (int n = 1; n < pts; ++n) {
5487 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005488 }
5489 SkDebugf("\n");
5490}
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005491
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005492static void debugShowCubicIntersection(int pts, const Work& wt, const Intersections& i) {
5493 SkASSERT(i.used() == pts);
5494 if (!pts) {
5495 SkDebugf("%s no self intersect " CUBIC_DEBUG_STR "\n", __FUNCTION__,
5496 CUBIC_DEBUG_DATA(wt.pts()));
5497 return;
5498 }
5499 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5500 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5501 SkDebugf(" " T_DEBUG_STR(wtTs, 1), i.fT[1][0]);
5502 SkDebugf("\n");
5503}
5504
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005505#else
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005506static void debugShowLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005507}
caryclark@google.coma461ff02012-10-11 12:54:23 +00005508
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005509static void debugShowQuadLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005510}
5511
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005512static void debugShowQuadIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005513}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005514
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005515static void debugShowCubicLineIntersection(int , const Work& , const Work& ,
5516 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005517}
5518
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005519static void debugShowCubicQuadIntersection(int , const Work& , const Work& ,
5520 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005521}
5522
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005523static void debugShowCubicIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005524}
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005525
5526static void debugShowCubicIntersection(int , const Work& , const Intersections& ) {
5527}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005528#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005529
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005530static bool addIntersectTs(Contour* test, Contour* next) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005531
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005532 if (test != next) {
5533 if (test->bounds().fBottom < next->bounds().fTop) {
5534 return false;
5535 }
5536 if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5537 return true;
5538 }
5539 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005540 Work wt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005541 wt.init(test);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005542 bool foundCommonContour = test == next;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005543 do {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005544 Work wn;
5545 wn.init(next);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005546 if (test == next && !wn.startAfter(wt)) {
5547 continue;
5548 }
5549 do {
5550 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5551 continue;
5552 }
5553 int pts;
5554 Intersections ts;
5555 bool swap = false;
5556 switch (wt.segmentType()) {
5557 case Work::kHorizontalLine_Segment:
5558 swap = true;
5559 switch (wn.segmentType()) {
5560 case Work::kHorizontalLine_Segment:
5561 case Work::kVerticalLine_Segment:
5562 case Work::kLine_Segment: {
5563 pts = HLineIntersect(wn.pts(), wt.left(),
5564 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005565 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005566 break;
5567 }
5568 case Work::kQuad_Segment: {
5569 pts = HQuadIntersect(wn.pts(), wt.left(),
5570 wt.right(), wt.y(), wt.xFlipped(), ts);
5571 break;
5572 }
5573 case Work::kCubic_Segment: {
5574 pts = HCubicIntersect(wn.pts(), wt.left(),
5575 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005576 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005577 break;
5578 }
5579 default:
5580 SkASSERT(0);
5581 }
5582 break;
5583 case Work::kVerticalLine_Segment:
5584 swap = true;
5585 switch (wn.segmentType()) {
5586 case Work::kHorizontalLine_Segment:
5587 case Work::kVerticalLine_Segment:
5588 case Work::kLine_Segment: {
5589 pts = VLineIntersect(wn.pts(), wt.top(),
5590 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005591 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005592 break;
5593 }
5594 case Work::kQuad_Segment: {
5595 pts = VQuadIntersect(wn.pts(), wt.top(),
5596 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5597 break;
5598 }
5599 case Work::kCubic_Segment: {
5600 pts = VCubicIntersect(wn.pts(), wt.top(),
5601 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005602 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005603 break;
5604 }
5605 default:
5606 SkASSERT(0);
5607 }
5608 break;
5609 case Work::kLine_Segment:
5610 switch (wn.segmentType()) {
5611 case Work::kHorizontalLine_Segment:
5612 pts = HLineIntersect(wt.pts(), wn.left(),
5613 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005614 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005615 break;
5616 case Work::kVerticalLine_Segment:
5617 pts = VLineIntersect(wt.pts(), wn.top(),
5618 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005619 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005620 break;
5621 case Work::kLine_Segment: {
5622 pts = LineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005623 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005624 break;
5625 }
5626 case Work::kQuad_Segment: {
5627 swap = true;
5628 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005629 debugShowQuadLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005630 break;
5631 }
5632 case Work::kCubic_Segment: {
5633 swap = true;
5634 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005635 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005636 break;
5637 }
5638 default:
5639 SkASSERT(0);
5640 }
5641 break;
5642 case Work::kQuad_Segment:
5643 switch (wn.segmentType()) {
5644 case Work::kHorizontalLine_Segment:
5645 pts = HQuadIntersect(wt.pts(), wn.left(),
5646 wn.right(), wn.y(), wn.xFlipped(), ts);
5647 break;
5648 case Work::kVerticalLine_Segment:
5649 pts = VQuadIntersect(wt.pts(), wn.top(),
5650 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5651 break;
5652 case Work::kLine_Segment: {
5653 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005654 debugShowQuadLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005655 break;
5656 }
5657 case Work::kQuad_Segment: {
5658 pts = QuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005659 debugShowQuadIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005660 break;
5661 }
5662 case Work::kCubic_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005663 #if APPROXIMATE_CUBICS
5664 swap = true;
5665 pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005666 debugShowCubicQuadIntersection(pts, wn, wt, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005667 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005668 wt.promoteToCubic();
5669 pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005670 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005671 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005672 break;
5673 }
5674 default:
5675 SkASSERT(0);
5676 }
5677 break;
5678 case Work::kCubic_Segment:
5679 switch (wn.segmentType()) {
5680 case Work::kHorizontalLine_Segment:
5681 pts = HCubicIntersect(wt.pts(), wn.left(),
5682 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005683 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005684 break;
5685 case Work::kVerticalLine_Segment:
5686 pts = VCubicIntersect(wt.pts(), wn.top(),
5687 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005688 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005689 break;
5690 case Work::kLine_Segment: {
5691 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005692 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005693 break;
5694 }
5695 case Work::kQuad_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005696 #if APPROXIMATE_CUBICS
5697 pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005698 debugShowCubicQuadIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005699 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005700 wn.promoteToCubic();
5701 pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005702 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005703 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005704 break;
5705 }
5706 case Work::kCubic_Segment: {
5707 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005708 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005709 break;
5710 }
5711 default:
5712 SkASSERT(0);
5713 }
5714 break;
5715 default:
5716 SkASSERT(0);
5717 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005718 if (!foundCommonContour && pts > 0) {
5719 test->addCross(next);
5720 next->addCross(test);
5721 foundCommonContour = true;
5722 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005723 // in addition to recording T values, record matching segment
caryclark@google.com73ca6242013-01-17 21:02:47 +00005724 if (ts.unsortable()) {
5725 bool start = true;
5726 for (int pt = 0; pt < ts.used(); ++pt) {
5727 // FIXME: if unsortable, the other points to the original. This logic is
5728 // untested downstream.
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005729 SkPoint point = ts.fPt[pt].asSkPoint();
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005730 int testTAt = wt.addUnsortableT(wt, start, point, ts.fT[swap][pt]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005731 wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt);
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005732 testTAt = wn.addUnsortableT(wn, start ^ ts.fFlip, point, ts.fT[!swap][pt]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005733 wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt);
5734 start ^= true;
5735 }
5736 continue;
5737 }
caryclark@google.com32546db2012-08-31 20:55:07 +00005738 if (pts == 2) {
5739 if (wn.segmentType() <= Work::kLine_Segment
5740 && wt.segmentType() <= Work::kLine_Segment) {
5741 wt.addCoincident(wn, ts, swap);
5742 continue;
5743 }
caryclark@google.combeda3892013-02-07 13:13:41 +00005744 if (wn.segmentType() >= Work::kQuad_Segment
5745 && wt.segmentType() >= Work::kQuad_Segment
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005746 && ts.fIsCoincident[0]) {
5747 SkASSERT(ts.coincidentUsed() == 2);
caryclark@google.com32546db2012-08-31 20:55:07 +00005748 wt.addCoincident(wn, ts, swap);
5749 continue;
5750 }
5751
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00005752 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00005753 for (int pt = 0; pt < pts; ++pt) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005754 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5755 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005756 SkPoint point = ts.fPt[pt].asSkPoint();
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005757 int testTAt = wt.addT(wn, point, ts.fT[swap][pt]);
5758 int nextTAt = wn.addT(wt, point, ts.fT[!swap][pt]);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005759 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
5760 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005761 }
5762 } while (wn.advance());
5763 } while (wt.advance());
5764 return true;
5765}
5766
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005767static void addSelfIntersectTs(Contour* test) {
5768 Work wt;
5769 wt.init(test);
5770 do {
5771 if (wt.segmentType() != Work::kCubic_Segment) {
5772 continue;
5773 }
5774 Intersections ts;
5775 int pts = CubicIntersect(wt.pts(), ts);
5776 debugShowCubicIntersection(pts, wt, ts);
5777 if (!pts) {
5778 continue;
5779 }
5780 SkASSERT(pts == 1);
5781 SkASSERT(ts.fT[0][0] >= 0 && ts.fT[0][0] <= 1);
5782 SkASSERT(ts.fT[1][0] >= 0 && ts.fT[1][0] <= 1);
5783 SkPoint point = ts.fPt[0].asSkPoint();
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00005784 int testTAt = wt.addSelfT(wt, point, ts.fT[0][0]);
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005785 int nextTAt = wt.addT(wt, point, ts.fT[1][0]);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005786 wt.addOtherT(testTAt, ts.fT[1][0], nextTAt);
5787 wt.addOtherT(nextTAt, ts.fT[0][0], testTAt);
5788 } while (wt.advance());
5789}
5790
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005791// resolve any coincident pairs found while intersecting, and
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005792// see if coincidence is formed by clipping non-concident segments
caryclark@google.com4eeda372012-12-06 21:47:48 +00005793static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005794 int contourCount = contourList.count();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005795#if ONE_PASS_COINCIDENCE_CHECK
caryclark@google.comf25edfe2012-06-01 18:20:10 +00005796 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005797 Contour* contour = contourList[cIndex];
caryclark@google.com7ba591e2012-11-20 14:21:54 +00005798 contour->resolveCoincidence(contourList);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005799 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005800#else
5801 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5802 Contour* contour = contourList[cIndex];
5803 contour->addCoincidentPoints();
5804 }
5805 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5806 Contour* contour = contourList[cIndex];
5807 contour->calcCoincidentWinding();
5808 }
5809#endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005810 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5811 Contour* contour = contourList[cIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00005812 contour->findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005813 }
5814}
5815
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005816static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005817 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005818 SkPoint basePt;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005819 double tAtMid = current->tAtMid(index, endIndex, mid);
5820 current->xyAtT(tAtMid, basePt);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005821 int contourCount = contourList.count();
5822 SkScalar bestY = SK_ScalarMin;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005823 Segment* bestSeg = NULL;
5824 int bestTIndex;
5825 bool bestOpp;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005826 bool hitSomething = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005827 for (int cTest = 0; cTest < contourCount; ++cTest) {
5828 Contour* contour = contourList[cTest];
5829 bool testOpp = contour->operand() ^ current->operand() ^ opp;
5830 if (basePt.fY < contour->bounds().fTop) {
5831 continue;
5832 }
5833 if (bestY > contour->bounds().fBottom) {
5834 continue;
5835 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005836 int segmentCount = contour->segments().count();
5837 for (int test = 0; test < segmentCount; ++test) {
5838 Segment* testSeg = &contour->segments()[test];
5839 SkScalar testY = bestY;
5840 double testHit;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005841 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
5842 testOpp, testSeg == current);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005843 if (testTIndex < 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005844 if (testTIndex == SK_MinS32) {
5845 hitSomething = true;
5846 bestSeg = NULL;
5847 goto abortContours; // vertical encountered, return and try different point
5848 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005849 continue;
5850 }
5851 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005852 double baseT = current->t(index);
5853 double endT = current->t(endIndex);
5854 double newMid = (testHit - baseT) / (endT - baseT);
5855#if DEBUG_WINDING
5856 SkPoint midXY, newXY;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005857 double midT = current->tAtMid(index, endIndex, mid);
5858 current->xyAtT(midT, midXY);
5859 double newMidT = current->tAtMid(index, endIndex, newMid);
5860 current->xyAtT(newMidT, newXY);
caryclark@google.com3586ece2012-12-27 18:46:58 +00005861 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
5862 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
5863 current->debugID(), mid, newMid,
5864 baseT, current->xAtT(index), current->yAtT(index),
5865 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
5866 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
5867 endT, current->xAtT(endIndex), current->yAtT(endIndex));
5868#endif
5869 mid = newMid * 2; // calling loop with divide by 2 before continuing
5870 return SK_MinS32;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005871 }
5872 bestSeg = testSeg;
5873 bestHit = testHit;
5874 bestOpp = testOpp;
5875 bestTIndex = testTIndex;
5876 bestY = testY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005877 }
5878 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005879abortContours:
caryclark@google.com10227bf2012-12-28 22:10:41 +00005880 int result;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005881 if (!bestSeg) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00005882 result = hitSomething ? SK_MinS32 : 0;
5883 } else {
5884 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
5885 current = bestSeg;
5886 index = bestTIndex;
5887 endIndex = bestSeg->nextSpan(bestTIndex, 1);
5888 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
5889 tryAgain = true;
5890 return 0;
5891 }
5892 result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
5893 SkASSERT(bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005894 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005895 double baseT = current->t(index);
5896 double endT = current->t(endIndex);
5897 bestHit = baseT + mid * (endT - baseT);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005898 return result;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005899}
5900
caryclark@google.com24bec792012-08-20 12:43:57 +00005901static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
5902 int contourCount = contourList.count();
5903 Segment* result;
5904 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5905 Contour* contour = contourList[cIndex];
5906 result = contour->undoneSegment(start, end);
5907 if (result) {
5908 return result;
5909 }
5910 }
5911 return NULL;
5912}
5913
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005914#define OLD_FIND_CHASE 1
caryclark@google.com24bec792012-08-20 12:43:57 +00005915
caryclark@google.com31143cf2012-11-09 22:14:19 +00005916static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005917 while (chase.count()) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005918 Span* span;
5919 chase.pop(&span);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005920 const Span& backPtr = span->fOther->span(span->fOtherIndex);
5921 Segment* segment = backPtr.fOther;
5922 tIndex = backPtr.fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005923 SkTDArray<Angle> angles;
5924 int done = 0;
5925 if (segment->activeAngle(tIndex, done, angles)) {
5926 Angle* last = angles.end() - 1;
5927 tIndex = last->start();
5928 endIndex = last->end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005929 #if TRY_ROTATE
5930 *chase.insert(0) = span;
5931 #else
5932 *chase.append() = span;
5933 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005934 return last->segment();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005935 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005936 if (done == angles.count()) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00005937 continue;
5938 }
5939 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005940 bool sortable = Segment::SortAngles(angles, sorted);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005941 int angleCount = sorted.count();
caryclark@google.com03f97062012-08-21 13:13:52 +00005942#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005943 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00005944#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005945 if (!sortable) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005946 continue;
5947 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005948 // find first angle, initialize winding to computed fWindSum
5949 int firstIndex = -1;
5950 const Angle* angle;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005951#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005952 int winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005953 do {
5954 angle = sorted[++firstIndex];
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005955 segment = angle->segment();
5956 winding = segment->windSum(angle);
5957 } while (winding == SK_MinS32);
5958 int spanWinding = segment->spanSign(angle->start(), angle->end());
5959 #if DEBUG_WINDING
caryclark@google.com31143cf2012-11-09 22:14:19 +00005960 SkDebugf("%s winding=%d spanWinding=%d\n",
5961 __FUNCTION__, winding, spanWinding);
caryclark@google.com47580692012-07-23 12:14:49 +00005962 #endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005963 // turn span winding into contour winding
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005964 if (spanWinding * winding < 0) {
5965 winding += spanWinding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005966 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005967 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005968 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005969 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005970 // we care about first sign and whether wind sum indicates this
5971 // edge is inside or outside. Maybe need to pass span winding
5972 // or first winding or something into this function?
5973 // advance to first undone angle, then return it and winding
5974 // (to set whether edges are active or not)
5975 int nextIndex = firstIndex + 1;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005976 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005977 angle = sorted[firstIndex];
caryclark@google.com2ddff932012-08-07 21:25:27 +00005978 winding -= angle->segment()->spanSign(angle);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005979#else
5980 do {
5981 angle = sorted[++firstIndex];
5982 segment = angle->segment();
5983 } while (segment->windSum(angle) == SK_MinS32);
5984 #if DEBUG_SORT
5985 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5986 #endif
5987 int sumWinding = segment->updateWindingReverse(angle);
5988 int nextIndex = firstIndex + 1;
5989 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5990 Segment* first = NULL;
5991#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005992 do {
5993 SkASSERT(nextIndex != firstIndex);
5994 if (nextIndex == angleCount) {
5995 nextIndex = 0;
5996 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005997 angle = sorted[nextIndex];
caryclark@google.com9764cc62012-07-12 19:29:45 +00005998 segment = angle->segment();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005999#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00006000 int maxWinding = winding;
caryclark@google.com2ddff932012-08-07 21:25:27 +00006001 winding -= segment->spanSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00006002 #if DEBUG_SORT
caryclark@google.com2ddff932012-08-07 21:25:27 +00006003 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
6004 segment->debugID(), maxWinding, winding, angle->sign());
caryclark@google.com534aa5b2012-08-02 20:08:21 +00006005 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00006006 tIndex = angle->start();
6007 endIndex = angle->end();
6008 int lesser = SkMin32(tIndex, endIndex);
6009 const Span& nextSpan = segment->span(lesser);
6010 if (!nextSpan.fDone) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00006011#if 1
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006012 // FIXME: this be wrong? assign startWinding if edge is in
caryclark@google.com9764cc62012-07-12 19:29:45 +00006013 // same direction. If the direction is opposite, winding to
6014 // assign is flipped sign or +/- 1?
caryclark@google.com59823f72012-08-09 18:17:47 +00006015 if (useInnerWinding(maxWinding, winding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00006016 maxWinding = winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00006017 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006018 segment->markAndChaseWinding(angle, maxWinding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00006019#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00006020 break;
6021 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006022#else
6023 int start = angle->start();
6024 int end = angle->end();
6025 int maxWinding;
6026 segment->setUpWinding(start, end, maxWinding, sumWinding);
6027 if (!segment->done(angle)) {
6028 if (!first) {
6029 first = segment;
6030 tIndex = start;
6031 endIndex = end;
6032 }
6033 (void) segment->markAngle(maxWinding, sumWinding, true, angle);
6034 }
6035#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00006036 } while (++nextIndex != lastIndex);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006037 #if TRY_ROTATE
6038 *chase.insert(0) = span;
6039 #else
6040 *chase.append() = span;
6041 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00006042 return segment;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00006043 }
6044 return NULL;
6045}
6046
caryclark@google.com027de222012-07-12 12:52:50 +00006047#if DEBUG_ACTIVE_SPANS
6048static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00006049 int index;
6050 for (index = 0; index < contourList.count(); ++ index) {
caryclark@google.com027de222012-07-12 12:52:50 +00006051 contourList[index]->debugShowActiveSpans();
6052 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00006053 for (index = 0; index < contourList.count(); ++ index) {
6054 contourList[index]->validateActiveSpans();
6055 }
caryclark@google.com027de222012-07-12 12:52:50 +00006056}
6057#endif
6058
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006059static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006060 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006061 Segment* result;
6062 do {
caryclark@google.comf839c032012-10-26 21:03:50 +00006063 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006064 int contourCount = contourList.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00006065 Segment* topStart = NULL;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006066 done = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00006067 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
6068 Contour* contour = contourList[cIndex];
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006069 if (contour->done()) {
6070 continue;
6071 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006072 const Bounds& bounds = contour->bounds();
6073 if (bounds.fBottom < topLeft.fY) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006074 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00006075 continue;
6076 }
6077 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006078 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00006079 continue;
6080 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006081 contour->topSortableSegment(topLeft, bestXY, topStart);
6082 if (!contour->done()) {
6083 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00006084 }
6085 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006086 if (!topStart) {
6087 return NULL;
6088 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006089 topLeft = bestXY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006090 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006091 } while (!result);
6092 return result;
6093}
caryclark@google.com31143cf2012-11-09 22:14:19 +00006094
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006095static int rightAngleWinding(SkTDArray<Contour*>& contourList,
caryclark@google.com3586ece2012-12-27 18:46:58 +00006096 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006097 bool opp) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006098 double test = 0.9;
6099 int contourWinding;
6100 do {
caryclark@google.com3586ece2012-12-27 18:46:58 +00006101 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
6102 tryAgain, test, opp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006103 if (contourWinding != SK_MinS32 || tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006104 return contourWinding;
6105 }
6106 test /= 2;
6107 } while (!approximately_negative(test));
6108 SkASSERT(0); // should be OK to comment out, but interested when this hits
6109 return contourWinding;
6110}
6111
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006112static void skipVertical(SkTDArray<Contour*>& contourList,
6113 Segment*& current, int& index, int& endIndex) {
6114 if (!current->isVertical(index, endIndex)) {
6115 return;
6116 }
6117 int contourCount = contourList.count();
6118 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
6119 Contour* contour = contourList[cIndex];
6120 if (contour->done()) {
6121 continue;
6122 }
6123 current = contour->nonVerticalSegment(index, endIndex);
6124 if (current) {
6125 return;
6126 }
6127 }
6128}
6129
caryclark@google.com3586ece2012-12-27 18:46:58 +00006130static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006131 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
6132 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
6133 true);
6134 if (!current) {
6135 return NULL;
6136 }
6137 if (firstContour) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00006138 current->initWinding(index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006139 firstContour = false;
6140 return current;
6141 }
6142 int minIndex = SkMin32(index, endIndex);
6143 int sumWinding = current->windSum(minIndex);
6144 if (sumWinding != SK_MinS32) {
6145 return current;
6146 }
6147 sumWinding = current->computeSum(index, endIndex, binary);
6148 if (sumWinding != SK_MinS32) {
6149 return current;
6150 }
6151 int contourWinding;
6152 int oppContourWinding = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006153 // the simple upward projection of the unresolved points hit unsortable angles
6154 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006155 bool tryAgain;
6156 double tHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006157 SkScalar hitDx = 0;
6158 SkScalar hitOppDx = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006159 do {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006160 // if current is vertical, find another candidate which is not
6161 // if only remaining candidates are vertical, then they can be marked done
caryclark@google.com10227bf2012-12-28 22:10:41 +00006162 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006163 skipVertical(contourList, current, index, endIndex);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006164 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006165 tryAgain = false;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006166 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006167 tryAgain, false);
6168 if (tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006169 continue;
6170 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006171 if (!binary) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006172 break;
6173 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00006174 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006175 tryAgain, true);
6176 } while (tryAgain);
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00006177
caryclark@google.com3586ece2012-12-27 18:46:58 +00006178 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006179 return current;
6180}
6181
6182// rewrite that abandons keeping local track of winding
caryclark@google.com3586ece2012-12-27 18:46:58 +00006183static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006184 bool firstContour = true;
6185 bool unsortable = false;
6186 bool topUnsortable = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006187 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
6188 do {
6189 int index, endIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006190 bool topDone;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006191 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006192 topUnsortable, topDone, false);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006193 if (!current) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006194 if (topUnsortable || !topDone) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006195 topUnsortable = false;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006196 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006197 topLeft.fX = topLeft.fY = SK_ScalarMin;
6198 continue;
6199 }
6200 break;
6201 }
6202 SkTDArray<Span*> chaseArray;
6203 do {
6204 if (current->activeWinding(index, endIndex)) {
6205 do {
6206 #if DEBUG_ACTIVE_SPANS
6207 if (!unsortable && current->done()) {
6208 debugShowActiveSpans(contourList);
6209 }
6210 #endif
6211 SkASSERT(unsortable || !current->done());
6212 int nextStart = index;
6213 int nextEnd = endIndex;
6214 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
6215 unsortable);
6216 if (!next) {
6217 if (!unsortable && simple.hasMove()
6218 && current->verb() != SkPath::kLine_Verb
6219 && !simple.isClosed()) {
6220 current->addCurveTo(index, endIndex, simple, true);
6221 SkASSERT(simple.isClosed());
6222 }
6223 break;
6224 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006225 #if DEBUG_FLOW
6226 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6227 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
6228 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
6229 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006230 current->addCurveTo(index, endIndex, simple, true);
6231 current = next;
6232 index = nextStart;
6233 endIndex = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006234 } while (!simple.isClosed() && (!unsortable
caryclark@google.com10227bf2012-12-28 22:10:41 +00006235 || !current->done(SkMin32(index, endIndex))));
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006236 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
6237 SkASSERT(unsortable);
6238 int min = SkMin32(index, endIndex);
6239 if (!current->done(min)) {
6240 current->addCurveTo(index, endIndex, simple, true);
6241 current->markDoneUnary(min);
6242 }
6243 }
6244 simple.close();
6245 } else {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006246 Span* last = current->markAndChaseDoneUnary(index, endIndex);
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00006247 if (last && !last->fLoop) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006248 *chaseArray.append() = last;
6249 }
6250 }
6251 current = findChase(chaseArray, index, endIndex);
6252 #if DEBUG_ACTIVE_SPANS
6253 debugShowActiveSpans(contourList);
6254 #endif
6255 if (!current) {
6256 break;
6257 }
6258 } while (true);
6259 } while (true);
6260 return simple.someAssemblyRequired();
6261}
6262
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006263// returns true if all edges were processed
caryclark@google.comf839c032012-10-26 21:03:50 +00006264static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006265 Segment* current;
6266 int start, end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006267 bool unsortable = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006268 bool closable = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00006269 while ((current = findUndone(contourList, start, end))) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006270 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006271 #if DEBUG_ACTIVE_SPANS
6272 if (!unsortable && current->done()) {
6273 debugShowActiveSpans(contourList);
6274 }
6275 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006276 SkASSERT(unsortable || !current->done());
caryclark@google.com24bec792012-08-20 12:43:57 +00006277 int nextStart = start;
6278 int nextEnd = end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006279 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
caryclark@google.com24bec792012-08-20 12:43:57 +00006280 if (!next) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006281 if (!unsortable && simple.hasMove()
caryclark@google.comf839c032012-10-26 21:03:50 +00006282 && current->verb() != SkPath::kLine_Verb
6283 && !simple.isClosed()) {
6284 current->addCurveTo(start, end, simple, true);
6285 SkASSERT(simple.isClosed());
caryclark@google.comc899ad92012-08-23 15:24:42 +00006286 }
caryclark@google.com24bec792012-08-20 12:43:57 +00006287 break;
6288 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006289 #if DEBUG_FLOW
6290 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6291 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
6292 current->xyAtT(end).fX, current->xyAtT(end).fY);
6293 #endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006294 current->addCurveTo(start, end, simple, true);
caryclark@google.com24bec792012-08-20 12:43:57 +00006295 current = next;
6296 start = nextStart;
6297 end = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006298 } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006299 if (!simple.isClosed()) {
6300 SkASSERT(unsortable);
6301 int min = SkMin32(start, end);
6302 if (!current->done(min)) {
6303 current->addCurveTo(start, end, simple, true);
6304 current->markDone(min, 1);
6305 }
6306 closable = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00006307 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006308 simple.close();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00006309 #if DEBUG_ACTIVE_SPANS
6310 debugShowActiveSpans(contourList);
6311 #endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00006312 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006313 return closable;
caryclark@google.com24bec792012-08-20 12:43:57 +00006314}
6315
caryclark@google.comb45a1b42012-05-18 20:50:33 +00006316static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
6317 int contourCount = contourList.count();
6318 for (int cTest = 0; cTest < contourCount; ++cTest) {
6319 Contour* contour = contourList[cTest];
6320 contour->fixOtherTIndex();
6321 }
6322}
6323
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006324static void sortSegments(SkTDArray<Contour*>& contourList) {
6325 int contourCount = contourList.count();
6326 for (int cTest = 0; cTest < contourCount; ++cTest) {
6327 Contour* contour = contourList[cTest];
6328 contour->sortSegments();
6329 }
6330}
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006331
caryclark@google.com4eeda372012-12-06 21:47:48 +00006332static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
6333 bool evenOdd, bool oppEvenOdd) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006334 int count = contours.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006335 if (count == 0) {
6336 return;
6337 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006338 for (int index = 0; index < count; ++index) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00006339 Contour& contour = contours[index];
6340 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
6341 *list.append() = &contour;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006342 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006343 QSort<Contour>(list.begin(), list.end() - 1);
6344}
6345
caryclark@google.comf839c032012-10-26 21:03:50 +00006346static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006347 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006348}
6349
caryclark@google.com10227bf2012-12-28 22:10:41 +00006350static bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
6351 return distances[one] < distances[two];
6352}
caryclark@google.comf839c032012-10-26 21:03:50 +00006353 /*
6354 check start and end of each contour
6355 if not the same, record them
6356 match them up
6357 connect closest
6358 reassemble contour pieces into new path
6359 */
6360static void assemble(const PathWrapper& path, PathWrapper& simple) {
6361#if DEBUG_PATH_CONSTRUCTION
6362 SkDebugf("%s\n", __FUNCTION__);
6363#endif
6364 SkTArray<Contour> contours;
6365 EdgeBuilder builder(path, contours);
6366 builder.finish();
6367 int count = contours.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006368 int outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006369 SkTDArray<int> runs; // indices of partial contours
caryclark@google.com0b7da432012-10-31 19:00:20 +00006370 for (outer = 0; outer < count; ++outer) {
6371 const Contour& eContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006372 const SkPoint& eStart = eContour.start();
6373 const SkPoint& eEnd = eContour.end();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006374#if DEBUG_ASSEMBLE
6375 SkDebugf("%s contour", __FUNCTION__);
6376 if (!approximatelyEqual(eStart, eEnd)) {
6377 SkDebugf("[%d]", runs.count());
6378 } else {
6379 SkDebugf(" ");
6380 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006381 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006382 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
6383#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006384 if (approximatelyEqual(eStart, eEnd)) {
6385 eContour.toPath(simple);
6386 continue;
6387 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006388 *runs.append() = outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006389 }
6390 count = runs.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006391 if (count == 0) {
6392 return;
6393 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006394 SkTDArray<int> sLink, eLink;
6395 sLink.setCount(count);
6396 eLink.setCount(count);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006397 int rIndex, iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006398 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006399 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006400 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006401 SkTDArray<double> distances;
6402 const int ends = count * 2; // all starts and ends
6403 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
6404 distances.setCount(entries);
6405 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
6406 outer = runs[rIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006407 const Contour& oContour = contours[outer];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006408 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
6409 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
6410 * ends - rIndex - 1;
6411 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
6412 int inner = runs[iIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006413 const Contour& iContour = contours[inner];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006414 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
6415 double dx = iPt.fX - oPt.fX;
6416 double dy = iPt.fY - oPt.fY;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006417 double dist = dx * dx + dy * dy;
caryclark@google.com10227bf2012-12-28 22:10:41 +00006418 distances[row + iIndex] = dist; // oStart distance from iStart
6419 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006420 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006421 SkTDArray<int> sortedDist;
6422 sortedDist.setCount(entries);
6423 for (rIndex = 0; rIndex < entries; ++rIndex) {
6424 sortedDist[rIndex] = rIndex;
6425 }
6426 QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
6427 int remaining = count; // number of start/end pairs
6428 for (rIndex = 0; rIndex < entries; ++rIndex) {
6429 int pair = sortedDist[rIndex];
6430 int row = pair / ends;
6431 int col = pair - row * ends;
6432 int thingOne = row < col ? row : ends - row - 2;
6433 int ndxOne = thingOne >> 1;
6434 bool endOne = thingOne & 1;
6435 int* linkOne = endOne ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006436 if (linkOne[ndxOne] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006437 continue;
6438 }
6439 int thingTwo = row < col ? col : ends - row + col - 1;
6440 int ndxTwo = thingTwo >> 1;
6441 bool endTwo = thingTwo & 1;
6442 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006443 if (linkTwo[ndxTwo] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006444 continue;
6445 }
6446 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
6447 bool flip = endOne == endTwo;
6448 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
6449 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
6450 if (!--remaining) {
6451 break;
6452 }
6453 }
6454 SkASSERT(!remaining);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006455#if DEBUG_ASSEMBLE
6456 for (rIndex = 0; rIndex < count; ++rIndex) {
6457 int s = sLink[rIndex];
6458 int e = eLink[rIndex];
6459 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
6460 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
caryclark@google.comf839c032012-10-26 21:03:50 +00006461 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006462#endif
6463 rIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00006464 do {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006465 bool forward = true;
6466 bool first = true;
6467 int sIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006468 SkASSERT(sIndex != SK_MaxS32);
6469 sLink[rIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006470 int eIndex;
6471 if (sIndex < 0) {
6472 eIndex = sLink[~sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006473 sLink[~sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006474 } else {
6475 eIndex = eLink[sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006476 eLink[sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006477 }
caryclark@google.comaa358312013-01-29 20:28:49 +00006478 SkASSERT(eIndex != SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006479#if DEBUG_ASSEMBLE
6480 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006481 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
6482 eIndex < 0 ? ~eIndex : eIndex);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006483#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006484 do {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006485 outer = runs[rIndex];
6486 const Contour& contour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006487 if (first) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006488 first = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006489 const SkPoint* startPtr = &contour.start();
caryclark@google.comf839c032012-10-26 21:03:50 +00006490 simple.deferredMove(startPtr[0]);
6491 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006492 if (forward) {
6493 contour.toPartialForward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006494 } else {
6495 contour.toPartialBackward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006496 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006497#if DEBUG_ASSEMBLE
6498 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006499 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006500 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
6501#endif
6502 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006503 simple.close();
caryclark@google.comf839c032012-10-26 21:03:50 +00006504 break;
6505 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006506 if (forward) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006507 eIndex = eLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006508 SkASSERT(eIndex != SK_MaxS32);
6509 eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006510 if (eIndex >= 0) {
6511 SkASSERT(sLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006512 sLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006513 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006514 SkASSERT(eLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006515 eLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006516 }
6517 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006518 eIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006519 SkASSERT(eIndex != SK_MaxS32);
6520 sLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006521 if (eIndex >= 0) {
6522 SkASSERT(eLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006523 eLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006524 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006525 SkASSERT(sLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006526 sLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006527 }
6528 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006529 rIndex = eIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006530 if (rIndex < 0) {
6531 forward ^= 1;
6532 rIndex = ~rIndex;
6533 }
6534 } while (true);
6535 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006536 if (sLink[rIndex] != SK_MaxS32) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006537 break;
6538 }
6539 }
6540 } while (rIndex < count);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006541#if DEBUG_ASSEMBLE
6542 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006543 SkASSERT(sLink[rIndex] == SK_MaxS32);
6544 SkASSERT(eLink[rIndex] == SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006545 }
6546#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006547}
6548
6549void simplifyx(const SkPath& path, SkPath& result) {
caryclark@google.com1304bb22013-03-13 20:29:41 +00006550#if DEBUG_SORT || DEBUG_SWAP_TOP
caryclark@google.comc83c70e2013-02-22 21:50:07 +00006551 gDebugSortCount = gDebugSortCountDefault;
6552#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006553 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
caryclark@google.comf839c032012-10-26 21:03:50 +00006554 result.reset();
6555 result.setFillType(SkPath::kEvenOdd_FillType);
6556 PathWrapper simple(result);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006557
6558 // turn path into list of segments
6559 SkTArray<Contour> contours;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006560 EdgeBuilder builder(path, contours);
caryclark@google.com235f56a2012-09-14 14:19:30 +00006561 builder.finish();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006562 SkTDArray<Contour*> contourList;
caryclark@google.com4eeda372012-12-06 21:47:48 +00006563 makeContourList(contours, contourList, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006564 Contour** currentPtr = contourList.begin();
6565 if (!currentPtr) {
6566 return;
6567 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006568 Contour** listEnd = contourList.end();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006569 // find all intersections between segments
6570 do {
6571 Contour** nextPtr = currentPtr;
6572 Contour* current = *currentPtr++;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00006573 if (current->containsCubics()) {
6574 addSelfIntersectTs(current);
6575 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006576 Contour* next;
6577 do {
6578 next = *nextPtr++;
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00006579 } while (addIntersectTs(current, next) && nextPtr != listEnd);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006580 } while (currentPtr != listEnd);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006581 // eat through coincident edges
caryclark@google.com4eeda372012-12-06 21:47:48 +00006582 coincidenceCheck(contourList, 0);
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00006583 fixOtherTIndex(contourList);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006584 sortSegments(contourList);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006585#if DEBUG_ACTIVE_SPANS
6586 debugShowActiveSpans(contourList);
6587#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006588 // construct closed contours
caryclark@google.com3586ece2012-12-27 18:46:58 +00006589 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00006590 : !bridgeXor(contourList, simple))
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006591 { // if some edges could not be resolved, assemble remaining fragments
caryclark@google.comf839c032012-10-26 21:03:50 +00006592 SkPath temp;
6593 temp.setFillType(SkPath::kEvenOdd_FillType);
6594 PathWrapper assembled(temp);
6595 assemble(simple, assembled);
6596 result = *assembled.nativePath();
caryclark@google.com24bec792012-08-20 12:43:57 +00006597 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006598}