blob: 4684cda7ef02ad80eba297bcb9a90aa5f3d01d39 [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.com4eeda372012-12-06 21:47:48 +000067#define DEBUG_ACTIVE_SPANS_SHORT_FORM 1
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.comc83c70e2013-02-22 21:50:07 +0000116#if DEBUG_SORT
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.combeda3892013-02-07 13:13:41 +0000884 // SkDebugf("*** %s quad is line\n", __FUNCTION__);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000885 fTangent1.quadEndPoints(quad);
caryclark@google.comaa358312013-01-29 20:28:49 +0000886 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000887 fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- compare sign only
888 } break;
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000889 case SkPath::kCubic_Verb: {
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000890 int nextC = 2;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000891 CubicSubDivideHD(fPts, startT, endT, fCurvePart);
892 fTangent1.cubicEndPoints(fCurvePart, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000893 if (dx() == 0 && dy() == 0) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000894 fTangent1.cubicEndPoints(fCurvePart, 0, 2);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000895 nextC = 3;
caryclark@google.comaa358312013-01-29 20:28:49 +0000896 if (dx() == 0 && dy() == 0) {
caryclark@google.com4aaaaea2013-02-28 16:12:39 +0000897 // SkDebugf("*** %s cubic is line\n", __FUNCTION__);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000898 fTangent1.cubicEndPoints(fCurvePart, 0, 3);
caryclark@google.comaa358312013-01-29 20:28:49 +0000899 }
caryclark@google.comaa358312013-01-29 20:28:49 +0000900 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000901 fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign only
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000902 if (nextC == 2 && approximately_zero(fSide)) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000903 fSide = -fTangent1.pointDistance(fCurvePart[3]);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000904 }
905 } break;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000906 default:
907 SkASSERT(0);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000908 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000909 fUnsortable = dx() == 0 && dy() == 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000910 if (fUnsortable) {
911 return;
912 }
913 SkASSERT(fStart != fEnd);
914 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
915 for (int index = fStart; index != fEnd; index += step) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000916#if 1
917 const Span& thisSpan = (*fSpans)[index];
918 const Span& nextSpan = (*fSpans)[index + step];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000919 if (thisSpan.fTiny || precisely_equal(thisSpan.fT, nextSpan.fT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000920 continue;
caryclark@google.comf839c032012-10-26 21:03:50 +0000921 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000922 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
923#if DEBUG_UNSORTABLE
924 if (fUnsortable) {
925 SkPoint iPt, ePt;
926 (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt);
927 (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt);
928 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
929 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
930 }
931#endif
932 return;
933#else
934 if ((*fSpans)[index].fUnsortableStart) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000935 fUnsortable = true;
936 return;
937 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000938#endif
caryclark@google.comf839c032012-10-26 21:03:50 +0000939 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000940#if 1
941#if DEBUG_UNSORTABLE
942 SkPoint iPt, ePt;
943 (*SegmentXYAtT[fVerb])(fPts, startT, &iPt);
944 (*SegmentXYAtT[fVerb])(fPts, endT, &ePt);
945 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
946 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
947#endif
948 fUnsortable = true;
949#endif
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000950 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000951
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000952 Segment* segment() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000953 return const_cast<Segment*>(fSegment);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000954 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000955
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000956 int sign() const {
caryclark@google.com495f8e42012-05-31 13:13:11 +0000957 return SkSign32(fStart - fEnd);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000958 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000959
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000960 const SkTDArray<Span>* spans() const {
961 return fSpans;
962 }
963
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000964 int start() const {
965 return fStart;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000966 }
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +0000967
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000968 bool unsortable() const {
969 return fUnsortable;
970 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000971
caryclark@google.comc899ad92012-08-23 15:24:42 +0000972#if DEBUG_ANGLE
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000973 const SkPoint* pts() const {
974 return fPts;
975 }
976
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000977 SkPath::Verb verb() const {
978 return fVerb;
979 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000980
caryclark@google.comc899ad92012-08-23 15:24:42 +0000981 void debugShow(const SkPoint& a) const {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000982 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
caryclark@google.comc899ad92012-08-23 15:24:42 +0000983 }
984#endif
985
caryclark@google.com15fa1382012-05-07 20:49:36 +0000986private:
caryclark@google.com235f56a2012-09-14 14:19:30 +0000987 const SkPoint* fPts;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000988 Cubic fCurvePart;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000989 SkPath::Verb fVerb;
990 double fSide;
991 LineParameters fTangent1;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000992 const SkTDArray<Span>* fSpans;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000993 const Segment* fSegment;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000994 int fStart;
995 int fEnd;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000996 bool fReversed;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000997 mutable bool fUnsortable; // this alone is editable by the less than operator
caryclark@google.com15fa1382012-05-07 20:49:36 +0000998};
999
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001000// Bounds, unlike Rect, does not consider a line to be empty.
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001001struct Bounds : public SkRect {
1002 static bool Intersects(const Bounds& a, const Bounds& b) {
1003 return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
1004 a.fTop <= b.fBottom && b.fTop <= a.fBottom;
1005 }
1006
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001007 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
1008 if (left < fLeft) {
1009 fLeft = left;
1010 }
1011 if (top < fTop) {
1012 fTop = top;
1013 }
1014 if (right > fRight) {
1015 fRight = right;
1016 }
1017 if (bottom > fBottom) {
1018 fBottom = bottom;
1019 }
1020 }
1021
1022 void add(const Bounds& toAdd) {
1023 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
1024 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001025
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001026 void add(const SkPoint& pt) {
1027 if (pt.fX < fLeft) fLeft = pt.fX;
1028 if (pt.fY < fTop) fTop = pt.fY;
1029 if (pt.fX > fRight) fRight = pt.fX;
1030 if (pt.fY > fBottom) fBottom = pt.fY;
1031 }
1032
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001033 bool isEmpty() {
1034 return fLeft > fRight || fTop > fBottom
caryclark@google.com235f56a2012-09-14 14:19:30 +00001035 || (fLeft == fRight && fTop == fBottom)
caryclark@google.combeda3892013-02-07 13:13:41 +00001036 || sk_double_isnan(fLeft) || sk_double_isnan(fRight)
1037 || sk_double_isnan(fTop) || sk_double_isnan(fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001038 }
1039
1040 void setCubicBounds(const SkPoint a[4]) {
1041 _Rect dRect;
caryclark@google.com32546db2012-08-31 20:55:07 +00001042 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001043 dRect.setBounds(cubic);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001044 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1045 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001046 }
1047
1048 void setQuadBounds(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +00001049 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001050 _Rect dRect;
1051 dRect.setBounds(quad);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001052 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1053 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001054 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001055
1056 void setPoint(const SkPoint& pt) {
1057 fLeft = fRight = pt.fX;
1058 fTop = fBottom = pt.fY;
1059 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001060};
1061
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001062// OPTIMIZATION: does the following also work, and is it any faster?
1063// return outerWinding * innerWinding > 0
1064// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
caryclark@google.com2ddff932012-08-07 21:25:27 +00001065static bool useInnerWinding(int outerWinding, int innerWinding) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001066 SkASSERT(outerWinding != SK_MaxS32);
1067 SkASSERT(innerWinding != SK_MaxS32);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001068 int absOut = abs(outerWinding);
1069 int absIn = abs(innerWinding);
1070 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
caryclark@google.com5e0500f2013-02-20 12:51:37 +00001071#if 0 && DEBUG_WINDING
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001072 if (outerWinding * innerWinding < 0) {
caryclark@google.com24bec792012-08-20 12:43:57 +00001073 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
caryclark@google.com2ddff932012-08-07 21:25:27 +00001074 outerWinding, innerWinding, result ? "true" : "false");
caryclark@google.com2ddff932012-08-07 21:25:27 +00001075 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001076#endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001077 return result;
1078}
1079
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001080#define F (false) // discard the edge
1081#define T (true) // keep the edge
1082
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001083static const bool gUnaryActiveEdge[2][2] = {
1084// from=0 from=1
1085// to=0,1 to=0,1
1086 {F, T}, {T, F},
1087};
1088
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001089static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
1090// miFrom=0 miFrom=1
1091// miTo=0 miTo=1 miTo=0 miTo=1
1092// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
1093// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
1094 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
1095 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
1096 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
1097 {{{{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 +00001098};
1099
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001100#undef F
1101#undef T
caryclark@google.com235f56a2012-09-14 14:19:30 +00001102
caryclark@google.comf839c032012-10-26 21:03:50 +00001103// wrap path to keep track of whether the contour is initialized and non-empty
1104class PathWrapper {
1105public:
1106 PathWrapper(SkPath& path)
1107 : fPathPtr(&path)
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001108 , fCloses(0)
1109 , fMoves(0)
caryclark@google.comf839c032012-10-26 21:03:50 +00001110 {
1111 init();
1112 }
1113
1114 void close() {
1115 if (!fHasMove) {
1116 return;
1117 }
1118 bool callClose = isClosed();
1119 lineTo();
1120 if (fEmpty) {
1121 return;
1122 }
1123 if (callClose) {
1124 #if DEBUG_PATH_CONSTRUCTION
1125 SkDebugf("path.close();\n");
1126 #endif
1127 fPathPtr->close();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001128 fCloses++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001129 }
1130 init();
1131 }
1132
1133 void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
1134 lineTo();
1135 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001136 fDefer[1] = pt3;
1137 nudge();
1138 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001139#if DEBUG_PATH_CONSTRUCTION
1140 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001141 pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001142#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001143 fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001144 fEmpty = false;
1145 }
1146
1147 void deferredLine(const SkPoint& pt) {
1148 if (pt == fDefer[1]) {
1149 return;
1150 }
1151 if (changedSlopes(pt)) {
1152 lineTo();
1153 fDefer[0] = fDefer[1];
1154 }
1155 fDefer[1] = pt;
1156 }
1157
1158 void deferredMove(const SkPoint& pt) {
1159 fMoved = true;
1160 fHasMove = true;
1161 fEmpty = true;
1162 fDefer[0] = fDefer[1] = pt;
1163 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001164
caryclark@google.comf839c032012-10-26 21:03:50 +00001165 void deferredMoveLine(const SkPoint& pt) {
1166 if (!fHasMove) {
1167 deferredMove(pt);
1168 }
1169 deferredLine(pt);
1170 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001171
caryclark@google.comf839c032012-10-26 21:03:50 +00001172 bool hasMove() const {
1173 return fHasMove;
1174 }
1175
1176 void init() {
1177 fEmpty = true;
1178 fHasMove = false;
1179 fMoved = false;
1180 }
1181
1182 bool isClosed() const {
1183 return !fEmpty && fFirstPt == fDefer[1];
1184 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001185
caryclark@google.comf839c032012-10-26 21:03:50 +00001186 void lineTo() {
1187 if (fDefer[0] == fDefer[1]) {
1188 return;
1189 }
1190 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001191 nudge();
caryclark@google.comf839c032012-10-26 21:03:50 +00001192 fEmpty = false;
1193#if DEBUG_PATH_CONSTRUCTION
1194 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
1195#endif
1196 fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
1197 fDefer[0] = fDefer[1];
1198 }
1199
1200 const SkPath* nativePath() const {
1201 return fPathPtr;
1202 }
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +00001203
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001204 void nudge() {
1205 if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX)
1206 || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) {
1207 return;
1208 }
1209 fDefer[1] = fFirstPt;
1210 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001211
1212 void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
1213 lineTo();
1214 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001215 fDefer[1] = pt2;
1216 nudge();
1217 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001218#if DEBUG_PATH_CONSTRUCTION
1219 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001220 pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001221#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001222 fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001223 fEmpty = false;
1224 }
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00001225
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001226 bool someAssemblyRequired() const {
1227 return fCloses < fMoves;
1228 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001229
1230protected:
1231 bool changedSlopes(const SkPoint& pt) const {
1232 if (fDefer[0] == fDefer[1]) {
1233 return false;
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001234 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001235 SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
1236 SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
1237 SkScalar lineDx = pt.fX - fDefer[1].fX;
1238 SkScalar lineDy = pt.fY - fDefer[1].fY;
1239 return deferDx * lineDy != deferDy * lineDx;
1240 }
1241
1242 void moveTo() {
1243 if (!fMoved) {
1244 return;
1245 }
1246 fFirstPt = fDefer[0];
1247#if DEBUG_PATH_CONSTRUCTION
1248 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
1249#endif
1250 fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
1251 fMoved = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001252 fMoves++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001253 }
1254
1255private:
1256 SkPath* fPathPtr;
1257 SkPoint fDefer[2];
1258 SkPoint fFirstPt;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001259 int fCloses;
1260 int fMoves;
caryclark@google.comf839c032012-10-26 21:03:50 +00001261 bool fEmpty;
1262 bool fHasMove;
1263 bool fMoved;
1264};
1265
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001266class Segment {
1267public:
1268 Segment() {
1269#if DEBUG_DUMP
1270 fID = ++gSegmentID;
1271#endif
1272 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00001273
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001274 bool operator<(const Segment& rh) const {
1275 return fBounds.fTop < rh.fBounds.fTop;
1276 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001277
caryclark@google.com4eeda372012-12-06 21:47:48 +00001278 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001279 if (activeAngleInner(index, done, angles)) {
1280 return true;
1281 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001282 int lesser = index;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001283 while (--lesser >= 0 && equalPoints(index, lesser)) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001284 if (activeAngleOther(lesser, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001285 return true;
1286 }
1287 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001288 lesser = index;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001289 do {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001290 if (activeAngleOther(index, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001291 return true;
1292 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001293 } while (++index < fTs.count() && equalPoints(index, lesser));
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001294 return false;
1295 }
1296
caryclark@google.com4eeda372012-12-06 21:47:48 +00001297 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001298 Span* span = &fTs[index];
1299 Segment* other = span->fOther;
1300 int oIndex = span->fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001301 return other->activeAngleInner(oIndex, done, angles);
1302 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001303
caryclark@google.com4eeda372012-12-06 21:47:48 +00001304 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001305 int next = nextExactSpan(index, 1);
caryclark@google.com9764cc62012-07-12 19:29:45 +00001306 if (next > 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001307 Span& upSpan = fTs[index];
1308 if (upSpan.fWindValue || upSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001309 addAngle(angles, index, next);
caryclark@google.comf839c032012-10-26 21:03:50 +00001310 if (upSpan.fDone || upSpan.fUnsortableEnd) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001311 done++;
1312 } else if (upSpan.fWindSum != SK_MinS32) {
1313 return true;
1314 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001315 } else if (!upSpan.fDone) {
1316 upSpan.fDone = true;
1317 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001318 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001319 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001320 int prev = nextExactSpan(index, -1);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001321 // edge leading into junction
caryclark@google.com9764cc62012-07-12 19:29:45 +00001322 if (prev >= 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001323 Span& downSpan = fTs[prev];
1324 if (downSpan.fWindValue || downSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001325 addAngle(angles, index, prev);
1326 if (downSpan.fDone) {
1327 done++;
1328 } else if (downSpan.fWindSum != SK_MinS32) {
1329 return true;
1330 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001331 } else if (!downSpan.fDone) {
1332 downSpan.fDone = true;
1333 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001334 }
1335 }
1336 return false;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001337 }
1338
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001339 SkPoint activeLeftTop(bool onlySortable, int* firstT) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001340 SkASSERT(!done());
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001341 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001342 int count = fTs.count();
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001343 // see if either end is not done since we want smaller Y of the pair
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001344 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00001345 bool lastUnsortable = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001346 double lastT = -1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001347 for (int index = 0; index < count; ++index) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001348 const Span& span = fTs[index];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001349 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001350 goto next;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001351 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001352 if (span.fDone && lastDone) {
1353 goto next;
1354 }
1355 if (approximately_negative(span.fT - lastT)) {
1356 goto next;
1357 }
1358 {
1359 const SkPoint& xy = xyAtT(&span);
1360 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
1361 topPt = xy;
1362 if (firstT) {
1363 *firstT = index;
1364 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001365 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001366 if (fVerb != SkPath::kLine_Verb && !lastDone) {
1367 SkPoint curveTop = (*SegmentTop[fVerb])(fPts, lastT, span.fT);
1368 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
1369 && topPt.fX > curveTop.fX)) {
1370 topPt = curveTop;
1371 if (firstT) {
1372 *firstT = index;
1373 }
1374 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001375 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001376 lastT = span.fT;
caryclark@google.comf839c032012-10-26 21:03:50 +00001377 }
1378 next:
1379 lastDone = span.fDone;
1380 lastUnsortable = span.fUnsortableEnd;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001381 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001382 return topPt;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001383 }
1384
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001385 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
1386 int sumMiWinding = updateWinding(endIndex, index);
1387 int sumSuWinding = updateOppWinding(endIndex, index);
1388 if (fOperand) {
1389 SkTSwap<int>(sumMiWinding, sumSuWinding);
1390 }
1391 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1392 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001393 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001394 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001395
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001396 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00001397 int& sumMiWinding, int& sumSuWinding,
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001398 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
1399 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1400 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001401 bool miFrom;
1402 bool miTo;
1403 bool suFrom;
1404 bool suTo;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001405 if (operand()) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001406 miFrom = (oppMaxWinding & xorMiMask) != 0;
1407 miTo = (oppSumWinding & xorMiMask) != 0;
1408 suFrom = (maxWinding & xorSuMask) != 0;
1409 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001410 } else {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001411 miFrom = (maxWinding & xorMiMask) != 0;
1412 miTo = (sumWinding & xorMiMask) != 0;
1413 suFrom = (oppMaxWinding & xorSuMask) != 0;
1414 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001415 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001416 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
caryclark@google.combeda3892013-02-07 13:13:41 +00001417#if DEBUG_ACTIVE_OP
1418 SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__,
1419 kShapeOpStr[op], miFrom, miTo, suFrom, suTo, result);
1420#endif
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001421 SkASSERT(result != -1);
1422 return result;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001423 }
1424
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001425 bool activeWinding(int index, int endIndex) {
1426 int sumWinding = updateWinding(endIndex, index);
1427 int maxWinding;
1428 return activeWinding(index, endIndex, maxWinding, sumWinding);
1429 }
1430
1431 bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
1432 setUpWinding(index, endIndex, maxWinding, sumWinding);
1433 bool from = maxWinding != 0;
1434 bool to = sumWinding != 0;
1435 bool result = gUnaryActiveEdge[from][to];
1436 SkASSERT(result != -1);
1437 return result;
1438 }
1439
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001440 void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001441 SkASSERT(start != end);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001442 Angle* angle = angles.append();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001443#if DEBUG_ANGLE
caryclark@google.com31143cf2012-11-09 22:14:19 +00001444 if (angles.count() > 1 && !fTs[start].fTiny) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001445 SkPoint angle0Pt, newPt;
1446 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
1447 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
1448 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
caryclark@google.com6d0032a2013-01-04 19:41:13 +00001449 SkASSERT(AlmostEqualUlps(angle0Pt.fX, newPt.fX));
1450 SkASSERT(AlmostEqualUlps(angle0Pt.fY, newPt.fY));
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001451 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001452#endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001453 angle->set(fPts, fVerb, this, start, end, fTs);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001454 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001455
caryclark@google.com2ddff932012-08-07 21:25:27 +00001456 void addCancelOutsides(double tStart, double oStart, Segment& other,
caryclark@google.comcc905052012-07-25 20:59:42 +00001457 double oEnd) {
1458 int tIndex = -1;
1459 int tCount = fTs.count();
1460 int oIndex = -1;
1461 int oCount = other.fTs.count();
caryclark@google.comcc905052012-07-25 20:59:42 +00001462 do {
1463 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001464 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001465 int tIndexStart = tIndex;
1466 do {
1467 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001468 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001469 int oIndexStart = oIndex;
1470 double nextT;
1471 do {
1472 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001473 } while (nextT < 1 && approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001474 double oNextT;
1475 do {
1476 oNextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001477 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001478 // at this point, spans before and after are at:
1479 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1480 // if tIndexStart == 0, no prior span
1481 // if nextT == 1, no following span
rmistry@google.comd6176b02012-08-23 18:14:13 +00001482
caryclark@google.comcc905052012-07-25 20:59:42 +00001483 // advance the span with zero winding
1484 // if the following span exists (not past the end, non-zero winding)
1485 // connect the two edges
1486 if (!fTs[tIndexStart].fWindValue) {
1487 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1488 #if DEBUG_CONCIDENT
1489 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1490 __FUNCTION__, fID, other.fID, tIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001491 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
1492 xyAtT(tIndexStart).fY);
caryclark@google.comcc905052012-07-25 20:59:42 +00001493 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001494 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false,
1495 fTs[tIndexStart].fPt);
caryclark@google.comcc905052012-07-25 20:59:42 +00001496 }
1497 if (nextT < 1 && fTs[tIndex].fWindValue) {
1498 #if DEBUG_CONCIDENT
1499 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1500 __FUNCTION__, fID, other.fID, tIndex,
1501 fTs[tIndex].fT, xyAtT(tIndex).fX,
1502 xyAtT(tIndex).fY);
1503 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001504 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false, fTs[tIndex].fPt);
caryclark@google.comcc905052012-07-25 20:59:42 +00001505 }
1506 } else {
1507 SkASSERT(!other.fTs[oIndexStart].fWindValue);
1508 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1509 #if DEBUG_CONCIDENT
1510 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1511 __FUNCTION__, fID, other.fID, oIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001512 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
1513 other.xyAtT(oIndexStart).fY);
1514 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
caryclark@google.comcc905052012-07-25 20:59:42 +00001515 #endif
caryclark@google.comcc905052012-07-25 20:59:42 +00001516 }
1517 if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1518 #if DEBUG_CONCIDENT
1519 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1520 __FUNCTION__, fID, other.fID, oIndex,
1521 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1522 other.xyAtT(oIndex).fY);
1523 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1524 #endif
1525 }
1526 }
1527 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001528
caryclark@google.comcc905052012-07-25 20:59:42 +00001529 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1530 double oEnd) {
1531 // walk this to outsideTs[0]
1532 // walk other to outsideTs[1]
1533 // if either is > 0, add a pointer to the other, copying adjacent winding
1534 int tIndex = -1;
1535 int oIndex = -1;
1536 double tStart = outsideTs[0];
1537 double oStart = outsideTs[1];
1538 do {
1539 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001540 } while (!approximately_negative(tStart - fTs[tIndex].fT));
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001541 SkPoint ptStart = fTs[tIndex].fPt;
caryclark@google.comcc905052012-07-25 20:59:42 +00001542 do {
1543 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001544 } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001545 if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001546 addTPair(tStart, other, oStart, false, ptStart);
caryclark@google.comcc905052012-07-25 20:59:42 +00001547 }
1548 tStart = fTs[tIndex].fT;
1549 oStart = other.fTs[oIndex].fT;
1550 do {
1551 double nextT;
1552 do {
1553 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001554 } while (approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001555 tStart = nextT;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001556 ptStart = fTs[tIndex].fPt;
caryclark@google.comcc905052012-07-25 20:59:42 +00001557 do {
1558 nextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001559 } while (approximately_negative(nextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001560 oStart = nextT;
caryclark@google.com4eeda372012-12-06 21:47:48 +00001561 if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001562 break;
1563 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001564 addTPair(tStart, other, oStart, false, ptStart);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001565 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001566 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001567
caryclark@google.com4eeda372012-12-06 21:47:48 +00001568 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
1569 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001570 fBounds.setCubicBounds(pts);
1571 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001572
caryclark@google.comf839c032012-10-26 21:03:50 +00001573 /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001574 SkPoint edge[4];
caryclark@google.comf839c032012-10-26 21:03:50 +00001575 const SkPoint* ePtr;
1576 int lastT = fTs.count() - 1;
1577 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1578 ePtr = fPts;
1579 } else {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001580 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001581 subDivide(start, end, edge);
caryclark@google.comf839c032012-10-26 21:03:50 +00001582 ePtr = edge;
1583 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001584 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001585 bool reverse = ePtr == fPts && start != 0;
1586 if (reverse) {
1587 path.deferredMoveLine(ePtr[fVerb]);
1588 switch (fVerb) {
1589 case SkPath::kLine_Verb:
1590 path.deferredLine(ePtr[0]);
1591 break;
1592 case SkPath::kQuad_Verb:
1593 path.quadTo(ePtr[1], ePtr[0]);
1594 break;
1595 case SkPath::kCubic_Verb:
1596 path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1597 break;
1598 default:
1599 SkASSERT(0);
1600 }
1601 // return ePtr[0];
1602 } else {
1603 path.deferredMoveLine(ePtr[0]);
1604 switch (fVerb) {
1605 case SkPath::kLine_Verb:
1606 path.deferredLine(ePtr[1]);
1607 break;
1608 case SkPath::kQuad_Verb:
1609 path.quadTo(ePtr[1], ePtr[2]);
1610 break;
1611 case SkPath::kCubic_Verb:
1612 path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1613 break;
1614 default:
1615 SkASSERT(0);
1616 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001617 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001618 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001619 // return ePtr[fVerb];
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001620 }
1621
caryclark@google.com4eeda372012-12-06 21:47:48 +00001622 void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
1623 init(pts, SkPath::kLine_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001624 fBounds.set(pts, 2);
1625 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001626
caryclark@google.comf839c032012-10-26 21:03:50 +00001627#if 0
1628 const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001629 const SkPoint& pt = xyAtT(tIndex);
1630 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001631 path.deferredMove(pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001632 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00001633 return pt;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001634 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001635#endif
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001636
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001637 // add 2 to edge or out of range values to get T extremes
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001638 void addOtherT(int index, double otherT, int otherIndex) {
1639 Span& span = fTs[index];
caryclark@google.comf839c032012-10-26 21:03:50 +00001640 #if PIN_ADD_T
caryclark@google.com185c7c42012-10-19 18:26:24 +00001641 if (precisely_less_than_zero(otherT)) {
1642 otherT = 0;
1643 } else if (precisely_greater_than_one(otherT)) {
1644 otherT = 1;
1645 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001646 #endif
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001647 span.fOtherT = otherT;
1648 span.fOtherIndex = otherIndex;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001649 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001650
caryclark@google.com4eeda372012-12-06 21:47:48 +00001651 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
1652 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001653 fBounds.setQuadBounds(pts);
1654 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001655
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001656 // Defer all coincident edge processing until
1657 // after normal intersections have been computed
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001658
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001659// no need to be tricky; insert in normal T order
1660// resolve overlapping ts when considering coincidence later
1661
1662 // add non-coincident intersection. Resulting edges are sorted in T.
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001663 int addT(Segment* other, const SkPoint& pt, double& newT) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001664 // FIXME: in the pathological case where there is a ton of intercepts,
1665 // binary search?
1666 int insertedAt = -1;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001667 size_t tCount = fTs.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00001668 #if PIN_ADD_T
caryclark@google.comc899ad92012-08-23 15:24:42 +00001669 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
caryclark@google.com185c7c42012-10-19 18:26:24 +00001670 if (precisely_less_than_zero(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001671 newT = 0;
caryclark@google.com185c7c42012-10-19 18:26:24 +00001672 } else if (precisely_greater_than_one(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001673 newT = 1;
1674 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001675 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001676 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001677 // OPTIMIZATION: if there are three or more identical Ts, then
1678 // the fourth and following could be further insertion-sorted so
1679 // that all the edges are clockwise or counterclockwise.
1680 // This could later limit segment tests to the two adjacent
1681 // neighbors, although it doesn't help with determining which
1682 // circular direction to go in.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001683 if (newT < fTs[index].fT) {
1684 insertedAt = index;
1685 break;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001686 }
1687 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001688 Span* span;
1689 if (insertedAt >= 0) {
1690 span = fTs.insert(insertedAt);
1691 } else {
1692 insertedAt = tCount;
1693 span = fTs.append();
1694 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001695 span->fT = newT;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001696 span->fOther = other;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001697 span->fPt = pt;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001698 span->fWindSum = SK_MinS32;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001699 span->fOppSum = SK_MinS32;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001700 span->fWindValue = 1;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001701 span->fOppValue = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00001702 span->fTiny = false;
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00001703 span->fLoop = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001704 if ((span->fDone = newT == 1)) {
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00001705 ++fDoneSpans;
rmistry@google.comd6176b02012-08-23 18:14:13 +00001706 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001707 span->fUnsortableStart = false;
1708 span->fUnsortableEnd = false;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001709 int less = -1;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001710 while (&span[less + 1] - fTs.begin() > 0 && xyAtT(&span[less]) == xyAtT(span)) {
1711#if 1
1712 if (span[less].fDone) {
1713 break;
1714 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001715 double tInterval = newT - span[less].fT;
1716 if (precisely_negative(tInterval)) {
1717 break;
1718 }
1719 if (fVerb == SkPath::kCubic_Verb) {
1720 double tMid = newT - tInterval / 2;
1721 _Point midPt;
1722 CubicXYAtT(fPts, tMid, &midPt);
1723 if (!midPt.approximatelyEqual(xyAtT(span))) {
1724 break;
1725 }
1726 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001727 span[less].fTiny = true;
1728 span[less].fDone = true;
1729 if (approximately_negative(newT - span[less].fT)) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00001730 if (approximately_greater_than_one(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001731 span[less].fUnsortableStart = true;
1732 span[less - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001733 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001734 if (approximately_less_than_zero(span[less].fT)) {
1735 span[less + 1].fUnsortableStart = true;
1736 span[less].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001737 }
1738 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001739 ++fDoneSpans;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001740#else
1741 double tInterval = newT - span[less].fT;
1742 if (precisely_negative(tInterval)) {
1743 break;
1744 }
1745 if (fVerb == SkPath::kCubic_Verb) {
1746 double tMid = newT - tInterval / 2;
1747 _Point midPt;
1748 CubicXYAtT(fPts, tMid, &midPt);
1749 if (!midPt.approximatelyEqual(xyAtT(span))) {
1750 break;
1751 }
1752 }
1753 SkASSERT(span[less].fDone == span->fDone);
1754 if (span[less].fT == 0) {
1755 span->fT = newT = 0;
1756 } else {
1757 setSpanT(less, newT);
1758 }
1759#endif
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001760 --less;
caryclark@google.comf839c032012-10-26 21:03:50 +00001761 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001762 int more = 1;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001763 while (fTs.end() - &span[more - 1] > 1 && xyAtT(&span[more]) == xyAtT(span)) {
1764#if 1
1765 if (span[more - 1].fDone) {
1766 break;
1767 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001768 double tEndInterval = span[more].fT - newT;
1769 if (precisely_negative(tEndInterval)) {
1770 break;
1771 }
1772 if (fVerb == SkPath::kCubic_Verb) {
1773 double tMid = newT - tEndInterval / 2;
1774 _Point midEndPt;
1775 CubicXYAtT(fPts, tMid, &midEndPt);
1776 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
1777 break;
1778 }
1779 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001780 span[more - 1].fTiny = true;
1781 span[more - 1].fDone = true;
1782 if (approximately_negative(span[more].fT - newT)) {
1783 if (approximately_greater_than_one(span[more].fT)) {
1784 span[more + 1].fUnsortableStart = true;
1785 span[more].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001786 }
1787 if (approximately_less_than_zero(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001788 span[more].fUnsortableStart = true;
1789 span[more - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001790 }
1791 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001792 ++fDoneSpans;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001793#else
1794 double tEndInterval = span[more].fT - newT;
1795 if (precisely_negative(tEndInterval)) {
1796 break;
1797 }
1798 if (fVerb == SkPath::kCubic_Verb) {
1799 double tMid = newT - tEndInterval / 2;
1800 _Point midEndPt;
1801 CubicXYAtT(fPts, tMid, &midEndPt);
1802 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
1803 break;
1804 }
1805 }
1806 SkASSERT(span[more - 1].fDone == span[more].fDone);
1807 if (newT == 0) {
1808 setSpanT(more, 0);
1809 } else {
1810 span->fT = newT = span[more].fT;
1811 }
1812#endif
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001813 ++more;
caryclark@google.comf839c032012-10-26 21:03:50 +00001814 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001815 return insertedAt;
1816 }
1817
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001818 // set spans from start to end to decrement by one
1819 // note this walks other backwards
1820 // FIMXE: there's probably an edge case that can be constructed where
1821 // two span in one segment are separated by float epsilon on one span but
1822 // not the other, if one segment is very small. For this
1823 // case the counts asserted below may or may not be enough to separate the
caryclark@google.com2ddff932012-08-07 21:25:27 +00001824 // spans. Even if the counts work out, what if the spans aren't correctly
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001825 // sorted? It feels better in such a case to match the span's other span
1826 // pointer since both coincident segments must contain the same spans.
1827 void addTCancel(double startT, double endT, Segment& other,
1828 double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001829 SkASSERT(!approximately_negative(endT - startT));
1830 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00001831 bool binary = fOperand != other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001832 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001833 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001834 ++index;
1835 }
caryclark@google.comb9738012012-07-03 19:53:30 +00001836 int oIndex = other.fTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001837 while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001838 ;
caryclark@google.com59823f72012-08-09 18:17:47 +00001839 double tRatio = (oEndT - oStartT) / (endT - startT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001840 Span* test = &fTs[index];
1841 Span* oTest = &other.fTs[oIndex];
caryclark@google.com18063442012-07-25 12:05:18 +00001842 SkTDArray<double> outsideTs;
1843 SkTDArray<double> oOutsideTs;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001844 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001845 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
caryclark@google.comcc905052012-07-25 20:59:42 +00001846 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.com200c2112012-08-03 15:05:04 +00001847 double testT = test->fT;
1848 double oTestT = oTest->fT;
1849 Span* span = test;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001850 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001851 if (decrement) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001852 decrementSpan(span);
caryclark@google.com200c2112012-08-03 15:05:04 +00001853 } else if (track && span->fT < 1 && oTestT < 1) {
1854 TrackOutside(outsideTs, span->fT, oTestT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001855 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001856 span = &fTs[++index];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001857 } while (approximately_negative(span->fT - testT));
caryclark@google.com200c2112012-08-03 15:05:04 +00001858 Span* oSpan = oTest;
caryclark@google.com59823f72012-08-09 18:17:47 +00001859 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1860 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1861 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001862 while (approximately_negative(otherTMatchStart - oSpan->fT)
1863 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
caryclark@google.com03f97062012-08-21 13:13:52 +00001864 #ifdef SK_DEBUG
caryclark@google.com59823f72012-08-09 18:17:47 +00001865 SkASSERT(originalWindValue == oSpan->fWindValue);
caryclark@google.com03f97062012-08-21 13:13:52 +00001866 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001867 if (decrement) {
caryclark@google.com200c2112012-08-03 15:05:04 +00001868 other.decrementSpan(oSpan);
1869 } else if (track && oSpan->fT < 1 && testT < 1) {
1870 TrackOutside(oOutsideTs, oSpan->fT, testT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001871 }
1872 if (!oIndex) {
1873 break;
1874 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001875 oSpan = &other.fTs[--oIndex];
rmistry@google.comd6176b02012-08-23 18:14:13 +00001876 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001877 test = span;
1878 oTest = oSpan;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001879 } while (!approximately_negative(endT - test->fT));
1880 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
caryclark@google.com18063442012-07-25 12:05:18 +00001881 // FIXME: determine if canceled edges need outside ts added
caryclark@google.comcc905052012-07-25 20:59:42 +00001882 if (!done() && outsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001883 double tStart = outsideTs[0];
1884 double oStart = outsideTs[1];
1885 addCancelOutsides(tStart, oStart, other, oEndT);
1886 int count = outsideTs.count();
1887 if (count > 2) {
1888 double tStart = outsideTs[count - 2];
1889 double oStart = outsideTs[count - 1];
1890 addCancelOutsides(tStart, oStart, other, oEndT);
1891 }
caryclark@google.com18063442012-07-25 12:05:18 +00001892 }
caryclark@google.comcc905052012-07-25 20:59:42 +00001893 if (!other.done() && oOutsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001894 double tStart = oOutsideTs[0];
1895 double oStart = oOutsideTs[1];
1896 other.addCancelOutsides(tStart, oStart, *this, endT);
caryclark@google.com18063442012-07-25 12:05:18 +00001897 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001898 }
skia.committer@gmail.com631cdcb2013-03-01 12:12:55 +00001899
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00001900 int addSelfT(Segment* other, const SkPoint& pt, double& newT) {
1901 int result = addT(other, pt, newT);
1902 Span* span = &fTs[result];
1903 span->fLoop = true;
1904 return result;
1905 }
skia.committer@gmail.com15dd3002013-01-18 07:07:28 +00001906
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001907 int addUnsortableT(Segment* other, bool start, const SkPoint& pt, double& newT) {
1908 int result = addT(other, pt, newT);
caryclark@google.com73ca6242013-01-17 21:02:47 +00001909 Span* span = &fTs[result];
1910 if (start) {
1911 if (result > 0) {
1912 span[result - 1].fUnsortableEnd = true;
1913 }
1914 span[result].fUnsortableStart = true;
1915 } else {
1916 span[result].fUnsortableEnd = true;
1917 if (result + 1 < fTs.count()) {
1918 span[result + 1].fUnsortableStart = true;
1919 }
1920 }
1921 return result;
1922 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00001923
caryclark@google.com4eeda372012-12-06 21:47:48 +00001924 int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1925 SkTDArray<double>& outsideTs) {
1926 int oWindValue = oTest->fWindValue;
1927 int oOppValue = oTest->fOppValue;
1928 if (opp) {
1929 SkTSwap<int>(oWindValue, oOppValue);
1930 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001931 Span* const test = &fTs[index];
1932 Span* end = test;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001933 const double oStartT = oTest->fT;
1934 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001935 if (bumpSpan(end, oWindValue, oOppValue)) {
1936 TrackOutside(outsideTs, end->fT, oStartT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001937 }
1938 end = &fTs[++index];
1939 } while (approximately_negative(end->fT - test->fT));
1940 return index;
1941 }
1942
1943 // because of the order in which coincidences are resolved, this and other
1944 // may not have the same intermediate points. Compute the corresponding
1945 // intermediate T values (using this as the master, other as the follower)
1946 // and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com4eeda372012-12-06 21:47:48 +00001947 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1948 SkTDArray<double>& oOutsideTs) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001949 Span* const oTest = &fTs[oIndex];
1950 Span* oEnd = oTest;
1951 const double startT = test->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001952 const double oStartT = oTest->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001953 while (!approximately_negative(oEndT - oEnd->fT)
caryclark@google.com4eeda372012-12-06 21:47:48 +00001954 && approximately_negative(oEnd->fT - oStartT)) {
1955 zeroSpan(oEnd);
1956 TrackOutside(oOutsideTs, oEnd->fT, startT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001957 oEnd = &fTs[++oIndex];
1958 }
1959 return oIndex;
1960 }
1961
1962 // FIXME: need to test this case:
1963 // contourA has two segments that are coincident
1964 // contourB has two segments that are coincident in the same place
1965 // each ends up with +2/0 pairs for winding count
1966 // since logic below doesn't transfer count (only increments/decrements) can this be
1967 // resolved to +4/0 ?
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001968
1969 // set spans from start to end to increment the greater by one and decrement
1970 // the lesser
caryclark@google.com4eeda372012-12-06 21:47:48 +00001971 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001972 SkASSERT(!approximately_negative(endT - startT));
1973 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001974 bool opp = fOperand ^ other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001975 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001976 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001977 ++index;
1978 }
1979 int oIndex = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001980 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001981 ++oIndex;
1982 }
1983 Span* test = &fTs[index];
1984 Span* oTest = &other.fTs[oIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001985 SkTDArray<double> outsideTs;
1986 SkTDArray<double> oOutsideTs;
1987 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001988 // if either span has an opposite value and the operands don't match, resolve first
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001989 // SkASSERT(!test->fDone || !oTest->fDone);
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001990 if (test->fDone || oTest->fDone) {
1991 index = advanceCoincidentThis(oTest, opp, index);
1992 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
1993 } else {
1994 index = bumpCoincidentThis(oTest, opp, index, outsideTs);
1995 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
1996 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001997 test = &fTs[index];
1998 oTest = &other.fTs[oIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001999 } while (!approximately_negative(endT - test->fT));
2000 SkASSERT(approximately_negative(oTest->fT - oEndT));
2001 SkASSERT(approximately_negative(oEndT - oTest->fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00002002 if (!done() && outsideTs.count()) {
2003 addCoinOutsides(outsideTs, other, oEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002004 }
2005 if (!other.done() && oOutsideTs.count()) {
caryclark@google.comcc905052012-07-25 20:59:42 +00002006 other.addCoinOutsides(oOutsideTs, *this, endT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002007 }
2008 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002009
caryclark@google.comcc905052012-07-25 20:59:42 +00002010 // FIXME: this doesn't prevent the same span from being added twice
caryclark@google.comaa358312013-01-29 20:28:49 +00002011 // fix in caller, SkASSERT here?
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002012 void addTPair(double t, Segment& other, double otherT, bool borrowWind, const SkPoint& pt) {
caryclark@google.comcc905052012-07-25 20:59:42 +00002013 int tCount = fTs.count();
2014 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
2015 const Span& span = fTs[tIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002016 if (!approximately_negative(span.fT - t)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00002017 break;
2018 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00002019 if (approximately_negative(span.fT - t) && span.fOther == &other
2020 && approximately_equal(span.fOtherT, otherT)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00002021#if DEBUG_ADD_T_PAIR
2022 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
2023 __FUNCTION__, fID, t, other.fID, otherT);
2024#endif
2025 return;
2026 }
2027 }
caryclark@google.com47580692012-07-23 12:14:49 +00002028#if DEBUG_ADD_T_PAIR
2029 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
2030 __FUNCTION__, fID, t, other.fID, otherT);
2031#endif
caryclark@google.com7ff5c842013-02-26 15:56:05 +00002032 int insertedAt = addT(&other, pt, t);
2033 int otherInsertedAt = other.addT(this, pt, otherT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002034 addOtherT(insertedAt, otherT, otherInsertedAt);
caryclark@google.comb9738012012-07-03 19:53:30 +00002035 other.addOtherT(otherInsertedAt, t, insertedAt);
caryclark@google.com2ddff932012-08-07 21:25:27 +00002036 matchWindingValue(insertedAt, t, borrowWind);
2037 other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002038 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002039
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002040 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002041 // add edge leading into junction
caryclark@google.com4eeda372012-12-06 21:47:48 +00002042 int min = SkMin32(end, start);
2043 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002044 addAngle(angles, end, start);
2045 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002046 // add edge leading away from junction
caryclark@google.com495f8e42012-05-31 13:13:11 +00002047 int step = SkSign32(end - start);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002048 int tIndex = nextExactSpan(end, step);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002049 min = SkMin32(end, tIndex);
2050 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002051 addAngle(angles, end, tIndex);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002052 }
2053 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002054
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002055 int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
2056 Span* const test = &fTs[index];
2057 Span* end = test;
2058 do {
2059 end = &fTs[++index];
2060 } while (approximately_negative(end->fT - test->fT));
2061 return index;
2062 }
2063
2064 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
2065 Span* const oTest = &fTs[oIndex];
2066 Span* oEnd = oTest;
2067 const double oStartT = oTest->fT;
2068 while (!approximately_negative(oEndT - oEnd->fT)
2069 && approximately_negative(oEnd->fT - oStartT)) {
2070 oEnd = &fTs[++oIndex];
2071 }
2072 return oIndex;
2073 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00002074
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002075 bool betweenTs(int lesser, double testT, int greater) {
2076 if (lesser > greater) {
2077 SkTSwap<int>(lesser, greater);
2078 }
2079 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
2080 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002081
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002082 const Bounds& bounds() const {
2083 return fBounds;
2084 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002085
caryclark@google.com31143cf2012-11-09 22:14:19 +00002086 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002087 double referenceT = fTs[index].fT;
2088 int lesser = index;
caryclark@google.com31143cf2012-11-09 22:14:19 +00002089 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
2090 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00002091 buildAnglesInner(lesser, angles);
2092 }
2093 do {
2094 buildAnglesInner(index, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002095 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
2096 && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002097 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002098
2099 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
2100 Span* span = &fTs[index];
2101 Segment* other = span->fOther;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002102 // if there is only one live crossing, and no coincidence, continue
2103 // in the same direction
2104 // if there is coincidence, the only choice may be to reverse direction
2105 // find edge on either side of intersection
2106 int oIndex = span->fOtherIndex;
2107 // if done == -1, prior span has already been processed
2108 int step = 1;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002109 int next = other->nextExactSpan(oIndex, step);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002110 if (next < 0) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002111 step = -step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002112 next = other->nextExactSpan(oIndex, step);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002113 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002114 // add candidate into and away from junction
2115 other->addTwoAngles(next, oIndex, angles);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002116 }
2117
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002118 int computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002119 SkTDArray<Angle> angles;
2120 addTwoAngles(startIndex, endIndex, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002121 buildAngles(endIndex, angles, false);
caryclark@google.comd1688742012-09-18 20:08:37 +00002122 // OPTIMIZATION: check all angles to see if any have computed wind sum
2123 // before sorting (early exit if none)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002124 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002125 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002126#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002127 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002128#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002129 if (!sortable) {
2130 return SK_MinS32;
2131 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002132 int angleCount = angles.count();
2133 const Angle* angle;
2134 const Segment* base;
2135 int winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002136 int oWinding;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002137 int firstIndex = 0;
2138 do {
2139 angle = sorted[firstIndex];
2140 base = angle->segment();
2141 winding = base->windSum(angle);
2142 if (winding != SK_MinS32) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002143 oWinding = base->oppSum(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002144 break;
2145 }
2146 if (++firstIndex == angleCount) {
2147 return SK_MinS32;
2148 }
2149 } while (true);
2150 // turn winding into contourWinding
caryclark@google.com2ddff932012-08-07 21:25:27 +00002151 int spanWinding = base->spanSign(angle);
2152 bool inner = useInnerWinding(winding + spanWinding, winding);
2153 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00002154 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
caryclark@google.com59823f72012-08-09 18:17:47 +00002155 spanWinding, winding, angle->sign(), inner,
caryclark@google.com2ddff932012-08-07 21:25:27 +00002156 inner ? winding + spanWinding : winding);
2157 #endif
2158 if (inner) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002159 winding += spanWinding;
2160 }
2161 #if DEBUG_SORT
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002162 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002163 #endif
2164 int nextIndex = firstIndex + 1;
2165 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com2ddff932012-08-07 21:25:27 +00002166 winding -= base->spanSign(angle);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002167 oWinding -= base->oppSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002168 do {
2169 if (nextIndex == angleCount) {
2170 nextIndex = 0;
2171 }
2172 angle = sorted[nextIndex];
2173 Segment* segment = angle->segment();
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002174 bool opp = base->fOperand ^ segment->fOperand;
2175 int maxWinding, oMaxWinding;
2176 int spanSign = segment->spanSign(angle);
2177 int oppoSign = segment->oppSign(angle);
2178 if (opp) {
2179 oMaxWinding = oWinding;
2180 oWinding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002181 maxWinding = winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002182 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002183 winding -= oppoSign;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002184 }
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002185 } else {
2186 maxWinding = winding;
2187 winding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002188 oMaxWinding = oWinding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002189 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002190 oWinding -= oppoSign;
2191 }
2192 }
2193 if (segment->windSum(angle) == SK_MinS32) {
2194 if (opp) {
2195 if (useInnerWinding(oMaxWinding, oWinding)) {
2196 oMaxWinding = oWinding;
2197 }
2198 if (oppoSign && useInnerWinding(maxWinding, winding)) {
2199 maxWinding = winding;
2200 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002201 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002202 } else {
2203 if (useInnerWinding(maxWinding, winding)) {
2204 maxWinding = winding;
2205 }
2206 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
2207 oMaxWinding = oWinding;
2208 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002209 (void) segment->markAndChaseWinding(angle, maxWinding,
2210 binary ? oMaxWinding : 0);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002211 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002212 }
2213 } while (++nextIndex != lastIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002214 int minIndex = SkMin32(startIndex, endIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002215 return windSum(minIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002216 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002217
caryclark@google.com3586ece2012-12-27 18:46:58 +00002218 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
caryclark@google.com10227bf2012-12-28 22:10:41 +00002219 double mid, bool opp, bool current) const {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002220 SkScalar bottom = fBounds.fBottom;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002221 int bestTIndex = -1;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002222 if (bottom <= bestY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002223 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002224 }
2225 SkScalar top = fBounds.fTop;
2226 if (top >= basePt.fY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002227 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002228 }
2229 if (fBounds.fLeft > basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002230 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002231 }
2232 if (fBounds.fRight < basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002233 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002234 }
2235 if (fBounds.fLeft == fBounds.fRight) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002236 // if vertical, and directly above test point, wait for another one
caryclark@google.com6d0032a2013-01-04 19:41:13 +00002237 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002238 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002239 // intersect ray starting at basePt with edge
2240 Intersections intersections;
2241 // OPTIMIZE: use specialty function that intersects ray with curve,
2242 // returning t values only for curve (we don't care about t on ray)
2243 int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
2244 if (pts == 0 || (current && pts == 1)) {
2245 return bestTIndex;
2246 }
2247 if (current) {
2248 SkASSERT(pts > 1);
2249 int closestIdx = 0;
2250 double closest = fabs(intersections.fT[0][0] - mid);
2251 for (int idx = 1; idx < pts; ++idx) {
2252 double test = fabs(intersections.fT[0][idx] - mid);
2253 if (closest > test) {
2254 closestIdx = idx;
2255 closest = test;
2256 }
2257 }
2258 if (closestIdx < pts - 1) {
2259 intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
2260 }
2261 --pts;
2262 }
2263 double bestT = -1;
2264 for (int index = 0; index < pts; ++index) {
2265 double foundT = intersections.fT[0][index];
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002266 if (approximately_less_than_zero(foundT)
2267 || approximately_greater_than_one(foundT)) {
2268 continue;
2269 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002270 SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
2271 if (approximately_negative(testY - bestY)
2272 || approximately_negative(basePt.fY - testY)) {
caryclark@google.com47580692012-07-23 12:14:49 +00002273 continue;
2274 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002275 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002276 return SK_MinS32; // if the intersection is edge on, wait for another one
caryclark@google.com10227bf2012-12-28 22:10:41 +00002277 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002278 if (fVerb > SkPath::kLine_Verb) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002279 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
2280 if (approximately_zero(dx)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002281 return SK_MinS32; // hit vertical, wait for another one
caryclark@google.com3586ece2012-12-27 18:46:58 +00002282 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00002283 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002284 bestY = testY;
2285 bestT = foundT;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002286 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002287 if (bestT < 0) {
2288 return bestTIndex;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002289 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002290 SkASSERT(bestT >= 0);
2291 SkASSERT(bestT <= 1);
2292 int start;
2293 int end = 0;
2294 do {
2295 start = end;
2296 end = nextSpan(start, 1);
2297 } while (fTs[end].fT < bestT);
2298 // FIXME: see next candidate for a better pattern to find the next start/end pair
2299 while (start + 1 < end && fTs[start].fDone) {
2300 ++start;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002301 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002302 if (!isCanceled(start)) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002303 hitT = bestT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002304 bestTIndex = start;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002305 hitSomething = true;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002306 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002307 return bestTIndex;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002308 }
caryclark@google.com18063442012-07-25 12:05:18 +00002309
caryclark@google.com4eeda372012-12-06 21:47:48 +00002310 void decrementSpan(Span* span) {
caryclark@google.com18063442012-07-25 12:05:18 +00002311 SkASSERT(span->fWindValue > 0);
2312 if (--(span->fWindValue) == 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002313 if (!span->fOppValue && !span->fDone) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002314 span->fDone = true;
2315 ++fDoneSpans;
2316 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002317 }
2318 }
2319
2320 bool bumpSpan(Span* span, int windDelta, int oppDelta) {
2321 SkASSERT(!span->fDone);
2322 span->fWindValue += windDelta;
2323 SkASSERT(span->fWindValue >= 0);
2324 span->fOppValue += oppDelta;
2325 SkASSERT(span->fOppValue >= 0);
2326 if (fXor) {
2327 span->fWindValue &= 1;
2328 }
2329 if (fOppXor) {
2330 span->fOppValue &= 1;
2331 }
2332 if (!span->fWindValue && !span->fOppValue) {
2333 span->fDone = true;
2334 ++fDoneSpans;
caryclark@google.com18063442012-07-25 12:05:18 +00002335 return true;
2336 }
2337 return false;
2338 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002339
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002340 // OPTIMIZE
2341 // when the edges are initially walked, they don't automatically get the prior and next
2342 // 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 +00002343 // and would additionally remove the need for similar checks in condition edges. It would
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002344 // also allow intersection code to assume end of segment intersections (maybe?)
2345 bool complete() const {
2346 int count = fTs.count();
2347 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
2348 }
caryclark@google.com18063442012-07-25 12:05:18 +00002349
caryclark@google.com15fa1382012-05-07 20:49:36 +00002350 bool done() const {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002351 SkASSERT(fDoneSpans <= fTs.count());
2352 return fDoneSpans == fTs.count();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002353 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002354
caryclark@google.comf839c032012-10-26 21:03:50 +00002355 bool done(int min) const {
2356 return fTs[min].fDone;
2357 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002358
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002359 bool done(const Angle* angle) const {
2360 return done(SkMin32(angle->start(), angle->end()));
caryclark@google.com47580692012-07-23 12:14:49 +00002361 }
skia.committer@gmail.com044679e2013-02-15 07:16:57 +00002362
caryclark@google.com7ff5c842013-02-26 15:56:05 +00002363 SkVector dxdy(int index) const {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002364 return (*SegmentDXDYAtT[fVerb])(fPts, fTs[index].fT);
2365 }
2366
2367 SkScalar dy(int index) const {
2368 return (*SegmentDYAtT[fVerb])(fPts, fTs[index].fT);
2369 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00002370
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002371 bool equalPoints(int greaterTIndex, int lesserTIndex) {
2372 SkASSERT(greaterTIndex >= lesserTIndex);
2373 double greaterT = fTs[greaterTIndex].fT;
2374 double lesserT = fTs[lesserTIndex].fT;
2375 if (greaterT == lesserT) {
2376 return true;
2377 }
2378 if (!approximately_negative(greaterT - lesserT)) {
2379 return false;
2380 }
2381 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2382 }
2383
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002384 /*
2385 The M and S variable name parts stand for the operators.
2386 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2387 Su stands for Subtrahend
2388 The Opp variable name part designates that the value is for the Opposite operator.
2389 Opposite values result from combining coincident spans.
2390 */
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002391
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002392 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2393 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002394 const int startIndex = nextStart;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002395 const int endIndex = nextEnd;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002396 SkASSERT(startIndex != endIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002397 const int count = fTs.count();
2398 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2399 const int step = SkSign32(endIndex - startIndex);
2400 const int end = nextExactSpan(startIndex, step);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002401 SkASSERT(end >= 0);
2402 Span* endSpan = &fTs[end];
2403 Segment* other;
2404 if (isSimple(end)) {
2405 // mark the smaller of startIndex, endIndex done, and all adjacent
2406 // spans with the same T value (but not 'other' spans)
2407 #if DEBUG_WINDING
2408 SkDebugf("%s simple\n", __FUNCTION__);
2409 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002410 int min = SkMin32(startIndex, endIndex);
2411 if (fTs[min].fDone) {
2412 return NULL;
2413 }
2414 markDoneBinary(min);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002415 other = endSpan->fOther;
2416 nextStart = endSpan->fOtherIndex;
2417 double startT = other->fTs[nextStart].fT;
2418 nextEnd = nextStart;
2419 do {
2420 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002421 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002422 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002423 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2424 return other;
2425 }
2426 // more than one viable candidate -- measure angles to find best
2427 SkTDArray<Angle> angles;
2428 SkASSERT(startIndex - endIndex != 0);
2429 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2430 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002431 buildAngles(end, angles, true);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002432 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002433 bool sortable = SortAngles(angles, sorted);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002434 int angleCount = angles.count();
2435 int firstIndex = findStartingEdge(sorted, startIndex, end);
2436 SkASSERT(firstIndex >= 0);
2437 #if DEBUG_SORT
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002438 debugShowSort(__FUNCTION__, sorted, firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002439 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002440 if (!sortable) {
2441 unsortable = true;
2442 return NULL;
2443 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002444 SkASSERT(sorted[firstIndex]->segment() == this);
2445 #if DEBUG_WINDING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002446 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2447 sorted[firstIndex]->sign());
caryclark@google.com235f56a2012-09-14 14:19:30 +00002448 #endif
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002449 int sumMiWinding = updateWinding(endIndex, startIndex);
2450 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2451 if (operand()) {
2452 SkTSwap<int>(sumMiWinding, sumSuWinding);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002453 }
2454 int nextIndex = firstIndex + 1;
2455 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2456 const Angle* foundAngle = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002457 bool foundDone = false;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002458 // iterate through the angle, and compute everyone's winding
caryclark@google.com235f56a2012-09-14 14:19:30 +00002459 Segment* nextSegment;
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00002460 int activeCount = 0;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002461 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002462 SkASSERT(nextIndex != firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002463 if (nextIndex == angleCount) {
2464 nextIndex = 0;
2465 }
2466 const Angle* nextAngle = sorted[nextIndex];
2467 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002468 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2469 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2470 nextAngle->end(), op, sumMiWinding, sumSuWinding,
2471 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00002472 if (activeAngle) {
2473 ++activeCount;
2474 if (!foundAngle || (foundDone && activeCount & 1)) {
2475 if (nextSegment->tiny(nextAngle)) {
2476 unsortable = true;
2477 return NULL;
2478 }
2479 foundAngle = nextAngle;
2480 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
2481 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002482 }
2483 if (nextSegment->done()) {
2484 continue;
2485 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002486 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2487 continue;
2488 }
2489 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2490 oppSumWinding, activeAngle, nextAngle);
2491 if (last) {
2492 *chase.append() = last;
2493#if DEBUG_WINDING
2494 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2495 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2496#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002497 }
2498 } while (++nextIndex != lastIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002499 markDoneBinary(SkMin32(startIndex, endIndex));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002500 if (!foundAngle) {
2501 return NULL;
2502 }
2503 nextStart = foundAngle->start();
2504 nextEnd = foundAngle->end();
2505 nextSegment = foundAngle->segment();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002506
caryclark@google.com235f56a2012-09-14 14:19:30 +00002507 #if DEBUG_WINDING
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002508 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2509 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002510 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002511 return nextSegment;
2512 }
caryclark@google.com47580692012-07-23 12:14:49 +00002513
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002514 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2515 bool& unsortable) {
2516 const int startIndex = nextStart;
2517 const int endIndex = nextEnd;
2518 SkASSERT(startIndex != endIndex);
2519 const int count = fTs.count();
2520 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2521 const int step = SkSign32(endIndex - startIndex);
2522 const int end = nextExactSpan(startIndex, step);
2523 SkASSERT(end >= 0);
2524 Span* endSpan = &fTs[end];
2525 Segment* other;
2526 if (isSimple(end)) {
2527 // mark the smaller of startIndex, endIndex done, and all adjacent
2528 // spans with the same T value (but not 'other' spans)
2529 #if DEBUG_WINDING
2530 SkDebugf("%s simple\n", __FUNCTION__);
2531 #endif
2532 int min = SkMin32(startIndex, endIndex);
2533 if (fTs[min].fDone) {
2534 return NULL;
2535 }
2536 markDoneUnary(min);
2537 other = endSpan->fOther;
2538 nextStart = endSpan->fOtherIndex;
2539 double startT = other->fTs[nextStart].fT;
2540 nextEnd = nextStart;
2541 do {
2542 nextEnd += step;
2543 }
2544 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2545 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2546 return other;
2547 }
2548 // more than one viable candidate -- measure angles to find best
2549 SkTDArray<Angle> angles;
2550 SkASSERT(startIndex - endIndex != 0);
2551 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2552 addTwoAngles(startIndex, end, angles);
2553 buildAngles(end, angles, true);
2554 SkTDArray<Angle*> sorted;
2555 bool sortable = SortAngles(angles, sorted);
2556 int angleCount = angles.count();
2557 int firstIndex = findStartingEdge(sorted, startIndex, end);
2558 SkASSERT(firstIndex >= 0);
2559 #if DEBUG_SORT
2560 debugShowSort(__FUNCTION__, sorted, firstIndex);
2561 #endif
2562 if (!sortable) {
2563 unsortable = true;
2564 return NULL;
2565 }
2566 SkASSERT(sorted[firstIndex]->segment() == this);
2567 #if DEBUG_WINDING
2568 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2569 sorted[firstIndex]->sign());
2570 #endif
2571 int sumWinding = updateWinding(endIndex, startIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002572 int nextIndex = firstIndex + 1;
2573 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2574 const Angle* foundAngle = NULL;
2575 bool foundDone = false;
2576 // iterate through the angle, and compute everyone's winding
2577 Segment* nextSegment;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002578 int activeCount = 0;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002579 do {
2580 SkASSERT(nextIndex != firstIndex);
2581 if (nextIndex == angleCount) {
2582 nextIndex = 0;
2583 }
2584 const Angle* nextAngle = sorted[nextIndex];
2585 nextSegment = nextAngle->segment();
2586 int maxWinding;
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00002587 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002588 maxWinding, sumWinding);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002589 if (activeAngle) {
2590 ++activeCount;
2591 if (!foundAngle || (foundDone && activeCount & 1)) {
2592 if (nextSegment->tiny(nextAngle)) {
2593 unsortable = true;
2594 return NULL;
2595 }
2596 foundAngle = nextAngle;
2597 foundDone = nextSegment->done(nextAngle);
2598 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002599 }
2600 if (nextSegment->done()) {
2601 continue;
2602 }
2603 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2604 continue;
2605 }
2606 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2607 if (last) {
2608 *chase.append() = last;
2609#if DEBUG_WINDING
2610 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2611 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2612#endif
2613 }
2614 } while (++nextIndex != lastIndex);
2615 markDoneUnary(SkMin32(startIndex, endIndex));
2616 if (!foundAngle) {
2617 return NULL;
2618 }
2619 nextStart = foundAngle->start();
2620 nextEnd = foundAngle->end();
2621 nextSegment = foundAngle->segment();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002622 #if DEBUG_WINDING
2623 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2624 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2625 #endif
2626 return nextSegment;
2627 }
2628
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002629 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002630 const int startIndex = nextStart;
2631 const int endIndex = nextEnd;
2632 SkASSERT(startIndex != endIndex);
2633 int count = fTs.count();
2634 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2635 : startIndex > 0);
2636 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002637 int end = nextExactSpan(startIndex, step);
caryclark@google.com24bec792012-08-20 12:43:57 +00002638 SkASSERT(end >= 0);
2639 Span* endSpan = &fTs[end];
2640 Segment* other;
caryclark@google.com24bec792012-08-20 12:43:57 +00002641 if (isSimple(end)) {
2642 #if DEBUG_WINDING
2643 SkDebugf("%s simple\n", __FUNCTION__);
2644 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002645 int min = SkMin32(startIndex, endIndex);
2646 if (fTs[min].fDone) {
2647 return NULL;
2648 }
2649 markDone(min, 1);
caryclark@google.com24bec792012-08-20 12:43:57 +00002650 other = endSpan->fOther;
2651 nextStart = endSpan->fOtherIndex;
2652 double startT = other->fTs[nextStart].fT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002653 #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 +00002654 SkDEBUGCODE(bool firstLoop = true;)
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002655 if ((approximately_less_than_zero(startT) && step < 0)
2656 || (approximately_greater_than_one(startT) && step > 0)) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002657 step = -step;
2658 SkDEBUGCODE(firstLoop = false;)
2659 }
2660 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002661 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002662 nextEnd = nextStart;
2663 do {
2664 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002665 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002666 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002667 #if 01
caryclark@google.com24bec792012-08-20 12:43:57 +00002668 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2669 break;
2670 }
caryclark@google.com03f97062012-08-21 13:13:52 +00002671 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00002672 SkASSERT(firstLoop);
caryclark@google.com03f97062012-08-21 13:13:52 +00002673 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002674 SkDEBUGCODE(firstLoop = false;)
2675 step = -step;
2676 } while (true);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002677 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002678 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2679 return other;
2680 }
2681 SkTDArray<Angle> angles;
2682 SkASSERT(startIndex - endIndex != 0);
2683 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2684 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002685 buildAngles(end, angles, false);
caryclark@google.com24bec792012-08-20 12:43:57 +00002686 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002687 bool sortable = SortAngles(angles, sorted);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002688 if (!sortable) {
2689 unsortable = true;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002690 #if DEBUG_SORT
2691 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
2692 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002693 return NULL;
2694 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002695 int angleCount = angles.count();
2696 int firstIndex = findStartingEdge(sorted, startIndex, end);
2697 SkASSERT(firstIndex >= 0);
2698 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002699 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
caryclark@google.com24bec792012-08-20 12:43:57 +00002700 #endif
2701 SkASSERT(sorted[firstIndex]->segment() == this);
2702 int nextIndex = firstIndex + 1;
2703 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002704 const Angle* foundAngle = NULL;
2705 bool foundDone = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002706 Segment* nextSegment;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002707 int activeCount = 0;
caryclark@google.com24bec792012-08-20 12:43:57 +00002708 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002709 SkASSERT(nextIndex != firstIndex);
caryclark@google.com24bec792012-08-20 12:43:57 +00002710 if (nextIndex == angleCount) {
2711 nextIndex = 0;
2712 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002713 const Angle* nextAngle = sorted[nextIndex];
caryclark@google.com24bec792012-08-20 12:43:57 +00002714 nextSegment = nextAngle->segment();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002715 ++activeCount;
2716 if (!foundAngle || (foundDone && activeCount & 1)) {
2717 if (nextSegment->tiny(nextAngle)) {
2718 unsortable = true;
2719 return NULL;
2720 }
2721 foundAngle = nextAngle;
2722 foundDone = nextSegment->done(nextAngle);
2723 }
2724 if (nextSegment->done()) {
2725 continue;
caryclark@google.com24bec792012-08-20 12:43:57 +00002726 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002727 } while (++nextIndex != lastIndex);
2728 markDone(SkMin32(startIndex, endIndex), 1);
2729 if (!foundAngle) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002730 return NULL;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002731 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002732 nextStart = foundAngle->start();
2733 nextEnd = foundAngle->end();
2734 nextSegment = foundAngle->segment();
2735 #if DEBUG_WINDING
2736 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2737 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2738 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002739 return nextSegment;
2740 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002741
2742 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2743 int angleCount = sorted.count();
2744 int firstIndex = -1;
2745 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2746 const Angle* angle = sorted[angleIndex];
2747 if (angle->segment() == this && angle->start() == end &&
2748 angle->end() == start) {
2749 firstIndex = angleIndex;
2750 break;
2751 }
2752 }
2753 return firstIndex;
2754 }
2755
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002756 // FIXME: this is tricky code; needs its own unit test
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002757 // note that fOtherIndex isn't computed yet, so it can't be used here
caryclark@google.com4eeda372012-12-06 21:47:48 +00002758 void findTooCloseToCall() {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002759 int count = fTs.count();
2760 if (count < 3) { // require t=0, x, 1 at minimum
2761 return;
2762 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002763 int matchIndex = 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002764 int moCount;
2765 Span* match;
2766 Segment* mOther;
2767 do {
2768 match = &fTs[matchIndex];
2769 mOther = match->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002770 // FIXME: allow quads, cubics to be near coincident?
2771 if (mOther->fVerb == SkPath::kLine_Verb) {
2772 moCount = mOther->fTs.count();
2773 if (moCount >= 3) {
2774 break;
2775 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002776 }
2777 if (++matchIndex >= count) {
2778 return;
2779 }
2780 } while (true); // require t=0, x, 1 at minimum
caryclark@google.com15fa1382012-05-07 20:49:36 +00002781 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002782 const SkPoint* matchPt = &xyAtT(match);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002783 // look for a pair of nearby T values that map to the same (x,y) value
2784 // if found, see if the pair of other segments share a common point. If
2785 // so, the span from here to there is coincident.
caryclark@google.com15fa1382012-05-07 20:49:36 +00002786 for (int index = matchIndex + 1; index < count; ++index) {
2787 Span* test = &fTs[index];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002788 if (test->fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002789 continue;
2790 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002791 Segment* tOther = test->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002792 if (tOther->fVerb != SkPath::kLine_Verb) {
2793 continue; // FIXME: allow quads, cubics to be near coincident?
2794 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002795 int toCount = tOther->fTs.count();
2796 if (toCount < 3) { // require t=0, x, 1 at minimum
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002797 continue;
2798 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002799 const SkPoint* testPt = &xyAtT(test);
2800 if (*matchPt != *testPt) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002801 matchIndex = index;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002802 moCount = toCount;
2803 match = test;
2804 mOther = tOther;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002805 matchPt = testPt;
2806 continue;
2807 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002808 int moStart = -1;
2809 int moEnd = -1;
2810 double moStartT, moEndT;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002811 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002812 Span& moSpan = mOther->fTs[moIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002813 if (moSpan.fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002814 continue;
2815 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002816 if (moSpan.fOther == this) {
2817 if (moSpan.fOtherT == match->fT) {
2818 moStart = moIndex;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002819 moStartT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002820 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002821 continue;
2822 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002823 if (moSpan.fOther == tOther) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002824 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002825 moStart = -1;
2826 break;
2827 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002828 SkASSERT(moEnd == -1);
2829 moEnd = moIndex;
2830 moEndT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002831 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002832 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002833 if (moStart < 0 || moEnd < 0) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002834 continue;
2835 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002836 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002837 if (approximately_equal(moStartT, moEndT)) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002838 continue;
2839 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002840 int toStart = -1;
2841 int toEnd = -1;
2842 double toStartT, toEndT;
2843 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2844 Span& toSpan = tOther->fTs[toIndex];
caryclark@google.comc899ad92012-08-23 15:24:42 +00002845 if (toSpan.fDone) {
2846 continue;
2847 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002848 if (toSpan.fOther == this) {
2849 if (toSpan.fOtherT == test->fT) {
2850 toStart = toIndex;
2851 toStartT = toSpan.fT;
2852 }
2853 continue;
2854 }
2855 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002856 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002857 moStart = -1;
2858 break;
2859 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002860 SkASSERT(toEnd == -1);
2861 toEnd = toIndex;
2862 toEndT = toSpan.fT;
2863 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002864 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002865 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2866 if (toStart <= 0 || toEnd <= 0) {
2867 continue;
2868 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002869 if (approximately_equal(toStartT, toEndT)) {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002870 continue;
2871 }
2872 // test to see if the segment between there and here is linear
2873 if (!mOther->isLinear(moStart, moEnd)
2874 || !tOther->isLinear(toStart, toEnd)) {
2875 continue;
2876 }
caryclark@google.comc899ad92012-08-23 15:24:42 +00002877 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002878 if (flipped) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002879 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002880 } else {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002881 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002882 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002883 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002884 }
2885
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002886 // FIXME: either:
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002887 // a) mark spans with either end unsortable as done, or
2888 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2889 // when encountering an unsortable span
2890
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002891 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2892 // and use more concise logic like the old edge walker code?
2893 // FIXME: this needs to deal with coincident edges
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002894 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002895 // iterate through T intersections and return topmost
2896 // topmost tangent from y-min to first pt is closer to horizontal
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002897 SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002898 int firstT = -1;
caryclark@google.comd0a19eb2013-02-19 12:49:33 +00002899 /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002900 SkASSERT(firstT >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002901 // sort the edges to find the leftmost
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002902 int step = 1;
2903 int end = nextSpan(firstT, step);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002904 if (end == -1) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002905 step = -1;
2906 end = nextSpan(firstT, step);
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00002907 SkASSERT(end != -1);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002908 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002909 // if the topmost T is not on end, or is three-way or more, find left
2910 // look for left-ness from tLeft to firstT (matching y of other)
2911 SkTDArray<Angle> angles;
2912 SkASSERT(firstT - end != 0);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002913 addTwoAngles(end, firstT, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002914 buildAngles(firstT, angles, true);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002915 SkTDArray<Angle*> sorted;
caryclark@google.comf839c032012-10-26 21:03:50 +00002916 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002917 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002918 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002919 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002920 if (onlySortable && !sortable) {
2921 unsortable = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002922 return NULL;
2923 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002924 // skip edges that have already been processed
2925 firstT = -1;
2926 Segment* leftSegment;
2927 do {
2928 const Angle* angle = sorted[++firstT];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002929 SkASSERT(!onlySortable || !angle->unsortable());
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002930 leftSegment = angle->segment();
2931 tIndex = angle->end();
2932 endIndex = angle->start();
2933 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002934 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002935 bool bumpsUp = leftSegment->bumpsUp(tIndex, endIndex);
2936 SkPoint xyE = leftSegment->xyAtT(endIndex);
2937 SkPoint xyS = leftSegment->xyAtT(tIndex);
caryclark@google.com7ff5c842013-02-26 15:56:05 +00002938 SkVector dxyE = leftSegment->dxdy(endIndex);
2939 SkVector dxyS = leftSegment->dxdy(tIndex);
caryclark@google.com47d73da2013-02-17 01:41:25 +00002940 double cross = dxyE.cross(dxyS);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00002941 bool bumpCheck = bumpsUp && xyE.fY < xyS.fY && dxyE.fX < 0;
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00002942 if (xyE == xyS){
2943 SkDebugf("%s ignore loops\n", __FUNCTION__);
2944 cross = 0;
2945 }
caryclark@google.com47d73da2013-02-17 01:41:25 +00002946 #if DEBUG_SWAP_TOP
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002947 SkDebugf("%s xyE=(%1.9g,%1.9g) xyS=(%1.9g,%1.9g)\n", __FUNCTION__,
2948 xyE.fX, xyE.fY, xyS.fX, xyS.fY);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00002949 SkDebugf("%s dxyE=(%1.9g,%1.9g) dxyS=(%1.9g,%1.9g) cross=%1.9g bumpsUp=%s\n",
2950 __FUNCTION__,
2951 dxyE.fX, dxyE.fY, dxyS.fX, dxyS.fY, cross, bumpsUp ? "true" : "false");
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002952 if ((cross > 0) ^ bumpCheck) {
2953 leftSegment->bumpsUp(tIndex, endIndex);
2954 SkDebugf("%s cross bump disagree\n", __FUNCTION__);
2955 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00002956 #endif
2957 if (cross > 0 || bumpCheck) {
caryclark@google.com47d73da2013-02-17 01:41:25 +00002958 #if DEBUG_SWAP_TOP
2959 SkDebugf("%s swap\n", __FUNCTION__);
2960 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002961 SkTSwap(tIndex, endIndex);
2962 }
2963 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002964 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002965 return leftSegment;
2966 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002967
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002968 // FIXME: not crazy about this
2969 // when the intersections are performed, the other index is into an
2970 // incomplete array. as the array grows, the indices become incorrect
2971 // while the following fixes the indices up again, it isn't smart about
2972 // skipping segments whose indices are already correct
2973 // assuming we leave the code that wrote the index in the first place
2974 void fixOtherTIndex() {
2975 int iCount = fTs.count();
2976 for (int i = 0; i < iCount; ++i) {
2977 Span& iSpan = fTs[i];
2978 double oT = iSpan.fOtherT;
2979 Segment* other = iSpan.fOther;
2980 int oCount = other->fTs.count();
2981 for (int o = 0; o < oCount; ++o) {
2982 Span& oSpan = other->fTs[o];
2983 if (oT == oSpan.fT && this == oSpan.fOther) {
2984 iSpan.fOtherIndex = o;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002985 break;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002986 }
2987 }
2988 }
2989 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002990
caryclark@google.com4eeda372012-12-06 21:47:48 +00002991 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002992 fDoneSpans = 0;
2993 fOperand = operand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00002994 fXor = evenOdd;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002995 fPts = pts;
2996 fVerb = verb;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002997 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00002998
caryclark@google.com3586ece2012-12-27 18:46:58 +00002999 void initWinding(int start, int end) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003000 int local = spanSign(start, end);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003001 int oppLocal = oppSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00003002 (void) markAndChaseWinding(start, end, local, oppLocal);
caryclark@google.com73ca6242013-01-17 21:02:47 +00003003 // OPTIMIZATION: the reverse mark and chase could skip the first marking
3004 (void) markAndChaseWinding(end, start, local, oppLocal);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003005 }
3006
caryclark@google.com3586ece2012-12-27 18:46:58 +00003007 void initWinding(int start, int end, int winding, int oppWinding) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003008 int local = spanSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00003009 if (local * winding >= 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003010 winding += local;
3011 }
3012 int oppLocal = oppSign(start, end);
3013 if (oppLocal * oppWinding >= 0) {
3014 oppWinding += oppLocal;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003015 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003016 (void) markAndChaseWinding(start, end, winding, oppWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003017 }
3018
caryclark@google.com3586ece2012-12-27 18:46:58 +00003019/*
3020when we start with a vertical intersect, we try to use the dx to determine if the edge is to
3021the 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 +00003022sign or not. However, this isn't enough.
3023If 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 +00003024If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
3025from 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 +00003026the same winding is shared by both.
caryclark@google.com3586ece2012-12-27 18:46:58 +00003027*/
3028 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
3029 SkScalar hitOppDx) {
3030 SkASSERT(hitDx || !winding);
3031 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
3032 SkASSERT(dx);
3033 int windVal = windValue(SkMin32(start, end));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003034 #if DEBUG_WINDING_AT_T
3035 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
3036 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
3037 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00003038 if (!winding) {
3039 winding = dx < 0 ? windVal : -windVal;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003040 } else if (winding * dx < 0) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00003041 int sideWind = winding + (dx < 0 ? windVal : -windVal);
3042 if (abs(winding) < abs(sideWind)) {
3043 winding = sideWind;
3044 }
3045 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003046 #if DEBUG_WINDING_AT_T
3047 SkDebugf(" winding=%d\n", winding);
3048 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00003049 int oppLocal = oppSign(start, end);
3050 SkASSERT(hitOppDx || !oppWind || !oppLocal);
3051 int oppWindVal = oppValue(SkMin32(start, end));
3052 if (!oppWind) {
3053 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
3054 } else if (hitOppDx * dx >= 0) {
3055 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
3056 if (abs(oppWind) < abs(oppSideWind)) {
3057 oppWind = oppSideWind;
3058 }
3059 }
3060 (void) markAndChaseWinding(start, end, winding, oppWind);
3061 }
3062
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003063 bool intersected() const {
3064 return fTs.count() > 0;
3065 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00003066
caryclark@google.com10227bf2012-12-28 22:10:41 +00003067 bool isCanceled(int tIndex) const {
3068 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
3069 }
3070
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00003071 bool isConnected(int startIndex, int endIndex) const {
3072 return fTs[startIndex].fWindSum != SK_MinS32
3073 || fTs[endIndex].fWindSum != SK_MinS32;
3074 }
3075
caryclark@google.com235f56a2012-09-14 14:19:30 +00003076 bool isHorizontal() const {
3077 return fBounds.fTop == fBounds.fBottom;
3078 }
3079
caryclark@google.com15fa1382012-05-07 20:49:36 +00003080 bool isLinear(int start, int end) const {
3081 if (fVerb == SkPath::kLine_Verb) {
3082 return true;
3083 }
3084 if (fVerb == SkPath::kQuad_Verb) {
3085 SkPoint qPart[3];
3086 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
3087 return QuadIsLinear(qPart);
3088 } else {
3089 SkASSERT(fVerb == SkPath::kCubic_Verb);
3090 SkPoint cPart[4];
3091 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
3092 return CubicIsLinear(cPart);
3093 }
3094 }
caryclark@google.comb9738012012-07-03 19:53:30 +00003095
3096 // OPTIMIZE: successive calls could start were the last leaves off
3097 // or calls could specialize to walk forwards or backwards
3098 bool isMissing(double startT) const {
3099 size_t tCount = fTs.count();
3100 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003101 if (approximately_zero(startT - fTs[index].fT)) {
caryclark@google.comb9738012012-07-03 19:53:30 +00003102 return false;
3103 }
3104 }
3105 return true;
3106 }
3107
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003108 bool isSimple(int end) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003109 int count = fTs.count();
3110 if (count == 2) {
3111 return true;
3112 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003113 double t = fTs[end].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003114 if (approximately_less_than_zero(t)) {
3115 return !approximately_less_than_zero(fTs[1].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003116 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003117 if (approximately_greater_than_one(t)) {
3118 return !approximately_greater_than_one(fTs[count - 2].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003119 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003120 return false;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003121 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003122
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003123 bool isVertical() const {
3124 return fBounds.fLeft == fBounds.fRight;
3125 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003126
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003127 bool isVertical(int start, int end) const {
3128 return (*SegmentVertical[fVerb])(fPts, start, end);
3129 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003130
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003131 SkScalar leftMost(int start, int end) const {
3132 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
3133 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003134
caryclark@google.com495f8e42012-05-31 13:13:11 +00003135 // this span is excluded by the winding rule -- chase the ends
3136 // as long as they are unambiguous to mark connections as done
3137 // and give them the same winding value
caryclark@google.com59823f72012-08-09 18:17:47 +00003138 Span* markAndChaseDone(const Angle* angle, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003139 int index = angle->start();
3140 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003141 return markAndChaseDone(index, endIndex, winding);
3142 }
3143
caryclark@google.com31143cf2012-11-09 22:14:19 +00003144 Span* markAndChaseDone(int index, int endIndex, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003145 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003146 int min = SkMin32(index, endIndex);
3147 markDone(min, winding);
3148 Span* last;
3149 Segment* other = this;
3150 while ((other = other->nextChase(index, step, min, last))) {
3151 other->markDone(min, winding);
3152 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003153 return last;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003154 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003155
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003156 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
3157 int index = angle->start();
3158 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003159 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003160 int min = SkMin32(index, endIndex);
3161 markDoneBinary(min, winding, oppWinding);
3162 Span* last;
3163 Segment* other = this;
3164 while ((other = other->nextChase(index, step, min, last))) {
3165 other->markDoneBinary(min, winding, oppWinding);
3166 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003167 return last;
3168 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003169
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003170 Span* markAndChaseDoneBinary(int index, int endIndex) {
3171 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003172 int min = SkMin32(index, endIndex);
3173 markDoneBinary(min);
3174 Span* last;
3175 Segment* other = this;
3176 while ((other = other->nextChase(index, step, min, last))) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003177 if (other->done()) {
3178 return NULL;
3179 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003180 other->markDoneBinary(min);
3181 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003182 return last;
3183 }
3184
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003185 Span* markAndChaseDoneUnary(int index, int endIndex) {
3186 int step = SkSign32(endIndex - index);
3187 int min = SkMin32(index, endIndex);
3188 markDoneUnary(min);
3189 Span* last;
3190 Segment* other = this;
3191 while ((other = other->nextChase(index, step, min, last))) {
3192 if (other->done()) {
3193 return NULL;
3194 }
3195 other->markDoneUnary(min);
3196 }
3197 return last;
3198 }
3199
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003200 Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
3201 int index = angle->start();
3202 int endIndex = angle->end();
3203 return markAndChaseDone(index, endIndex, winding);
3204 }
3205
caryclark@google.com4eeda372012-12-06 21:47:48 +00003206 Span* markAndChaseWinding(const Angle* angle, const int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003207 int index = angle->start();
3208 int endIndex = angle->end();
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003209 int step = SkSign32(endIndex - index);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003210 int min = SkMin32(index, endIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00003211 markWinding(min, winding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003212 Span* last;
3213 Segment* other = this;
3214 while ((other = other->nextChase(index, step, min, last))) {
3215 if (other->fTs[min].fWindSum != SK_MinS32) {
3216 SkASSERT(other->fTs[min].fWindSum == winding);
3217 return NULL;
3218 }
3219 other->markWinding(min, winding);
3220 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003221 return last;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003222 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003223
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003224 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003225 int min = SkMin32(index, endIndex);
3226 int step = SkSign32(endIndex - index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003227 markWinding(min, winding, oppWinding);
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) {
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00003232 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003233 return NULL;
3234 }
3235 other->markWinding(min, winding, oppWinding);
3236 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003237 return last;
3238 }
3239
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003240 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
3241 int start = angle->start();
3242 int end = angle->end();
3243 return markAndChaseWinding(start, end, winding, oppWinding);
3244 }
3245
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003246 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
3247 SkASSERT(angle->segment() == this);
3248 if (useInnerWinding(maxWinding, sumWinding)) {
3249 maxWinding = sumWinding;
3250 }
3251 Span* last;
3252 if (activeAngle) {
3253 last = markAndChaseWinding(angle, maxWinding);
3254 } else {
3255 last = markAndChaseDoneUnary(angle, maxWinding);
3256 }
3257 return last;
3258 }
3259
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003260 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
3261 bool activeAngle, const Angle* angle) {
3262 SkASSERT(angle->segment() == this);
3263 if (useInnerWinding(maxWinding, sumWinding)) {
3264 maxWinding = sumWinding;
3265 }
3266 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
3267 oppMaxWinding = oppSumWinding;
3268 }
3269 Span* last;
3270 if (activeAngle) {
3271 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3272 } else {
3273 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
3274 }
3275 return last;
3276 }
3277
caryclark@google.com495f8e42012-05-31 13:13:11 +00003278 // FIXME: this should also mark spans with equal (x,y)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003279 // This may be called when the segment is already marked done. While this
3280 // wastes time, it shouldn't do any more than spin through the T spans.
rmistry@google.comd6176b02012-08-23 18:14:13 +00003281 // OPTIMIZATION: abort on first done found (assuming that this code is
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003282 // always called to mark segments done).
caryclark@google.com59823f72012-08-09 18:17:47 +00003283 void markDone(int index, int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003284 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003285 SkASSERT(winding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003286 double referenceT = fTs[index].fT;
3287 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003288 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3289 markOneDone(__FUNCTION__, lesser, winding);
3290 }
3291 do {
3292 markOneDone(__FUNCTION__, index, winding);
3293 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003294 }
3295
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003296 void markDoneBinary(int index, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003297 // SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003298 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003299 double referenceT = fTs[index].fT;
3300 int lesser = index;
3301 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003302 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003303 }
3304 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003305 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
3306 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3307 }
3308
3309 void markDoneBinary(int index) {
3310 double referenceT = fTs[index].fT;
3311 int lesser = index;
3312 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3313 markOneDoneBinary(__FUNCTION__, lesser);
3314 }
3315 do {
3316 markOneDoneBinary(__FUNCTION__, index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003317 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003318 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00003319
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003320 void markDoneUnary(int index, int winding) {
3321 // SkASSERT(!done());
3322 SkASSERT(winding);
3323 double referenceT = fTs[index].fT;
3324 int lesser = index;
3325 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3326 markOneDoneUnary(__FUNCTION__, lesser, winding);
3327 }
3328 do {
3329 markOneDoneUnary(__FUNCTION__, index, winding);
3330 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3331 }
3332
3333 void markDoneUnary(int index) {
3334 double referenceT = fTs[index].fT;
3335 int lesser = index;
3336 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3337 markOneDoneUnary(__FUNCTION__, lesser);
3338 }
3339 do {
3340 markOneDoneUnary(__FUNCTION__, index);
3341 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3342 }
3343
caryclark@google.com24bec792012-08-20 12:43:57 +00003344 void markOneDone(const char* funName, int tIndex, int winding) {
3345 Span* span = markOneWinding(funName, tIndex, winding);
3346 if (!span) {
3347 return;
3348 }
3349 span->fDone = true;
3350 fDoneSpans++;
3351 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003352
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003353 void markOneDoneBinary(const char* funName, int tIndex) {
3354 Span* span = verifyOneWinding(funName, tIndex);
3355 if (!span) {
3356 return;
3357 }
3358 span->fDone = true;
3359 fDoneSpans++;
3360 }
3361
3362 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003363 Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
3364 if (!span) {
3365 return;
3366 }
3367 span->fDone = true;
3368 fDoneSpans++;
3369 }
3370
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003371 void markOneDoneUnary(const char* funName, int tIndex) {
3372 Span* span = verifyOneWindingU(funName, tIndex);
3373 if (!span) {
3374 return;
3375 }
3376 span->fDone = true;
3377 fDoneSpans++;
3378 }
3379
3380 void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3381 Span* span = markOneWinding(funName, tIndex, winding);
3382 if (!span) {
3383 return;
3384 }
3385 span->fDone = true;
3386 fDoneSpans++;
3387 }
3388
caryclark@google.com24bec792012-08-20 12:43:57 +00003389 Span* markOneWinding(const char* funName, int tIndex, int winding) {
3390 Span& span = fTs[tIndex];
3391 if (span.fDone) {
3392 return NULL;
3393 }
3394 #if DEBUG_MARK_DONE
3395 debugShowNewWinding(funName, span, winding);
3396 #endif
3397 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com03f97062012-08-21 13:13:52 +00003398 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00003399 SkASSERT(abs(winding) <= gDebugMaxWindSum);
caryclark@google.com03f97062012-08-21 13:13:52 +00003400 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00003401 span.fWindSum = winding;
3402 return &span;
3403 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003404
caryclark@google.com31143cf2012-11-09 22:14:19 +00003405 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
3406 Span& span = fTs[tIndex];
3407 if (span.fDone) {
3408 return NULL;
3409 }
3410 #if DEBUG_MARK_DONE
3411 debugShowNewWinding(funName, span, winding, oppWinding);
3412 #endif
3413 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3414 #ifdef SK_DEBUG
3415 SkASSERT(abs(winding) <= gDebugMaxWindSum);
3416 #endif
3417 span.fWindSum = winding;
3418 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3419 #ifdef SK_DEBUG
3420 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
3421 #endif
3422 span.fOppSum = oppWinding;
3423 return &span;
3424 }
3425
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003426 bool bumpsUp(int tStart, int tEnd) const {
3427 SkPoint edge[4];
caryclark@google.comc83c70e2013-02-22 21:50:07 +00003428 subDivide(tStart, tEnd, edge);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003429 switch (fVerb) {
3430 case SkPath::kLine_Verb:
3431 SkASSERT(0); // shouldn't call in for lines
3432 return true;
3433 case SkPath::kQuad_Verb:
3434 return approximately_greater(edge[0].fY, edge[1].fY)
3435 && approximately_lesser(edge[1].fY, edge[2].fY);
3436 case SkPath::kCubic_Verb:
3437 return (approximately_greater(edge[0].fY, edge[1].fY)
3438 && approximately_lesser(edge[1].fY, edge[3].fY))
3439 || (approximately_greater(edge[0].fY, edge[2].fY)
3440 && approximately_lesser(edge[2].fY, edge[3].fY));
3441 default:
3442 SkASSERT(0);
3443 return false;
3444 }
3445 }
3446
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003447 Span* verifyOneWinding(const char* funName, int tIndex) {
3448 Span& span = fTs[tIndex];
3449 if (span.fDone) {
3450 return NULL;
3451 }
3452 #if DEBUG_MARK_DONE
3453 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3454 #endif
3455 SkASSERT(span.fWindSum != SK_MinS32);
3456 SkASSERT(span.fOppSum != SK_MinS32);
3457 return &span;
3458 }
3459
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003460 Span* verifyOneWindingU(const char* funName, int tIndex) {
3461 Span& span = fTs[tIndex];
3462 if (span.fDone) {
3463 return NULL;
3464 }
3465 #if DEBUG_MARK_DONE
3466 debugShowNewWinding(funName, span, span.fWindSum);
3467 #endif
3468 SkASSERT(span.fWindSum != SK_MinS32);
3469 return &span;
3470 }
3471
caryclark@google.comf839c032012-10-26 21:03:50 +00003472 // note that just because a span has one end that is unsortable, that's
3473 // not enough to mark it done. The other end may be sortable, allowing the
3474 // span to be added.
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003475 // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003476 void markUnsortable(int start, int end) {
3477 Span* span = &fTs[start];
3478 if (start < end) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003479#if DEBUG_UNSORTABLE
3480 SkDebugf("%s start id=%d [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fID, start,
3481 xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003482#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003483 span->fUnsortableStart = true;
3484 } else {
3485 --span;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003486#if DEBUG_UNSORTABLE
3487 SkDebugf("%s end id=%d [%d] (%1.9g,%1.9g) next:(%1.9g,%1.9g)\n", __FUNCTION__, fID,
3488 start - 1, xAtT(start - 1), yAtT(start - 1), xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003489#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003490 span->fUnsortableEnd = true;
3491 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003492 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003493 return;
3494 }
3495 span->fDone = true;
3496 fDoneSpans++;
3497 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003498
caryclark@google.com59823f72012-08-09 18:17:47 +00003499 void markWinding(int index, int winding) {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003500 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003501 SkASSERT(winding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003502 double referenceT = fTs[index].fT;
3503 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003504 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3505 markOneWinding(__FUNCTION__, lesser, winding);
3506 }
3507 do {
3508 markOneWinding(__FUNCTION__, index, winding);
3509 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003510 }
3511
3512 void markWinding(int index, int winding, int oppWinding) {
3513 // SkASSERT(!done());
caryclark@google.com4eeda372012-12-06 21:47:48 +00003514 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003515 double referenceT = fTs[index].fT;
3516 int lesser = index;
3517 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3518 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003519 }
3520 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003521 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3522 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003523 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003524
caryclark@google.com2ddff932012-08-07 21:25:27 +00003525 void matchWindingValue(int tIndex, double t, bool borrowWind) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003526 int nextDoorWind = SK_MaxS32;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003527 int nextOppWind = SK_MaxS32;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003528 if (tIndex > 0) {
3529 const Span& below = fTs[tIndex - 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003530 if (approximately_negative(t - below.fT)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003531 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003532 nextOppWind = below.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003533 }
3534 }
3535 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3536 const Span& above = fTs[tIndex + 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003537 if (approximately_negative(above.fT - t)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003538 nextDoorWind = above.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003539 nextOppWind = above.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003540 }
3541 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003542 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3543 const Span& below = fTs[tIndex - 1];
3544 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003545 nextOppWind = below.fOppValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003546 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003547 if (nextDoorWind != SK_MaxS32) {
3548 Span& newSpan = fTs[tIndex];
3549 newSpan.fWindValue = nextDoorWind;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003550 newSpan.fOppValue = nextOppWind;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003551 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003552 newSpan.fDone = true;
3553 ++fDoneSpans;
3554 }
3555 }
3556 }
3557
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003558 bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3559 // find bounds
3560 Bounds bounds;
3561 bounds.setPoint(xyAtT(index));
3562 bounds.add(xyAtT(endIndex));
3563 SkScalar width = bounds.width();
3564 SkScalar height = bounds.height();
3565 if (width > height) {
3566 if (approximately_negative(width)) {
3567 unsortable = true; // edge is too small to resolve meaningfully
3568 }
3569 return false;
3570 } else {
3571 if (approximately_negative(height)) {
3572 unsortable = true; // edge is too small to resolve meaningfully
3573 }
3574 return true;
3575 }
3576 }
3577
caryclark@google.com9764cc62012-07-12 19:29:45 +00003578 // return span if when chasing, two or more radiating spans are not done
3579 // OPTIMIZATION: ? multiple spans is detected when there is only one valid
3580 // candidate and the remaining spans have windValue == 0 (canceled by
3581 // coincidence). The coincident edges could either be removed altogether,
3582 // or this code could be more complicated in detecting this case. Worth it?
3583 bool multipleSpans(int end) const {
3584 return end > 0 && end < fTs.count() - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00003585 }
3586
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003587 bool nextCandidate(int& start, int& end) const {
caryclark@google.com10227bf2012-12-28 22:10:41 +00003588 while (fTs[end].fDone) {
3589 if (fTs[end].fT == 1) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003590 return false;
3591 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00003592 ++end;
3593 }
3594 start = end;
3595 end = nextExactSpan(start, 1);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003596 return true;
3597 }
3598
caryclark@google.com4eeda372012-12-06 21:47:48 +00003599 Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
3600 int end = nextExactSpan(index, step);
3601 SkASSERT(end >= 0);
3602 if (multipleSpans(end)) {
3603 last = &fTs[end];
3604 return NULL;
3605 }
3606 const Span& endSpan = fTs[end];
3607 Segment* other = endSpan.fOther;
3608 index = endSpan.fOtherIndex;
caryclark@google.comaa358312013-01-29 20:28:49 +00003609 SkASSERT(index >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003610 int otherEnd = other->nextExactSpan(index, step);
caryclark@google.comaa358312013-01-29 20:28:49 +00003611 SkASSERT(otherEnd >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003612 min = SkMin32(index, otherEnd);
3613 return other;
3614 }
3615
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003616 // This has callers for two different situations: one establishes the end
3617 // of the current span, and one establishes the beginning of the next span
3618 // (thus the name). When this is looking for the end of the current span,
3619 // coincidence is found when the beginning Ts contain -step and the end
3620 // contains step. When it is looking for the beginning of the next, the
3621 // first Ts found can be ignored and the last Ts should contain -step.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003622 // OPTIMIZATION: probably should split into two functions
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003623 int nextSpan(int from, int step) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003624 const Span& fromSpan = fTs[from];
caryclark@google.com495f8e42012-05-31 13:13:11 +00003625 int count = fTs.count();
3626 int to = from;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003627 while (step > 0 ? ++to < count : --to >= 0) {
3628 const Span& span = fTs[to];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003629 if (approximately_zero(span.fT - fromSpan.fT)) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003630 continue;
3631 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003632 return to;
3633 }
3634 return -1;
3635 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +00003636
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003637 // FIXME
3638 // this returns at any difference in T, vs. a preset minimum. It may be
3639 // that all callers to nextSpan should use this instead.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003640 // OPTIMIZATION splitting this into separate loops for up/down steps
3641 // would allow using precisely_negative instead of precisely_zero
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003642 int nextExactSpan(int from, int step) const {
3643 const Span& fromSpan = fTs[from];
3644 int count = fTs.count();
3645 int to = from;
3646 while (step > 0 ? ++to < count : --to >= 0) {
3647 const Span& span = fTs[to];
caryclark@google.coma461ff02012-10-11 12:54:23 +00003648 if (precisely_zero(span.fT - fromSpan.fT)) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003649 continue;
3650 }
3651 return to;
3652 }
3653 return -1;
3654 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003655
caryclark@google.com235f56a2012-09-14 14:19:30 +00003656 bool operand() const {
3657 return fOperand;
3658 }
3659
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003660 int oppSign(const Angle* angle) const {
3661 SkASSERT(angle->segment() == this);
3662 return oppSign(angle->start(), angle->end());
3663 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003664
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003665 int oppSign(int startIndex, int endIndex) const {
3666 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3667 : fTs[endIndex].fOppValue;
3668#if DEBUG_WIND_BUMP
3669 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3670#endif
3671 return result;
3672 }
3673
caryclark@google.com31143cf2012-11-09 22:14:19 +00003674 int oppSum(int tIndex) const {
3675 return fTs[tIndex].fOppSum;
3676 }
3677
3678 int oppSum(const Angle* angle) const {
3679 int lesser = SkMin32(angle->start(), angle->end());
3680 return fTs[lesser].fOppSum;
caryclark@google.com235f56a2012-09-14 14:19:30 +00003681 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003682
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003683 int oppValue(int tIndex) const {
3684 return fTs[tIndex].fOppValue;
3685 }
3686
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003687 int oppValue(const Angle* angle) const {
3688 int lesser = SkMin32(angle->start(), angle->end());
3689 return fTs[lesser].fOppValue;
3690 }
3691
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003692 const SkPoint* pts() const {
3693 return fPts;
3694 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003695
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003696 void reset() {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003697 init(NULL, (SkPath::Verb) -1, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003698 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3699 fTs.reset();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003700 }
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +00003701
caryclark@google.com4eeda372012-12-06 21:47:48 +00003702 void setOppXor(bool isOppXor) {
3703 fOppXor = isOppXor;
3704 }
skia.committer@gmail.com12eea2b2013-02-27 07:10:10 +00003705
caryclark@google.com7ff5c842013-02-26 15:56:05 +00003706 void setSpanT(int index, double t) {
3707 Span& span = fTs[index];
3708 span.fT = t;
3709 span.fOther->fTs[span.fOtherIndex].fOtherT = t;
3710 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003711
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003712 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3713 int deltaSum = spanSign(index, endIndex);
3714 maxWinding = sumWinding;
3715 sumWinding = sumWinding -= deltaSum;
3716 }
3717
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003718 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3719 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3720 int deltaSum = spanSign(index, endIndex);
3721 int oppDeltaSum = oppSign(index, endIndex);
3722 if (operand()) {
3723 maxWinding = sumSuWinding;
3724 sumWinding = sumSuWinding -= deltaSum;
3725 oppMaxWinding = sumMiWinding;
3726 oppSumWinding = sumMiWinding -= oppDeltaSum;
3727 } else {
3728 maxWinding = sumMiWinding;
3729 sumWinding = sumMiWinding -= deltaSum;
3730 oppMaxWinding = sumSuWinding;
3731 oppSumWinding = sumSuWinding -= oppDeltaSum;
3732 }
3733 }
3734
caryclark@google.comf839c032012-10-26 21:03:50 +00003735 // This marks all spans unsortable so that this info is available for early
3736 // exclusion in find top and others. This could be optimized to only mark
3737 // adjacent spans that unsortable. However, this makes it difficult to later
3738 // determine starting points for edge detection in find top and the like.
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003739 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
caryclark@google.comf839c032012-10-26 21:03:50 +00003740 bool sortable = true;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003741 int angleCount = angles.count();
3742 int angleIndex;
3743 angleList.setReserve(angleCount);
3744 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003745 Angle& angle = angles[angleIndex];
caryclark@google.comf839c032012-10-26 21:03:50 +00003746 *angleList.append() = &angle;
3747 sortable &= !angle.unsortable();
3748 }
3749 if (sortable) {
3750 QSort<Angle>(angleList.begin(), angleList.end() - 1);
3751 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3752 if (angles[angleIndex].unsortable()) {
3753 sortable = false;
3754 break;
3755 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003756 }
3757 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003758 if (!sortable) {
3759 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3760 Angle& angle = angles[angleIndex];
3761 angle.segment()->markUnsortable(angle.start(), angle.end());
3762 }
3763 }
3764 return sortable;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003765 }
3766
caryclark@google.com1577e8f2012-05-22 17:01:14 +00003767 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003768 const Span& span(int tIndex) const {
3769 return fTs[tIndex];
3770 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003771
caryclark@google.com235f56a2012-09-14 14:19:30 +00003772 int spanSign(const Angle* angle) const {
3773 SkASSERT(angle->segment() == this);
3774 return spanSign(angle->start(), angle->end());
3775 }
3776
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003777 int spanSign(int startIndex, int endIndex) const {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003778 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3779 : fTs[endIndex].fWindValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003780#if DEBUG_WIND_BUMP
3781 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3782#endif
3783 return result;
3784 }
skia.committer@gmail.com58433de2013-02-23 07:02:45 +00003785
caryclark@google.comc83c70e2013-02-22 21:50:07 +00003786 void subDivide(int start, int end, SkPoint edge[4]) const {
3787 edge[0] = fTs[start].fPt;
3788 edge[fVerb] = fTs[end].fPt;
3789 if (fVerb == SkPath::kQuad_Verb || fVerb == SkPath::kCubic_Verb) {
3790 _Point sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[fVerb].fX, edge[fVerb].fY }};
3791 if (fVerb == SkPath::kQuad_Verb) {
3792 MAKE_CONST_QUAD(aQuad, fPts);
3793 edge[1] = sub_divide(aQuad, sub[0], sub[1], fTs[start].fT, fTs[end].fT).asSkPoint();
3794 } else {
3795 MAKE_CONST_CUBIC(aCubic, fPts);
3796 sub_divide(aCubic, sub[0], sub[1], fTs[start].fT, fTs[end].fT, sub);
3797 edge[1] = sub[0].asSkPoint();
3798 edge[2] = sub[1].asSkPoint();
3799 }
3800 }
3801 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003802
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003803 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003804 double t(int tIndex) const {
3805 return fTs[tIndex].fT;
3806 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003807
caryclark@google.com10227bf2012-12-28 22:10:41 +00003808 double tAtMid(int start, int end, double mid) const {
3809 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
3810 }
3811
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003812 bool tiny(const Angle* angle) const {
3813 int start = angle->start();
3814 int end = angle->end();
caryclark@google.comf839c032012-10-26 21:03:50 +00003815 const Span& mSpan = fTs[SkMin32(start, end)];
3816 return mSpan.fTiny;
3817 }
3818
caryclark@google.com18063442012-07-25 12:05:18 +00003819 static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3820 double start) {
3821 int outCount = outsideTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003822 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
caryclark@google.com18063442012-07-25 12:05:18 +00003823 *outsideTs.append() = end;
3824 *outsideTs.append() = start;
3825 }
3826 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003827
caryclark@google.com24bec792012-08-20 12:43:57 +00003828 void undoneSpan(int& start, int& end) {
3829 size_t tCount = fTs.count();
3830 size_t index;
3831 for (index = 0; index < tCount; ++index) {
3832 if (!fTs[index].fDone) {
3833 break;
3834 }
3835 }
3836 SkASSERT(index < tCount - 1);
3837 start = index;
3838 double startT = fTs[index].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003839 while (approximately_negative(fTs[++index].fT - startT))
caryclark@google.com24bec792012-08-20 12:43:57 +00003840 SkASSERT(index < tCount);
3841 SkASSERT(index < tCount);
3842 end = index;
3843 }
caryclark@google.com18063442012-07-25 12:05:18 +00003844
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003845 bool unsortable(int index) const {
3846 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3847 }
3848
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003849 void updatePts(const SkPoint pts[]) {
3850 fPts = pts;
3851 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003852
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003853 int updateOppWinding(int index, int endIndex) const {
3854 int lesser = SkMin32(index, endIndex);
3855 int oppWinding = oppSum(lesser);
3856 int oppSpanWinding = oppSign(index, endIndex);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003857 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)
3858 && oppWinding != SK_MaxS32) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003859 oppWinding -= oppSpanWinding;
3860 }
3861 return oppWinding;
3862 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003863
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003864 int updateOppWinding(const Angle* angle) const {
3865 int startIndex = angle->start();
3866 int endIndex = angle->end();
3867 return updateOppWinding(endIndex, startIndex);
3868 }
3869
3870 int updateOppWindingReverse(const Angle* angle) const {
3871 int startIndex = angle->start();
3872 int endIndex = angle->end();
3873 return updateOppWinding(startIndex, endIndex);
3874 }
3875
3876 int updateWinding(int index, int endIndex) const {
3877 int lesser = SkMin32(index, endIndex);
3878 int winding = windSum(lesser);
3879 int spanWinding = spanSign(index, endIndex);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003880 if (winding && useInnerWinding(winding - spanWinding, winding) && winding != SK_MaxS32) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003881 winding -= spanWinding;
3882 }
3883 return winding;
3884 }
3885
3886 int updateWinding(const Angle* angle) const {
3887 int startIndex = angle->start();
3888 int endIndex = angle->end();
3889 return updateWinding(endIndex, startIndex);
3890 }
3891
3892 int updateWindingReverse(const Angle* angle) const {
3893 int startIndex = angle->start();
3894 int endIndex = angle->end();
3895 return updateWinding(startIndex, endIndex);
3896 }
3897
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003898 SkPath::Verb verb() const {
3899 return fVerb;
3900 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003901
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003902 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003903 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3904 return SK_MinS32;
3905 }
3906 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3907 SkASSERT(winding != SK_MinS32);
3908 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003909 #if DEBUG_WINDING_AT_T
3910 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003911 #endif
3912 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark@google.com3586ece2012-12-27 18:46:58 +00003913 dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003914 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3915 dx = fPts[2].fX - fPts[1].fX - dx;
3916 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003917 if (dx == 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003918 #if DEBUG_WINDING_AT_T
3919 SkDebugf(" dx=0 winding=SK_MinS32\n");
3920 #endif
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003921 return SK_MinS32;
3922 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003923 if (winding * dx > 0) { // if same signs, result is negative
3924 winding += dx > 0 ? -windVal : windVal;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003925 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003926 #if DEBUG_WINDING_AT_T
3927 SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding);
3928 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003929 return winding;
3930 }
3931
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003932 int windSum(int tIndex) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003933 return fTs[tIndex].fWindSum;
3934 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003935
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003936 int windSum(const Angle* angle) const {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003937 int start = angle->start();
3938 int end = angle->end();
3939 int index = SkMin32(start, end);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003940 return windSum(index);
caryclark@google.com495f8e42012-05-31 13:13:11 +00003941 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003942
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003943 int windValue(int tIndex) const {
3944 return fTs[tIndex].fWindValue;
3945 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003946
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003947 int windValue(const Angle* angle) const {
3948 int start = angle->start();
3949 int end = angle->end();
3950 int index = SkMin32(start, end);
3951 return windValue(index);
3952 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00003953
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003954 int windValueAt(double t) const {
3955 int count = fTs.count();
3956 for (int index = 0; index < count; ++index) {
3957 if (fTs[index].fT == t) {
3958 return fTs[index].fWindValue;
3959 }
3960 }
3961 SkASSERT(0);
3962 return 0;
3963 }
3964
caryclark@google.com3586ece2012-12-27 18:46:58 +00003965 SkScalar xAtT(int index) const {
3966 return xAtT(&fTs[index]);
3967 }
3968
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003969 SkScalar xAtT(const Span* span) const {
3970 return xyAtT(span).fX;
3971 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003972
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003973 const SkPoint& xyAtT(int index) const {
3974 return xyAtT(&fTs[index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003975 }
3976
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003977 const SkPoint& xyAtT(const Span* span) const {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003978 if (SkScalarIsNaN(span->fPt.fX)) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00003979 SkASSERT(0); // make sure this path is never used
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003980 if (span->fT == 0) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003981 span->fPt = fPts[0];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003982 } else if (span->fT == 1) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003983 span->fPt = fPts[fVerb];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003984 } else {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003985 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003986 }
3987 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00003988 return span->fPt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003989 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003990
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003991 // used only by right angle winding finding
caryclark@google.com10227bf2012-12-28 22:10:41 +00003992 void xyAtT(double mid, SkPoint& pt) const {
3993 (*SegmentXYAtT[fVerb])(fPts, mid, &pt);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003994 }
3995
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003996 SkScalar yAtT(int index) const {
3997 return yAtT(&fTs[index]);
3998 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003999
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004000 SkScalar yAtT(const Span* span) const {
4001 return xyAtT(span).fY;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004002 }
4003
caryclark@google.com4eeda372012-12-06 21:47:48 +00004004 void zeroCoincidentOpp(Span* oTest, int index) {
4005 Span* const test = &fTs[index];
4006 Span* end = test;
4007 do {
4008 end->fOppValue = 0;
4009 end = &fTs[++index];
4010 } while (approximately_negative(end->fT - test->fT));
4011 }
4012
4013 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
4014 Span* const oTest = &fTs[oIndex];
4015 Span* oEnd = oTest;
4016 const double startT = test->fT;
4017 const double oStartT = oTest->fT;
4018 double otherTMatch = (test->fT - startT) * tRatio + oStartT;
4019 while (!approximately_negative(oEndT - oEnd->fT)
4020 && approximately_negative(oEnd->fT - otherTMatch)) {
4021 oEnd->fOppValue = 0;
4022 oEnd = &fTs[++oIndex];
4023 }
4024 }
4025
4026 void zeroSpan(Span* span) {
4027 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
caryclark@google.com6ec15262012-11-16 20:16:50 +00004028 span->fWindValue = 0;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004029 span->fOppValue = 0;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004030 SkASSERT(!span->fDone);
4031 span->fDone = true;
4032 ++fDoneSpans;
caryclark@google.com6ec15262012-11-16 20:16:50 +00004033 }
4034
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004035#if DEBUG_DUMP
4036 void dump() const {
4037 const char className[] = "Segment";
4038 const int tab = 4;
4039 for (int i = 0; i < fTs.count(); ++i) {
4040 SkPoint out;
4041 (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
4042 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004043 " otherT=%1.9g windSum=%d\n",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004044 tab + sizeof(className), className, fID,
4045 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004046 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004047 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00004048 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004049 tab + sizeof(className), className, fID,
caryclark@google.com15fa1382012-05-07 20:49:36 +00004050 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004051 }
4052#endif
4053
caryclark@google.com47580692012-07-23 12:14:49 +00004054#if DEBUG_CONCIDENT
caryclark@google.comaa358312013-01-29 20:28:49 +00004055 // SkASSERT if pair has not already been added
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004056 void debugAddTPair(double t, const Segment& other, double otherT) const {
caryclark@google.comcc905052012-07-25 20:59:42 +00004057 for (int i = 0; i < fTs.count(); ++i) {
4058 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
4059 return;
4060 }
4061 }
4062 SkASSERT(0);
4063 }
4064#endif
4065
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004066#if DEBUG_DUMP
4067 int debugID() const {
4068 return fID;
4069 }
4070#endif
4071
caryclark@google.com24bec792012-08-20 12:43:57 +00004072#if DEBUG_WINDING
4073 void debugShowSums() const {
4074 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
4075 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
4076 for (int i = 0; i < fTs.count(); ++i) {
4077 const Span& span = fTs[i];
4078 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
4079 if (span.fWindSum == SK_MinS32) {
4080 SkDebugf("?");
4081 } else {
4082 SkDebugf("%d", span.fWindSum);
4083 }
4084 SkDebugf("]");
4085 }
4086 SkDebugf("\n");
4087 }
4088#endif
4089
caryclark@google.comcc905052012-07-25 20:59:42 +00004090#if DEBUG_CONCIDENT
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004091 void debugShowTs() const {
caryclark@google.com24bec792012-08-20 12:43:57 +00004092 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com4eeda372012-12-06 21:47:48 +00004093 int lastWind = -1;
4094 int lastOpp = -1;
4095 double lastT = -1;
4096 int i;
4097 for (i = 0; i < fTs.count(); ++i) {
4098 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
4099 || lastOpp != fTs[i].fOppValue;
4100 if (change && lastWind >= 0) {
4101 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
4102 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
4103 }
4104 if (change) {
4105 SkDebugf(" [o=%d", fTs[i].fOther->fID);
4106 lastWind = fTs[i].fWindValue;
4107 lastOpp = fTs[i].fOppValue;
4108 lastT = fTs[i].fT;
4109 } else {
4110 SkDebugf(",%d", fTs[i].fOther->fID);
4111 }
4112 }
4113 if (i <= 0) {
4114 return;
4115 }
4116 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
4117 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
4118 if (fOperand) {
4119 SkDebugf(" operand");
4120 }
4121 if (done()) {
4122 SkDebugf(" done");
caryclark@google.com47580692012-07-23 12:14:49 +00004123 }
4124 SkDebugf("\n");
4125 }
4126#endif
4127
caryclark@google.com027de222012-07-12 12:52:50 +00004128#if DEBUG_ACTIVE_SPANS
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004129 void debugShowActiveSpans() const {
caryclark@google.com027de222012-07-12 12:52:50 +00004130 if (done()) {
4131 return;
4132 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004133#if DEBUG_ACTIVE_SPANS_SHORT_FORM
4134 int lastId = -1;
4135 double lastT = -1;
4136#endif
caryclark@google.com027de222012-07-12 12:52:50 +00004137 for (int i = 0; i < fTs.count(); ++i) {
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004138 SkASSERT(&fTs[i] == &fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOther->
4139 fTs[fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOtherIndex]);
caryclark@google.com027de222012-07-12 12:52:50 +00004140 if (fTs[i].fDone) {
4141 continue;
4142 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004143#if DEBUG_ACTIVE_SPANS_SHORT_FORM
4144 if (lastId == fID && lastT == fTs[i].fT) {
4145 continue;
4146 }
4147 lastId = fID;
4148 lastT = fTs[i].fT;
4149#endif
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004150 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com027de222012-07-12 12:52:50 +00004151 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4152 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4153 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4154 }
4155 const Span* span = &fTs[i];
rmistry@google.comd6176b02012-08-23 18:14:13 +00004156 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
caryclark@google.com0c803d02012-08-06 11:15:47 +00004157 xAtT(span), yAtT(span));
caryclark@google.com47d73da2013-02-17 01:41:25 +00004158 int iEnd = i + 1;
4159 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) {
4160 ++iEnd;
4161 }
4162 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT);
caryclark@google.com027de222012-07-12 12:52:50 +00004163 const Segment* other = fTs[i].fOther;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004164 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
4165 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
4166 if (fTs[i].fWindSum == SK_MinS32) {
4167 SkDebugf("?");
4168 } else {
4169 SkDebugf("%d", fTs[i].fWindSum);
4170 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004171 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
caryclark@google.com027de222012-07-12 12:52:50 +00004172 }
4173 }
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +00004174
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004175 // This isn't useful yet -- but leaving it in for now in case i think of something
4176 // to use it for
4177 void validateActiveSpans() const {
4178 if (done()) {
4179 return;
4180 }
4181 int tCount = fTs.count();
4182 for (int index = 0; index < tCount; ++index) {
4183 if (fTs[index].fDone) {
4184 continue;
4185 }
4186 // count number of connections which are not done
4187 int first = index;
4188 double baseT = fTs[index].fT;
4189 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
4190 --first;
4191 }
4192 int last = index;
4193 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
4194 ++last;
4195 }
4196 int connections = 0;
4197 connections += first > 0 && !fTs[first - 1].fDone;
4198 for (int test = first; test <= last; ++test) {
4199 connections += !fTs[test].fDone;
4200 const Segment* other = fTs[test].fOther;
4201 int oIndex = fTs[test].fOtherIndex;
4202 connections += !other->fTs[oIndex].fDone;
4203 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
4204 }
4205 // SkASSERT(!(connections & 1));
4206 }
4207 }
caryclark@google.com027de222012-07-12 12:52:50 +00004208#endif
4209
caryclark@google.com0c803d02012-08-06 11:15:47 +00004210#if DEBUG_MARK_DONE
4211 void debugShowNewWinding(const char* fun, const Span& span, int winding) {
4212 const SkPoint& pt = xyAtT(&span);
4213 SkDebugf("%s id=%d", fun, fID);
4214 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4215 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4216 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4217 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004218 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4219 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +00004220 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d windSum=",
skia.committer@gmail.com64334352013-03-06 07:01:46 +00004221 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +00004222 (&span)[1].fT, winding);
caryclark@google.com0c803d02012-08-06 11:15:47 +00004223 if (span.fWindSum == SK_MinS32) {
4224 SkDebugf("?");
4225 } else {
4226 SkDebugf("%d", span.fWindSum);
4227 }
4228 SkDebugf(" windValue=%d\n", span.fWindValue);
4229 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004230
4231 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
4232 const SkPoint& pt = xyAtT(&span);
4233 SkDebugf("%s id=%d", fun, fID);
4234 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4235 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4236 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4237 }
4238 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4239 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +00004240 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 +00004241 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +00004242 (&span)[1].fT, winding, oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004243 if (span.fOppSum == SK_MinS32) {
4244 SkDebugf("?");
4245 } else {
4246 SkDebugf("%d", span.fOppSum);
4247 }
4248 SkDebugf(" windSum=");
4249 if (span.fWindSum == SK_MinS32) {
4250 SkDebugf("?");
4251 } else {
4252 SkDebugf("%d", span.fWindSum);
4253 }
4254 SkDebugf(" windValue=%d\n", span.fWindValue);
4255 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00004256#endif
4257
caryclark@google.com47580692012-07-23 12:14:49 +00004258#if DEBUG_SORT
caryclark@google.com03f97062012-08-21 13:13:52 +00004259 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
caryclark@google.com31143cf2012-11-09 22:14:19 +00004260 const int contourWinding, const int oppContourWinding) const {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004261 if (--gDebugSortCount < 0) {
4262 return;
4263 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004264 SkASSERT(angles[first]->segment() == this);
caryclark@google.com200c2112012-08-03 15:05:04 +00004265 SkASSERT(angles.count() > 1);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004266 int lastSum = contourWinding;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004267 int oppLastSum = oppContourWinding;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004268 const Angle* firstAngle = angles[first];
4269 int windSum = lastSum - spanSign(firstAngle);
4270 int oppoSign = oppSign(firstAngle);
4271 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004272 #define WIND_AS_STRING(x) char x##Str[12]; if (!valid_wind(x)) strcpy(x##Str, "?"); \
4273 else snprintf(x##Str, sizeof(x##Str), "%d", x)
4274 WIND_AS_STRING(contourWinding);
4275 WIND_AS_STRING(oppContourWinding);
4276 SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FUNCTION__,
4277 contourWindingStr, oppContourWindingStr, spanSign(angles[first]));
caryclark@google.comafe56de2012-07-24 18:11:03 +00004278 int index = first;
4279 bool firstTime = true;
caryclark@google.com47580692012-07-23 12:14:49 +00004280 do {
4281 const Angle& angle = *angles[index];
4282 const Segment& segment = *angle.segment();
4283 int start = angle.start();
4284 int end = angle.end();
4285 const Span& sSpan = segment.fTs[start];
4286 const Span& eSpan = segment.fTs[end];
4287 const Span& mSpan = segment.fTs[SkMin32(start, end)];
caryclark@google.com31143cf2012-11-09 22:14:19 +00004288 bool opp = segment.fOperand ^ fOperand;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004289 if (!firstTime) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004290 oppoSign = segment.oppSign(&angle);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004291 if (opp) {
4292 oppLastSum = oppWindSum;
4293 oppWindSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004294 if (oppoSign) {
4295 lastSum = windSum;
4296 windSum -= oppoSign;
4297 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004298 } else {
4299 lastSum = windSum;
4300 windSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004301 if (oppoSign) {
4302 oppLastSum = oppWindSum;
4303 oppWindSum -= oppoSign;
4304 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004305 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004306 }
skia.committer@gmail.com64334352013-03-06 07:01:46 +00004307 SkDebugf("%s [%d] %s", __FUNCTION__, index,
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +00004308 angle.unsortable() ? "*** UNSORTABLE *** " : "");
4309 #if COMPACT_DEBUG_SORT
4310 SkDebugf("id=%d %s start=%d (%1.9g,%,1.9g) end=%d (%1.9g,%,1.9g)",
caryclark@google.comc91dfe42012-10-16 12:06:27 +00004311 segment.fID, kLVerbStr[segment.fVerb],
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004312 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
caryclark@google.comd4c8e1e2013-03-05 14:13:13 +00004313 segment.xAtT(&eSpan), segment.yAtT(&eSpan));
4314 #else
4315 switch (segment.fVerb) {
4316 case SkPath::kLine_Verb:
4317 SkDebugf(LINE_DEBUG_STR, LINE_DEBUG_DATA(segment.fPts));
4318 break;
4319 case SkPath::kQuad_Verb:
4320 SkDebugf(QUAD_DEBUG_STR, QUAD_DEBUG_DATA(segment.fPts));
4321 break;
4322 case SkPath::kCubic_Verb:
4323 SkDebugf(CUBIC_DEBUG_STR, CUBIC_DEBUG_DATA(segment.fPts));
4324 break;
4325 }
4326 SkDebugf(" tStart=%1.9g tEnd=%1.9g", sSpan.fT, eSpan.fT);
4327 #endif
4328 SkDebugf(" sign=%d windValue=%d windSum=", angle.sign(), mSpan.fWindValue);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004329 winding_printf(mSpan.fWindSum);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004330 int last, wind;
4331 if (opp) {
4332 last = oppLastSum;
4333 wind = oppWindSum;
4334 } else {
4335 last = lastSum;
4336 wind = windSum;
4337 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004338 bool useInner = valid_wind(last) && valid_wind(wind) && useInnerWinding(last, wind);
4339 WIND_AS_STRING(last);
4340 WIND_AS_STRING(wind);
4341 WIND_AS_STRING(lastSum);
4342 WIND_AS_STRING(oppLastSum);
4343 WIND_AS_STRING(windSum);
4344 WIND_AS_STRING(oppWindSum);
4345 #undef WIND_AS_STRING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004346 if (!oppoSign) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004347 SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr : lastStr);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004348 } else {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004349 SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : oppLastSumStr,
4350 opp ? windSumStr : oppWindSumStr);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004351 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004352 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004353#if false && DEBUG_ANGLE
caryclark@google.comc899ad92012-08-23 15:24:42 +00004354 angle.debugShow(segment.xyAtT(&sSpan));
4355#endif
caryclark@google.com47580692012-07-23 12:14:49 +00004356 ++index;
4357 if (index == angles.count()) {
4358 index = 0;
4359 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004360 if (firstTime) {
4361 firstTime = false;
4362 }
caryclark@google.com47580692012-07-23 12:14:49 +00004363 } while (index != first);
4364 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00004365
4366 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
4367 const Angle* firstAngle = angles[first];
4368 const Segment* segment = firstAngle->segment();
4369 int winding = segment->updateWinding(firstAngle);
4370 int oppWinding = segment->updateOppWinding(firstAngle);
4371 debugShowSort(fun, angles, first, winding, oppWinding);
4372 }
4373
caryclark@google.com47580692012-07-23 12:14:49 +00004374#endif
4375
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004376#if DEBUG_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004377 static char as_digit(int value) {
4378 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
4379 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004380#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004381
caryclark@google.com729e1c42012-11-21 21:36:34 +00004382#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004383 int debugShowWindingValues(int slotCount, int ofInterest) const {
4384 if (!(1 << fID & ofInterest)) {
4385 return 0;
4386 }
4387 int sum = 0;
4388 SkTDArray<char> slots;
4389 slots.setCount(slotCount * 2);
4390 memset(slots.begin(), ' ', slotCount * 2);
4391 for (int i = 0; i < fTs.count(); ++i) {
4392 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
4393 // continue;
4394 // }
4395 sum += fTs[i].fWindValue;
4396 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
4397 sum += fTs[i].fOppValue;
4398 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
4399 }
4400 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
4401 slots.begin() + slotCount);
4402 return sum;
4403 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004404#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004405
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004406private:
4407 const SkPoint* fPts;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004408 Bounds fBounds;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004409 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
caryclark@google.com4eeda372012-12-06 21:47:48 +00004410 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
caryclark@google.com24bec792012-08-20 12:43:57 +00004411 int fDoneSpans; // quick check that segment is finished
caryclark@google.com4eeda372012-12-06 21:47:48 +00004412 // OPTIMIZATION: force the following to be byte-sized
4413 SkPath::Verb fVerb;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004414 bool fOperand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004415 bool fXor; // set if original contour had even-odd fill
4416 bool fOppXor; // set if opposite operand had even-odd fill
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004417#if DEBUG_DUMP
4418 int fID;
4419#endif
4420};
4421
caryclark@google.comb9738012012-07-03 19:53:30 +00004422class Contour;
4423
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004424struct Coincidence {
caryclark@google.comb9738012012-07-03 19:53:30 +00004425 Contour* fContours[2];
4426 int fSegments[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004427 double fTs[2][2];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004428 SkPoint fPts[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004429};
4430
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004431class Contour {
4432public:
4433 Contour() {
4434 reset();
4435#if DEBUG_DUMP
4436 fID = ++gContourID;
4437#endif
4438 }
4439
4440 bool operator<(const Contour& rh) const {
4441 return fBounds.fTop == rh.fBounds.fTop
4442 ? fBounds.fLeft < rh.fBounds.fLeft
4443 : fBounds.fTop < rh.fBounds.fTop;
4444 }
4445
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004446 void addCoincident(int index, Contour* other, int otherIndex,
4447 const Intersections& ts, bool swap) {
4448 Coincidence& coincidence = *fCoincidences.append();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004449 coincidence.fContours[0] = this; // FIXME: no need to store
caryclark@google.comb9738012012-07-03 19:53:30 +00004450 coincidence.fContours[1] = other;
4451 coincidence.fSegments[0] = index;
4452 coincidence.fSegments[1] = otherIndex;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004453 coincidence.fTs[swap][0] = ts.fT[0][0];
4454 coincidence.fTs[swap][1] = ts.fT[0][1];
4455 coincidence.fTs[!swap][0] = ts.fT[1][0];
4456 coincidence.fTs[!swap][1] = ts.fT[1][1];
4457 coincidence.fPts[0] = ts.fPt[0].asSkPoint();
4458 coincidence.fPts[1] = ts.fPt[1].asSkPoint();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004459 }
4460
4461 void addCross(const Contour* crosser) {
4462#ifdef DEBUG_CROSS
4463 for (int index = 0; index < fCrosses.count(); ++index) {
4464 SkASSERT(fCrosses[index] != crosser);
4465 }
4466#endif
4467 *fCrosses.append() = crosser;
4468 }
4469
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004470 void addCubic(const SkPoint pts[4]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004471 fSegments.push_back().addCubic(pts, fOperand, fXor);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004472 fContainsCurves = fContainsCubics = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004473 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004474
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004475 int addLine(const SkPoint pts[2]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004476 fSegments.push_back().addLine(pts, fOperand, fXor);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004477 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004478 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004479
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004480 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
4481 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
4482 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004483
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004484 int addQuad(const SkPoint pts[3]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004485 fSegments.push_back().addQuad(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004486 fContainsCurves = true;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004487 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004488 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004489
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004490 int addT(int segIndex, Contour* other, int otherIndex, const SkPoint& pt, double& newT) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004491 setContainsIntercepts();
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004492 return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004493 }
4494
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00004495 int addSelfT(int segIndex, Contour* other, int otherIndex, const SkPoint& pt, double& newT) {
4496 setContainsIntercepts();
4497 return fSegments[segIndex].addSelfT(&other->fSegments[otherIndex], pt, newT);
4498 }
4499
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004500 int addUnsortableT(int segIndex, Contour* other, int otherIndex, bool start,
4501 const SkPoint& pt, double& newT) {
4502 return fSegments[segIndex].addUnsortableT(&other->fSegments[otherIndex], start, pt, newT);
caryclark@google.com73ca6242013-01-17 21:02:47 +00004503 }
4504
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004505 const Bounds& bounds() const {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004506 return fBounds;
4507 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004508
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004509 void complete() {
4510 setBounds();
4511 fContainsIntercepts = false;
4512 }
skia.committer@gmail.com58433de2013-02-23 07:02:45 +00004513
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004514 bool containsCubics() const {
4515 return fContainsCubics;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004516 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004517
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004518 bool crosses(const Contour* crosser) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004519 for (int index = 0; index < fCrosses.count(); ++index) {
4520 if (fCrosses[index] == crosser) {
4521 return true;
4522 }
4523 }
4524 return false;
4525 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004526
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004527 bool done() const {
4528 return fDone;
4529 }
4530
caryclark@google.comf839c032012-10-26 21:03:50 +00004531 const SkPoint& end() const {
4532 const Segment& segment = fSegments.back();
4533 return segment.pts()[segment.verb()];
4534 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004535
caryclark@google.com4eeda372012-12-06 21:47:48 +00004536 void findTooCloseToCall() {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004537 int segmentCount = fSegments.count();
4538 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004539 fSegments[sIndex].findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004540 }
4541 }
4542
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004543 void fixOtherTIndex() {
4544 int segmentCount = fSegments.count();
4545 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4546 fSegments[sIndex].fixOtherTIndex();
4547 }
4548 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004549
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004550 Segment* nonVerticalSegment(int& start, int& end) {
4551 int segmentCount = fSortedSegments.count();
4552 SkASSERT(segmentCount > 0);
4553 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4554 Segment* testSegment = fSortedSegments[sortedIndex];
4555 if (testSegment->done()) {
4556 continue;
4557 }
4558 start = end = 0;
4559 while (testSegment->nextCandidate(start, end)) {
4560 if (!testSegment->isVertical(start, end)) {
4561 return testSegment;
4562 }
4563 }
4564 }
4565 return NULL;
4566 }
4567
caryclark@google.com31143cf2012-11-09 22:14:19 +00004568 bool operand() const {
4569 return fOperand;
4570 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004571
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004572 void reset() {
4573 fSegments.reset();
4574 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004575 fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004576 }
caryclark@google.comb9738012012-07-03 19:53:30 +00004577
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004578 void resolveCoincidence(SkTDArray<Contour*>& contourList) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004579 int count = fCoincidences.count();
4580 for (int index = 0; index < count; ++index) {
4581 Coincidence& coincidence = fCoincidences[index];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004582 SkASSERT(coincidence.fContours[0] == this);
caryclark@google.comb9738012012-07-03 19:53:30 +00004583 int thisIndex = coincidence.fSegments[0];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004584 Segment& thisOne = fSegments[thisIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004585 Contour* otherContour = coincidence.fContours[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004586 int otherIndex = coincidence.fSegments[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004587 Segment& other = otherContour->fSegments[otherIndex];
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004588 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004589 continue;
4590 }
caryclark@google.com47580692012-07-23 12:14:49 +00004591 #if DEBUG_CONCIDENT
4592 thisOne.debugShowTs();
4593 other.debugShowTs();
4594 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004595 double startT = coincidence.fTs[0][0];
4596 double endT = coincidence.fTs[0][1];
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004597 bool cancelers = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004598 if (startT > endT) {
4599 SkTSwap<double>(startT, endT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004600 cancelers ^= true; // FIXME: just assign true
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004601 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004602 SkASSERT(!approximately_negative(endT - startT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004603 double oStartT = coincidence.fTs[1][0];
4604 double oEndT = coincidence.fTs[1][1];
4605 if (oStartT > oEndT) {
4606 SkTSwap<double>(oStartT, oEndT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004607 cancelers ^= true;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004608 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004609 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00004610 bool opp = fOperand ^ otherContour->fOperand;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004611 if (cancelers && !opp) {
4612 // make sure startT and endT have t entries
caryclark@google.com2ddff932012-08-07 21:25:27 +00004613 if (startT > 0 || oEndT < 1
4614 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004615 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004616 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00004617 if (oStartT > 0 || endT < 1
4618 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004619 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004620 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004621 if (!thisOne.done() && !other.done()) {
4622 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4623 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004624 } else {
caryclark@google.com200c2112012-08-03 15:05:04 +00004625 if (startT > 0 || oStartT > 0
4626 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004627 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004628 }
caryclark@google.com200c2112012-08-03 15:05:04 +00004629 if (endT < 1 || oEndT < 1
4630 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004631 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004632 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004633 if (!thisOne.done() && !other.done()) {
4634 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4635 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004636 }
caryclark@google.com47580692012-07-23 12:14:49 +00004637 #if DEBUG_CONCIDENT
4638 thisOne.debugShowTs();
4639 other.debugShowTs();
4640 #endif
caryclark@google.com729e1c42012-11-21 21:36:34 +00004641 #if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004642 debugShowWindingValues(contourList);
4643 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004644 }
4645 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004646
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004647 // first pass, add missing T values
4648 // second pass, determine winding values of overlaps
4649 void addCoincidentPoints() {
4650 int count = fCoincidences.count();
4651 for (int index = 0; index < count; ++index) {
4652 Coincidence& coincidence = fCoincidences[index];
4653 SkASSERT(coincidence.fContours[0] == this);
4654 int thisIndex = coincidence.fSegments[0];
4655 Segment& thisOne = fSegments[thisIndex];
4656 Contour* otherContour = coincidence.fContours[1];
4657 int otherIndex = coincidence.fSegments[1];
4658 Segment& other = otherContour->fSegments[otherIndex];
4659 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
4660 // OPTIMIZATION: remove from array
4661 continue;
4662 }
4663 #if DEBUG_CONCIDENT
4664 thisOne.debugShowTs();
4665 other.debugShowTs();
4666 #endif
4667 double startT = coincidence.fTs[0][0];
4668 double endT = coincidence.fTs[0][1];
4669 bool cancelers;
4670 if ((cancelers = startT > endT)) {
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004671 SkTSwap(startT, endT);
4672 SkTSwap(coincidence.fPts[0], coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004673 }
4674 SkASSERT(!approximately_negative(endT - startT));
4675 double oStartT = coincidence.fTs[1][0];
4676 double oEndT = coincidence.fTs[1][1];
4677 if (oStartT > oEndT) {
4678 SkTSwap<double>(oStartT, oEndT);
4679 cancelers ^= true;
4680 }
4681 SkASSERT(!approximately_negative(oEndT - oStartT));
4682 bool opp = fOperand ^ otherContour->fOperand;
4683 if (cancelers && !opp) {
4684 // make sure startT and endT have t entries
4685 if (startT > 0 || oEndT < 1
4686 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004687 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004688 }
4689 if (oStartT > 0 || endT < 1
4690 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004691 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004692 }
4693 } else {
4694 if (startT > 0 || oStartT > 0
4695 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004696 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004697 }
4698 if (endT < 1 || oEndT < 1
4699 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004700 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004701 }
4702 }
4703 #if DEBUG_CONCIDENT
4704 thisOne.debugShowTs();
4705 other.debugShowTs();
4706 #endif
4707 }
4708 }
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00004709
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004710 void calcCoincidentWinding() {
4711 int count = fCoincidences.count();
4712 for (int index = 0; index < count; ++index) {
4713 Coincidence& coincidence = fCoincidences[index];
4714 SkASSERT(coincidence.fContours[0] == this);
4715 int thisIndex = coincidence.fSegments[0];
4716 Segment& thisOne = fSegments[thisIndex];
4717 if (thisOne.done()) {
4718 continue;
4719 }
4720 Contour* otherContour = coincidence.fContours[1];
4721 int otherIndex = coincidence.fSegments[1];
4722 Segment& other = otherContour->fSegments[otherIndex];
4723 if (other.done()) {
4724 continue;
4725 }
4726 double startT = coincidence.fTs[0][0];
4727 double endT = coincidence.fTs[0][1];
4728 bool cancelers;
4729 if ((cancelers = startT > endT)) {
4730 SkTSwap<double>(startT, endT);
4731 }
4732 SkASSERT(!approximately_negative(endT - startT));
4733 double oStartT = coincidence.fTs[1][0];
4734 double oEndT = coincidence.fTs[1][1];
4735 if (oStartT > oEndT) {
4736 SkTSwap<double>(oStartT, oEndT);
4737 cancelers ^= true;
4738 }
4739 SkASSERT(!approximately_negative(oEndT - oStartT));
4740 bool opp = fOperand ^ otherContour->fOperand;
4741 if (cancelers && !opp) {
4742 // make sure startT and endT have t entries
4743 if (!thisOne.done() && !other.done()) {
4744 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4745 }
4746 } else {
4747 if (!thisOne.done() && !other.done()) {
4748 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4749 }
4750 }
4751 #if DEBUG_CONCIDENT
4752 thisOne.debugShowTs();
4753 other.debugShowTs();
4754 #endif
4755 }
4756 }
4757
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004758 SkTArray<Segment>& segments() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004759 return fSegments;
4760 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004761
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004762 void setContainsIntercepts() {
4763 fContainsIntercepts = true;
4764 }
4765
caryclark@google.com235f56a2012-09-14 14:19:30 +00004766 void setOperand(bool isOp) {
4767 fOperand = isOp;
4768 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00004769
caryclark@google.com4eeda372012-12-06 21:47:48 +00004770 void setOppXor(bool isOppXor) {
4771 fOppXor = isOppXor;
4772 int segmentCount = fSegments.count();
4773 for (int test = 0; test < segmentCount; ++test) {
4774 fSegments[test].setOppXor(isOppXor);
4775 }
4776 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004777
caryclark@google.com235f56a2012-09-14 14:19:30 +00004778 void setXor(bool isXor) {
4779 fXor = isXor;
4780 }
4781
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004782 void sortSegments() {
4783 int segmentCount = fSegments.count();
4784 fSortedSegments.setReserve(segmentCount);
4785 for (int test = 0; test < segmentCount; ++test) {
4786 *fSortedSegments.append() = &fSegments[test];
4787 }
4788 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4789 fFirstSorted = 0;
4790 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004791
caryclark@google.comf839c032012-10-26 21:03:50 +00004792 const SkPoint& start() const {
4793 return fSegments.front().pts()[0];
4794 }
4795
4796 void toPath(PathWrapper& path) const {
4797 int segmentCount = fSegments.count();
4798 const SkPoint& pt = fSegments.front().pts()[0];
4799 path.deferredMove(pt);
4800 for (int test = 0; test < segmentCount; ++test) {
4801 fSegments[test].addCurveTo(0, 1, path, true);
4802 }
4803 path.close();
4804 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004805
caryclark@google.comf839c032012-10-26 21:03:50 +00004806 void toPartialBackward(PathWrapper& path) const {
4807 int segmentCount = fSegments.count();
4808 for (int test = segmentCount - 1; test >= 0; --test) {
4809 fSegments[test].addCurveTo(1, 0, path, true);
4810 }
4811 }
4812
4813 void toPartialForward(PathWrapper& path) const {
4814 int segmentCount = fSegments.count();
4815 for (int test = 0; test < segmentCount; ++test) {
4816 fSegments[test].addCurveTo(0, 1, path, true);
4817 }
4818 }
4819
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004820 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004821 int segmentCount = fSortedSegments.count();
4822 SkASSERT(segmentCount > 0);
caryclark@google.comf839c032012-10-26 21:03:50 +00004823 int sortedIndex = fFirstSorted;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004824 fDone = true; // may be cleared below
caryclark@google.comf839c032012-10-26 21:03:50 +00004825 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4826 Segment* testSegment = fSortedSegments[sortedIndex];
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004827 if (testSegment->done()) {
caryclark@google.comf839c032012-10-26 21:03:50 +00004828 if (sortedIndex == fFirstSorted) {
4829 ++fFirstSorted;
4830 }
4831 continue;
4832 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004833 fDone = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004834 SkPoint testXY = testSegment->activeLeftTop(true, NULL);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004835 if (topStart) {
4836 if (testXY.fY < topLeft.fY) {
4837 continue;
4838 }
4839 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4840 continue;
4841 }
4842 if (bestXY.fY < testXY.fY) {
4843 continue;
4844 }
4845 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4846 continue;
4847 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004848 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004849 topStart = testSegment;
caryclark@google.comf839c032012-10-26 21:03:50 +00004850 bestXY = testXY;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004851 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004852 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004853
caryclark@google.com24bec792012-08-20 12:43:57 +00004854 Segment* undoneSegment(int& start, int& end) {
4855 int segmentCount = fSegments.count();
4856 for (int test = 0; test < segmentCount; ++test) {
4857 Segment* testSegment = &fSegments[test];
4858 if (testSegment->done()) {
4859 continue;
4860 }
4861 testSegment->undoneSpan(start, end);
4862 return testSegment;
4863 }
4864 return NULL;
4865 }
4866
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004867 int updateSegment(int index, const SkPoint* pts) {
4868 Segment& segment = fSegments[index];
4869 segment.updatePts(pts);
4870 return segment.verb() + 1;
4871 }
4872
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004873#if DEBUG_TEST
4874 SkTArray<Segment>& debugSegments() {
4875 return fSegments;
4876 }
4877#endif
4878
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004879#if DEBUG_DUMP
4880 void dump() {
4881 int i;
4882 const char className[] = "Contour";
4883 const int tab = 4;
4884 SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4885 for (i = 0; i < fSegments.count(); ++i) {
4886 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4887 className, i);
4888 fSegments[i].dump();
4889 }
4890 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4891 tab + sizeof(className), className,
4892 fBounds.fLeft, fBounds.fTop,
4893 fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004894 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4895 className, fContainsIntercepts);
4896 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4897 className, fContainsCurves);
4898 }
4899#endif
4900
caryclark@google.com027de222012-07-12 12:52:50 +00004901#if DEBUG_ACTIVE_SPANS
4902 void debugShowActiveSpans() {
4903 for (int index = 0; index < fSegments.count(); ++index) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004904 fSegments[index].debugShowActiveSpans();
caryclark@google.com027de222012-07-12 12:52:50 +00004905 }
4906 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004907
4908 void validateActiveSpans() {
4909 for (int index = 0; index < fSegments.count(); ++index) {
4910 fSegments[index].validateActiveSpans();
4911 }
4912 }
caryclark@google.com027de222012-07-12 12:52:50 +00004913#endif
4914
caryclark@google.com729e1c42012-11-21 21:36:34 +00004915#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004916 int debugShowWindingValues(int totalSegments, int ofInterest) {
4917 int count = fSegments.count();
4918 int sum = 0;
4919 for (int index = 0; index < count; ++index) {
4920 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4921 }
4922 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4923 return sum;
4924 }
4925
4926 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4927 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4928 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4929 int ofInterest = 1 << 5 | 1 << 8;
4930 int total = 0;
4931 int index;
4932 for (index = 0; index < contourList.count(); ++index) {
4933 total += contourList[index]->segments().count();
4934 }
4935 int sum = 0;
4936 for (index = 0; index < contourList.count(); ++index) {
4937 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4938 }
4939 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4940 }
4941#endif
4942
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004943protected:
4944 void setBounds() {
4945 int count = fSegments.count();
4946 if (count == 0) {
4947 SkDebugf("%s empty contour\n", __FUNCTION__);
4948 SkASSERT(0);
4949 // FIXME: delete empty contour?
4950 return;
4951 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004952 fBounds = fSegments.front().bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004953 for (int index = 1; index < count; ++index) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004954 fBounds.add(fSegments[index].bounds());
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004955 }
4956 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004957
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004958private:
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004959 SkTArray<Segment> fSegments;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004960 SkTDArray<Segment*> fSortedSegments;
4961 int fFirstSorted;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004962 SkTDArray<Coincidence> fCoincidences;
4963 SkTDArray<const Contour*> fCrosses;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004964 Bounds fBounds;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004965 bool fContainsIntercepts; // FIXME: is this used by anybody?
4966 bool fContainsCubics;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004967 bool fContainsCurves;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004968 bool fDone;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004969 bool fOperand; // true for the second argument to a binary operator
4970 bool fXor;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004971 bool fOppXor;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004972#if DEBUG_DUMP
4973 int fID;
4974#endif
4975};
4976
4977class EdgeBuilder {
4978public:
4979
caryclark@google.comf839c032012-10-26 21:03:50 +00004980EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
4981 : fPath(path.nativePath())
4982 , fContours(contours)
4983{
4984 init();
4985}
4986
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004987EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
caryclark@google.com235f56a2012-09-14 14:19:30 +00004988 : fPath(&path)
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004989 , fContours(contours)
4990{
caryclark@google.comf839c032012-10-26 21:03:50 +00004991 init();
4992}
4993
4994void init() {
4995 fCurrentContour = NULL;
4996 fOperand = false;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004997 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004998#if DEBUG_DUMP
4999 gContourID = 0;
5000 gSegmentID = 0;
5001#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00005002 fSecondHalf = preFetch();
5003}
5004
5005void addOperand(const SkPath& path) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00005006 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
5007 fPathVerbs.pop();
caryclark@google.com235f56a2012-09-14 14:19:30 +00005008 fPath = &path;
caryclark@google.com729e1c42012-11-21 21:36:34 +00005009 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.com235f56a2012-09-14 14:19:30 +00005010 preFetch();
5011}
5012
5013void finish() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005014 walk();
caryclark@google.com235f56a2012-09-14 14:19:30 +00005015 complete();
5016 if (fCurrentContour && !fCurrentContour->segments().count()) {
5017 fContours.pop_back();
5018 }
5019 // correct pointers in contours since fReducePts may have moved as it grew
5020 int cIndex = 0;
5021 int extraCount = fExtra.count();
5022 SkASSERT(extraCount == 0 || fExtra[0] == -1);
5023 int eIndex = 0;
5024 int rIndex = 0;
5025 while (++eIndex < extraCount) {
5026 int offset = fExtra[eIndex];
5027 if (offset < 0) {
5028 ++cIndex;
5029 continue;
5030 }
5031 fCurrentContour = &fContours[cIndex];
5032 rIndex += fCurrentContour->updateSegment(offset - 1,
5033 &fReducePts[rIndex]);
5034 }
5035 fExtra.reset(); // we're done with this
5036}
5037
5038ShapeOpMask xorMask() const {
caryclark@google.com729e1c42012-11-21 21:36:34 +00005039 return fXorMask[fOperand];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005040}
5041
5042protected:
5043
5044void complete() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005045 if (fCurrentContour && fCurrentContour->segments().count()) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005046 fCurrentContour->complete();
5047 fCurrentContour = NULL;
5048 }
5049}
5050
caryclark@google.com235f56a2012-09-14 14:19:30 +00005051// FIXME:remove once we can access path pts directly
5052int preFetch() {
5053 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005054 SkPoint pts[4];
5055 SkPath::Verb verb;
5056 do {
5057 verb = iter.next(pts);
5058 *fPathVerbs.append() = verb;
5059 if (verb == SkPath::kMove_Verb) {
5060 *fPathPts.append() = pts[0];
5061 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
5062 fPathPts.append(verb, &pts[1]);
5063 }
5064 } while (verb != SkPath::kDone_Verb);
caryclark@google.com31143cf2012-11-09 22:14:19 +00005065 return fPathVerbs.count() - 1;
caryclark@google.com235f56a2012-09-14 14:19:30 +00005066}
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005067
caryclark@google.com235f56a2012-09-14 14:19:30 +00005068void walk() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005069 SkPath::Verb reducedVerb;
5070 uint8_t* verbPtr = fPathVerbs.begin();
caryclark@google.com235f56a2012-09-14 14:19:30 +00005071 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005072 const SkPoint* pointsPtr = fPathPts.begin();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005073 const SkPoint* finalCurveStart = NULL;
5074 const SkPoint* finalCurveEnd = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00005075 SkPath::Verb verb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005076 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
5077 switch (verb) {
5078 case SkPath::kMove_Verb:
5079 complete();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005080 if (!fCurrentContour) {
5081 fCurrentContour = fContours.push_back_n(1);
caryclark@google.com235f56a2012-09-14 14:19:30 +00005082 fCurrentContour->setOperand(fOperand);
caryclark@google.com729e1c42012-11-21 21:36:34 +00005083 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005084 *fExtra.append() = -1; // start new contour
5085 }
caryclark@google.com59823f72012-08-09 18:17:47 +00005086 finalCurveEnd = pointsPtr++;
caryclark@google.com31143cf2012-11-09 22:14:19 +00005087 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005088 case SkPath::kLine_Verb:
5089 // skip degenerate points
5090 if (pointsPtr[-1].fX != pointsPtr[0].fX
5091 || pointsPtr[-1].fY != pointsPtr[0].fY) {
5092 fCurrentContour->addLine(&pointsPtr[-1]);
5093 }
5094 break;
5095 case SkPath::kQuad_Verb:
rmistry@google.comd6176b02012-08-23 18:14:13 +00005096
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005097 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
5098 if (reducedVerb == 0) {
5099 break; // skip degenerate points
5100 }
5101 if (reducedVerb == 1) {
rmistry@google.comd6176b02012-08-23 18:14:13 +00005102 *fExtra.append() =
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005103 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005104 break;
5105 }
5106 fCurrentContour->addQuad(&pointsPtr[-1]);
5107 break;
5108 case SkPath::kCubic_Verb:
5109 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
5110 if (reducedVerb == 0) {
5111 break; // skip degenerate points
5112 }
5113 if (reducedVerb == 1) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005114 *fExtra.append() =
5115 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005116 break;
5117 }
5118 if (reducedVerb == 2) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005119 *fExtra.append() =
5120 fCurrentContour->addQuad(fReducePts.end() - 3);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005121 break;
5122 }
5123 fCurrentContour->addCubic(&pointsPtr[-1]);
5124 break;
5125 case SkPath::kClose_Verb:
5126 SkASSERT(fCurrentContour);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005127 if (finalCurveStart && finalCurveEnd
5128 && *finalCurveStart != *finalCurveEnd) {
5129 *fReducePts.append() = *finalCurveStart;
5130 *fReducePts.append() = *finalCurveEnd;
5131 *fExtra.append() =
5132 fCurrentContour->addLine(fReducePts.end() - 2);
5133 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005134 complete();
caryclark@google.com31143cf2012-11-09 22:14:19 +00005135 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005136 default:
5137 SkDEBUGFAIL("bad verb");
5138 return;
5139 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005140 finalCurveStart = &pointsPtr[verb - 1];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005141 pointsPtr += verb;
5142 SkASSERT(fCurrentContour);
caryclark@google.com31143cf2012-11-09 22:14:19 +00005143 nextVerb:
caryclark@google.com235f56a2012-09-14 14:19:30 +00005144 if (verbPtr == endOfFirstHalf) {
5145 fOperand = true;
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00005146 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005147 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005148}
5149
5150private:
caryclark@google.com235f56a2012-09-14 14:19:30 +00005151 const SkPath* fPath;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005152 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005153 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005154 Contour* fCurrentContour;
5155 SkTArray<Contour>& fContours;
5156 SkTDArray<SkPoint> fReducePts; // segments created on the fly
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005157 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
caryclark@google.com729e1c42012-11-21 21:36:34 +00005158 ShapeOpMask fXorMask[2];
caryclark@google.com235f56a2012-09-14 14:19:30 +00005159 int fSecondHalf;
5160 bool fOperand;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005161};
5162
5163class Work {
5164public:
5165 enum SegmentType {
5166 kHorizontalLine_Segment = -1,
5167 kVerticalLine_Segment = 0,
5168 kLine_Segment = SkPath::kLine_Verb,
5169 kQuad_Segment = SkPath::kQuad_Verb,
5170 kCubic_Segment = SkPath::kCubic_Verb,
5171 };
rmistry@google.comd6176b02012-08-23 18:14:13 +00005172
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005173 void addCoincident(Work& other, const Intersections& ts, bool swap) {
5174 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
5175 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005176
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005177 // FIXME: does it make sense to write otherIndex now if we're going to
5178 // fix it up later?
5179 void addOtherT(int index, double otherT, int otherIndex) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005180 fContour->addOtherT(fIndex, index, otherT, otherIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005181 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005182
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005183 // Avoid collapsing t values that are close to the same since
5184 // we walk ts to describe consecutive intersections. Since a pair of ts can
5185 // be nearly equal, any problems caused by this should be taken care
5186 // of later.
5187 // On the edge or out of range values are negative; add 2 to get end
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005188 int addT(const Work& other, const SkPoint& pt, double& newT) {
5189 return fContour->addT(fIndex, other.fContour, other.fIndex, pt, newT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005190 }
skia.committer@gmail.com631cdcb2013-03-01 12:12:55 +00005191
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00005192 int addSelfT(const Work& other, const SkPoint& pt, double& newT) {
5193 return fContour->addSelfT(fIndex, other.fContour, other.fIndex, pt, newT);
5194 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005195
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005196 int addUnsortableT(const Work& other, bool start, const SkPoint& pt, double& newT) {
5197 return fContour->addUnsortableT(fIndex, other.fContour, other.fIndex, start, pt, newT);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005198 }
5199
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005200 bool advance() {
5201 return ++fIndex < fLast;
5202 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005203
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005204 SkScalar bottom() const {
5205 return bounds().fBottom;
5206 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005207
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005208 const Bounds& bounds() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005209 return fContour->segments()[fIndex].bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005210 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00005211
caryclark@google.com73ca6242013-01-17 21:02:47 +00005212#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005213 const SkPoint* cubic() const {
5214 return fCubic;
5215 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005216#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005217
5218 void init(Contour* contour) {
5219 fContour = contour;
5220 fIndex = 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005221 fLast = contour->segments().count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005222 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00005223
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00005224 bool isAdjacent(const Work& next) {
5225 return fContour == next.fContour && fIndex + 1 == next.fIndex;
5226 }
5227
5228 bool isFirstLast(const Work& next) {
5229 return fContour == next.fContour && fIndex == 0
5230 && next.fIndex == fLast - 1;
5231 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005232
5233 SkScalar left() const {
5234 return bounds().fLeft;
5235 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005236
caryclark@google.com73ca6242013-01-17 21:02:47 +00005237#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005238 void promoteToCubic() {
5239 fCubic[0] = pts()[0];
5240 fCubic[2] = pts()[1];
5241 fCubic[3] = pts()[2];
5242 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
5243 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
5244 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
5245 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
5246 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005247#endif
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005248
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005249 const SkPoint* pts() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005250 return fContour->segments()[fIndex].pts();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005251 }
5252
5253 SkScalar right() const {
5254 return bounds().fRight;
5255 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005256
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005257 ptrdiff_t segmentIndex() const {
5258 return fIndex;
5259 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005260
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005261 SegmentType segmentType() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005262 const Segment& segment = fContour->segments()[fIndex];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005263 SegmentType type = (SegmentType) segment.verb();
5264 if (type != kLine_Segment) {
5265 return type;
5266 }
5267 if (segment.isHorizontal()) {
5268 return kHorizontalLine_Segment;
5269 }
5270 if (segment.isVertical()) {
5271 return kVerticalLine_Segment;
5272 }
5273 return kLine_Segment;
5274 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005275
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005276 bool startAfter(const Work& after) {
5277 fIndex = after.fIndex;
5278 return advance();
5279 }
5280
5281 SkScalar top() const {
5282 return bounds().fTop;
5283 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005284
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005285 SkPath::Verb verb() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005286 return fContour->segments()[fIndex].verb();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005287 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005288
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005289 SkScalar x() const {
5290 return bounds().fLeft;
5291 }
5292
5293 bool xFlipped() const {
5294 return x() != pts()[0].fX;
5295 }
5296
5297 SkScalar y() const {
5298 return bounds().fTop;
5299 }
5300
5301 bool yFlipped() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005302 return y() != pts()[0].fY;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005303 }
5304
5305protected:
5306 Contour* fContour;
caryclark@google.com73ca6242013-01-17 21:02:47 +00005307#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005308 SkPoint fCubic[4];
caryclark@google.com73ca6242013-01-17 21:02:47 +00005309#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005310 int fIndex;
5311 int fLast;
5312};
5313
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005314#if DEBUG_ADD_INTERSECTING_TS
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005315
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005316static void debugShowLineIntersection(int pts, const Work& wt, const Work& wn,
5317 const Intersections& i) {
5318 SkASSERT(i.used() == pts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005319 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005320 SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n",
5321 __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005322 return;
5323 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005324 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " LINE_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5325 i.fT[0][0], LINE_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005326 if (pts == 2) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005327 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 +00005328 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005329 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005330 if (pts == 2) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005331 SkDebugf(" " T_DEBUG_STR(wnTs, 1), i.fT[1][1]);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005332 }
5333 SkDebugf("\n");
5334}
5335
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005336static void debugShowQuadLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005337 const Work& wn, const Intersections& i) {
5338 SkASSERT(i.used() == pts);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005339 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005340 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " LINE_DEBUG_STR "\n",
5341 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005342 return;
5343 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005344 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5345 i.fT[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5346 for (int n = 1; n < pts; ++n) {
5347 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 +00005348 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005349 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
5350 for (int n = 1; n < pts; ++n) {
5351 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005352 }
5353 SkDebugf("\n");
5354}
5355
caryclark@google.coma461ff02012-10-11 12:54:23 +00005356static void debugShowQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005357 const Work& wn, const Intersections& i) {
5358 SkASSERT(i.used() == pts);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005359 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005360 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " QUAD_DEBUG_STR "\n",
5361 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
caryclark@google.coma461ff02012-10-11 12:54:23 +00005362 return;
5363 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005364 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5365 i.fT[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5366 for (int n = 1; n < pts; ++n) {
5367 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 +00005368 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005369 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i.fT[1][0], QUAD_DEBUG_DATA(wn.pts()));
5370 for (int n = 1; n < pts; ++n) {
5371 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005372 }
caryclark@google.comb9738012012-07-03 19:53:30 +00005373 SkDebugf("\n");
5374}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005375
5376static void debugShowCubicLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005377 const Work& wn, const Intersections& i) {
5378 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005379 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005380 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " LINE_DEBUG_STR "\n",
5381 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005382 return;
5383 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005384 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5385 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5386 for (int n = 1; n < pts; ++n) {
5387 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 +00005388 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005389 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
5390 for (int n = 1; n < pts; ++n) {
5391 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005392 }
5393 SkDebugf("\n");
5394}
5395
caryclark@google.com73ca6242013-01-17 21:02:47 +00005396static void debugShowCubicQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005397 const Work& wn, const Intersections& i) {
5398 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005399 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005400 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " QUAD_DEBUG_STR "\n",
5401 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005402 return;
5403 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005404 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5405 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5406 for (int n = 1; n < pts; ++n) {
5407 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 +00005408 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005409 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i.fT[1][0], QUAD_DEBUG_DATA(wn.pts()));
5410 for (int n = 1; n < pts; ++n) {
5411 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005412 }
5413 SkDebugf("\n");
5414}
5415
caryclark@google.com73ca6242013-01-17 21:02:47 +00005416static void debugShowCubicIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005417 const Work& wn, const Intersections& i) {
5418 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005419 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005420 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " CUBIC_DEBUG_STR "\n",
5421 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), CUBIC_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005422 return;
5423 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005424 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5425 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5426 for (int n = 1; n < pts; ++n) {
5427 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 +00005428 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005429 SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i.fT[1][0], CUBIC_DEBUG_DATA(wn.pts()));
5430 for (int n = 1; n < pts; ++n) {
5431 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005432 }
5433 SkDebugf("\n");
5434}
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005435
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005436static void debugShowCubicIntersection(int pts, const Work& wt, const Intersections& i) {
5437 SkASSERT(i.used() == pts);
5438 if (!pts) {
5439 SkDebugf("%s no self intersect " CUBIC_DEBUG_STR "\n", __FUNCTION__,
5440 CUBIC_DEBUG_DATA(wt.pts()));
5441 return;
5442 }
5443 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5444 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5445 SkDebugf(" " T_DEBUG_STR(wtTs, 1), i.fT[1][0]);
5446 SkDebugf("\n");
5447}
5448
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005449#else
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005450static void debugShowLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005451}
caryclark@google.coma461ff02012-10-11 12:54:23 +00005452
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005453static void debugShowQuadLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005454}
5455
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005456static void debugShowQuadIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005457}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005458
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005459static void debugShowCubicLineIntersection(int , const Work& , const Work& ,
5460 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005461}
5462
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005463static void debugShowCubicQuadIntersection(int , const Work& , const Work& ,
5464 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005465}
5466
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005467static void debugShowCubicIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005468}
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005469
5470static void debugShowCubicIntersection(int , const Work& , const Intersections& ) {
5471}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005472#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005473
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005474static bool addIntersectTs(Contour* test, Contour* next) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005475
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005476 if (test != next) {
5477 if (test->bounds().fBottom < next->bounds().fTop) {
5478 return false;
5479 }
5480 if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5481 return true;
5482 }
5483 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005484 Work wt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005485 wt.init(test);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005486 bool foundCommonContour = test == next;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005487 do {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005488 Work wn;
5489 wn.init(next);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005490 if (test == next && !wn.startAfter(wt)) {
5491 continue;
5492 }
5493 do {
5494 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5495 continue;
5496 }
5497 int pts;
5498 Intersections ts;
5499 bool swap = false;
5500 switch (wt.segmentType()) {
5501 case Work::kHorizontalLine_Segment:
5502 swap = true;
5503 switch (wn.segmentType()) {
5504 case Work::kHorizontalLine_Segment:
5505 case Work::kVerticalLine_Segment:
5506 case Work::kLine_Segment: {
5507 pts = HLineIntersect(wn.pts(), wt.left(),
5508 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005509 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005510 break;
5511 }
5512 case Work::kQuad_Segment: {
5513 pts = HQuadIntersect(wn.pts(), wt.left(),
5514 wt.right(), wt.y(), wt.xFlipped(), ts);
5515 break;
5516 }
5517 case Work::kCubic_Segment: {
5518 pts = HCubicIntersect(wn.pts(), wt.left(),
5519 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005520 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005521 break;
5522 }
5523 default:
5524 SkASSERT(0);
5525 }
5526 break;
5527 case Work::kVerticalLine_Segment:
5528 swap = true;
5529 switch (wn.segmentType()) {
5530 case Work::kHorizontalLine_Segment:
5531 case Work::kVerticalLine_Segment:
5532 case Work::kLine_Segment: {
5533 pts = VLineIntersect(wn.pts(), wt.top(),
5534 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005535 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005536 break;
5537 }
5538 case Work::kQuad_Segment: {
5539 pts = VQuadIntersect(wn.pts(), wt.top(),
5540 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5541 break;
5542 }
5543 case Work::kCubic_Segment: {
5544 pts = VCubicIntersect(wn.pts(), wt.top(),
5545 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005546 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005547 break;
5548 }
5549 default:
5550 SkASSERT(0);
5551 }
5552 break;
5553 case Work::kLine_Segment:
5554 switch (wn.segmentType()) {
5555 case Work::kHorizontalLine_Segment:
5556 pts = HLineIntersect(wt.pts(), wn.left(),
5557 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005558 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005559 break;
5560 case Work::kVerticalLine_Segment:
5561 pts = VLineIntersect(wt.pts(), wn.top(),
5562 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005563 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005564 break;
5565 case Work::kLine_Segment: {
5566 pts = LineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005567 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005568 break;
5569 }
5570 case Work::kQuad_Segment: {
5571 swap = true;
5572 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005573 debugShowQuadLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005574 break;
5575 }
5576 case Work::kCubic_Segment: {
5577 swap = true;
5578 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005579 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005580 break;
5581 }
5582 default:
5583 SkASSERT(0);
5584 }
5585 break;
5586 case Work::kQuad_Segment:
5587 switch (wn.segmentType()) {
5588 case Work::kHorizontalLine_Segment:
5589 pts = HQuadIntersect(wt.pts(), wn.left(),
5590 wn.right(), wn.y(), wn.xFlipped(), ts);
5591 break;
5592 case Work::kVerticalLine_Segment:
5593 pts = VQuadIntersect(wt.pts(), wn.top(),
5594 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5595 break;
5596 case Work::kLine_Segment: {
5597 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005598 debugShowQuadLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005599 break;
5600 }
5601 case Work::kQuad_Segment: {
5602 pts = QuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005603 debugShowQuadIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005604 break;
5605 }
5606 case Work::kCubic_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005607 #if APPROXIMATE_CUBICS
5608 swap = true;
5609 pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005610 debugShowCubicQuadIntersection(pts, wn, wt, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005611 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005612 wt.promoteToCubic();
5613 pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005614 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005615 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005616 break;
5617 }
5618 default:
5619 SkASSERT(0);
5620 }
5621 break;
5622 case Work::kCubic_Segment:
5623 switch (wn.segmentType()) {
5624 case Work::kHorizontalLine_Segment:
5625 pts = HCubicIntersect(wt.pts(), wn.left(),
5626 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005627 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005628 break;
5629 case Work::kVerticalLine_Segment:
5630 pts = VCubicIntersect(wt.pts(), wn.top(),
5631 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005632 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005633 break;
5634 case Work::kLine_Segment: {
5635 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005636 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005637 break;
5638 }
5639 case Work::kQuad_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005640 #if APPROXIMATE_CUBICS
5641 pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005642 debugShowCubicQuadIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005643 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005644 wn.promoteToCubic();
5645 pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005646 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005647 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005648 break;
5649 }
5650 case Work::kCubic_Segment: {
5651 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005652 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005653 break;
5654 }
5655 default:
5656 SkASSERT(0);
5657 }
5658 break;
5659 default:
5660 SkASSERT(0);
5661 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005662 if (!foundCommonContour && pts > 0) {
5663 test->addCross(next);
5664 next->addCross(test);
5665 foundCommonContour = true;
5666 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005667 // in addition to recording T values, record matching segment
caryclark@google.com73ca6242013-01-17 21:02:47 +00005668 if (ts.unsortable()) {
5669 bool start = true;
5670 for (int pt = 0; pt < ts.used(); ++pt) {
5671 // FIXME: if unsortable, the other points to the original. This logic is
5672 // untested downstream.
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005673 SkPoint point = ts.fPt[pt].asSkPoint();
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005674 int testTAt = wt.addUnsortableT(wt, start, point, ts.fT[swap][pt]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005675 wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt);
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005676 testTAt = wn.addUnsortableT(wn, start ^ ts.fFlip, point, ts.fT[!swap][pt]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005677 wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt);
5678 start ^= true;
5679 }
5680 continue;
5681 }
caryclark@google.com32546db2012-08-31 20:55:07 +00005682 if (pts == 2) {
5683 if (wn.segmentType() <= Work::kLine_Segment
5684 && wt.segmentType() <= Work::kLine_Segment) {
5685 wt.addCoincident(wn, ts, swap);
5686 continue;
5687 }
caryclark@google.combeda3892013-02-07 13:13:41 +00005688 if (wn.segmentType() >= Work::kQuad_Segment
5689 && wt.segmentType() >= Work::kQuad_Segment
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005690 && ts.fIsCoincident[0]) {
5691 SkASSERT(ts.coincidentUsed() == 2);
caryclark@google.com32546db2012-08-31 20:55:07 +00005692 wt.addCoincident(wn, ts, swap);
5693 continue;
5694 }
5695
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00005696 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00005697 for (int pt = 0; pt < pts; ++pt) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005698 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5699 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005700 SkPoint point = ts.fPt[pt].asSkPoint();
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005701 int testTAt = wt.addT(wn, point, ts.fT[swap][pt]);
5702 int nextTAt = wn.addT(wt, point, ts.fT[!swap][pt]);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005703 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
5704 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005705 }
5706 } while (wn.advance());
5707 } while (wt.advance());
5708 return true;
5709}
5710
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005711static void addSelfIntersectTs(Contour* test) {
5712 Work wt;
5713 wt.init(test);
5714 do {
5715 if (wt.segmentType() != Work::kCubic_Segment) {
5716 continue;
5717 }
5718 Intersections ts;
5719 int pts = CubicIntersect(wt.pts(), ts);
5720 debugShowCubicIntersection(pts, wt, ts);
5721 if (!pts) {
5722 continue;
5723 }
5724 SkASSERT(pts == 1);
5725 SkASSERT(ts.fT[0][0] >= 0 && ts.fT[0][0] <= 1);
5726 SkASSERT(ts.fT[1][0] >= 0 && ts.fT[1][0] <= 1);
5727 SkPoint point = ts.fPt[0].asSkPoint();
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00005728 int testTAt = wt.addSelfT(wt, point, ts.fT[0][0]);
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005729 int nextTAt = wt.addT(wt, point, ts.fT[1][0]);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005730 wt.addOtherT(testTAt, ts.fT[1][0], nextTAt);
5731 wt.addOtherT(nextTAt, ts.fT[0][0], testTAt);
5732 } while (wt.advance());
5733}
5734
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005735// resolve any coincident pairs found while intersecting, and
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005736// see if coincidence is formed by clipping non-concident segments
caryclark@google.com4eeda372012-12-06 21:47:48 +00005737static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005738 int contourCount = contourList.count();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005739#if ONE_PASS_COINCIDENCE_CHECK
caryclark@google.comf25edfe2012-06-01 18:20:10 +00005740 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005741 Contour* contour = contourList[cIndex];
caryclark@google.com7ba591e2012-11-20 14:21:54 +00005742 contour->resolveCoincidence(contourList);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005743 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005744#else
5745 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5746 Contour* contour = contourList[cIndex];
5747 contour->addCoincidentPoints();
5748 }
5749 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5750 Contour* contour = contourList[cIndex];
5751 contour->calcCoincidentWinding();
5752 }
5753#endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005754 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5755 Contour* contour = contourList[cIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00005756 contour->findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005757 }
5758}
5759
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005760static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005761 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005762 SkPoint basePt;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005763 double tAtMid = current->tAtMid(index, endIndex, mid);
5764 current->xyAtT(tAtMid, basePt);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005765 int contourCount = contourList.count();
5766 SkScalar bestY = SK_ScalarMin;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005767 Segment* bestSeg = NULL;
5768 int bestTIndex;
5769 bool bestOpp;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005770 bool hitSomething = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005771 for (int cTest = 0; cTest < contourCount; ++cTest) {
5772 Contour* contour = contourList[cTest];
5773 bool testOpp = contour->operand() ^ current->operand() ^ opp;
5774 if (basePt.fY < contour->bounds().fTop) {
5775 continue;
5776 }
5777 if (bestY > contour->bounds().fBottom) {
5778 continue;
5779 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005780 int segmentCount = contour->segments().count();
5781 for (int test = 0; test < segmentCount; ++test) {
5782 Segment* testSeg = &contour->segments()[test];
5783 SkScalar testY = bestY;
5784 double testHit;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005785 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
5786 testOpp, testSeg == current);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005787 if (testTIndex < 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005788 if (testTIndex == SK_MinS32) {
5789 hitSomething = true;
5790 bestSeg = NULL;
5791 goto abortContours; // vertical encountered, return and try different point
5792 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005793 continue;
5794 }
5795 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005796 double baseT = current->t(index);
5797 double endT = current->t(endIndex);
5798 double newMid = (testHit - baseT) / (endT - baseT);
5799#if DEBUG_WINDING
5800 SkPoint midXY, newXY;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005801 double midT = current->tAtMid(index, endIndex, mid);
5802 current->xyAtT(midT, midXY);
5803 double newMidT = current->tAtMid(index, endIndex, newMid);
5804 current->xyAtT(newMidT, newXY);
caryclark@google.com3586ece2012-12-27 18:46:58 +00005805 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
5806 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
5807 current->debugID(), mid, newMid,
5808 baseT, current->xAtT(index), current->yAtT(index),
5809 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
5810 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
5811 endT, current->xAtT(endIndex), current->yAtT(endIndex));
5812#endif
5813 mid = newMid * 2; // calling loop with divide by 2 before continuing
5814 return SK_MinS32;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005815 }
5816 bestSeg = testSeg;
5817 bestHit = testHit;
5818 bestOpp = testOpp;
5819 bestTIndex = testTIndex;
5820 bestY = testY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005821 }
5822 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005823abortContours:
caryclark@google.com10227bf2012-12-28 22:10:41 +00005824 int result;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005825 if (!bestSeg) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00005826 result = hitSomething ? SK_MinS32 : 0;
5827 } else {
5828 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
5829 current = bestSeg;
5830 index = bestTIndex;
5831 endIndex = bestSeg->nextSpan(bestTIndex, 1);
5832 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
5833 tryAgain = true;
5834 return 0;
5835 }
5836 result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
5837 SkASSERT(bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005838 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005839 double baseT = current->t(index);
5840 double endT = current->t(endIndex);
5841 bestHit = baseT + mid * (endT - baseT);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005842 return result;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005843}
5844
caryclark@google.com24bec792012-08-20 12:43:57 +00005845static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
5846 int contourCount = contourList.count();
5847 Segment* result;
5848 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5849 Contour* contour = contourList[cIndex];
5850 result = contour->undoneSegment(start, end);
5851 if (result) {
5852 return result;
5853 }
5854 }
5855 return NULL;
5856}
5857
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005858#define OLD_FIND_CHASE 1
caryclark@google.com24bec792012-08-20 12:43:57 +00005859
caryclark@google.com31143cf2012-11-09 22:14:19 +00005860static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005861 while (chase.count()) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005862 Span* span;
5863 chase.pop(&span);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005864 const Span& backPtr = span->fOther->span(span->fOtherIndex);
5865 Segment* segment = backPtr.fOther;
5866 tIndex = backPtr.fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005867 SkTDArray<Angle> angles;
5868 int done = 0;
5869 if (segment->activeAngle(tIndex, done, angles)) {
5870 Angle* last = angles.end() - 1;
5871 tIndex = last->start();
5872 endIndex = last->end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005873 #if TRY_ROTATE
5874 *chase.insert(0) = span;
5875 #else
5876 *chase.append() = span;
5877 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005878 return last->segment();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005879 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005880 if (done == angles.count()) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00005881 continue;
5882 }
5883 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005884 bool sortable = Segment::SortAngles(angles, sorted);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005885 int angleCount = sorted.count();
caryclark@google.com03f97062012-08-21 13:13:52 +00005886#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005887 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00005888#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005889 if (!sortable) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005890 continue;
5891 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005892 // find first angle, initialize winding to computed fWindSum
5893 int firstIndex = -1;
5894 const Angle* angle;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005895#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005896 int winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005897 do {
5898 angle = sorted[++firstIndex];
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005899 segment = angle->segment();
5900 winding = segment->windSum(angle);
5901 } while (winding == SK_MinS32);
5902 int spanWinding = segment->spanSign(angle->start(), angle->end());
5903 #if DEBUG_WINDING
caryclark@google.com31143cf2012-11-09 22:14:19 +00005904 SkDebugf("%s winding=%d spanWinding=%d\n",
5905 __FUNCTION__, winding, spanWinding);
caryclark@google.com47580692012-07-23 12:14:49 +00005906 #endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005907 // turn span winding into contour winding
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005908 if (spanWinding * winding < 0) {
5909 winding += spanWinding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005910 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005911 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005912 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005913 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005914 // we care about first sign and whether wind sum indicates this
5915 // edge is inside or outside. Maybe need to pass span winding
5916 // or first winding or something into this function?
5917 // advance to first undone angle, then return it and winding
5918 // (to set whether edges are active or not)
5919 int nextIndex = firstIndex + 1;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005920 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005921 angle = sorted[firstIndex];
caryclark@google.com2ddff932012-08-07 21:25:27 +00005922 winding -= angle->segment()->spanSign(angle);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005923#else
5924 do {
5925 angle = sorted[++firstIndex];
5926 segment = angle->segment();
5927 } while (segment->windSum(angle) == SK_MinS32);
5928 #if DEBUG_SORT
5929 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5930 #endif
5931 int sumWinding = segment->updateWindingReverse(angle);
5932 int nextIndex = firstIndex + 1;
5933 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5934 Segment* first = NULL;
5935#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005936 do {
5937 SkASSERT(nextIndex != firstIndex);
5938 if (nextIndex == angleCount) {
5939 nextIndex = 0;
5940 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005941 angle = sorted[nextIndex];
caryclark@google.com9764cc62012-07-12 19:29:45 +00005942 segment = angle->segment();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005943#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005944 int maxWinding = winding;
caryclark@google.com2ddff932012-08-07 21:25:27 +00005945 winding -= segment->spanSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005946 #if DEBUG_SORT
caryclark@google.com2ddff932012-08-07 21:25:27 +00005947 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
5948 segment->debugID(), maxWinding, winding, angle->sign());
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005949 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005950 tIndex = angle->start();
5951 endIndex = angle->end();
5952 int lesser = SkMin32(tIndex, endIndex);
5953 const Span& nextSpan = segment->span(lesser);
5954 if (!nextSpan.fDone) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005955#if 1
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005956 // FIXME: this be wrong? assign startWinding if edge is in
caryclark@google.com9764cc62012-07-12 19:29:45 +00005957 // same direction. If the direction is opposite, winding to
5958 // assign is flipped sign or +/- 1?
caryclark@google.com59823f72012-08-09 18:17:47 +00005959 if (useInnerWinding(maxWinding, winding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005960 maxWinding = winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005961 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005962 segment->markAndChaseWinding(angle, maxWinding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005963#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005964 break;
5965 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005966#else
5967 int start = angle->start();
5968 int end = angle->end();
5969 int maxWinding;
5970 segment->setUpWinding(start, end, maxWinding, sumWinding);
5971 if (!segment->done(angle)) {
5972 if (!first) {
5973 first = segment;
5974 tIndex = start;
5975 endIndex = end;
5976 }
5977 (void) segment->markAngle(maxWinding, sumWinding, true, angle);
5978 }
5979#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005980 } while (++nextIndex != lastIndex);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005981 #if TRY_ROTATE
5982 *chase.insert(0) = span;
5983 #else
5984 *chase.append() = span;
5985 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005986 return segment;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005987 }
5988 return NULL;
5989}
5990
caryclark@google.com027de222012-07-12 12:52:50 +00005991#if DEBUG_ACTIVE_SPANS
5992static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005993 int index;
5994 for (index = 0; index < contourList.count(); ++ index) {
caryclark@google.com027de222012-07-12 12:52:50 +00005995 contourList[index]->debugShowActiveSpans();
5996 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005997 for (index = 0; index < contourList.count(); ++ index) {
5998 contourList[index]->validateActiveSpans();
5999 }
caryclark@google.com027de222012-07-12 12:52:50 +00006000}
6001#endif
6002
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006003static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006004 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006005 Segment* result;
6006 do {
caryclark@google.comf839c032012-10-26 21:03:50 +00006007 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006008 int contourCount = contourList.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00006009 Segment* topStart = NULL;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006010 done = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00006011 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
6012 Contour* contour = contourList[cIndex];
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006013 if (contour->done()) {
6014 continue;
6015 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006016 const Bounds& bounds = contour->bounds();
6017 if (bounds.fBottom < topLeft.fY) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006018 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00006019 continue;
6020 }
6021 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006022 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00006023 continue;
6024 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006025 contour->topSortableSegment(topLeft, bestXY, topStart);
6026 if (!contour->done()) {
6027 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00006028 }
6029 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006030 if (!topStart) {
6031 return NULL;
6032 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006033 topLeft = bestXY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006034 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006035 } while (!result);
6036 return result;
6037}
caryclark@google.com31143cf2012-11-09 22:14:19 +00006038
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006039static int rightAngleWinding(SkTDArray<Contour*>& contourList,
caryclark@google.com3586ece2012-12-27 18:46:58 +00006040 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006041 bool opp) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006042 double test = 0.9;
6043 int contourWinding;
6044 do {
caryclark@google.com3586ece2012-12-27 18:46:58 +00006045 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
6046 tryAgain, test, opp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006047 if (contourWinding != SK_MinS32 || tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006048 return contourWinding;
6049 }
6050 test /= 2;
6051 } while (!approximately_negative(test));
6052 SkASSERT(0); // should be OK to comment out, but interested when this hits
6053 return contourWinding;
6054}
6055
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006056static void skipVertical(SkTDArray<Contour*>& contourList,
6057 Segment*& current, int& index, int& endIndex) {
6058 if (!current->isVertical(index, endIndex)) {
6059 return;
6060 }
6061 int contourCount = contourList.count();
6062 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
6063 Contour* contour = contourList[cIndex];
6064 if (contour->done()) {
6065 continue;
6066 }
6067 current = contour->nonVerticalSegment(index, endIndex);
6068 if (current) {
6069 return;
6070 }
6071 }
6072}
6073
caryclark@google.com3586ece2012-12-27 18:46:58 +00006074static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006075 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
6076 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
6077 true);
6078 if (!current) {
6079 return NULL;
6080 }
6081 if (firstContour) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00006082 current->initWinding(index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006083 firstContour = false;
6084 return current;
6085 }
6086 int minIndex = SkMin32(index, endIndex);
6087 int sumWinding = current->windSum(minIndex);
6088 if (sumWinding != SK_MinS32) {
6089 return current;
6090 }
6091 sumWinding = current->computeSum(index, endIndex, binary);
6092 if (sumWinding != SK_MinS32) {
6093 return current;
6094 }
6095 int contourWinding;
6096 int oppContourWinding = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006097 // the simple upward projection of the unresolved points hit unsortable angles
6098 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006099 bool tryAgain;
6100 double tHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006101 SkScalar hitDx = 0;
6102 SkScalar hitOppDx = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006103 do {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006104 // if current is vertical, find another candidate which is not
6105 // if only remaining candidates are vertical, then they can be marked done
caryclark@google.com10227bf2012-12-28 22:10:41 +00006106 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006107 skipVertical(contourList, current, index, endIndex);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006108 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006109 tryAgain = false;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006110 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006111 tryAgain, false);
6112 if (tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006113 continue;
6114 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006115 if (!binary) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006116 break;
6117 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00006118 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006119 tryAgain, true);
6120 } while (tryAgain);
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00006121
caryclark@google.com3586ece2012-12-27 18:46:58 +00006122 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006123 return current;
6124}
6125
6126// rewrite that abandons keeping local track of winding
caryclark@google.com3586ece2012-12-27 18:46:58 +00006127static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006128 bool firstContour = true;
6129 bool unsortable = false;
6130 bool topUnsortable = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006131 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
6132 do {
6133 int index, endIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006134 bool topDone;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006135 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006136 topUnsortable, topDone, false);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006137 if (!current) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006138 if (topUnsortable || !topDone) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006139 topUnsortable = false;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006140 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006141 topLeft.fX = topLeft.fY = SK_ScalarMin;
6142 continue;
6143 }
6144 break;
6145 }
6146 SkTDArray<Span*> chaseArray;
6147 do {
6148 if (current->activeWinding(index, endIndex)) {
6149 do {
6150 #if DEBUG_ACTIVE_SPANS
6151 if (!unsortable && current->done()) {
6152 debugShowActiveSpans(contourList);
6153 }
6154 #endif
6155 SkASSERT(unsortable || !current->done());
6156 int nextStart = index;
6157 int nextEnd = endIndex;
6158 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
6159 unsortable);
6160 if (!next) {
6161 if (!unsortable && simple.hasMove()
6162 && current->verb() != SkPath::kLine_Verb
6163 && !simple.isClosed()) {
6164 current->addCurveTo(index, endIndex, simple, true);
6165 SkASSERT(simple.isClosed());
6166 }
6167 break;
6168 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006169 #if DEBUG_FLOW
6170 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6171 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
6172 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
6173 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006174 current->addCurveTo(index, endIndex, simple, true);
6175 current = next;
6176 index = nextStart;
6177 endIndex = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006178 } while (!simple.isClosed() && (!unsortable
caryclark@google.com10227bf2012-12-28 22:10:41 +00006179 || !current->done(SkMin32(index, endIndex))));
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006180 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
6181 SkASSERT(unsortable);
6182 int min = SkMin32(index, endIndex);
6183 if (!current->done(min)) {
6184 current->addCurveTo(index, endIndex, simple, true);
6185 current->markDoneUnary(min);
6186 }
6187 }
6188 simple.close();
6189 } else {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006190 Span* last = current->markAndChaseDoneUnary(index, endIndex);
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00006191 if (last && !last->fLoop) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006192 *chaseArray.append() = last;
6193 }
6194 }
6195 current = findChase(chaseArray, index, endIndex);
6196 #if DEBUG_ACTIVE_SPANS
6197 debugShowActiveSpans(contourList);
6198 #endif
6199 if (!current) {
6200 break;
6201 }
6202 } while (true);
6203 } while (true);
6204 return simple.someAssemblyRequired();
6205}
6206
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006207// returns true if all edges were processed
caryclark@google.comf839c032012-10-26 21:03:50 +00006208static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006209 Segment* current;
6210 int start, end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006211 bool unsortable = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006212 bool closable = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00006213 while ((current = findUndone(contourList, start, end))) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006214 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006215 #if DEBUG_ACTIVE_SPANS
6216 if (!unsortable && current->done()) {
6217 debugShowActiveSpans(contourList);
6218 }
6219 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006220 SkASSERT(unsortable || !current->done());
caryclark@google.com24bec792012-08-20 12:43:57 +00006221 int nextStart = start;
6222 int nextEnd = end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006223 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
caryclark@google.com24bec792012-08-20 12:43:57 +00006224 if (!next) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006225 if (!unsortable && simple.hasMove()
caryclark@google.comf839c032012-10-26 21:03:50 +00006226 && current->verb() != SkPath::kLine_Verb
6227 && !simple.isClosed()) {
6228 current->addCurveTo(start, end, simple, true);
6229 SkASSERT(simple.isClosed());
caryclark@google.comc899ad92012-08-23 15:24:42 +00006230 }
caryclark@google.com24bec792012-08-20 12:43:57 +00006231 break;
6232 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006233 #if DEBUG_FLOW
6234 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6235 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
6236 current->xyAtT(end).fX, current->xyAtT(end).fY);
6237 #endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006238 current->addCurveTo(start, end, simple, true);
caryclark@google.com24bec792012-08-20 12:43:57 +00006239 current = next;
6240 start = nextStart;
6241 end = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006242 } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006243 if (!simple.isClosed()) {
6244 SkASSERT(unsortable);
6245 int min = SkMin32(start, end);
6246 if (!current->done(min)) {
6247 current->addCurveTo(start, end, simple, true);
6248 current->markDone(min, 1);
6249 }
6250 closable = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00006251 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006252 simple.close();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00006253 #if DEBUG_ACTIVE_SPANS
6254 debugShowActiveSpans(contourList);
6255 #endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00006256 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006257 return closable;
caryclark@google.com24bec792012-08-20 12:43:57 +00006258}
6259
caryclark@google.comb45a1b42012-05-18 20:50:33 +00006260static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
6261 int contourCount = contourList.count();
6262 for (int cTest = 0; cTest < contourCount; ++cTest) {
6263 Contour* contour = contourList[cTest];
6264 contour->fixOtherTIndex();
6265 }
6266}
6267
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006268static void sortSegments(SkTDArray<Contour*>& contourList) {
6269 int contourCount = contourList.count();
6270 for (int cTest = 0; cTest < contourCount; ++cTest) {
6271 Contour* contour = contourList[cTest];
6272 contour->sortSegments();
6273 }
6274}
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006275
caryclark@google.com4eeda372012-12-06 21:47:48 +00006276static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
6277 bool evenOdd, bool oppEvenOdd) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006278 int count = contours.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006279 if (count == 0) {
6280 return;
6281 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006282 for (int index = 0; index < count; ++index) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00006283 Contour& contour = contours[index];
6284 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
6285 *list.append() = &contour;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006286 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006287 QSort<Contour>(list.begin(), list.end() - 1);
6288}
6289
caryclark@google.comf839c032012-10-26 21:03:50 +00006290static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006291 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006292}
6293
caryclark@google.com10227bf2012-12-28 22:10:41 +00006294static bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
6295 return distances[one] < distances[two];
6296}
caryclark@google.comf839c032012-10-26 21:03:50 +00006297 /*
6298 check start and end of each contour
6299 if not the same, record them
6300 match them up
6301 connect closest
6302 reassemble contour pieces into new path
6303 */
6304static void assemble(const PathWrapper& path, PathWrapper& simple) {
6305#if DEBUG_PATH_CONSTRUCTION
6306 SkDebugf("%s\n", __FUNCTION__);
6307#endif
6308 SkTArray<Contour> contours;
6309 EdgeBuilder builder(path, contours);
6310 builder.finish();
6311 int count = contours.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006312 int outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006313 SkTDArray<int> runs; // indices of partial contours
caryclark@google.com0b7da432012-10-31 19:00:20 +00006314 for (outer = 0; outer < count; ++outer) {
6315 const Contour& eContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006316 const SkPoint& eStart = eContour.start();
6317 const SkPoint& eEnd = eContour.end();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006318#if DEBUG_ASSEMBLE
6319 SkDebugf("%s contour", __FUNCTION__);
6320 if (!approximatelyEqual(eStart, eEnd)) {
6321 SkDebugf("[%d]", runs.count());
6322 } else {
6323 SkDebugf(" ");
6324 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006325 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006326 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
6327#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006328 if (approximatelyEqual(eStart, eEnd)) {
6329 eContour.toPath(simple);
6330 continue;
6331 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006332 *runs.append() = outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006333 }
6334 count = runs.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006335 if (count == 0) {
6336 return;
6337 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006338 SkTDArray<int> sLink, eLink;
6339 sLink.setCount(count);
6340 eLink.setCount(count);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006341 int rIndex, iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006342 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006343 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006344 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006345 SkTDArray<double> distances;
6346 const int ends = count * 2; // all starts and ends
6347 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
6348 distances.setCount(entries);
6349 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
6350 outer = runs[rIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006351 const Contour& oContour = contours[outer];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006352 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
6353 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
6354 * ends - rIndex - 1;
6355 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
6356 int inner = runs[iIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006357 const Contour& iContour = contours[inner];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006358 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
6359 double dx = iPt.fX - oPt.fX;
6360 double dy = iPt.fY - oPt.fY;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006361 double dist = dx * dx + dy * dy;
caryclark@google.com10227bf2012-12-28 22:10:41 +00006362 distances[row + iIndex] = dist; // oStart distance from iStart
6363 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006364 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006365 SkTDArray<int> sortedDist;
6366 sortedDist.setCount(entries);
6367 for (rIndex = 0; rIndex < entries; ++rIndex) {
6368 sortedDist[rIndex] = rIndex;
6369 }
6370 QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
6371 int remaining = count; // number of start/end pairs
6372 for (rIndex = 0; rIndex < entries; ++rIndex) {
6373 int pair = sortedDist[rIndex];
6374 int row = pair / ends;
6375 int col = pair - row * ends;
6376 int thingOne = row < col ? row : ends - row - 2;
6377 int ndxOne = thingOne >> 1;
6378 bool endOne = thingOne & 1;
6379 int* linkOne = endOne ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006380 if (linkOne[ndxOne] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006381 continue;
6382 }
6383 int thingTwo = row < col ? col : ends - row + col - 1;
6384 int ndxTwo = thingTwo >> 1;
6385 bool endTwo = thingTwo & 1;
6386 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006387 if (linkTwo[ndxTwo] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006388 continue;
6389 }
6390 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
6391 bool flip = endOne == endTwo;
6392 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
6393 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
6394 if (!--remaining) {
6395 break;
6396 }
6397 }
6398 SkASSERT(!remaining);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006399#if DEBUG_ASSEMBLE
6400 for (rIndex = 0; rIndex < count; ++rIndex) {
6401 int s = sLink[rIndex];
6402 int e = eLink[rIndex];
6403 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
6404 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
caryclark@google.comf839c032012-10-26 21:03:50 +00006405 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006406#endif
6407 rIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00006408 do {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006409 bool forward = true;
6410 bool first = true;
6411 int sIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006412 SkASSERT(sIndex != SK_MaxS32);
6413 sLink[rIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006414 int eIndex;
6415 if (sIndex < 0) {
6416 eIndex = sLink[~sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006417 sLink[~sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006418 } else {
6419 eIndex = eLink[sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006420 eLink[sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006421 }
caryclark@google.comaa358312013-01-29 20:28:49 +00006422 SkASSERT(eIndex != SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006423#if DEBUG_ASSEMBLE
6424 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006425 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
6426 eIndex < 0 ? ~eIndex : eIndex);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006427#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006428 do {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006429 outer = runs[rIndex];
6430 const Contour& contour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006431 if (first) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006432 first = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006433 const SkPoint* startPtr = &contour.start();
caryclark@google.comf839c032012-10-26 21:03:50 +00006434 simple.deferredMove(startPtr[0]);
6435 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006436 if (forward) {
6437 contour.toPartialForward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006438 } else {
6439 contour.toPartialBackward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006440 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006441#if DEBUG_ASSEMBLE
6442 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006443 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006444 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
6445#endif
6446 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006447 simple.close();
caryclark@google.comf839c032012-10-26 21:03:50 +00006448 break;
6449 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006450 if (forward) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006451 eIndex = eLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006452 SkASSERT(eIndex != SK_MaxS32);
6453 eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006454 if (eIndex >= 0) {
6455 SkASSERT(sLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006456 sLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006457 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006458 SkASSERT(eLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006459 eLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006460 }
6461 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006462 eIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006463 SkASSERT(eIndex != SK_MaxS32);
6464 sLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006465 if (eIndex >= 0) {
6466 SkASSERT(eLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006467 eLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006468 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006469 SkASSERT(sLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006470 sLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006471 }
6472 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006473 rIndex = eIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006474 if (rIndex < 0) {
6475 forward ^= 1;
6476 rIndex = ~rIndex;
6477 }
6478 } while (true);
6479 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006480 if (sLink[rIndex] != SK_MaxS32) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006481 break;
6482 }
6483 }
6484 } while (rIndex < count);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006485#if DEBUG_ASSEMBLE
6486 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006487 SkASSERT(sLink[rIndex] == SK_MaxS32);
6488 SkASSERT(eLink[rIndex] == SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006489 }
6490#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006491}
6492
6493void simplifyx(const SkPath& path, SkPath& result) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00006494#if DEBUG_SORT
6495 gDebugSortCount = gDebugSortCountDefault;
6496#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006497 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
caryclark@google.comf839c032012-10-26 21:03:50 +00006498 result.reset();
6499 result.setFillType(SkPath::kEvenOdd_FillType);
6500 PathWrapper simple(result);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006501
6502 // turn path into list of segments
6503 SkTArray<Contour> contours;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006504 EdgeBuilder builder(path, contours);
caryclark@google.com235f56a2012-09-14 14:19:30 +00006505 builder.finish();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006506 SkTDArray<Contour*> contourList;
caryclark@google.com4eeda372012-12-06 21:47:48 +00006507 makeContourList(contours, contourList, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006508 Contour** currentPtr = contourList.begin();
6509 if (!currentPtr) {
6510 return;
6511 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006512 Contour** listEnd = contourList.end();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006513 // find all intersections between segments
6514 do {
6515 Contour** nextPtr = currentPtr;
6516 Contour* current = *currentPtr++;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00006517 if (current->containsCubics()) {
6518 addSelfIntersectTs(current);
6519 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006520 Contour* next;
6521 do {
6522 next = *nextPtr++;
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00006523 } while (addIntersectTs(current, next) && nextPtr != listEnd);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006524 } while (currentPtr != listEnd);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006525 // eat through coincident edges
caryclark@google.com4eeda372012-12-06 21:47:48 +00006526 coincidenceCheck(contourList, 0);
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00006527 fixOtherTIndex(contourList);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006528 sortSegments(contourList);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006529#if DEBUG_ACTIVE_SPANS
6530 debugShowActiveSpans(contourList);
6531#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006532 // construct closed contours
caryclark@google.com3586ece2012-12-27 18:46:58 +00006533 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00006534 : !bridgeXor(contourList, simple))
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006535 { // if some edges could not be resolved, assemble remaining fragments
caryclark@google.comf839c032012-10-26 21:03:50 +00006536 SkPath temp;
6537 temp.setFillType(SkPath::kEvenOdd_FillType);
6538 PathWrapper assembled(temp);
6539 assemble(simple, assembled);
6540 result = *assembled.nativePath();
caryclark@google.com24bec792012-08-20 12:43:57 +00006541 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006542}