blob: cbf33d0439d86ec1371a90329f6c80c66c77553b [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.coma461ff02012-10-11 12:54:23 +000031
caryclark@google.com47580692012-07-23 12:14:49 +000032#define DEBUG_UNUSED 0 // set to expose unused functions
caryclark@google.com8f9f4682013-01-03 21:18:16 +000033#define FORCE_RELEASE 1 // set force release to 1 for multiple thread -- no debugging
caryclark@google.comfa0588f2012-04-26 21:01:06 +000034
caryclark@google.com31143cf2012-11-09 22:14:19 +000035#if FORCE_RELEASE || defined SK_RELEASE
caryclark@google.com47580692012-07-23 12:14:49 +000036
37const bool gRunTestsInOneThread = false;
38
39#define DEBUG_ACTIVE_SPANS 0
caryclark@google.com4eeda372012-12-06 21:47:48 +000040#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000041#define DEBUG_ADD_INTERSECTING_TS 0
caryclark@google.com47580692012-07-23 12:14:49 +000042#define DEBUG_ADD_T_PAIR 0
caryclark@google.comc899ad92012-08-23 15:24:42 +000043#define DEBUG_ANGLE 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000044#define DEBUG_ASSEMBLE 0
caryclark@google.com47580692012-07-23 12:14:49 +000045#define DEBUG_CONCIDENT 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000046#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000047#define DEBUG_FLOW 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000048#define DEBUG_MARK_DONE 0
caryclark@google.comf839c032012-10-26 21:03:50 +000049#define DEBUG_PATH_CONSTRUCTION 0
caryclark@google.com729e1c42012-11-21 21:36:34 +000050#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000051#define DEBUG_SORT 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000052#define DEBUG_UNSORTABLE 0
caryclark@google.comafe56de2012-07-24 18:11:03 +000053#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000054#define DEBUG_WINDING 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000055#define DEBUG_WINDING_AT_T 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000056
57#else
58
caryclark@google.com47580692012-07-23 12:14:49 +000059const bool gRunTestsInOneThread = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +000060
caryclark@google.comc91dfe42012-10-16 12:06:27 +000061#define DEBUG_ACTIVE_SPANS 1
caryclark@google.com4eeda372012-12-06 21:47:48 +000062#define DEBUG_ACTIVE_SPANS_SHORT_FORM 1
caryclark@google.com6aea33f2012-10-09 14:11:58 +000063#define DEBUG_ADD_INTERSECTING_TS 1
64#define DEBUG_ADD_T_PAIR 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000065#define DEBUG_ANGLE 1
caryclark@google.come7bd5f42012-12-13 19:47:53 +000066#define DEBUG_ASSEMBLE 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000067#define DEBUG_CONCIDENT 1
caryclark@google.com534aa5b2012-08-02 20:08:21 +000068#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000069#define DEBUG_FLOW 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000070#define DEBUG_MARK_DONE 1
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000071#define DEBUG_PATH_CONSTRUCTION 1
caryclark@google.com729e1c42012-11-21 21:36:34 +000072#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000073#define DEBUG_SORT 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000074#define DEBUG_UNSORTABLE 1
caryclark@google.comafe56de2012-07-24 18:11:03 +000075#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000076#define DEBUG_WINDING 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000077#define DEBUG_WINDING_AT_T 1
caryclark@google.comfa0588f2012-04-26 21:01:06 +000078
79#endif
80
caryclark@google.com6aea33f2012-10-09 14:11:58 +000081#define DEBUG_DUMP (DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | DEBUG_PATH_CONSTRUCTION)
caryclark@google.com027de222012-07-12 12:52:50 +000082
caryclark@google.comfa0588f2012-04-26 21:01:06 +000083#if DEBUG_DUMP
84static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000085// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
caryclark@google.comfa0588f2012-04-26 21:01:06 +000086static int gContourID;
87static int gSegmentID;
88#endif
89
caryclark@google.com8dcf1142012-07-02 20:27:02 +000090#ifndef DEBUG_TEST
91#define DEBUG_TEST 0
92#endif
93
caryclark@google.com32546db2012-08-31 20:55:07 +000094#define MAKE_CONST_LINE(line, pts) \
95 const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}
96#define MAKE_CONST_QUAD(quad, pts) \
97 const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
98 {pts[2].fX, pts[2].fY}}
99#define MAKE_CONST_CUBIC(cubic, pts) \
100 const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
101 {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}}
102
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000103static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
104 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000105 MAKE_CONST_LINE(aLine, a);
106 MAKE_CONST_LINE(bLine, b);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000107 return intersect(aLine, bLine, intersections.fT[0], intersections.fT[1]);
108}
109
110static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
111 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000112 MAKE_CONST_QUAD(aQuad, a);
113 MAKE_CONST_LINE(bLine, b);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000114 return intersect(aQuad, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000115}
116
caryclark@google.com32546db2012-08-31 20:55:07 +0000117static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000118 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000119 MAKE_CONST_CUBIC(aCubic, a);
120 MAKE_CONST_LINE(bLine, b);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000121 return intersect(aCubic, bLine, intersections.fT[0], intersections.fT[1]);
122}
123
124static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
125 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000126 MAKE_CONST_QUAD(aQuad, a);
127 MAKE_CONST_QUAD(bQuad, b);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000128#define TRY_QUARTIC_SOLUTION 1
129#if TRY_QUARTIC_SOLUTION
130 intersect2(aQuad, bQuad, intersections);
131#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000132 intersect(aQuad, bQuad, intersections);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000133#endif
caryclark@google.com32546db2012-08-31 20:55:07 +0000134 return intersections.fUsed ? intersections.fUsed : intersections.fCoincidentUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000135}
136
137static int CubicIntersect(const SkPoint a[4], const SkPoint b[4],
138 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000139 MAKE_CONST_CUBIC(aCubic, a);
140 MAKE_CONST_CUBIC(bCubic, b);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000141 intersect(aCubic, bCubic, intersections);
142 return intersections.fUsed;
143}
144
145static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
146 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000147 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000148 return horizontalIntersect(aLine, left, right, y, flipped, intersections);
149}
150
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000151static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
152 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000153 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000154 return horizontalIntersect(aQuad, left, right, y, flipped, intersections);
155}
156
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000157static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
158 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000159 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000160 return horizontalIntersect(aCubic, left, right, y, flipped, intersections);
161}
162
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000163static int (* const HSegmentIntersect[])(const SkPoint [], SkScalar ,
164 SkScalar , SkScalar , bool , Intersections& ) = {
165 NULL,
166 HLineIntersect,
167 HQuadIntersect,
168 HCubicIntersect
169};
170
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000171static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom,
172 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000173 MAKE_CONST_LINE(aLine, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000174 return verticalIntersect(aLine, top, bottom, x, flipped, intersections);
175}
176
177static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom,
178 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000179 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000180 return verticalIntersect(aQuad, top, bottom, x, flipped, intersections);
181}
182
183static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom,
184 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000185 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000186 return verticalIntersect(aCubic, top, bottom, x, flipped, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000187}
188
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000189static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar ,
190 SkScalar , SkScalar , bool , Intersections& ) = {
191 NULL,
192 VLineIntersect,
193 VQuadIntersect,
194 VCubicIntersect
195};
196
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000197static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000198 MAKE_CONST_LINE(line, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000199 double x, y;
200 xy_at_t(line, t, x, y);
201 out->fX = SkDoubleToScalar(x);
202 out->fY = SkDoubleToScalar(y);
203}
204
205static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000206 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000207 double x, y;
208 xy_at_t(quad, t, x, y);
209 out->fX = SkDoubleToScalar(x);
210 out->fY = SkDoubleToScalar(y);
211}
212
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000213static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
214 MAKE_CONST_QUAD(quad, a);
215 xy_at_t(quad, t, out->x, out->y);
216}
217
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000218static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000219 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000220 double x, y;
221 xy_at_t(cubic, t, x, y);
222 out->fX = SkDoubleToScalar(x);
223 out->fY = SkDoubleToScalar(y);
224}
225
226static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
227 NULL,
228 LineXYAtT,
229 QuadXYAtT,
230 CubicXYAtT
231};
232
233static SkScalar LineXAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000234 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000235 double x;
236 xy_at_t(aLine, t, x, *(double*) 0);
237 return SkDoubleToScalar(x);
238}
239
240static SkScalar QuadXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000241 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000242 double x;
243 xy_at_t(quad, t, x, *(double*) 0);
244 return SkDoubleToScalar(x);
245}
246
247static SkScalar CubicXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000248 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000249 double x;
250 xy_at_t(cubic, t, x, *(double*) 0);
251 return SkDoubleToScalar(x);
252}
253
254static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
255 NULL,
256 LineXAtT,
257 QuadXAtT,
258 CubicXAtT
259};
260
261static SkScalar LineYAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000262 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000263 double y;
264 xy_at_t(aLine, t, *(double*) 0, y);
265 return SkDoubleToScalar(y);
266}
267
268static SkScalar QuadYAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000269 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000270 double y;
271 xy_at_t(quad, t, *(double*) 0, y);
272 return SkDoubleToScalar(y);
273}
274
275static SkScalar CubicYAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000276 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000277 double y;
278 xy_at_t(cubic, t, *(double*) 0, y);
279 return SkDoubleToScalar(y);
280}
281
282static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
283 NULL,
284 LineYAtT,
285 QuadYAtT,
286 CubicYAtT
287};
288
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000289static SkScalar LineDXAtT(const SkPoint a[2], double ) {
290 return a[1].fX - a[0].fX;
291}
292
293static SkScalar QuadDXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000294 MAKE_CONST_QUAD(quad, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000295 double x;
296 dxdy_at_t(quad, t, x, *(double*) 0);
297 return SkDoubleToScalar(x);
298}
299
300static SkScalar CubicDXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000301 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000302 double x;
303 dxdy_at_t(cubic, t, x, *(double*) 0);
304 return SkDoubleToScalar(x);
305}
306
307static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
308 NULL,
309 LineDXAtT,
310 QuadDXAtT,
311 CubicDXAtT
312};
313
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000314static SkScalar LineDYAtT(const SkPoint a[2], double ) {
315 return a[1].fY - a[0].fY;
316}
317
318static SkScalar QuadDYAtT(const SkPoint a[3], double t) {
319 MAKE_CONST_QUAD(quad, a);
320 double y;
321 dxdy_at_t(quad, t, *(double*) 0, y);
322 return SkDoubleToScalar(y);
323}
324
325static SkScalar CubicDYAtT(const SkPoint a[4], double t) {
326 MAKE_CONST_CUBIC(cubic, a);
327 double y;
328 dxdy_at_t(cubic, t, *(double*) 0, y);
329 return SkDoubleToScalar(y);
330}
331
332static SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = {
333 NULL,
334 LineDYAtT,
335 QuadDYAtT,
336 CubicDYAtT
337};
338
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000339static void LineSubDivide(const SkPoint a[2], double startT, double endT,
340 SkPoint sub[2]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000341 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000342 _Line dst;
343 sub_divide(aLine, startT, endT, dst);
344 sub[0].fX = SkDoubleToScalar(dst[0].x);
345 sub[0].fY = SkDoubleToScalar(dst[0].y);
346 sub[1].fX = SkDoubleToScalar(dst[1].x);
347 sub[1].fY = SkDoubleToScalar(dst[1].y);
348}
349
350static void QuadSubDivide(const SkPoint a[3], double startT, double endT,
351 SkPoint sub[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000352 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000353 Quadratic dst;
354 sub_divide(aQuad, startT, endT, dst);
355 sub[0].fX = SkDoubleToScalar(dst[0].x);
356 sub[0].fY = SkDoubleToScalar(dst[0].y);
357 sub[1].fX = SkDoubleToScalar(dst[1].x);
358 sub[1].fY = SkDoubleToScalar(dst[1].y);
359 sub[2].fX = SkDoubleToScalar(dst[2].x);
360 sub[2].fY = SkDoubleToScalar(dst[2].y);
361}
362
363static void CubicSubDivide(const SkPoint a[4], double startT, double endT,
364 SkPoint sub[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000365 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000366 Cubic dst;
367 sub_divide(aCubic, startT, endT, dst);
368 sub[0].fX = SkDoubleToScalar(dst[0].x);
369 sub[0].fY = SkDoubleToScalar(dst[0].y);
370 sub[1].fX = SkDoubleToScalar(dst[1].x);
371 sub[1].fY = SkDoubleToScalar(dst[1].y);
372 sub[2].fX = SkDoubleToScalar(dst[2].x);
373 sub[2].fY = SkDoubleToScalar(dst[2].y);
374 sub[3].fX = SkDoubleToScalar(dst[3].x);
375 sub[3].fY = SkDoubleToScalar(dst[3].y);
376}
377
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000378static void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
379 SkPoint []) = {
380 NULL,
381 LineSubDivide,
382 QuadSubDivide,
383 CubicSubDivide
384};
385
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000386static void LineSubDivideHD(const SkPoint a[2], double startT, double endT,
caryclark@google.com32546db2012-08-31 20:55:07 +0000387 _Line sub) {
388 MAKE_CONST_LINE(aLine, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000389 _Line dst;
390 sub_divide(aLine, startT, endT, dst);
391 sub[0] = dst[0];
392 sub[1] = dst[1];
393}
394
395static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT,
caryclark@google.com32546db2012-08-31 20:55:07 +0000396 Quadratic sub) {
397 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000398 Quadratic dst;
399 sub_divide(aQuad, startT, endT, dst);
400 sub[0] = dst[0];
401 sub[1] = dst[1];
402 sub[2] = dst[2];
403}
404
405static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT,
caryclark@google.com32546db2012-08-31 20:55:07 +0000406 Cubic sub) {
407 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000408 Cubic dst;
409 sub_divide(aCubic, startT, endT, dst);
410 sub[0] = dst[0];
411 sub[1] = dst[1];
412 sub[2] = dst[2];
413 sub[3] = dst[3];
414}
415
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000416#if DEBUG_UNUSED
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000417static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
418 SkRect& bounds) {
419 SkPoint dst[3];
420 QuadSubDivide(a, startT, endT, dst);
421 bounds.fLeft = bounds.fRight = dst[0].fX;
422 bounds.fTop = bounds.fBottom = dst[0].fY;
423 for (int index = 1; index < 3; ++index) {
424 bounds.growToInclude(dst[index].fX, dst[index].fY);
425 }
426}
427
428static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
429 SkRect& bounds) {
430 SkPoint dst[4];
431 CubicSubDivide(a, startT, endT, dst);
432 bounds.fLeft = bounds.fRight = dst[0].fX;
433 bounds.fTop = bounds.fBottom = dst[0].fY;
434 for (int index = 1; index < 4; ++index) {
435 bounds.growToInclude(dst[index].fX, dst[index].fY);
436 }
437}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000438#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000439
caryclark@google.com15fa1382012-05-07 20:49:36 +0000440static SkPath::Verb QuadReduceOrder(const SkPoint a[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000441 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000442 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000443 Quadratic dst;
444 int order = reduceOrder(aQuad, dst);
caryclark@google.com24bec792012-08-20 12:43:57 +0000445 if (order == 2) { // quad became line
446 for (int index = 0; index < order; ++index) {
447 SkPoint* pt = reducePts.append();
448 pt->fX = SkDoubleToScalar(dst[index].x);
449 pt->fY = SkDoubleToScalar(dst[index].y);
450 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000451 }
452 return (SkPath::Verb) (order - 1);
453}
454
455static SkPath::Verb CubicReduceOrder(const SkPoint a[4],
456 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000457 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000458 Cubic dst;
459 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed);
caryclark@google.com24bec792012-08-20 12:43:57 +0000460 if (order == 2 || order == 3) { // cubic became line or quad
461 for (int index = 0; index < order; ++index) {
462 SkPoint* pt = reducePts.append();
463 pt->fX = SkDoubleToScalar(dst[index].x);
464 pt->fY = SkDoubleToScalar(dst[index].y);
465 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000466 }
467 return (SkPath::Verb) (order - 1);
468}
469
caryclark@google.com15fa1382012-05-07 20:49:36 +0000470static bool QuadIsLinear(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000471 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000472 return isLinear(aQuad, 0, 2);
473}
474
475static bool CubicIsLinear(const SkPoint a[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000476 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000477 return isLinear(aCubic, 0, 3);
478}
479
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000480static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000481 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000482 double x[2];
483 xy_at_t(aLine, startT, x[0], *(double*) 0);
caryclark@google.com495f8e42012-05-31 13:13:11 +0000484 xy_at_t(aLine, endT, x[1], *(double*) 0);
485 return SkMinScalar((float) x[0], (float) x[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000486}
487
488static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000489 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000490 return (float) leftMostT(aQuad, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000491}
492
493static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000494 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000495 return (float) leftMostT(aCubic, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000496}
497
498static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
499 NULL,
500 LineLeftMost,
501 QuadLeftMost,
502 CubicLeftMost
503};
504
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000505#if 0 // currently unused
caryclark@google.com235f56a2012-09-14 14:19:30 +0000506static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
507 Intersections& intersections) {
508 MAKE_CONST_QUAD(aQuad, a);
509 MAKE_CONST_LINE(bLine, b);
510 return intersectRay(aQuad, bLine, intersections);
511}
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000512#endif
513
514static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine,
515 Intersections& intersections) {
516 MAKE_CONST_QUAD(aQuad, a);
517 return intersectRay(aQuad, bLine, intersections);
518}
caryclark@google.com235f56a2012-09-14 14:19:30 +0000519
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000520static bool LineVertical(const SkPoint a[2], double startT, double endT) {
521 MAKE_CONST_LINE(aLine, a);
522 double x[2];
523 xy_at_t(aLine, startT, x[0], *(double*) 0);
524 xy_at_t(aLine, endT, x[1], *(double*) 0);
525 return approximately_equal((float) x[0], (float) x[1]);
526}
527
528static bool QuadVertical(const SkPoint a[3], double startT, double endT) {
529 SkPoint dst[3];
530 QuadSubDivide(a, startT, endT, dst);
531 return approximately_equal(dst[0].fX, dst[1].fX) && approximately_equal(dst[1].fX, dst[2].fX);
532}
533
534static bool CubicVertical(const SkPoint a[4], double startT, double endT) {
535 SkPoint dst[4];
536 CubicSubDivide(a, startT, endT, dst);
537 return approximately_equal(dst[0].fX, dst[1].fX) && approximately_equal(dst[1].fX, dst[2].fX)
538 && approximately_equal(dst[2].fX, dst[3].fX);
539}
540
541static bool (* const SegmentVertical[])(const SkPoint [], double , double) = {
542 NULL,
543 LineVertical,
544 QuadVertical,
545 CubicVertical
546};
547
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000548class Segment;
549
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000550struct Span {
551 Segment* fOther;
552 mutable SkPoint fPt; // lazily computed as needed
553 double fT;
554 double fOtherT; // value at fOther[fOtherIndex].fT
555 int fOtherIndex; // can't be used during intersection
caryclark@google.com31143cf2012-11-09 22:14:19 +0000556 int fWindSum; // accumulated from contours surrounding this one.
557 int fOppSum; // for binary operators: the opposite winding sum
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000558 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
caryclark@google.com57cff8d2012-11-14 21:14:56 +0000559 int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000560 bool fDone; // if set, this span to next higher T has been processed
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000561 bool fUnsortableStart; // set when start is part of an unsortable pair
562 bool fUnsortableEnd; // set when end is part of an unsortable pair
caryclark@google.comf839c032012-10-26 21:03:50 +0000563 bool fTiny; // if set, span may still be considered once for edge following
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000564};
565
caryclark@google.com15fa1382012-05-07 20:49:36 +0000566// sorting angles
567// given angles of {dx dy ddx ddy dddx dddy} sort them
568class Angle {
569public:
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000570 // FIXME: this is bogus for quads and cubics
571 // if the quads and cubics' line from end pt to ctrl pt are coincident,
572 // there's no obvious way to determine the curve ordering from the
573 // derivatives alone. In particular, if one quadratic's coincident tangent
574 // is longer than the other curve, the final control point can place the
575 // longer curve on either side of the shorter one.
576 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
577 // may provide some help, but nothing has been figured out yet.
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000578
caryclark@google.com32546db2012-08-31 20:55:07 +0000579 /*(
580 for quads and cubics, set up a parameterized line (e.g. LineParameters )
581 for points [0] to [1]. See if point [2] is on that line, or on one side
582 or the other. If it both quads' end points are on the same side, choose
583 the shorter tangent. If the tangents are equal, choose the better second
584 tangent angle
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000585
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000586 maybe I could set up LineParameters lazily
caryclark@google.com32546db2012-08-31 20:55:07 +0000587 */
caryclark@google.com15fa1382012-05-07 20:49:36 +0000588 bool operator<(const Angle& rh) const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000589 double y = dy();
590 double ry = rh.dy();
591 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
592 return y < 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000593 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000594 double x = dx();
595 double rx = rh.dx();
596 if (y == 0 && ry == 0 && x * rx < 0) {
597 return x < rx;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000598 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000599 double x_ry = x * ry;
600 double rx_y = rx * y;
601 double cmp = x_ry - rx_y;
caryclark@google.comc899ad92012-08-23 15:24:42 +0000602 if (!approximately_zero(cmp)) {
caryclark@google.com15fa1382012-05-07 20:49:36 +0000603 return cmp < 0;
604 }
caryclark@google.comd1688742012-09-18 20:08:37 +0000605 if (approximately_zero(x_ry) && approximately_zero(rx_y)
606 && !approximately_zero_squared(cmp)) {
607 return cmp < 0;
608 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000609 // at this point, the initial tangent line is coincident
caryclark@google.com31143cf2012-11-09 22:14:19 +0000610 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
611 || !approximately_zero(rh.fSide))) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000612 // FIXME: running demo will trigger this assertion
613 // (don't know if commenting out will trigger further assertion or not)
614 // commenting it out allows demo to run in release, though
615 // SkASSERT(fSide != rh.fSide);
616 return fSide < rh.fSide;
617 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000618 // see if either curve can be lengthened and try the tangent compare again
619 if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
620 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
621 Angle longer = *this;
622 Angle rhLonger = rh;
623 if (longer.lengthen() | rhLonger.lengthen()) {
624 return longer < rhLonger;
625 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000626 #if 0
caryclark@google.coma461ff02012-10-11 12:54:23 +0000627 // what if we extend in the other direction?
628 longer = *this;
629 rhLonger = rh;
630 if (longer.reverseLengthen() | rhLonger.reverseLengthen()) {
631 return longer < rhLonger;
632 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000633 #endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000634 }
caryclark@google.com185c7c42012-10-19 18:26:24 +0000635 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
caryclark@google.com31143cf2012-11-09 22:14:19 +0000636 || (rh.fVerb == SkPath::kLine_Verb
637 && approximately_zero(rx) && approximately_zero(ry))) {
caryclark@google.com185c7c42012-10-19 18:26:24 +0000638 // See general unsortable comment below. This case can happen when
639 // one line has a non-zero change in t but no change in x and y.
640 fUnsortable = true;
641 rh.fUnsortable = true;
642 return this < &rh; // even with no solution, return a stable sort
643 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000644 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
645 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
646 fUnsortable = true;
647 rh.fUnsortable = true;
648 return this < &rh; // even with no solution, return a stable sort
649 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000650 SkASSERT(fVerb == SkPath::kQuad_Verb); // worry about cubics later
651 SkASSERT(rh.fVerb == SkPath::kQuad_Verb);
skia.committer@gmail.comc1ad0222012-09-19 02:01:47 +0000652 // FIXME: until I can think of something better, project a ray from the
caryclark@google.comd1688742012-09-18 20:08:37 +0000653 // end of the shorter tangent to midway between the end points
654 // through both curves and use the resulting angle to sort
caryclark@google.com235f56a2012-09-14 14:19:30 +0000655 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
656 double len = fTangent1.normalSquared();
657 double rlen = rh.fTangent1.normalSquared();
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000658 _Line ray;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000659 Intersections i, ri;
caryclark@google.comd1688742012-09-18 20:08:37 +0000660 int roots, rroots;
661 bool flip = false;
662 do {
663 const Quadratic& q = (len < rlen) ^ flip ? fQ : rh.fQ;
664 double midX = (q[0].x + q[2].x) / 2;
665 double midY = (q[0].y + q[2].y) / 2;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000666 ray[0] = q[1];
667 ray[1].x = midX;
668 ray[1].y = midY;
caryclark@google.comd1688742012-09-18 20:08:37 +0000669 SkASSERT(ray[0] != ray[1]);
670 roots = QuadRayIntersect(fPts, ray, i);
671 rroots = QuadRayIntersect(rh.fPts, ray, ri);
672 } while ((roots == 0 || rroots == 0) && (flip ^= true));
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000673 if (roots == 0 || rroots == 0) {
674 // FIXME: we don't have a solution in this case. The interim solution
675 // is to mark the edges as unsortable, exclude them from this and
676 // future computations, and allow the returned path to be fragmented
677 fUnsortable = true;
678 rh.fUnsortable = true;
679 return this < &rh; // even with no solution, return a stable sort
680 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000681 _Point loc;
682 double best = SK_ScalarInfinity;
683 double dx, dy, dist;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000684 int index;
685 for (index = 0; index < roots; ++index) {
686 QuadXYAtT(fPts, i.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000687 dx = loc.x - ray[0].x;
688 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000689 dist = dx * dx + dy * dy;
690 if (best > dist) {
691 best = dist;
692 }
693 }
694 for (index = 0; index < rroots; ++index) {
695 QuadXYAtT(rh.fPts, ri.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000696 dx = loc.x - ray[0].x;
697 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000698 dist = dx * dx + dy * dy;
699 if (best > dist) {
700 return fSide < 0;
701 }
702 }
703 return fSide > 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000704 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000705
caryclark@google.com47580692012-07-23 12:14:49 +0000706 double dx() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000707 return fTangent1.dx();
caryclark@google.com47580692012-07-23 12:14:49 +0000708 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000709
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000710 double dy() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000711 return fTangent1.dy();
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000712 }
713
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000714 int end() const {
715 return fEnd;
716 }
717
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000718 bool isHorizontal() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000719 return dy() == 0 && fVerb == SkPath::kLine_Verb;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000720 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000721
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000722 bool lengthen() {
723 int newEnd = fEnd;
724 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
725 fEnd = newEnd;
726 setSpans();
727 return true;
728 }
729 return false;
730 }
731
caryclark@google.coma461ff02012-10-11 12:54:23 +0000732 bool reverseLengthen() {
733 if (fReversed) {
734 return false;
735 }
736 int newEnd = fStart;
737 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
738 fEnd = newEnd;
739 fReversed = true;
740 setSpans();
741 return true;
742 }
743 return false;
744 }
745
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000746 void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000747 int start, int end, const SkTDArray<Span>& spans) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000748 fSegment = segment;
749 fStart = start;
750 fEnd = end;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000751 fPts = orig;
752 fVerb = verb;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000753 fSpans = &spans;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000754 fReversed = false;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000755 fUnsortable = false;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000756 setSpans();
757 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000758
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000759
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000760 void setSpans() {
761 double startT = (*fSpans)[fStart].fT;
762 double endT = (*fSpans)[fEnd].fT;
763 switch (fVerb) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000764 case SkPath::kLine_Verb:
765 _Line l;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000766 LineSubDivideHD(fPts, startT, endT, l);
caryclark@google.com32546db2012-08-31 20:55:07 +0000767 // OPTIMIZATION: for pure line compares, we never need fTangent1.c
768 fTangent1.lineEndPoints(l);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000769 fSide = 0;
caryclark@google.com32546db2012-08-31 20:55:07 +0000770 break;
771 case SkPath::kQuad_Verb:
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000772 QuadSubDivideHD(fPts, startT, endT, fQ);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000773 fTangent1.quadEndPoints(fQ, 0, 1);
774 fSide = -fTangent1.pointDistance(fQ[2]); // not normalized -- compare sign only
caryclark@google.com32546db2012-08-31 20:55:07 +0000775 break;
776 case SkPath::kCubic_Verb:
777 Cubic c;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000778 CubicSubDivideHD(fPts, startT, endT, c);
caryclark@google.com32546db2012-08-31 20:55:07 +0000779 fTangent1.cubicEndPoints(c, 0, 1);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000780 fSide = -fTangent1.pointDistance(c[2]); // not normalized -- compare sign only
caryclark@google.com32546db2012-08-31 20:55:07 +0000781 break;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000782 default:
783 SkASSERT(0);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000784 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000785 fUnsortable = dx() == 0 && dy() == 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000786 if (fUnsortable) {
787 return;
788 }
789 SkASSERT(fStart != fEnd);
790 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
791 for (int index = fStart; index != fEnd; index += step) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000792#if 1
793 const Span& thisSpan = (*fSpans)[index];
794 const Span& nextSpan = (*fSpans)[index + step];
795 if (thisSpan.fTiny || thisSpan.fT == nextSpan.fT) {
796 continue;
caryclark@google.comf839c032012-10-26 21:03:50 +0000797 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000798 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
799#if DEBUG_UNSORTABLE
800 if (fUnsortable) {
801 SkPoint iPt, ePt;
802 (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt);
803 (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt);
804 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
805 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
806 }
807#endif
808 return;
809#else
810 if ((*fSpans)[index].fUnsortableStart) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000811 fUnsortable = true;
812 return;
813 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000814#endif
caryclark@google.comf839c032012-10-26 21:03:50 +0000815 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000816#if 1
817#if DEBUG_UNSORTABLE
818 SkPoint iPt, ePt;
819 (*SegmentXYAtT[fVerb])(fPts, startT, &iPt);
820 (*SegmentXYAtT[fVerb])(fPts, endT, &ePt);
821 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
822 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
823#endif
824 fUnsortable = true;
825#endif
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000826 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000827
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000828 Segment* segment() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000829 return const_cast<Segment*>(fSegment);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000830 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000831
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000832 int sign() const {
caryclark@google.com495f8e42012-05-31 13:13:11 +0000833 return SkSign32(fStart - fEnd);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000834 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000835
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000836 const SkTDArray<Span>* spans() const {
837 return fSpans;
838 }
839
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000840 int start() const {
841 return fStart;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000842 }
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +0000843
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000844 bool unsortable() const {
845 return fUnsortable;
846 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000847
caryclark@google.comc899ad92012-08-23 15:24:42 +0000848#if DEBUG_ANGLE
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000849 const SkPoint* pts() const {
850 return fPts;
851 }
852
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000853 SkPath::Verb verb() const {
854 return fVerb;
855 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000856
caryclark@google.comc899ad92012-08-23 15:24:42 +0000857 void debugShow(const SkPoint& a) const {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000858 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
caryclark@google.comc899ad92012-08-23 15:24:42 +0000859 }
860#endif
861
caryclark@google.com15fa1382012-05-07 20:49:36 +0000862private:
caryclark@google.com235f56a2012-09-14 14:19:30 +0000863 const SkPoint* fPts;
864 Quadratic fQ;
865 SkPath::Verb fVerb;
866 double fSide;
867 LineParameters fTangent1;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000868 const SkTDArray<Span>* fSpans;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000869 const Segment* fSegment;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000870 int fStart;
871 int fEnd;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000872 bool fReversed;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000873 mutable bool fUnsortable; // this alone is editable by the less than operator
caryclark@google.com15fa1382012-05-07 20:49:36 +0000874};
875
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000876// Bounds, unlike Rect, does not consider a line to be empty.
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000877struct Bounds : public SkRect {
878 static bool Intersects(const Bounds& a, const Bounds& b) {
879 return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
880 a.fTop <= b.fBottom && b.fTop <= a.fBottom;
881 }
882
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000883 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
884 if (left < fLeft) {
885 fLeft = left;
886 }
887 if (top < fTop) {
888 fTop = top;
889 }
890 if (right > fRight) {
891 fRight = right;
892 }
893 if (bottom > fBottom) {
894 fBottom = bottom;
895 }
896 }
897
898 void add(const Bounds& toAdd) {
899 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
900 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000901
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000902 void add(const SkPoint& pt) {
903 if (pt.fX < fLeft) fLeft = pt.fX;
904 if (pt.fY < fTop) fTop = pt.fY;
905 if (pt.fX > fRight) fRight = pt.fX;
906 if (pt.fY > fBottom) fBottom = pt.fY;
907 }
908
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000909 bool isEmpty() {
910 return fLeft > fRight || fTop > fBottom
caryclark@google.com235f56a2012-09-14 14:19:30 +0000911 || (fLeft == fRight && fTop == fBottom)
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000912 || isnan(fLeft) || isnan(fRight)
913 || isnan(fTop) || isnan(fBottom);
914 }
915
916 void setCubicBounds(const SkPoint a[4]) {
917 _Rect dRect;
caryclark@google.com32546db2012-08-31 20:55:07 +0000918 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000919 dRect.setBounds(cubic);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000920 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
921 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000922 }
923
924 void setQuadBounds(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000925 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000926 _Rect dRect;
927 dRect.setBounds(quad);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000928 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
929 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000930 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000931
932 void setPoint(const SkPoint& pt) {
933 fLeft = fRight = pt.fX;
934 fTop = fBottom = pt.fY;
935 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000936};
937
caryclark@google.com7ba591e2012-11-20 14:21:54 +0000938// OPTIMIZATION: does the following also work, and is it any faster?
939// return outerWinding * innerWinding > 0
940// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
caryclark@google.com2ddff932012-08-07 21:25:27 +0000941static bool useInnerWinding(int outerWinding, int innerWinding) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000942 // SkASSERT(outerWinding != innerWinding);
caryclark@google.com2ddff932012-08-07 21:25:27 +0000943 int absOut = abs(outerWinding);
944 int absIn = abs(innerWinding);
945 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
946 if (outerWinding * innerWinding < 0) {
947#if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +0000948 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
caryclark@google.com2ddff932012-08-07 21:25:27 +0000949 outerWinding, innerWinding, result ? "true" : "false");
950#endif
951 }
952 return result;
953}
954
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000955#define F (false) // discard the edge
956#define T (true) // keep the edge
957
caryclark@google.comd0deb4f2012-12-17 13:58:08 +0000958static const bool gUnaryActiveEdge[2][2] = {
959// from=0 from=1
960// to=0,1 to=0,1
961 {F, T}, {T, F},
962};
963
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000964static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
965// miFrom=0 miFrom=1
966// miTo=0 miTo=1 miTo=0 miTo=1
967// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
968// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
969 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
970 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
971 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
972 {{{{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 +0000973};
974
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000975#undef F
976#undef T
caryclark@google.com235f56a2012-09-14 14:19:30 +0000977
caryclark@google.comf839c032012-10-26 21:03:50 +0000978// wrap path to keep track of whether the contour is initialized and non-empty
979class PathWrapper {
980public:
981 PathWrapper(SkPath& path)
982 : fPathPtr(&path)
caryclark@google.comd0deb4f2012-12-17 13:58:08 +0000983 , fCloses(0)
984 , fMoves(0)
caryclark@google.comf839c032012-10-26 21:03:50 +0000985 {
986 init();
987 }
988
989 void close() {
990 if (!fHasMove) {
991 return;
992 }
993 bool callClose = isClosed();
994 lineTo();
995 if (fEmpty) {
996 return;
997 }
998 if (callClose) {
999 #if DEBUG_PATH_CONSTRUCTION
1000 SkDebugf("path.close();\n");
1001 #endif
1002 fPathPtr->close();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001003 fCloses++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001004 }
1005 init();
1006 }
1007
1008 void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
1009 lineTo();
1010 moveTo();
1011#if DEBUG_PATH_CONSTRUCTION
1012 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
1013 pt1.fX, pt1.fY, pt2.fX, pt2.fY, pt3.fX, pt3.fY);
1014#endif
1015 fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, pt3.fX, pt3.fY);
1016 fDefer[0] = fDefer[1] = pt3;
1017 fEmpty = false;
1018 }
1019
1020 void deferredLine(const SkPoint& pt) {
1021 if (pt == fDefer[1]) {
1022 return;
1023 }
1024 if (changedSlopes(pt)) {
1025 lineTo();
1026 fDefer[0] = fDefer[1];
1027 }
1028 fDefer[1] = pt;
1029 }
1030
1031 void deferredMove(const SkPoint& pt) {
1032 fMoved = true;
1033 fHasMove = true;
1034 fEmpty = true;
1035 fDefer[0] = fDefer[1] = pt;
1036 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001037
caryclark@google.comf839c032012-10-26 21:03:50 +00001038 void deferredMoveLine(const SkPoint& pt) {
1039 if (!fHasMove) {
1040 deferredMove(pt);
1041 }
1042 deferredLine(pt);
1043 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001044
caryclark@google.comf839c032012-10-26 21:03:50 +00001045 bool hasMove() const {
1046 return fHasMove;
1047 }
1048
1049 void init() {
1050 fEmpty = true;
1051 fHasMove = false;
1052 fMoved = false;
1053 }
1054
1055 bool isClosed() const {
1056 return !fEmpty && fFirstPt == fDefer[1];
1057 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001058
caryclark@google.comf839c032012-10-26 21:03:50 +00001059 void lineTo() {
1060 if (fDefer[0] == fDefer[1]) {
1061 return;
1062 }
1063 moveTo();
1064 fEmpty = false;
1065#if DEBUG_PATH_CONSTRUCTION
1066 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
1067#endif
1068 fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
1069 fDefer[0] = fDefer[1];
1070 }
1071
1072 const SkPath* nativePath() const {
1073 return fPathPtr;
1074 }
1075
1076 void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
1077 lineTo();
1078 moveTo();
1079#if DEBUG_PATH_CONSTRUCTION
1080 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
1081 pt1.fX, pt1.fY, pt2.fX, pt2.fY);
1082#endif
1083 fPathPtr->quadTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY);
1084 fDefer[0] = fDefer[1] = pt2;
1085 fEmpty = false;
1086 }
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00001087
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001088 bool someAssemblyRequired() const {
1089 return fCloses < fMoves;
1090 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001091
1092protected:
1093 bool changedSlopes(const SkPoint& pt) const {
1094 if (fDefer[0] == fDefer[1]) {
1095 return false;
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001096 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001097 SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
1098 SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
1099 SkScalar lineDx = pt.fX - fDefer[1].fX;
1100 SkScalar lineDy = pt.fY - fDefer[1].fY;
1101 return deferDx * lineDy != deferDy * lineDx;
1102 }
1103
1104 void moveTo() {
1105 if (!fMoved) {
1106 return;
1107 }
1108 fFirstPt = fDefer[0];
1109#if DEBUG_PATH_CONSTRUCTION
1110 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
1111#endif
1112 fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
1113 fMoved = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001114 fMoves++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001115 }
1116
1117private:
1118 SkPath* fPathPtr;
1119 SkPoint fDefer[2];
1120 SkPoint fFirstPt;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001121 int fCloses;
1122 int fMoves;
caryclark@google.comf839c032012-10-26 21:03:50 +00001123 bool fEmpty;
1124 bool fHasMove;
1125 bool fMoved;
1126};
1127
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001128class Segment {
1129public:
1130 Segment() {
1131#if DEBUG_DUMP
1132 fID = ++gSegmentID;
1133#endif
1134 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00001135
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001136 bool operator<(const Segment& rh) const {
1137 return fBounds.fTop < rh.fBounds.fTop;
1138 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001139
caryclark@google.com4eeda372012-12-06 21:47:48 +00001140 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001141 if (activeAngleInner(index, done, angles)) {
1142 return true;
1143 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001144 int lesser = index;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001145 while (--lesser >= 0 && equalPoints(index, lesser)) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001146 if (activeAngleOther(lesser, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001147 return true;
1148 }
1149 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001150 lesser = index;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001151 do {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001152 if (activeAngleOther(index, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001153 return true;
1154 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001155 } while (++index < fTs.count() && equalPoints(index, lesser));
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001156 return false;
1157 }
1158
caryclark@google.com4eeda372012-12-06 21:47:48 +00001159 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001160 Span* span = &fTs[index];
1161 Segment* other = span->fOther;
1162 int oIndex = span->fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001163 return other->activeAngleInner(oIndex, done, angles);
1164 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001165
caryclark@google.com4eeda372012-12-06 21:47:48 +00001166 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001167 int next = nextExactSpan(index, 1);
caryclark@google.com9764cc62012-07-12 19:29:45 +00001168 if (next > 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001169 Span& upSpan = fTs[index];
1170 if (upSpan.fWindValue || upSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001171 addAngle(angles, index, next);
caryclark@google.comf839c032012-10-26 21:03:50 +00001172 if (upSpan.fDone || upSpan.fUnsortableEnd) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001173 done++;
1174 } else if (upSpan.fWindSum != SK_MinS32) {
1175 return true;
1176 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001177 } else if (!upSpan.fDone) {
1178 upSpan.fDone = true;
1179 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001180 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001181 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001182 int prev = nextExactSpan(index, -1);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001183 // edge leading into junction
caryclark@google.com9764cc62012-07-12 19:29:45 +00001184 if (prev >= 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001185 Span& downSpan = fTs[prev];
1186 if (downSpan.fWindValue || downSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001187 addAngle(angles, index, prev);
1188 if (downSpan.fDone) {
1189 done++;
1190 } else if (downSpan.fWindSum != SK_MinS32) {
1191 return true;
1192 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001193 } else if (!downSpan.fDone) {
1194 downSpan.fDone = true;
1195 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001196 }
1197 }
1198 return false;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001199 }
1200
caryclark@google.comf839c032012-10-26 21:03:50 +00001201 void activeLeftTop(SkPoint& result) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001202 SkASSERT(!done());
1203 int count = fTs.count();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001204 result.fX = result.fY = SK_ScalarMax;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001205 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00001206 bool lastUnsortable = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001207 for (int index = 0; index < count; ++index) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001208 const Span& span = fTs[index];
1209 if (span.fUnsortableStart | lastUnsortable) {
1210 goto next;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001211 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001212 if (!span.fDone | !lastDone) {
1213 const SkPoint& xy = xyAtT(index);
1214 if (result.fY < xy.fY) {
1215 goto next;
1216 }
1217 if (result.fY == xy.fY && result.fX < xy.fX) {
1218 goto next;
1219 }
1220 result = xy;
1221 }
1222 next:
1223 lastDone = span.fDone;
1224 lastUnsortable = span.fUnsortableEnd;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001225 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001226 }
1227
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001228 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
1229 int sumMiWinding = updateWinding(endIndex, index);
1230 int sumSuWinding = updateOppWinding(endIndex, index);
1231 if (fOperand) {
1232 SkTSwap<int>(sumMiWinding, sumSuWinding);
1233 }
1234 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1235 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001236 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001237 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001238
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001239 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00001240 int& sumMiWinding, int& sumSuWinding,
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001241 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
1242 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1243 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001244 bool miFrom;
1245 bool miTo;
1246 bool suFrom;
1247 bool suTo;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001248 if (operand()) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001249 miFrom = (oppMaxWinding & xorMiMask) != 0;
1250 miTo = (oppSumWinding & xorMiMask) != 0;
1251 suFrom = (maxWinding & xorSuMask) != 0;
1252 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001253 } else {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001254 miFrom = (maxWinding & xorMiMask) != 0;
1255 miTo = (sumWinding & xorMiMask) != 0;
1256 suFrom = (oppMaxWinding & xorSuMask) != 0;
1257 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001258 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001259 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
1260 SkASSERT(result != -1);
1261 return result;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001262 }
1263
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001264 bool activeWinding(int index, int endIndex) {
1265 int sumWinding = updateWinding(endIndex, index);
1266 int maxWinding;
1267 return activeWinding(index, endIndex, maxWinding, sumWinding);
1268 }
1269
1270 bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
1271 setUpWinding(index, endIndex, maxWinding, sumWinding);
1272 bool from = maxWinding != 0;
1273 bool to = sumWinding != 0;
1274 bool result = gUnaryActiveEdge[from][to];
1275 SkASSERT(result != -1);
1276 return result;
1277 }
1278
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001279 void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001280 SkASSERT(start != end);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001281 Angle* angle = angles.append();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001282#if DEBUG_ANGLE
caryclark@google.com31143cf2012-11-09 22:14:19 +00001283 if (angles.count() > 1 && !fTs[start].fTiny) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001284 SkPoint angle0Pt, newPt;
1285 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
1286 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
1287 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
1288 SkASSERT(approximately_equal(angle0Pt.fX, newPt.fX));
1289 SkASSERT(approximately_equal(angle0Pt.fY, newPt.fY));
1290 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001291#endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001292 angle->set(fPts, fVerb, this, start, end, fTs);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001293 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001294
caryclark@google.com2ddff932012-08-07 21:25:27 +00001295 void addCancelOutsides(double tStart, double oStart, Segment& other,
caryclark@google.comcc905052012-07-25 20:59:42 +00001296 double oEnd) {
1297 int tIndex = -1;
1298 int tCount = fTs.count();
1299 int oIndex = -1;
1300 int oCount = other.fTs.count();
caryclark@google.comcc905052012-07-25 20:59:42 +00001301 do {
1302 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001303 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001304 int tIndexStart = tIndex;
1305 do {
1306 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001307 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001308 int oIndexStart = oIndex;
1309 double nextT;
1310 do {
1311 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001312 } while (nextT < 1 && approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001313 double oNextT;
1314 do {
1315 oNextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001316 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001317 // at this point, spans before and after are at:
1318 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1319 // if tIndexStart == 0, no prior span
1320 // if nextT == 1, no following span
rmistry@google.comd6176b02012-08-23 18:14:13 +00001321
caryclark@google.comcc905052012-07-25 20:59:42 +00001322 // advance the span with zero winding
1323 // if the following span exists (not past the end, non-zero winding)
1324 // connect the two edges
1325 if (!fTs[tIndexStart].fWindValue) {
1326 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1327 #if DEBUG_CONCIDENT
1328 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1329 __FUNCTION__, fID, other.fID, tIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001330 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
1331 xyAtT(tIndexStart).fY);
caryclark@google.comcc905052012-07-25 20:59:42 +00001332 #endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001333 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001334 }
1335 if (nextT < 1 && fTs[tIndex].fWindValue) {
1336 #if DEBUG_CONCIDENT
1337 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1338 __FUNCTION__, fID, other.fID, tIndex,
1339 fTs[tIndex].fT, xyAtT(tIndex).fX,
1340 xyAtT(tIndex).fY);
1341 #endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001342 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001343 }
1344 } else {
1345 SkASSERT(!other.fTs[oIndexStart].fWindValue);
1346 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1347 #if DEBUG_CONCIDENT
1348 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1349 __FUNCTION__, fID, other.fID, oIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001350 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
1351 other.xyAtT(oIndexStart).fY);
1352 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
caryclark@google.comcc905052012-07-25 20:59:42 +00001353 #endif
caryclark@google.comcc905052012-07-25 20:59:42 +00001354 }
1355 if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1356 #if DEBUG_CONCIDENT
1357 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1358 __FUNCTION__, fID, other.fID, oIndex,
1359 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1360 other.xyAtT(oIndex).fY);
1361 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1362 #endif
1363 }
1364 }
1365 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001366
caryclark@google.comcc905052012-07-25 20:59:42 +00001367 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1368 double oEnd) {
1369 // walk this to outsideTs[0]
1370 // walk other to outsideTs[1]
1371 // if either is > 0, add a pointer to the other, copying adjacent winding
1372 int tIndex = -1;
1373 int oIndex = -1;
1374 double tStart = outsideTs[0];
1375 double oStart = outsideTs[1];
1376 do {
1377 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001378 } while (!approximately_negative(tStart - fTs[tIndex].fT));
caryclark@google.comcc905052012-07-25 20:59:42 +00001379 do {
1380 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001381 } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001382 if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001383 addTPair(tStart, other, oStart, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001384 }
1385 tStart = fTs[tIndex].fT;
1386 oStart = other.fTs[oIndex].fT;
1387 do {
1388 double nextT;
1389 do {
1390 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001391 } while (approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001392 tStart = nextT;
1393 do {
1394 nextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001395 } while (approximately_negative(nextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001396 oStart = nextT;
caryclark@google.com4eeda372012-12-06 21:47:48 +00001397 if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001398 break;
1399 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00001400 addTPair(tStart, other, oStart, false);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001401 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001402 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001403
caryclark@google.com4eeda372012-12-06 21:47:48 +00001404 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
1405 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001406 fBounds.setCubicBounds(pts);
1407 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001408
caryclark@google.comf839c032012-10-26 21:03:50 +00001409 /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001410 SkPoint edge[4];
caryclark@google.comf839c032012-10-26 21:03:50 +00001411 const SkPoint* ePtr;
1412 int lastT = fTs.count() - 1;
1413 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1414 ePtr = fPts;
1415 } else {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001416 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
caryclark@google.comf839c032012-10-26 21:03:50 +00001417 (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
1418 ePtr = edge;
1419 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001420 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001421 bool reverse = ePtr == fPts && start != 0;
1422 if (reverse) {
1423 path.deferredMoveLine(ePtr[fVerb]);
1424 switch (fVerb) {
1425 case SkPath::kLine_Verb:
1426 path.deferredLine(ePtr[0]);
1427 break;
1428 case SkPath::kQuad_Verb:
1429 path.quadTo(ePtr[1], ePtr[0]);
1430 break;
1431 case SkPath::kCubic_Verb:
1432 path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1433 break;
1434 default:
1435 SkASSERT(0);
1436 }
1437 // return ePtr[0];
1438 } else {
1439 path.deferredMoveLine(ePtr[0]);
1440 switch (fVerb) {
1441 case SkPath::kLine_Verb:
1442 path.deferredLine(ePtr[1]);
1443 break;
1444 case SkPath::kQuad_Verb:
1445 path.quadTo(ePtr[1], ePtr[2]);
1446 break;
1447 case SkPath::kCubic_Verb:
1448 path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1449 break;
1450 default:
1451 SkASSERT(0);
1452 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001453 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001454 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001455 // return ePtr[fVerb];
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001456 }
1457
caryclark@google.com4eeda372012-12-06 21:47:48 +00001458 void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
1459 init(pts, SkPath::kLine_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001460 fBounds.set(pts, 2);
1461 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001462
caryclark@google.comf839c032012-10-26 21:03:50 +00001463#if 0
1464 const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001465 const SkPoint& pt = xyAtT(tIndex);
1466 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001467 path.deferredMove(pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001468 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00001469 return pt;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001470 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001471#endif
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001472
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001473 // add 2 to edge or out of range values to get T extremes
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001474 void addOtherT(int index, double otherT, int otherIndex) {
1475 Span& span = fTs[index];
caryclark@google.comf839c032012-10-26 21:03:50 +00001476 #if PIN_ADD_T
caryclark@google.com185c7c42012-10-19 18:26:24 +00001477 if (precisely_less_than_zero(otherT)) {
1478 otherT = 0;
1479 } else if (precisely_greater_than_one(otherT)) {
1480 otherT = 1;
1481 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001482 #endif
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001483 span.fOtherT = otherT;
1484 span.fOtherIndex = otherIndex;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001485 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001486
caryclark@google.com4eeda372012-12-06 21:47:48 +00001487 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
1488 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001489 fBounds.setQuadBounds(pts);
1490 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001491
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001492 // Defer all coincident edge processing until
1493 // after normal intersections have been computed
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001494
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001495// no need to be tricky; insert in normal T order
1496// resolve overlapping ts when considering coincidence later
1497
1498 // add non-coincident intersection. Resulting edges are sorted in T.
1499 int addT(double newT, Segment* other) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001500 // FIXME: in the pathological case where there is a ton of intercepts,
1501 // binary search?
1502 int insertedAt = -1;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001503 size_t tCount = fTs.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00001504 #if PIN_ADD_T
caryclark@google.comc899ad92012-08-23 15:24:42 +00001505 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
caryclark@google.com185c7c42012-10-19 18:26:24 +00001506 if (precisely_less_than_zero(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001507 newT = 0;
caryclark@google.com185c7c42012-10-19 18:26:24 +00001508 } else if (precisely_greater_than_one(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001509 newT = 1;
1510 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001511 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001512 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001513 // OPTIMIZATION: if there are three or more identical Ts, then
1514 // the fourth and following could be further insertion-sorted so
1515 // that all the edges are clockwise or counterclockwise.
1516 // This could later limit segment tests to the two adjacent
1517 // neighbors, although it doesn't help with determining which
1518 // circular direction to go in.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001519 if (newT < fTs[index].fT) {
1520 insertedAt = index;
1521 break;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001522 }
1523 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001524 Span* span;
1525 if (insertedAt >= 0) {
1526 span = fTs.insert(insertedAt);
1527 } else {
1528 insertedAt = tCount;
1529 span = fTs.append();
1530 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001531 span->fT = newT;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001532 span->fOther = other;
caryclark@google.com27c449a2012-07-27 18:26:38 +00001533 span->fPt.fX = SK_ScalarNaN;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001534 span->fWindSum = SK_MinS32;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001535 span->fOppSum = SK_MinS32;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001536 span->fWindValue = 1;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001537 span->fOppValue = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00001538 span->fTiny = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001539 if ((span->fDone = newT == 1)) {
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00001540 ++fDoneSpans;
rmistry@google.comd6176b02012-08-23 18:14:13 +00001541 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001542 span->fUnsortableStart = false;
1543 span->fUnsortableEnd = false;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001544 int less = -1;
1545 while (&span[less + 1] - fTs.begin() > 0 && !span[less].fDone
1546 && !precisely_negative(newT - span[less].fT)
1547 // && approximately_negative(newT - span[less].fT)
1548 && xyAtT(&span[less]) == xyAtT(span)) {
1549 span[less].fTiny = true;
1550 span[less].fDone = true;
1551 if (approximately_negative(newT - span[less].fT)) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00001552 if (approximately_greater_than_one(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001553 span[less].fUnsortableStart = true;
1554 span[less - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001555 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001556 if (approximately_less_than_zero(span[less].fT)) {
1557 span[less + 1].fUnsortableStart = true;
1558 span[less].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001559 }
1560 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001561 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001562 --less;
caryclark@google.comf839c032012-10-26 21:03:50 +00001563 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001564 int more = 1;
1565 while (fTs.end() - &span[more - 1] > 1 && !span[more - 1].fDone
1566 && !precisely_negative(span[more].fT - newT)
1567 // && approximately_negative(span[more].fT - newT)
1568 && xyAtT(&span[more]) == xyAtT(span)) {
1569 span[more - 1].fTiny = true;
1570 span[more - 1].fDone = true;
1571 if (approximately_negative(span[more].fT - newT)) {
1572 if (approximately_greater_than_one(span[more].fT)) {
1573 span[more + 1].fUnsortableStart = true;
1574 span[more].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001575 }
1576 if (approximately_less_than_zero(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001577 span[more].fUnsortableStart = true;
1578 span[more - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001579 }
1580 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001581 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001582 ++more;
caryclark@google.comf839c032012-10-26 21:03:50 +00001583 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001584 return insertedAt;
1585 }
1586
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001587 // set spans from start to end to decrement by one
1588 // note this walks other backwards
1589 // FIMXE: there's probably an edge case that can be constructed where
1590 // two span in one segment are separated by float epsilon on one span but
1591 // not the other, if one segment is very small. For this
1592 // case the counts asserted below may or may not be enough to separate the
caryclark@google.com2ddff932012-08-07 21:25:27 +00001593 // spans. Even if the counts work out, what if the spans aren't correctly
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001594 // sorted? It feels better in such a case to match the span's other span
1595 // pointer since both coincident segments must contain the same spans.
1596 void addTCancel(double startT, double endT, Segment& other,
1597 double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001598 SkASSERT(!approximately_negative(endT - startT));
1599 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00001600 bool binary = fOperand != other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001601 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001602 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001603 ++index;
1604 }
caryclark@google.comb9738012012-07-03 19:53:30 +00001605 int oIndex = other.fTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001606 while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001607 ;
caryclark@google.com59823f72012-08-09 18:17:47 +00001608 double tRatio = (oEndT - oStartT) / (endT - startT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001609 Span* test = &fTs[index];
1610 Span* oTest = &other.fTs[oIndex];
caryclark@google.com18063442012-07-25 12:05:18 +00001611 SkTDArray<double> outsideTs;
1612 SkTDArray<double> oOutsideTs;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001613 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001614 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
caryclark@google.comcc905052012-07-25 20:59:42 +00001615 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.com200c2112012-08-03 15:05:04 +00001616 double testT = test->fT;
1617 double oTestT = oTest->fT;
1618 Span* span = test;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001619 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001620 if (decrement) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001621 decrementSpan(span);
caryclark@google.com200c2112012-08-03 15:05:04 +00001622 } else if (track && span->fT < 1 && oTestT < 1) {
1623 TrackOutside(outsideTs, span->fT, oTestT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001624 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001625 span = &fTs[++index];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001626 } while (approximately_negative(span->fT - testT));
caryclark@google.com200c2112012-08-03 15:05:04 +00001627 Span* oSpan = oTest;
caryclark@google.com59823f72012-08-09 18:17:47 +00001628 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1629 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1630 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001631 while (approximately_negative(otherTMatchStart - oSpan->fT)
1632 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
caryclark@google.com03f97062012-08-21 13:13:52 +00001633 #ifdef SK_DEBUG
caryclark@google.com59823f72012-08-09 18:17:47 +00001634 SkASSERT(originalWindValue == oSpan->fWindValue);
caryclark@google.com03f97062012-08-21 13:13:52 +00001635 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001636 if (decrement) {
caryclark@google.com200c2112012-08-03 15:05:04 +00001637 other.decrementSpan(oSpan);
1638 } else if (track && oSpan->fT < 1 && testT < 1) {
1639 TrackOutside(oOutsideTs, oSpan->fT, testT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001640 }
1641 if (!oIndex) {
1642 break;
1643 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001644 oSpan = &other.fTs[--oIndex];
rmistry@google.comd6176b02012-08-23 18:14:13 +00001645 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001646 test = span;
1647 oTest = oSpan;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001648 } while (!approximately_negative(endT - test->fT));
1649 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
caryclark@google.com18063442012-07-25 12:05:18 +00001650 // FIXME: determine if canceled edges need outside ts added
caryclark@google.comcc905052012-07-25 20:59:42 +00001651 if (!done() && outsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001652 double tStart = outsideTs[0];
1653 double oStart = outsideTs[1];
1654 addCancelOutsides(tStart, oStart, other, oEndT);
1655 int count = outsideTs.count();
1656 if (count > 2) {
1657 double tStart = outsideTs[count - 2];
1658 double oStart = outsideTs[count - 1];
1659 addCancelOutsides(tStart, oStart, other, oEndT);
1660 }
caryclark@google.com18063442012-07-25 12:05:18 +00001661 }
caryclark@google.comcc905052012-07-25 20:59:42 +00001662 if (!other.done() && oOutsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001663 double tStart = oOutsideTs[0];
1664 double oStart = oOutsideTs[1];
1665 other.addCancelOutsides(tStart, oStart, *this, endT);
caryclark@google.com18063442012-07-25 12:05:18 +00001666 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001667 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00001668
caryclark@google.com4eeda372012-12-06 21:47:48 +00001669 int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1670 SkTDArray<double>& outsideTs) {
1671 int oWindValue = oTest->fWindValue;
1672 int oOppValue = oTest->fOppValue;
1673 if (opp) {
1674 SkTSwap<int>(oWindValue, oOppValue);
1675 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001676 Span* const test = &fTs[index];
1677 Span* end = test;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001678 const double oStartT = oTest->fT;
1679 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001680 if (bumpSpan(end, oWindValue, oOppValue)) {
1681 TrackOutside(outsideTs, end->fT, oStartT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001682 }
1683 end = &fTs[++index];
1684 } while (approximately_negative(end->fT - test->fT));
1685 return index;
1686 }
1687
1688 // because of the order in which coincidences are resolved, this and other
1689 // may not have the same intermediate points. Compute the corresponding
1690 // intermediate T values (using this as the master, other as the follower)
1691 // and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com4eeda372012-12-06 21:47:48 +00001692 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1693 SkTDArray<double>& oOutsideTs) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001694 Span* const oTest = &fTs[oIndex];
1695 Span* oEnd = oTest;
1696 const double startT = test->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001697 const double oStartT = oTest->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001698 while (!approximately_negative(oEndT - oEnd->fT)
caryclark@google.com4eeda372012-12-06 21:47:48 +00001699 && approximately_negative(oEnd->fT - oStartT)) {
1700 zeroSpan(oEnd);
1701 TrackOutside(oOutsideTs, oEnd->fT, startT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001702 oEnd = &fTs[++oIndex];
1703 }
1704 return oIndex;
1705 }
1706
1707 // FIXME: need to test this case:
1708 // contourA has two segments that are coincident
1709 // contourB has two segments that are coincident in the same place
1710 // each ends up with +2/0 pairs for winding count
1711 // since logic below doesn't transfer count (only increments/decrements) can this be
1712 // resolved to +4/0 ?
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001713
1714 // set spans from start to end to increment the greater by one and decrement
1715 // the lesser
caryclark@google.com4eeda372012-12-06 21:47:48 +00001716 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001717 SkASSERT(!approximately_negative(endT - startT));
1718 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001719 bool opp = fOperand ^ other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001720 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001721 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001722 ++index;
1723 }
1724 int oIndex = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001725 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001726 ++oIndex;
1727 }
1728 Span* test = &fTs[index];
1729 Span* oTest = &other.fTs[oIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001730 SkTDArray<double> outsideTs;
1731 SkTDArray<double> oOutsideTs;
1732 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001733 // if either span has an opposite value and the operands don't match, resolve first
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001734 // SkASSERT(!test->fDone || !oTest->fDone);
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001735 if (test->fDone || oTest->fDone) {
1736 index = advanceCoincidentThis(oTest, opp, index);
1737 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
1738 } else {
1739 index = bumpCoincidentThis(oTest, opp, index, outsideTs);
1740 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
1741 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001742 test = &fTs[index];
1743 oTest = &other.fTs[oIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001744 } while (!approximately_negative(endT - test->fT));
1745 SkASSERT(approximately_negative(oTest->fT - oEndT));
1746 SkASSERT(approximately_negative(oEndT - oTest->fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001747 if (!done() && outsideTs.count()) {
1748 addCoinOutsides(outsideTs, other, oEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001749 }
1750 if (!other.done() && oOutsideTs.count()) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001751 other.addCoinOutsides(oOutsideTs, *this, endT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001752 }
1753 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001754
caryclark@google.comcc905052012-07-25 20:59:42 +00001755 // FIXME: this doesn't prevent the same span from being added twice
1756 // fix in caller, assert here?
caryclark@google.com2ddff932012-08-07 21:25:27 +00001757 void addTPair(double t, Segment& other, double otherT, bool borrowWind) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001758 int tCount = fTs.count();
1759 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1760 const Span& span = fTs[tIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001761 if (!approximately_negative(span.fT - t)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001762 break;
1763 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001764 if (approximately_negative(span.fT - t) && span.fOther == &other
1765 && approximately_equal(span.fOtherT, otherT)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001766#if DEBUG_ADD_T_PAIR
1767 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1768 __FUNCTION__, fID, t, other.fID, otherT);
1769#endif
1770 return;
1771 }
1772 }
caryclark@google.com47580692012-07-23 12:14:49 +00001773#if DEBUG_ADD_T_PAIR
1774 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1775 __FUNCTION__, fID, t, other.fID, otherT);
1776#endif
caryclark@google.comb9738012012-07-03 19:53:30 +00001777 int insertedAt = addT(t, &other);
1778 int otherInsertedAt = other.addT(otherT, this);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001779 addOtherT(insertedAt, otherT, otherInsertedAt);
caryclark@google.comb9738012012-07-03 19:53:30 +00001780 other.addOtherT(otherInsertedAt, t, insertedAt);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001781 matchWindingValue(insertedAt, t, borrowWind);
1782 other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001783 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001784
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001785 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001786 // add edge leading into junction
caryclark@google.com4eeda372012-12-06 21:47:48 +00001787 int min = SkMin32(end, start);
1788 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001789 addAngle(angles, end, start);
1790 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001791 // add edge leading away from junction
caryclark@google.com495f8e42012-05-31 13:13:11 +00001792 int step = SkSign32(end - start);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001793 int tIndex = nextExactSpan(end, step);
caryclark@google.com4eeda372012-12-06 21:47:48 +00001794 min = SkMin32(end, tIndex);
1795 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001796 addAngle(angles, end, tIndex);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001797 }
1798 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001799
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001800 int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
1801 Span* const test = &fTs[index];
1802 Span* end = test;
1803 do {
1804 end = &fTs[++index];
1805 } while (approximately_negative(end->fT - test->fT));
1806 return index;
1807 }
1808
1809 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
1810 Span* const oTest = &fTs[oIndex];
1811 Span* oEnd = oTest;
1812 const double oStartT = oTest->fT;
1813 while (!approximately_negative(oEndT - oEnd->fT)
1814 && approximately_negative(oEnd->fT - oStartT)) {
1815 oEnd = &fTs[++oIndex];
1816 }
1817 return oIndex;
1818 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00001819
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001820 bool betweenTs(int lesser, double testT, int greater) {
1821 if (lesser > greater) {
1822 SkTSwap<int>(lesser, greater);
1823 }
1824 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
1825 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001826
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001827 const Bounds& bounds() const {
1828 return fBounds;
1829 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001830
caryclark@google.com31143cf2012-11-09 22:14:19 +00001831 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001832 double referenceT = fTs[index].fT;
1833 int lesser = index;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001834 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
1835 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00001836 buildAnglesInner(lesser, angles);
1837 }
1838 do {
1839 buildAnglesInner(index, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001840 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
1841 && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001842 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001843
1844 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
1845 Span* span = &fTs[index];
1846 Segment* other = span->fOther;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001847 // if there is only one live crossing, and no coincidence, continue
1848 // in the same direction
1849 // if there is coincidence, the only choice may be to reverse direction
1850 // find edge on either side of intersection
1851 int oIndex = span->fOtherIndex;
1852 // if done == -1, prior span has already been processed
1853 int step = 1;
caryclark@google.coma461ff02012-10-11 12:54:23 +00001854 int next = other->nextExactSpan(oIndex, step);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001855 if (next < 0) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001856 step = -step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00001857 next = other->nextExactSpan(oIndex, step);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001858 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001859 // add candidate into and away from junction
1860 other->addTwoAngles(next, oIndex, angles);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001861 }
1862
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001863 int computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001864 SkTDArray<Angle> angles;
1865 addTwoAngles(startIndex, endIndex, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001866 buildAngles(endIndex, angles, false);
caryclark@google.comd1688742012-09-18 20:08:37 +00001867 // OPTIMIZATION: check all angles to see if any have computed wind sum
1868 // before sorting (early exit if none)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001869 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001870 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00001871#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00001872 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00001873#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001874 if (!sortable) {
1875 return SK_MinS32;
1876 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001877 int angleCount = angles.count();
1878 const Angle* angle;
1879 const Segment* base;
1880 int winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001881 int oWinding;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001882 int firstIndex = 0;
1883 do {
1884 angle = sorted[firstIndex];
1885 base = angle->segment();
1886 winding = base->windSum(angle);
1887 if (winding != SK_MinS32) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001888 oWinding = base->oppSum(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001889 break;
1890 }
1891 if (++firstIndex == angleCount) {
1892 return SK_MinS32;
1893 }
1894 } while (true);
1895 // turn winding into contourWinding
caryclark@google.com2ddff932012-08-07 21:25:27 +00001896 int spanWinding = base->spanSign(angle);
1897 bool inner = useInnerWinding(winding + spanWinding, winding);
1898 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00001899 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
caryclark@google.com59823f72012-08-09 18:17:47 +00001900 spanWinding, winding, angle->sign(), inner,
caryclark@google.com2ddff932012-08-07 21:25:27 +00001901 inner ? winding + spanWinding : winding);
1902 #endif
1903 if (inner) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001904 winding += spanWinding;
1905 }
1906 #if DEBUG_SORT
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001907 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001908 #endif
1909 int nextIndex = firstIndex + 1;
1910 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com2ddff932012-08-07 21:25:27 +00001911 winding -= base->spanSign(angle);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001912 oWinding -= base->oppSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001913 do {
1914 if (nextIndex == angleCount) {
1915 nextIndex = 0;
1916 }
1917 angle = sorted[nextIndex];
1918 Segment* segment = angle->segment();
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001919 bool opp = base->fOperand ^ segment->fOperand;
1920 int maxWinding, oMaxWinding;
1921 int spanSign = segment->spanSign(angle);
1922 int oppoSign = segment->oppSign(angle);
1923 if (opp) {
1924 oMaxWinding = oWinding;
1925 oWinding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00001926 maxWinding = winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001927 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001928 winding -= oppoSign;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001929 }
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001930 } else {
1931 maxWinding = winding;
1932 winding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00001933 oMaxWinding = oWinding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001934 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001935 oWinding -= oppoSign;
1936 }
1937 }
1938 if (segment->windSum(angle) == SK_MinS32) {
1939 if (opp) {
1940 if (useInnerWinding(oMaxWinding, oWinding)) {
1941 oMaxWinding = oWinding;
1942 }
1943 if (oppoSign && useInnerWinding(maxWinding, winding)) {
1944 maxWinding = winding;
1945 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001946 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001947 } else {
1948 if (useInnerWinding(maxWinding, winding)) {
1949 maxWinding = winding;
1950 }
1951 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
1952 oMaxWinding = oWinding;
1953 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001954 (void) segment->markAndChaseWinding(angle, maxWinding,
1955 binary ? oMaxWinding : 0);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001956 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001957 }
1958 } while (++nextIndex != lastIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00001959 int minIndex = SkMin32(startIndex, endIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00001960 return windSum(minIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001961 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001962
caryclark@google.com3586ece2012-12-27 18:46:58 +00001963 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
caryclark@google.com10227bf2012-12-28 22:10:41 +00001964 double mid, bool opp, bool current) const {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001965 SkScalar bottom = fBounds.fBottom;
caryclark@google.com10227bf2012-12-28 22:10:41 +00001966 int bestTIndex = -1;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001967 if (bottom <= bestY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00001968 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001969 }
1970 SkScalar top = fBounds.fTop;
1971 if (top >= basePt.fY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00001972 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001973 }
1974 if (fBounds.fLeft > basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00001975 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001976 }
1977 if (fBounds.fRight < basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00001978 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001979 }
1980 if (fBounds.fLeft == fBounds.fRight) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001981 // if vertical, and directly above test point, wait for another one
1982 return approximately_equal(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001983 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00001984 // intersect ray starting at basePt with edge
1985 Intersections intersections;
1986 // OPTIMIZE: use specialty function that intersects ray with curve,
1987 // returning t values only for curve (we don't care about t on ray)
1988 int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
1989 if (pts == 0 || (current && pts == 1)) {
1990 return bestTIndex;
1991 }
1992 if (current) {
1993 SkASSERT(pts > 1);
1994 int closestIdx = 0;
1995 double closest = fabs(intersections.fT[0][0] - mid);
1996 for (int idx = 1; idx < pts; ++idx) {
1997 double test = fabs(intersections.fT[0][idx] - mid);
1998 if (closest > test) {
1999 closestIdx = idx;
2000 closest = test;
2001 }
2002 }
2003 if (closestIdx < pts - 1) {
2004 intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
2005 }
2006 --pts;
2007 }
2008 double bestT = -1;
2009 for (int index = 0; index < pts; ++index) {
2010 double foundT = intersections.fT[0][index];
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002011 if (approximately_less_than_zero(foundT)
2012 || approximately_greater_than_one(foundT)) {
2013 continue;
2014 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002015 SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
2016 if (approximately_negative(testY - bestY)
2017 || approximately_negative(basePt.fY - testY)) {
caryclark@google.com47580692012-07-23 12:14:49 +00002018 continue;
2019 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002020 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002021 return SK_MinS32; // if the intersection is edge on, wait for another one
caryclark@google.com10227bf2012-12-28 22:10:41 +00002022 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002023 if (fVerb > SkPath::kLine_Verb) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002024 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
2025 if (approximately_zero(dx)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002026 return SK_MinS32; // hit vertical, wait for another one
caryclark@google.com3586ece2012-12-27 18:46:58 +00002027 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00002028 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002029 bestY = testY;
2030 bestT = foundT;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002031 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002032 if (bestT < 0) {
2033 return bestTIndex;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002034 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002035 SkASSERT(bestT >= 0);
2036 SkASSERT(bestT <= 1);
2037 int start;
2038 int end = 0;
2039 do {
2040 start = end;
2041 end = nextSpan(start, 1);
2042 } while (fTs[end].fT < bestT);
2043 // FIXME: see next candidate for a better pattern to find the next start/end pair
2044 while (start + 1 < end && fTs[start].fDone) {
2045 ++start;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002046 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002047 if (!isCanceled(start)) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002048 hitT = bestT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002049 bestTIndex = start;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002050 hitSomething = true;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002051 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002052 return bestTIndex;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002053 }
caryclark@google.com18063442012-07-25 12:05:18 +00002054
caryclark@google.com4eeda372012-12-06 21:47:48 +00002055 void decrementSpan(Span* span) {
caryclark@google.com18063442012-07-25 12:05:18 +00002056 SkASSERT(span->fWindValue > 0);
2057 if (--(span->fWindValue) == 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002058 if (!span->fOppValue && !span->fDone) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002059 span->fDone = true;
2060 ++fDoneSpans;
2061 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002062 }
2063 }
2064
2065 bool bumpSpan(Span* span, int windDelta, int oppDelta) {
2066 SkASSERT(!span->fDone);
2067 span->fWindValue += windDelta;
2068 SkASSERT(span->fWindValue >= 0);
2069 span->fOppValue += oppDelta;
2070 SkASSERT(span->fOppValue >= 0);
2071 if (fXor) {
2072 span->fWindValue &= 1;
2073 }
2074 if (fOppXor) {
2075 span->fOppValue &= 1;
2076 }
2077 if (!span->fWindValue && !span->fOppValue) {
2078 span->fDone = true;
2079 ++fDoneSpans;
caryclark@google.com18063442012-07-25 12:05:18 +00002080 return true;
2081 }
2082 return false;
2083 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002084
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002085 // OPTIMIZE
2086 // when the edges are initially walked, they don't automatically get the prior and next
2087 // 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 +00002088 // and would additionally remove the need for similar checks in condition edges. It would
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002089 // also allow intersection code to assume end of segment intersections (maybe?)
2090 bool complete() const {
2091 int count = fTs.count();
2092 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
2093 }
caryclark@google.com18063442012-07-25 12:05:18 +00002094
caryclark@google.com15fa1382012-05-07 20:49:36 +00002095 bool done() const {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002096 SkASSERT(fDoneSpans <= fTs.count());
2097 return fDoneSpans == fTs.count();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002098 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002099
caryclark@google.comf839c032012-10-26 21:03:50 +00002100 bool done(int min) const {
2101 return fTs[min].fDone;
2102 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002103
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002104 bool done(const Angle* angle) const {
2105 return done(SkMin32(angle->start(), angle->end()));
caryclark@google.com47580692012-07-23 12:14:49 +00002106 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00002107
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002108 bool equalPoints(int greaterTIndex, int lesserTIndex) {
2109 SkASSERT(greaterTIndex >= lesserTIndex);
2110 double greaterT = fTs[greaterTIndex].fT;
2111 double lesserT = fTs[lesserTIndex].fT;
2112 if (greaterT == lesserT) {
2113 return true;
2114 }
2115 if (!approximately_negative(greaterT - lesserT)) {
2116 return false;
2117 }
2118 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2119 }
2120
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002121 /*
2122 The M and S variable name parts stand for the operators.
2123 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2124 Su stands for Subtrahend
2125 The Opp variable name part designates that the value is for the Opposite operator.
2126 Opposite values result from combining coincident spans.
2127 */
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002128
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002129 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2130 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002131 const int startIndex = nextStart;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002132 const int endIndex = nextEnd;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002133 SkASSERT(startIndex != endIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002134 const int count = fTs.count();
2135 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2136 const int step = SkSign32(endIndex - startIndex);
2137 const int end = nextExactSpan(startIndex, step);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002138 SkASSERT(end >= 0);
2139 Span* endSpan = &fTs[end];
2140 Segment* other;
2141 if (isSimple(end)) {
2142 // mark the smaller of startIndex, endIndex done, and all adjacent
2143 // spans with the same T value (but not 'other' spans)
2144 #if DEBUG_WINDING
2145 SkDebugf("%s simple\n", __FUNCTION__);
2146 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002147 int min = SkMin32(startIndex, endIndex);
2148 if (fTs[min].fDone) {
2149 return NULL;
2150 }
2151 markDoneBinary(min);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002152 other = endSpan->fOther;
2153 nextStart = endSpan->fOtherIndex;
2154 double startT = other->fTs[nextStart].fT;
2155 nextEnd = nextStart;
2156 do {
2157 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002158 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002159 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002160 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2161 return other;
2162 }
2163 // more than one viable candidate -- measure angles to find best
2164 SkTDArray<Angle> angles;
2165 SkASSERT(startIndex - endIndex != 0);
2166 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2167 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002168 buildAngles(end, angles, true);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002169 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002170 bool sortable = SortAngles(angles, sorted);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002171 int angleCount = angles.count();
2172 int firstIndex = findStartingEdge(sorted, startIndex, end);
2173 SkASSERT(firstIndex >= 0);
2174 #if DEBUG_SORT
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002175 debugShowSort(__FUNCTION__, sorted, firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002176 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002177 if (!sortable) {
2178 unsortable = true;
2179 return NULL;
2180 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002181 SkASSERT(sorted[firstIndex]->segment() == this);
2182 #if DEBUG_WINDING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002183 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2184 sorted[firstIndex]->sign());
caryclark@google.com235f56a2012-09-14 14:19:30 +00002185 #endif
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002186 int sumMiWinding = updateWinding(endIndex, startIndex);
2187 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2188 if (operand()) {
2189 SkTSwap<int>(sumMiWinding, sumSuWinding);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002190 }
2191 int nextIndex = firstIndex + 1;
2192 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2193 const Angle* foundAngle = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002194 bool foundDone = false;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002195 // iterate through the angle, and compute everyone's winding
caryclark@google.com235f56a2012-09-14 14:19:30 +00002196 Segment* nextSegment;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002197 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002198 SkASSERT(nextIndex != firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002199 if (nextIndex == angleCount) {
2200 nextIndex = 0;
2201 }
2202 const Angle* nextAngle = sorted[nextIndex];
2203 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002204 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2205 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2206 nextAngle->end(), op, sumMiWinding, sumSuWinding,
2207 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
2208 if (activeAngle && (!foundAngle || foundDone)) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002209 foundAngle = nextAngle;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002210 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002211 }
2212 if (nextSegment->done()) {
2213 continue;
2214 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002215 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2216 continue;
2217 }
2218 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2219 oppSumWinding, activeAngle, nextAngle);
2220 if (last) {
2221 *chase.append() = last;
2222#if DEBUG_WINDING
2223 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2224 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2225#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002226 }
2227 } while (++nextIndex != lastIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002228 markDoneBinary(SkMin32(startIndex, endIndex));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002229 if (!foundAngle) {
2230 return NULL;
2231 }
2232 nextStart = foundAngle->start();
2233 nextEnd = foundAngle->end();
2234 nextSegment = foundAngle->segment();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002235
caryclark@google.com235f56a2012-09-14 14:19:30 +00002236 #if DEBUG_WINDING
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002237 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2238 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002239 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002240 return nextSegment;
2241 }
caryclark@google.com47580692012-07-23 12:14:49 +00002242
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002243 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2244 bool& unsortable) {
2245 const int startIndex = nextStart;
2246 const int endIndex = nextEnd;
2247 SkASSERT(startIndex != endIndex);
2248 const int count = fTs.count();
2249 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2250 const int step = SkSign32(endIndex - startIndex);
2251 const int end = nextExactSpan(startIndex, step);
2252 SkASSERT(end >= 0);
2253 Span* endSpan = &fTs[end];
2254 Segment* other;
2255 if (isSimple(end)) {
2256 // mark the smaller of startIndex, endIndex done, and all adjacent
2257 // spans with the same T value (but not 'other' spans)
2258 #if DEBUG_WINDING
2259 SkDebugf("%s simple\n", __FUNCTION__);
2260 #endif
2261 int min = SkMin32(startIndex, endIndex);
2262 if (fTs[min].fDone) {
2263 return NULL;
2264 }
2265 markDoneUnary(min);
2266 other = endSpan->fOther;
2267 nextStart = endSpan->fOtherIndex;
2268 double startT = other->fTs[nextStart].fT;
2269 nextEnd = nextStart;
2270 do {
2271 nextEnd += step;
2272 }
2273 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2274 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2275 return other;
2276 }
2277 // more than one viable candidate -- measure angles to find best
2278 SkTDArray<Angle> angles;
2279 SkASSERT(startIndex - endIndex != 0);
2280 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2281 addTwoAngles(startIndex, end, angles);
2282 buildAngles(end, angles, true);
2283 SkTDArray<Angle*> sorted;
2284 bool sortable = SortAngles(angles, sorted);
2285 int angleCount = angles.count();
2286 int firstIndex = findStartingEdge(sorted, startIndex, end);
2287 SkASSERT(firstIndex >= 0);
2288 #if DEBUG_SORT
2289 debugShowSort(__FUNCTION__, sorted, firstIndex);
2290 #endif
2291 if (!sortable) {
2292 unsortable = true;
2293 return NULL;
2294 }
2295 SkASSERT(sorted[firstIndex]->segment() == this);
2296 #if DEBUG_WINDING
2297 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2298 sorted[firstIndex]->sign());
2299 #endif
2300 int sumWinding = updateWinding(endIndex, startIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002301 int nextIndex = firstIndex + 1;
2302 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2303 const Angle* foundAngle = NULL;
2304 bool foundDone = false;
2305 // iterate through the angle, and compute everyone's winding
2306 Segment* nextSegment;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002307 int activeCount = 0;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002308 do {
2309 SkASSERT(nextIndex != firstIndex);
2310 if (nextIndex == angleCount) {
2311 nextIndex = 0;
2312 }
2313 const Angle* nextAngle = sorted[nextIndex];
2314 nextSegment = nextAngle->segment();
2315 int maxWinding;
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00002316 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002317 maxWinding, sumWinding);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002318 if (activeAngle) {
2319 ++activeCount;
2320 if (!foundAngle || (foundDone && activeCount & 1)) {
2321 if (nextSegment->tiny(nextAngle)) {
2322 unsortable = true;
2323 return NULL;
2324 }
2325 foundAngle = nextAngle;
2326 foundDone = nextSegment->done(nextAngle);
2327 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002328 }
2329 if (nextSegment->done()) {
2330 continue;
2331 }
2332 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2333 continue;
2334 }
2335 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2336 if (last) {
2337 *chase.append() = last;
2338#if DEBUG_WINDING
2339 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2340 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2341#endif
2342 }
2343 } while (++nextIndex != lastIndex);
2344 markDoneUnary(SkMin32(startIndex, endIndex));
2345 if (!foundAngle) {
2346 return NULL;
2347 }
2348 nextStart = foundAngle->start();
2349 nextEnd = foundAngle->end();
2350 nextSegment = foundAngle->segment();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002351 #if DEBUG_WINDING
2352 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2353 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2354 #endif
2355 return nextSegment;
2356 }
2357
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002358 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002359 const int startIndex = nextStart;
2360 const int endIndex = nextEnd;
2361 SkASSERT(startIndex != endIndex);
2362 int count = fTs.count();
2363 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2364 : startIndex > 0);
2365 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002366 int end = nextExactSpan(startIndex, step);
caryclark@google.com24bec792012-08-20 12:43:57 +00002367 SkASSERT(end >= 0);
2368 Span* endSpan = &fTs[end];
2369 Segment* other;
caryclark@google.com24bec792012-08-20 12:43:57 +00002370 if (isSimple(end)) {
2371 #if DEBUG_WINDING
2372 SkDebugf("%s simple\n", __FUNCTION__);
2373 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002374 int min = SkMin32(startIndex, endIndex);
2375 if (fTs[min].fDone) {
2376 return NULL;
2377 }
2378 markDone(min, 1);
caryclark@google.com24bec792012-08-20 12:43:57 +00002379 other = endSpan->fOther;
2380 nextStart = endSpan->fOtherIndex;
2381 double startT = other->fTs[nextStart].fT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002382 #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 +00002383 SkDEBUGCODE(bool firstLoop = true;)
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002384 if ((approximately_less_than_zero(startT) && step < 0)
2385 || (approximately_greater_than_one(startT) && step > 0)) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002386 step = -step;
2387 SkDEBUGCODE(firstLoop = false;)
2388 }
2389 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002390 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002391 nextEnd = nextStart;
2392 do {
2393 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002394 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002395 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002396 #if 01
caryclark@google.com24bec792012-08-20 12:43:57 +00002397 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2398 break;
2399 }
caryclark@google.com03f97062012-08-21 13:13:52 +00002400 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00002401 SkASSERT(firstLoop);
caryclark@google.com03f97062012-08-21 13:13:52 +00002402 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002403 SkDEBUGCODE(firstLoop = false;)
2404 step = -step;
2405 } while (true);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002406 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002407 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2408 return other;
2409 }
2410 SkTDArray<Angle> angles;
2411 SkASSERT(startIndex - endIndex != 0);
2412 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2413 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002414 buildAngles(end, angles, false);
caryclark@google.com24bec792012-08-20 12:43:57 +00002415 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002416 bool sortable = SortAngles(angles, sorted);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002417 if (!sortable) {
2418 unsortable = true;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002419 #if DEBUG_SORT
2420 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
2421 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002422 return NULL;
2423 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002424 int angleCount = angles.count();
2425 int firstIndex = findStartingEdge(sorted, startIndex, end);
2426 SkASSERT(firstIndex >= 0);
2427 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002428 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
caryclark@google.com24bec792012-08-20 12:43:57 +00002429 #endif
2430 SkASSERT(sorted[firstIndex]->segment() == this);
2431 int nextIndex = firstIndex + 1;
2432 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002433 const Angle* foundAngle = NULL;
2434 bool foundDone = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002435 Segment* nextSegment;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002436 int activeCount = 0;
caryclark@google.com24bec792012-08-20 12:43:57 +00002437 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002438 SkASSERT(nextIndex != firstIndex);
caryclark@google.com24bec792012-08-20 12:43:57 +00002439 if (nextIndex == angleCount) {
2440 nextIndex = 0;
2441 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002442 const Angle* nextAngle = sorted[nextIndex];
caryclark@google.com24bec792012-08-20 12:43:57 +00002443 nextSegment = nextAngle->segment();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002444 ++activeCount;
2445 if (!foundAngle || (foundDone && activeCount & 1)) {
2446 if (nextSegment->tiny(nextAngle)) {
2447 unsortable = true;
2448 return NULL;
2449 }
2450 foundAngle = nextAngle;
2451 foundDone = nextSegment->done(nextAngle);
2452 }
2453 if (nextSegment->done()) {
2454 continue;
caryclark@google.com24bec792012-08-20 12:43:57 +00002455 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002456 } while (++nextIndex != lastIndex);
2457 markDone(SkMin32(startIndex, endIndex), 1);
2458 if (!foundAngle) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002459 return NULL;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002460 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002461 nextStart = foundAngle->start();
2462 nextEnd = foundAngle->end();
2463 nextSegment = foundAngle->segment();
2464 #if DEBUG_WINDING
2465 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2466 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2467 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002468 return nextSegment;
2469 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002470
2471 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2472 int angleCount = sorted.count();
2473 int firstIndex = -1;
2474 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2475 const Angle* angle = sorted[angleIndex];
2476 if (angle->segment() == this && angle->start() == end &&
2477 angle->end() == start) {
2478 firstIndex = angleIndex;
2479 break;
2480 }
2481 }
2482 return firstIndex;
2483 }
2484
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002485 // FIXME: this is tricky code; needs its own unit test
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002486 // note that fOtherIndex isn't computed yet, so it can't be used here
caryclark@google.com4eeda372012-12-06 21:47:48 +00002487 void findTooCloseToCall() {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002488 int count = fTs.count();
2489 if (count < 3) { // require t=0, x, 1 at minimum
2490 return;
2491 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002492 int matchIndex = 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002493 int moCount;
2494 Span* match;
2495 Segment* mOther;
2496 do {
2497 match = &fTs[matchIndex];
2498 mOther = match->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002499 // FIXME: allow quads, cubics to be near coincident?
2500 if (mOther->fVerb == SkPath::kLine_Verb) {
2501 moCount = mOther->fTs.count();
2502 if (moCount >= 3) {
2503 break;
2504 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002505 }
2506 if (++matchIndex >= count) {
2507 return;
2508 }
2509 } while (true); // require t=0, x, 1 at minimum
caryclark@google.com15fa1382012-05-07 20:49:36 +00002510 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002511 const SkPoint* matchPt = &xyAtT(match);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002512 // look for a pair of nearby T values that map to the same (x,y) value
2513 // if found, see if the pair of other segments share a common point. If
2514 // so, the span from here to there is coincident.
caryclark@google.com15fa1382012-05-07 20:49:36 +00002515 for (int index = matchIndex + 1; index < count; ++index) {
2516 Span* test = &fTs[index];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002517 if (test->fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002518 continue;
2519 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002520 Segment* tOther = test->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002521 if (tOther->fVerb != SkPath::kLine_Verb) {
2522 continue; // FIXME: allow quads, cubics to be near coincident?
2523 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002524 int toCount = tOther->fTs.count();
2525 if (toCount < 3) { // require t=0, x, 1 at minimum
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002526 continue;
2527 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002528 const SkPoint* testPt = &xyAtT(test);
2529 if (*matchPt != *testPt) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002530 matchIndex = index;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002531 moCount = toCount;
2532 match = test;
2533 mOther = tOther;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002534 matchPt = testPt;
2535 continue;
2536 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002537 int moStart = -1;
2538 int moEnd = -1;
2539 double moStartT, moEndT;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002540 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002541 Span& moSpan = mOther->fTs[moIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002542 if (moSpan.fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002543 continue;
2544 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002545 if (moSpan.fOther == this) {
2546 if (moSpan.fOtherT == match->fT) {
2547 moStart = moIndex;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002548 moStartT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002549 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002550 continue;
2551 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002552 if (moSpan.fOther == tOther) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002553 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002554 moStart = -1;
2555 break;
2556 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002557 SkASSERT(moEnd == -1);
2558 moEnd = moIndex;
2559 moEndT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002560 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002561 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002562 if (moStart < 0 || moEnd < 0) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002563 continue;
2564 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002565 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002566 if (approximately_equal(moStartT, moEndT)) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002567 continue;
2568 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002569 int toStart = -1;
2570 int toEnd = -1;
2571 double toStartT, toEndT;
2572 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2573 Span& toSpan = tOther->fTs[toIndex];
caryclark@google.comc899ad92012-08-23 15:24:42 +00002574 if (toSpan.fDone) {
2575 continue;
2576 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002577 if (toSpan.fOther == this) {
2578 if (toSpan.fOtherT == test->fT) {
2579 toStart = toIndex;
2580 toStartT = toSpan.fT;
2581 }
2582 continue;
2583 }
2584 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002585 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002586 moStart = -1;
2587 break;
2588 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002589 SkASSERT(toEnd == -1);
2590 toEnd = toIndex;
2591 toEndT = toSpan.fT;
2592 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002593 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002594 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2595 if (toStart <= 0 || toEnd <= 0) {
2596 continue;
2597 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002598 if (approximately_equal(toStartT, toEndT)) {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002599 continue;
2600 }
2601 // test to see if the segment between there and here is linear
2602 if (!mOther->isLinear(moStart, moEnd)
2603 || !tOther->isLinear(toStart, toEnd)) {
2604 continue;
2605 }
caryclark@google.comc899ad92012-08-23 15:24:42 +00002606 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002607 if (flipped) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002608 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002609 } else {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002610 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002611 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002612 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002613 }
2614
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002615 // start here;
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00002616 // either:
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002617 // a) mark spans with either end unsortable as done, or
2618 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2619 // when encountering an unsortable span
2620
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002621 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2622 // and use more concise logic like the old edge walker code?
2623 // FIXME: this needs to deal with coincident edges
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002624 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002625 // iterate through T intersections and return topmost
2626 // topmost tangent from y-min to first pt is closer to horizontal
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002627 SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002628 int firstT = -1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002629 SkPoint topPt;
2630 topPt.fY = SK_ScalarMax;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002631 int count = fTs.count();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002632 // see if either end is not done since we want smaller Y of the pair
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002633 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002634 bool lastUnsortable = false;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002635 for (int index = 0; index < count; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002636 const Span& span = fTs[index];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002637 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002638 goto next;
2639 }
2640 if (!span.fDone | !lastDone) {
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002641 const SkPoint& intercept = xyAtT(&span);
2642 if (topPt.fY > intercept.fY || (topPt.fY == intercept.fY
2643 && topPt.fX > intercept.fX)) {
2644 topPt = intercept;
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002645 firstT = index;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002646 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002647 }
caryclark@google.comf839c032012-10-26 21:03:50 +00002648 next:
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002649 lastDone = span.fDone;
caryclark@google.comf839c032012-10-26 21:03:50 +00002650 lastUnsortable = span.fUnsortableEnd;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002651 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002652 SkASSERT(firstT >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002653 // sort the edges to find the leftmost
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002654 int step = 1;
2655 int end = nextSpan(firstT, step);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002656 if (end == -1) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002657 step = -1;
2658 end = nextSpan(firstT, step);
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00002659 SkASSERT(end != -1);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002660 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002661 // if the topmost T is not on end, or is three-way or more, find left
2662 // look for left-ness from tLeft to firstT (matching y of other)
2663 SkTDArray<Angle> angles;
2664 SkASSERT(firstT - end != 0);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002665 addTwoAngles(end, firstT, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002666 buildAngles(firstT, angles, true);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002667 SkTDArray<Angle*> sorted;
caryclark@google.comf839c032012-10-26 21:03:50 +00002668 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002669 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002670 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002671 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002672 if (onlySortable && !sortable) {
2673 unsortable = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002674 return NULL;
2675 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002676 // skip edges that have already been processed
2677 firstT = -1;
2678 Segment* leftSegment;
2679 do {
2680 const Angle* angle = sorted[++firstT];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002681 SkASSERT(!onlySortable || !angle->unsortable());
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002682 leftSegment = angle->segment();
2683 tIndex = angle->end();
2684 endIndex = angle->start();
2685 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002686 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002687 return leftSegment;
2688 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002689
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002690 // FIXME: not crazy about this
2691 // when the intersections are performed, the other index is into an
2692 // incomplete array. as the array grows, the indices become incorrect
2693 // while the following fixes the indices up again, it isn't smart about
2694 // skipping segments whose indices are already correct
2695 // assuming we leave the code that wrote the index in the first place
2696 void fixOtherTIndex() {
2697 int iCount = fTs.count();
2698 for (int i = 0; i < iCount; ++i) {
2699 Span& iSpan = fTs[i];
2700 double oT = iSpan.fOtherT;
2701 Segment* other = iSpan.fOther;
2702 int oCount = other->fTs.count();
2703 for (int o = 0; o < oCount; ++o) {
2704 Span& oSpan = other->fTs[o];
2705 if (oT == oSpan.fT && this == oSpan.fOther) {
2706 iSpan.fOtherIndex = o;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002707 break;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002708 }
2709 }
2710 }
2711 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002712
caryclark@google.com4eeda372012-12-06 21:47:48 +00002713 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002714 fDoneSpans = 0;
2715 fOperand = operand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00002716 fXor = evenOdd;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002717 fPts = pts;
2718 fVerb = verb;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002719 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00002720
caryclark@google.com3586ece2012-12-27 18:46:58 +00002721 void initWinding(int start, int end) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002722 int local = spanSign(start, end);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002723 int oppLocal = oppSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002724 (void) markAndChaseWinding(start, end, local, oppLocal);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002725 }
2726
caryclark@google.com3586ece2012-12-27 18:46:58 +00002727 void initWinding(int start, int end, int winding, int oppWinding) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002728 int local = spanSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002729 if (local * winding >= 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002730 winding += local;
2731 }
2732 int oppLocal = oppSign(start, end);
2733 if (oppLocal * oppWinding >= 0) {
2734 oppWinding += oppLocal;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002735 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002736 (void) markAndChaseWinding(start, end, winding, oppWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002737 }
2738
caryclark@google.com3586ece2012-12-27 18:46:58 +00002739/*
2740when we start with a vertical intersect, we try to use the dx to determine if the edge is to
2741the 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 +00002742sign or not. However, this isn't enough.
2743If 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 +00002744If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
2745from 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 +00002746the same winding is shared by both.
caryclark@google.com3586ece2012-12-27 18:46:58 +00002747*/
2748 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
2749 SkScalar hitOppDx) {
2750 SkASSERT(hitDx || !winding);
2751 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
2752 SkASSERT(dx);
2753 int windVal = windValue(SkMin32(start, end));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002754 #if DEBUG_WINDING_AT_T
2755 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
2756 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
2757 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002758 if (!winding) {
2759 winding = dx < 0 ? windVal : -windVal;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002760 } else if (winding * dx < 0) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00002761 int sideWind = winding + (dx < 0 ? windVal : -windVal);
2762 if (abs(winding) < abs(sideWind)) {
2763 winding = sideWind;
2764 }
2765 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002766 #if DEBUG_WINDING_AT_T
2767 SkDebugf(" winding=%d\n", winding);
2768 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002769 int oppLocal = oppSign(start, end);
2770 SkASSERT(hitOppDx || !oppWind || !oppLocal);
2771 int oppWindVal = oppValue(SkMin32(start, end));
2772 if (!oppWind) {
2773 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
2774 } else if (hitOppDx * dx >= 0) {
2775 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
2776 if (abs(oppWind) < abs(oppSideWind)) {
2777 oppWind = oppSideWind;
2778 }
2779 }
2780 (void) markAndChaseWinding(start, end, winding, oppWind);
2781 }
2782
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002783 bool intersected() const {
2784 return fTs.count() > 0;
2785 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002786
caryclark@google.com10227bf2012-12-28 22:10:41 +00002787 bool isCanceled(int tIndex) const {
2788 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
2789 }
2790
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002791 bool isConnected(int startIndex, int endIndex) const {
2792 return fTs[startIndex].fWindSum != SK_MinS32
2793 || fTs[endIndex].fWindSum != SK_MinS32;
2794 }
2795
caryclark@google.com235f56a2012-09-14 14:19:30 +00002796 bool isHorizontal() const {
2797 return fBounds.fTop == fBounds.fBottom;
2798 }
2799
caryclark@google.com15fa1382012-05-07 20:49:36 +00002800 bool isLinear(int start, int end) const {
2801 if (fVerb == SkPath::kLine_Verb) {
2802 return true;
2803 }
2804 if (fVerb == SkPath::kQuad_Verb) {
2805 SkPoint qPart[3];
2806 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
2807 return QuadIsLinear(qPart);
2808 } else {
2809 SkASSERT(fVerb == SkPath::kCubic_Verb);
2810 SkPoint cPart[4];
2811 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
2812 return CubicIsLinear(cPart);
2813 }
2814 }
caryclark@google.comb9738012012-07-03 19:53:30 +00002815
2816 // OPTIMIZE: successive calls could start were the last leaves off
2817 // or calls could specialize to walk forwards or backwards
2818 bool isMissing(double startT) const {
2819 size_t tCount = fTs.count();
2820 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002821 if (approximately_zero(startT - fTs[index].fT)) {
caryclark@google.comb9738012012-07-03 19:53:30 +00002822 return false;
2823 }
2824 }
2825 return true;
2826 }
2827
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002828 bool isSimple(int end) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002829 int count = fTs.count();
2830 if (count == 2) {
2831 return true;
2832 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002833 double t = fTs[end].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002834 if (approximately_less_than_zero(t)) {
2835 return !approximately_less_than_zero(fTs[1].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002836 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002837 if (approximately_greater_than_one(t)) {
2838 return !approximately_greater_than_one(fTs[count - 2].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002839 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002840 return false;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002841 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002842
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002843 bool isVertical() const {
2844 return fBounds.fLeft == fBounds.fRight;
2845 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00002846
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002847 bool isVertical(int start, int end) const {
2848 return (*SegmentVertical[fVerb])(fPts, start, end);
2849 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002850
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002851 SkScalar leftMost(int start, int end) const {
2852 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
2853 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002854
caryclark@google.com495f8e42012-05-31 13:13:11 +00002855 // this span is excluded by the winding rule -- chase the ends
2856 // as long as they are unambiguous to mark connections as done
2857 // and give them the same winding value
caryclark@google.com59823f72012-08-09 18:17:47 +00002858 Span* markAndChaseDone(const Angle* angle, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002859 int index = angle->start();
2860 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00002861 return markAndChaseDone(index, endIndex, winding);
2862 }
2863
caryclark@google.com31143cf2012-11-09 22:14:19 +00002864 Span* markAndChaseDone(int index, int endIndex, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002865 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002866 int min = SkMin32(index, endIndex);
2867 markDone(min, winding);
2868 Span* last;
2869 Segment* other = this;
2870 while ((other = other->nextChase(index, step, min, last))) {
2871 other->markDone(min, winding);
2872 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002873 return last;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002874 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002875
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002876 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
2877 int index = angle->start();
2878 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00002879 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002880 int min = SkMin32(index, endIndex);
2881 markDoneBinary(min, winding, oppWinding);
2882 Span* last;
2883 Segment* other = this;
2884 while ((other = other->nextChase(index, step, min, last))) {
2885 other->markDoneBinary(min, winding, oppWinding);
2886 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002887 return last;
2888 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002889
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002890 Span* markAndChaseDoneBinary(int index, int endIndex) {
2891 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002892 int min = SkMin32(index, endIndex);
2893 markDoneBinary(min);
2894 Span* last;
2895 Segment* other = this;
2896 while ((other = other->nextChase(index, step, min, last))) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002897 if (other->done()) {
2898 return NULL;
2899 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002900 other->markDoneBinary(min);
2901 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00002902 return last;
2903 }
2904
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002905 Span* markAndChaseDoneUnary(int index, int endIndex) {
2906 int step = SkSign32(endIndex - index);
2907 int min = SkMin32(index, endIndex);
2908 markDoneUnary(min);
2909 Span* last;
2910 Segment* other = this;
2911 while ((other = other->nextChase(index, step, min, last))) {
2912 if (other->done()) {
2913 return NULL;
2914 }
2915 other->markDoneUnary(min);
2916 }
2917 return last;
2918 }
2919
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002920 Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
2921 int index = angle->start();
2922 int endIndex = angle->end();
2923 return markAndChaseDone(index, endIndex, winding);
2924 }
2925
caryclark@google.com4eeda372012-12-06 21:47:48 +00002926 Span* markAndChaseWinding(const Angle* angle, const int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002927 int index = angle->start();
2928 int endIndex = angle->end();
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002929 int step = SkSign32(endIndex - index);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002930 int min = SkMin32(index, endIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00002931 markWinding(min, winding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002932 Span* last;
2933 Segment* other = this;
2934 while ((other = other->nextChase(index, step, min, last))) {
2935 if (other->fTs[min].fWindSum != SK_MinS32) {
2936 SkASSERT(other->fTs[min].fWindSum == winding);
2937 return NULL;
2938 }
2939 other->markWinding(min, winding);
2940 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002941 return last;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002942 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002943
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002944 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00002945 int min = SkMin32(index, endIndex);
2946 int step = SkSign32(endIndex - index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002947 markWinding(min, winding, oppWinding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002948 Span* last;
2949 Segment* other = this;
2950 while ((other = other->nextChase(index, step, min, last))) {
2951 if (other->fTs[min].fWindSum != SK_MinS32) {
2952 SkASSERT(other->fTs[min].fWindSum == winding);
2953 return NULL;
2954 }
2955 other->markWinding(min, winding, oppWinding);
2956 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00002957 return last;
2958 }
2959
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002960 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
2961 int start = angle->start();
2962 int end = angle->end();
2963 return markAndChaseWinding(start, end, winding, oppWinding);
2964 }
2965
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002966 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
2967 SkASSERT(angle->segment() == this);
2968 if (useInnerWinding(maxWinding, sumWinding)) {
2969 maxWinding = sumWinding;
2970 }
2971 Span* last;
2972 if (activeAngle) {
2973 last = markAndChaseWinding(angle, maxWinding);
2974 } else {
2975 last = markAndChaseDoneUnary(angle, maxWinding);
2976 }
2977 return last;
2978 }
2979
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002980 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
2981 bool activeAngle, const Angle* angle) {
2982 SkASSERT(angle->segment() == this);
2983 if (useInnerWinding(maxWinding, sumWinding)) {
2984 maxWinding = sumWinding;
2985 }
2986 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
2987 oppMaxWinding = oppSumWinding;
2988 }
2989 Span* last;
2990 if (activeAngle) {
2991 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
2992 } else {
2993 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
2994 }
2995 return last;
2996 }
2997
caryclark@google.com495f8e42012-05-31 13:13:11 +00002998 // FIXME: this should also mark spans with equal (x,y)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002999 // This may be called when the segment is already marked done. While this
3000 // wastes time, it shouldn't do any more than spin through the T spans.
rmistry@google.comd6176b02012-08-23 18:14:13 +00003001 // OPTIMIZATION: abort on first done found (assuming that this code is
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003002 // always called to mark segments done).
caryclark@google.com59823f72012-08-09 18:17:47 +00003003 void markDone(int index, int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003004 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003005 SkASSERT(winding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003006 double referenceT = fTs[index].fT;
3007 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003008 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3009 markOneDone(__FUNCTION__, lesser, winding);
3010 }
3011 do {
3012 markOneDone(__FUNCTION__, index, winding);
3013 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003014 }
3015
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003016 void markDoneBinary(int index, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003017 // SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003018 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003019 double referenceT = fTs[index].fT;
3020 int lesser = index;
3021 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003022 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003023 }
3024 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003025 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
3026 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3027 }
3028
3029 void markDoneBinary(int index) {
3030 double referenceT = fTs[index].fT;
3031 int lesser = index;
3032 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3033 markOneDoneBinary(__FUNCTION__, lesser);
3034 }
3035 do {
3036 markOneDoneBinary(__FUNCTION__, index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003037 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003038 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00003039
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003040 void markDoneUnary(int index, int winding) {
3041 // SkASSERT(!done());
3042 SkASSERT(winding);
3043 double referenceT = fTs[index].fT;
3044 int lesser = index;
3045 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3046 markOneDoneUnary(__FUNCTION__, lesser, winding);
3047 }
3048 do {
3049 markOneDoneUnary(__FUNCTION__, index, winding);
3050 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3051 }
3052
3053 void markDoneUnary(int index) {
3054 double referenceT = fTs[index].fT;
3055 int lesser = index;
3056 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3057 markOneDoneUnary(__FUNCTION__, lesser);
3058 }
3059 do {
3060 markOneDoneUnary(__FUNCTION__, index);
3061 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3062 }
3063
caryclark@google.com24bec792012-08-20 12:43:57 +00003064 void markOneDone(const char* funName, int tIndex, int winding) {
3065 Span* span = markOneWinding(funName, tIndex, winding);
3066 if (!span) {
3067 return;
3068 }
3069 span->fDone = true;
3070 fDoneSpans++;
3071 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003072
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003073 void markOneDoneBinary(const char* funName, int tIndex) {
3074 Span* span = verifyOneWinding(funName, tIndex);
3075 if (!span) {
3076 return;
3077 }
3078 span->fDone = true;
3079 fDoneSpans++;
3080 }
3081
3082 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003083 Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
3084 if (!span) {
3085 return;
3086 }
3087 span->fDone = true;
3088 fDoneSpans++;
3089 }
3090
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003091 void markOneDoneUnary(const char* funName, int tIndex) {
3092 Span* span = verifyOneWindingU(funName, tIndex);
3093 if (!span) {
3094 return;
3095 }
3096 span->fDone = true;
3097 fDoneSpans++;
3098 }
3099
3100 void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3101 Span* span = markOneWinding(funName, tIndex, winding);
3102 if (!span) {
3103 return;
3104 }
3105 span->fDone = true;
3106 fDoneSpans++;
3107 }
3108
caryclark@google.com24bec792012-08-20 12:43:57 +00003109 Span* markOneWinding(const char* funName, int tIndex, int winding) {
3110 Span& span = fTs[tIndex];
3111 if (span.fDone) {
3112 return NULL;
3113 }
3114 #if DEBUG_MARK_DONE
3115 debugShowNewWinding(funName, span, winding);
3116 #endif
3117 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com03f97062012-08-21 13:13:52 +00003118 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00003119 SkASSERT(abs(winding) <= gDebugMaxWindSum);
caryclark@google.com03f97062012-08-21 13:13:52 +00003120 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00003121 span.fWindSum = winding;
3122 return &span;
3123 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003124
caryclark@google.com31143cf2012-11-09 22:14:19 +00003125 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
3126 Span& span = fTs[tIndex];
3127 if (span.fDone) {
3128 return NULL;
3129 }
3130 #if DEBUG_MARK_DONE
3131 debugShowNewWinding(funName, span, winding, oppWinding);
3132 #endif
3133 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3134 #ifdef SK_DEBUG
3135 SkASSERT(abs(winding) <= gDebugMaxWindSum);
3136 #endif
3137 span.fWindSum = winding;
3138 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3139 #ifdef SK_DEBUG
3140 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
3141 #endif
3142 span.fOppSum = oppWinding;
3143 return &span;
3144 }
3145
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003146 Span* verifyOneWinding(const char* funName, int tIndex) {
3147 Span& span = fTs[tIndex];
3148 if (span.fDone) {
3149 return NULL;
3150 }
3151 #if DEBUG_MARK_DONE
3152 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3153 #endif
3154 SkASSERT(span.fWindSum != SK_MinS32);
3155 SkASSERT(span.fOppSum != SK_MinS32);
3156 return &span;
3157 }
3158
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003159 Span* verifyOneWindingU(const char* funName, int tIndex) {
3160 Span& span = fTs[tIndex];
3161 if (span.fDone) {
3162 return NULL;
3163 }
3164 #if DEBUG_MARK_DONE
3165 debugShowNewWinding(funName, span, span.fWindSum);
3166 #endif
3167 SkASSERT(span.fWindSum != SK_MinS32);
3168 return &span;
3169 }
3170
caryclark@google.comf839c032012-10-26 21:03:50 +00003171 // note that just because a span has one end that is unsortable, that's
3172 // not enough to mark it done. The other end may be sortable, allowing the
3173 // span to be added.
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003174 // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003175 void markUnsortable(int start, int end) {
3176 Span* span = &fTs[start];
3177 if (start < end) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003178#if DEBUG_UNSORTABLE
3179 SkDebugf("%s start id=%d [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fID, start,
3180 xAtT(start), yAtT(start));
3181#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003182 span->fUnsortableStart = true;
3183 } else {
3184 --span;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003185#if DEBUG_UNSORTABLE
3186 SkDebugf("%s end id=%d [%d] (%1.9g,%1.9g) next:(%1.9g,%1.9g)\n", __FUNCTION__, fID,
3187 start - 1, xAtT(start - 1), yAtT(start - 1), xAtT(start), yAtT(start));
3188#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003189 span->fUnsortableEnd = true;
3190 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003191 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003192 return;
3193 }
3194 span->fDone = true;
3195 fDoneSpans++;
3196 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003197
caryclark@google.com59823f72012-08-09 18:17:47 +00003198 void markWinding(int index, int winding) {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003199 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003200 SkASSERT(winding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003201 double referenceT = fTs[index].fT;
3202 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003203 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3204 markOneWinding(__FUNCTION__, lesser, winding);
3205 }
3206 do {
3207 markOneWinding(__FUNCTION__, index, winding);
3208 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003209 }
3210
3211 void markWinding(int index, int winding, int oppWinding) {
3212 // SkASSERT(!done());
caryclark@google.com4eeda372012-12-06 21:47:48 +00003213 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003214 double referenceT = fTs[index].fT;
3215 int lesser = index;
3216 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3217 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003218 }
3219 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003220 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3221 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003222 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003223
caryclark@google.com2ddff932012-08-07 21:25:27 +00003224 void matchWindingValue(int tIndex, double t, bool borrowWind) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003225 int nextDoorWind = SK_MaxS32;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003226 int nextOppWind = SK_MaxS32;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003227 if (tIndex > 0) {
3228 const Span& below = fTs[tIndex - 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003229 if (approximately_negative(t - below.fT)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003230 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003231 nextOppWind = below.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003232 }
3233 }
3234 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3235 const Span& above = fTs[tIndex + 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003236 if (approximately_negative(above.fT - t)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003237 nextDoorWind = above.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003238 nextOppWind = above.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003239 }
3240 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003241 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3242 const Span& below = fTs[tIndex - 1];
3243 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003244 nextOppWind = below.fOppValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003245 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003246 if (nextDoorWind != SK_MaxS32) {
3247 Span& newSpan = fTs[tIndex];
3248 newSpan.fWindValue = nextDoorWind;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003249 newSpan.fOppValue = nextOppWind;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003250 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003251 newSpan.fDone = true;
3252 ++fDoneSpans;
3253 }
3254 }
3255 }
3256
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003257 bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3258 // find bounds
3259 Bounds bounds;
3260 bounds.setPoint(xyAtT(index));
3261 bounds.add(xyAtT(endIndex));
3262 SkScalar width = bounds.width();
3263 SkScalar height = bounds.height();
3264 if (width > height) {
3265 if (approximately_negative(width)) {
3266 unsortable = true; // edge is too small to resolve meaningfully
3267 }
3268 return false;
3269 } else {
3270 if (approximately_negative(height)) {
3271 unsortable = true; // edge is too small to resolve meaningfully
3272 }
3273 return true;
3274 }
3275 }
3276
caryclark@google.com9764cc62012-07-12 19:29:45 +00003277 // return span if when chasing, two or more radiating spans are not done
3278 // OPTIMIZATION: ? multiple spans is detected when there is only one valid
3279 // candidate and the remaining spans have windValue == 0 (canceled by
3280 // coincidence). The coincident edges could either be removed altogether,
3281 // or this code could be more complicated in detecting this case. Worth it?
3282 bool multipleSpans(int end) const {
3283 return end > 0 && end < fTs.count() - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00003284 }
3285
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003286 bool nextCandidate(int& start, int& end) const {
caryclark@google.com10227bf2012-12-28 22:10:41 +00003287 while (fTs[end].fDone) {
3288 if (fTs[end].fT == 1) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003289 return false;
3290 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00003291 ++end;
3292 }
3293 start = end;
3294 end = nextExactSpan(start, 1);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003295 return true;
3296 }
3297
caryclark@google.com4eeda372012-12-06 21:47:48 +00003298 Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
3299 int end = nextExactSpan(index, step);
3300 SkASSERT(end >= 0);
3301 if (multipleSpans(end)) {
3302 last = &fTs[end];
3303 return NULL;
3304 }
3305 const Span& endSpan = fTs[end];
3306 Segment* other = endSpan.fOther;
3307 index = endSpan.fOtherIndex;
3308 int otherEnd = other->nextExactSpan(index, step);
3309 min = SkMin32(index, otherEnd);
3310 return other;
3311 }
3312
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003313 // This has callers for two different situations: one establishes the end
3314 // of the current span, and one establishes the beginning of the next span
3315 // (thus the name). When this is looking for the end of the current span,
3316 // coincidence is found when the beginning Ts contain -step and the end
3317 // contains step. When it is looking for the beginning of the next, the
3318 // first Ts found can be ignored and the last Ts should contain -step.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003319 // OPTIMIZATION: probably should split into two functions
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003320 int nextSpan(int from, int step) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003321 const Span& fromSpan = fTs[from];
caryclark@google.com495f8e42012-05-31 13:13:11 +00003322 int count = fTs.count();
3323 int to = from;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003324 while (step > 0 ? ++to < count : --to >= 0) {
3325 const Span& span = fTs[to];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003326 if (approximately_zero(span.fT - fromSpan.fT)) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003327 continue;
3328 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003329 return to;
3330 }
3331 return -1;
3332 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +00003333
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003334 // FIXME
3335 // this returns at any difference in T, vs. a preset minimum. It may be
3336 // that all callers to nextSpan should use this instead.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003337 // OPTIMIZATION splitting this into separate loops for up/down steps
3338 // would allow using precisely_negative instead of precisely_zero
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003339 int nextExactSpan(int from, int step) const {
3340 const Span& fromSpan = fTs[from];
3341 int count = fTs.count();
3342 int to = from;
3343 while (step > 0 ? ++to < count : --to >= 0) {
3344 const Span& span = fTs[to];
caryclark@google.coma461ff02012-10-11 12:54:23 +00003345 if (precisely_zero(span.fT - fromSpan.fT)) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003346 continue;
3347 }
3348 return to;
3349 }
3350 return -1;
3351 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003352
caryclark@google.com235f56a2012-09-14 14:19:30 +00003353 bool operand() const {
3354 return fOperand;
3355 }
3356
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003357 int oppSign(const Angle* angle) const {
3358 SkASSERT(angle->segment() == this);
3359 return oppSign(angle->start(), angle->end());
3360 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003361
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003362 int oppSign(int startIndex, int endIndex) const {
3363 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3364 : fTs[endIndex].fOppValue;
3365#if DEBUG_WIND_BUMP
3366 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3367#endif
3368 return result;
3369 }
3370
caryclark@google.com31143cf2012-11-09 22:14:19 +00003371 int oppSum(int tIndex) const {
3372 return fTs[tIndex].fOppSum;
3373 }
3374
3375 int oppSum(const Angle* angle) const {
3376 int lesser = SkMin32(angle->start(), angle->end());
3377 return fTs[lesser].fOppSum;
caryclark@google.com235f56a2012-09-14 14:19:30 +00003378 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003379
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003380 int oppValue(int tIndex) const {
3381 return fTs[tIndex].fOppValue;
3382 }
3383
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003384 int oppValue(const Angle* angle) const {
3385 int lesser = SkMin32(angle->start(), angle->end());
3386 return fTs[lesser].fOppValue;
3387 }
3388
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003389 const SkPoint* pts() const {
3390 return fPts;
3391 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003392
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003393 void reset() {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003394 init(NULL, (SkPath::Verb) -1, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003395 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3396 fTs.reset();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003397 }
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +00003398
caryclark@google.com4eeda372012-12-06 21:47:48 +00003399 void setOppXor(bool isOppXor) {
3400 fOppXor = isOppXor;
3401 }
3402
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003403 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3404 int deltaSum = spanSign(index, endIndex);
3405 maxWinding = sumWinding;
3406 sumWinding = sumWinding -= deltaSum;
3407 }
3408
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003409 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3410 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3411 int deltaSum = spanSign(index, endIndex);
3412 int oppDeltaSum = oppSign(index, endIndex);
3413 if (operand()) {
3414 maxWinding = sumSuWinding;
3415 sumWinding = sumSuWinding -= deltaSum;
3416 oppMaxWinding = sumMiWinding;
3417 oppSumWinding = sumMiWinding -= oppDeltaSum;
3418 } else {
3419 maxWinding = sumMiWinding;
3420 sumWinding = sumMiWinding -= deltaSum;
3421 oppMaxWinding = sumSuWinding;
3422 oppSumWinding = sumSuWinding -= oppDeltaSum;
3423 }
3424 }
3425
caryclark@google.comf839c032012-10-26 21:03:50 +00003426 // This marks all spans unsortable so that this info is available for early
3427 // exclusion in find top and others. This could be optimized to only mark
3428 // adjacent spans that unsortable. However, this makes it difficult to later
3429 // determine starting points for edge detection in find top and the like.
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003430 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
caryclark@google.comf839c032012-10-26 21:03:50 +00003431 bool sortable = true;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003432 int angleCount = angles.count();
3433 int angleIndex;
3434 angleList.setReserve(angleCount);
3435 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003436 Angle& angle = angles[angleIndex];
caryclark@google.comf839c032012-10-26 21:03:50 +00003437 *angleList.append() = &angle;
3438 sortable &= !angle.unsortable();
3439 }
3440 if (sortable) {
3441 QSort<Angle>(angleList.begin(), angleList.end() - 1);
3442 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3443 if (angles[angleIndex].unsortable()) {
3444 sortable = false;
3445 break;
3446 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003447 }
3448 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003449 if (!sortable) {
3450 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3451 Angle& angle = angles[angleIndex];
3452 angle.segment()->markUnsortable(angle.start(), angle.end());
3453 }
3454 }
3455 return sortable;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003456 }
3457
caryclark@google.com1577e8f2012-05-22 17:01:14 +00003458 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003459 const Span& span(int tIndex) const {
3460 return fTs[tIndex];
3461 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003462
caryclark@google.com235f56a2012-09-14 14:19:30 +00003463 int spanSign(const Angle* angle) const {
3464 SkASSERT(angle->segment() == this);
3465 return spanSign(angle->start(), angle->end());
3466 }
3467
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003468 int spanSign(int startIndex, int endIndex) const {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003469 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3470 : fTs[endIndex].fWindValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003471#if DEBUG_WIND_BUMP
3472 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3473#endif
3474 return result;
3475 }
3476
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003477 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003478 double t(int tIndex) const {
3479 return fTs[tIndex].fT;
3480 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003481
caryclark@google.com10227bf2012-12-28 22:10:41 +00003482 double tAtMid(int start, int end, double mid) const {
3483 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
3484 }
3485
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003486 bool tiny(const Angle* angle) const {
3487 int start = angle->start();
3488 int end = angle->end();
caryclark@google.comf839c032012-10-26 21:03:50 +00003489 const Span& mSpan = fTs[SkMin32(start, end)];
3490 return mSpan.fTiny;
3491 }
3492
caryclark@google.com18063442012-07-25 12:05:18 +00003493 static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3494 double start) {
3495 int outCount = outsideTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003496 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
caryclark@google.com18063442012-07-25 12:05:18 +00003497 *outsideTs.append() = end;
3498 *outsideTs.append() = start;
3499 }
3500 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003501
caryclark@google.com24bec792012-08-20 12:43:57 +00003502 void undoneSpan(int& start, int& end) {
3503 size_t tCount = fTs.count();
3504 size_t index;
3505 for (index = 0; index < tCount; ++index) {
3506 if (!fTs[index].fDone) {
3507 break;
3508 }
3509 }
3510 SkASSERT(index < tCount - 1);
3511 start = index;
3512 double startT = fTs[index].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003513 while (approximately_negative(fTs[++index].fT - startT))
caryclark@google.com24bec792012-08-20 12:43:57 +00003514 SkASSERT(index < tCount);
3515 SkASSERT(index < tCount);
3516 end = index;
3517 }
caryclark@google.com18063442012-07-25 12:05:18 +00003518
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003519 bool unsortable(int index) const {
3520 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3521 }
3522
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003523 void updatePts(const SkPoint pts[]) {
3524 fPts = pts;
3525 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003526
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003527 int updateOppWinding(int index, int endIndex) const {
3528 int lesser = SkMin32(index, endIndex);
3529 int oppWinding = oppSum(lesser);
3530 int oppSpanWinding = oppSign(index, endIndex);
3531 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)) {
3532 oppWinding -= oppSpanWinding;
3533 }
3534 return oppWinding;
3535 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003536
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003537 int updateOppWinding(const Angle* angle) const {
3538 int startIndex = angle->start();
3539 int endIndex = angle->end();
3540 return updateOppWinding(endIndex, startIndex);
3541 }
3542
3543 int updateOppWindingReverse(const Angle* angle) const {
3544 int startIndex = angle->start();
3545 int endIndex = angle->end();
3546 return updateOppWinding(startIndex, endIndex);
3547 }
3548
3549 int updateWinding(int index, int endIndex) const {
3550 int lesser = SkMin32(index, endIndex);
3551 int winding = windSum(lesser);
3552 int spanWinding = spanSign(index, endIndex);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003553 if (winding && useInnerWinding(winding - spanWinding, winding)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003554 winding -= spanWinding;
3555 }
3556 return winding;
3557 }
3558
3559 int updateWinding(const Angle* angle) const {
3560 int startIndex = angle->start();
3561 int endIndex = angle->end();
3562 return updateWinding(endIndex, startIndex);
3563 }
3564
3565 int updateWindingReverse(const Angle* angle) const {
3566 int startIndex = angle->start();
3567 int endIndex = angle->end();
3568 return updateWinding(startIndex, endIndex);
3569 }
3570
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003571 SkPath::Verb verb() const {
3572 return fVerb;
3573 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003574
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003575 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003576 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3577 return SK_MinS32;
3578 }
3579 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3580 SkASSERT(winding != SK_MinS32);
3581 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003582 #if DEBUG_WINDING_AT_T
3583 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003584 #endif
3585 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark@google.com3586ece2012-12-27 18:46:58 +00003586 dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003587 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3588 dx = fPts[2].fX - fPts[1].fX - dx;
3589 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003590 if (dx == 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003591 #if DEBUG_WINDING_AT_T
3592 SkDebugf(" dx=0 winding=SK_MinS32\n");
3593 #endif
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003594 return SK_MinS32;
3595 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003596 if (winding * dx > 0) { // if same signs, result is negative
3597 winding += dx > 0 ? -windVal : windVal;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003598 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003599 #if DEBUG_WINDING_AT_T
3600 SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding);
3601 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003602 return winding;
3603 }
3604
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003605 int windSum(int tIndex) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003606 return fTs[tIndex].fWindSum;
3607 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003608
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003609 int windSum(const Angle* angle) const {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003610 int start = angle->start();
3611 int end = angle->end();
3612 int index = SkMin32(start, end);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003613 return windSum(index);
caryclark@google.com495f8e42012-05-31 13:13:11 +00003614 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003615
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003616 int windValue(int tIndex) const {
3617 return fTs[tIndex].fWindValue;
3618 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003619
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003620 int windValue(const Angle* angle) const {
3621 int start = angle->start();
3622 int end = angle->end();
3623 int index = SkMin32(start, end);
3624 return windValue(index);
3625 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00003626
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003627 int windValueAt(double t) const {
3628 int count = fTs.count();
3629 for (int index = 0; index < count; ++index) {
3630 if (fTs[index].fT == t) {
3631 return fTs[index].fWindValue;
3632 }
3633 }
3634 SkASSERT(0);
3635 return 0;
3636 }
3637
caryclark@google.com3586ece2012-12-27 18:46:58 +00003638 SkScalar xAtT(int index) const {
3639 return xAtT(&fTs[index]);
3640 }
3641
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003642 SkScalar xAtT(const Span* span) const {
3643 return xyAtT(span).fX;
3644 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003645
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003646 const SkPoint& xyAtT(int index) const {
3647 return xyAtT(&fTs[index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003648 }
3649
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003650 const SkPoint& xyAtT(const Span* span) const {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003651 if (SkScalarIsNaN(span->fPt.fX)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003652 if (span->fT == 0) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003653 span->fPt = fPts[0];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003654 } else if (span->fT == 1) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003655 span->fPt = fPts[fVerb];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003656 } else {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003657 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003658 }
3659 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00003660 return span->fPt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003661 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003662
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003663 // used only by right angle winding finding
caryclark@google.com10227bf2012-12-28 22:10:41 +00003664 void xyAtT(double mid, SkPoint& pt) const {
3665 (*SegmentXYAtT[fVerb])(fPts, mid, &pt);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003666 }
3667
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003668 SkScalar yAtT(int index) const {
3669 return yAtT(&fTs[index]);
3670 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003671
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003672 SkScalar yAtT(const Span* span) const {
3673 return xyAtT(span).fY;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003674 }
3675
caryclark@google.com4eeda372012-12-06 21:47:48 +00003676 void zeroCoincidentOpp(Span* oTest, int index) {
3677 Span* const test = &fTs[index];
3678 Span* end = test;
3679 do {
3680 end->fOppValue = 0;
3681 end = &fTs[++index];
3682 } while (approximately_negative(end->fT - test->fT));
3683 }
3684
3685 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
3686 Span* const oTest = &fTs[oIndex];
3687 Span* oEnd = oTest;
3688 const double startT = test->fT;
3689 const double oStartT = oTest->fT;
3690 double otherTMatch = (test->fT - startT) * tRatio + oStartT;
3691 while (!approximately_negative(oEndT - oEnd->fT)
3692 && approximately_negative(oEnd->fT - otherTMatch)) {
3693 oEnd->fOppValue = 0;
3694 oEnd = &fTs[++oIndex];
3695 }
3696 }
3697
3698 void zeroSpan(Span* span) {
3699 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
caryclark@google.com6ec15262012-11-16 20:16:50 +00003700 span->fWindValue = 0;
caryclark@google.com729e1c42012-11-21 21:36:34 +00003701 span->fOppValue = 0;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003702 SkASSERT(!span->fDone);
3703 span->fDone = true;
3704 ++fDoneSpans;
caryclark@google.com6ec15262012-11-16 20:16:50 +00003705 }
3706
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003707#if DEBUG_DUMP
3708 void dump() const {
3709 const char className[] = "Segment";
3710 const int tab = 4;
3711 for (int i = 0; i < fTs.count(); ++i) {
3712 SkPoint out;
3713 (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
3714 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003715 " otherT=%1.9g windSum=%d\n",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003716 tab + sizeof(className), className, fID,
3717 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003718 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003719 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00003720 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003721 tab + sizeof(className), className, fID,
caryclark@google.com15fa1382012-05-07 20:49:36 +00003722 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003723 }
3724#endif
3725
caryclark@google.com47580692012-07-23 12:14:49 +00003726#if DEBUG_CONCIDENT
caryclark@google.comcc905052012-07-25 20:59:42 +00003727 // assert if pair has not already been added
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003728 void debugAddTPair(double t, const Segment& other, double otherT) const {
caryclark@google.comcc905052012-07-25 20:59:42 +00003729 for (int i = 0; i < fTs.count(); ++i) {
3730 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
3731 return;
3732 }
3733 }
3734 SkASSERT(0);
3735 }
3736#endif
3737
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003738#if DEBUG_DUMP
3739 int debugID() const {
3740 return fID;
3741 }
3742#endif
3743
caryclark@google.com24bec792012-08-20 12:43:57 +00003744#if DEBUG_WINDING
3745 void debugShowSums() const {
3746 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
3747 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
3748 for (int i = 0; i < fTs.count(); ++i) {
3749 const Span& span = fTs[i];
3750 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
3751 if (span.fWindSum == SK_MinS32) {
3752 SkDebugf("?");
3753 } else {
3754 SkDebugf("%d", span.fWindSum);
3755 }
3756 SkDebugf("]");
3757 }
3758 SkDebugf("\n");
3759 }
3760#endif
3761
caryclark@google.comcc905052012-07-25 20:59:42 +00003762#if DEBUG_CONCIDENT
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003763 void debugShowTs() const {
caryclark@google.com24bec792012-08-20 12:43:57 +00003764 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003765 int lastWind = -1;
3766 int lastOpp = -1;
3767 double lastT = -1;
3768 int i;
3769 for (i = 0; i < fTs.count(); ++i) {
3770 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
3771 || lastOpp != fTs[i].fOppValue;
3772 if (change && lastWind >= 0) {
3773 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3774 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3775 }
3776 if (change) {
3777 SkDebugf(" [o=%d", fTs[i].fOther->fID);
3778 lastWind = fTs[i].fWindValue;
3779 lastOpp = fTs[i].fOppValue;
3780 lastT = fTs[i].fT;
3781 } else {
3782 SkDebugf(",%d", fTs[i].fOther->fID);
3783 }
3784 }
3785 if (i <= 0) {
3786 return;
3787 }
3788 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3789 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3790 if (fOperand) {
3791 SkDebugf(" operand");
3792 }
3793 if (done()) {
3794 SkDebugf(" done");
caryclark@google.com47580692012-07-23 12:14:49 +00003795 }
3796 SkDebugf("\n");
3797 }
3798#endif
3799
caryclark@google.com027de222012-07-12 12:52:50 +00003800#if DEBUG_ACTIVE_SPANS
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003801 void debugShowActiveSpans() const {
caryclark@google.com027de222012-07-12 12:52:50 +00003802 if (done()) {
3803 return;
3804 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003805#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3806 int lastId = -1;
3807 double lastT = -1;
3808#endif
caryclark@google.com027de222012-07-12 12:52:50 +00003809 for (int i = 0; i < fTs.count(); ++i) {
3810 if (fTs[i].fDone) {
3811 continue;
3812 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003813#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3814 if (lastId == fID && lastT == fTs[i].fT) {
3815 continue;
3816 }
3817 lastId = fID;
3818 lastT = fTs[i].fT;
3819#endif
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003820 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com027de222012-07-12 12:52:50 +00003821 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3822 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3823 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3824 }
3825 const Span* span = &fTs[i];
rmistry@google.comd6176b02012-08-23 18:14:13 +00003826 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
caryclark@google.com0c803d02012-08-06 11:15:47 +00003827 xAtT(span), yAtT(span));
caryclark@google.com027de222012-07-12 12:52:50 +00003828 const Segment* other = fTs[i].fOther;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003829 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
3830 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
3831 if (fTs[i].fWindSum == SK_MinS32) {
3832 SkDebugf("?");
3833 } else {
3834 SkDebugf("%d", fTs[i].fWindSum);
3835 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003836 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
caryclark@google.com027de222012-07-12 12:52:50 +00003837 }
3838 }
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +00003839
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003840 // This isn't useful yet -- but leaving it in for now in case i think of something
3841 // to use it for
3842 void validateActiveSpans() const {
3843 if (done()) {
3844 return;
3845 }
3846 int tCount = fTs.count();
3847 for (int index = 0; index < tCount; ++index) {
3848 if (fTs[index].fDone) {
3849 continue;
3850 }
3851 // count number of connections which are not done
3852 int first = index;
3853 double baseT = fTs[index].fT;
3854 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
3855 --first;
3856 }
3857 int last = index;
3858 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
3859 ++last;
3860 }
3861 int connections = 0;
3862 connections += first > 0 && !fTs[first - 1].fDone;
3863 for (int test = first; test <= last; ++test) {
3864 connections += !fTs[test].fDone;
3865 const Segment* other = fTs[test].fOther;
3866 int oIndex = fTs[test].fOtherIndex;
3867 connections += !other->fTs[oIndex].fDone;
3868 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
3869 }
3870 // SkASSERT(!(connections & 1));
3871 }
3872 }
caryclark@google.com027de222012-07-12 12:52:50 +00003873#endif
3874
caryclark@google.com0c803d02012-08-06 11:15:47 +00003875#if DEBUG_MARK_DONE
3876 void debugShowNewWinding(const char* fun, const Span& span, int winding) {
3877 const SkPoint& pt = xyAtT(&span);
3878 SkDebugf("%s id=%d", fun, fID);
3879 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3880 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3881 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3882 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003883 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3884 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3885 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d windSum=",
3886 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, winding);
caryclark@google.com0c803d02012-08-06 11:15:47 +00003887 if (span.fWindSum == SK_MinS32) {
3888 SkDebugf("?");
3889 } else {
3890 SkDebugf("%d", span.fWindSum);
3891 }
3892 SkDebugf(" windValue=%d\n", span.fWindValue);
3893 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003894
3895 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
3896 const SkPoint& pt = xyAtT(&span);
3897 SkDebugf("%s id=%d", fun, fID);
3898 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3899 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3900 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3901 }
3902 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3903 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3904 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=",
3905 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
3906 winding, oppWinding);
3907 if (span.fOppSum == SK_MinS32) {
3908 SkDebugf("?");
3909 } else {
3910 SkDebugf("%d", span.fOppSum);
3911 }
3912 SkDebugf(" windSum=");
3913 if (span.fWindSum == SK_MinS32) {
3914 SkDebugf("?");
3915 } else {
3916 SkDebugf("%d", span.fWindSum);
3917 }
3918 SkDebugf(" windValue=%d\n", span.fWindValue);
3919 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003920#endif
3921
caryclark@google.com47580692012-07-23 12:14:49 +00003922#if DEBUG_SORT
caryclark@google.com03f97062012-08-21 13:13:52 +00003923 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
caryclark@google.com31143cf2012-11-09 22:14:19 +00003924 const int contourWinding, const int oppContourWinding) const {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003925 SkASSERT(angles[first]->segment() == this);
caryclark@google.com200c2112012-08-03 15:05:04 +00003926 SkASSERT(angles.count() > 1);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003927 int lastSum = contourWinding;
caryclark@google.com31143cf2012-11-09 22:14:19 +00003928 int oppLastSum = oppContourWinding;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003929 const Angle* firstAngle = angles[first];
3930 int windSum = lastSum - spanSign(firstAngle);
3931 int oppoSign = oppSign(firstAngle);
3932 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.com31143cf2012-11-09 22:14:19 +00003933 SkDebugf("%s %s contourWinding=%d oppContourWinding=%d sign=%d\n", fun, __FUNCTION__,
3934 contourWinding, oppContourWinding, spanSign(angles[first]));
caryclark@google.comafe56de2012-07-24 18:11:03 +00003935 int index = first;
3936 bool firstTime = true;
caryclark@google.com47580692012-07-23 12:14:49 +00003937 do {
3938 const Angle& angle = *angles[index];
3939 const Segment& segment = *angle.segment();
3940 int start = angle.start();
3941 int end = angle.end();
3942 const Span& sSpan = segment.fTs[start];
3943 const Span& eSpan = segment.fTs[end];
3944 const Span& mSpan = segment.fTs[SkMin32(start, end)];
caryclark@google.com31143cf2012-11-09 22:14:19 +00003945 bool opp = segment.fOperand ^ fOperand;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003946 if (!firstTime) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003947 oppoSign = segment.oppSign(&angle);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003948 if (opp) {
3949 oppLastSum = oppWindSum;
3950 oppWindSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003951 if (oppoSign) {
3952 lastSum = windSum;
3953 windSum -= oppoSign;
3954 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003955 } else {
3956 lastSum = windSum;
3957 windSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003958 if (oppoSign) {
3959 oppLastSum = oppWindSum;
3960 oppWindSum -= oppoSign;
3961 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003962 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00003963 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003964 SkDebugf("%s [%d] %sid=%d %s start=%d (%1.9g,%,1.9g) end=%d (%1.9g,%,1.9g)"
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003965 " sign=%d windValue=%d windSum=",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003966 __FUNCTION__, index, angle.unsortable() ? "*** UNSORTABLE *** " : "",
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003967 segment.fID, kLVerbStr[segment.fVerb],
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003968 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
3969 segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(),
3970 mSpan.fWindValue);
3971 if (mSpan.fWindSum == SK_MinS32) {
3972 SkDebugf("?");
3973 } else {
3974 SkDebugf("%d", mSpan.fWindSum);
3975 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003976 int last, wind;
3977 if (opp) {
3978 last = oppLastSum;
3979 wind = oppWindSum;
3980 } else {
3981 last = lastSum;
3982 wind = windSum;
3983 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003984 if (!oppoSign) {
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003985 SkDebugf(" %d->%d (max=%d)", last, wind,
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003986 useInnerWinding(last, wind) ? wind : last);
3987 } else {
3988 SkDebugf(" %d->%d (%d->%d)", last, wind, opp ? lastSum : oppLastSum,
3989 opp ? windSum : oppWindSum);
3990 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003991 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003992#if false && DEBUG_ANGLE
caryclark@google.comc899ad92012-08-23 15:24:42 +00003993 angle.debugShow(segment.xyAtT(&sSpan));
3994#endif
caryclark@google.com47580692012-07-23 12:14:49 +00003995 ++index;
3996 if (index == angles.count()) {
3997 index = 0;
3998 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003999 if (firstTime) {
4000 firstTime = false;
4001 }
caryclark@google.com47580692012-07-23 12:14:49 +00004002 } while (index != first);
4003 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00004004
4005 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
4006 const Angle* firstAngle = angles[first];
4007 const Segment* segment = firstAngle->segment();
4008 int winding = segment->updateWinding(firstAngle);
4009 int oppWinding = segment->updateOppWinding(firstAngle);
4010 debugShowSort(fun, angles, first, winding, oppWinding);
4011 }
4012
caryclark@google.com47580692012-07-23 12:14:49 +00004013#endif
4014
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004015#if DEBUG_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004016 static char as_digit(int value) {
4017 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
4018 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004019#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004020
caryclark@google.com729e1c42012-11-21 21:36:34 +00004021#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004022 int debugShowWindingValues(int slotCount, int ofInterest) const {
4023 if (!(1 << fID & ofInterest)) {
4024 return 0;
4025 }
4026 int sum = 0;
4027 SkTDArray<char> slots;
4028 slots.setCount(slotCount * 2);
4029 memset(slots.begin(), ' ', slotCount * 2);
4030 for (int i = 0; i < fTs.count(); ++i) {
4031 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
4032 // continue;
4033 // }
4034 sum += fTs[i].fWindValue;
4035 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
4036 sum += fTs[i].fOppValue;
4037 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
4038 }
4039 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
4040 slots.begin() + slotCount);
4041 return sum;
4042 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004043#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004044
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004045private:
4046 const SkPoint* fPts;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004047 Bounds fBounds;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004048 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
caryclark@google.com4eeda372012-12-06 21:47:48 +00004049 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
caryclark@google.com24bec792012-08-20 12:43:57 +00004050 int fDoneSpans; // quick check that segment is finished
caryclark@google.com4eeda372012-12-06 21:47:48 +00004051 // OPTIMIZATION: force the following to be byte-sized
4052 SkPath::Verb fVerb;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004053 bool fOperand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004054 bool fXor; // set if original contour had even-odd fill
4055 bool fOppXor; // set if opposite operand had even-odd fill
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004056#if DEBUG_DUMP
4057 int fID;
4058#endif
4059};
4060
caryclark@google.comb9738012012-07-03 19:53:30 +00004061class Contour;
4062
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004063struct Coincidence {
caryclark@google.comb9738012012-07-03 19:53:30 +00004064 Contour* fContours[2];
4065 int fSegments[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004066 double fTs[2][2];
4067};
4068
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004069class Contour {
4070public:
4071 Contour() {
4072 reset();
4073#if DEBUG_DUMP
4074 fID = ++gContourID;
4075#endif
4076 }
4077
4078 bool operator<(const Contour& rh) const {
4079 return fBounds.fTop == rh.fBounds.fTop
4080 ? fBounds.fLeft < rh.fBounds.fLeft
4081 : fBounds.fTop < rh.fBounds.fTop;
4082 }
4083
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004084 void addCoincident(int index, Contour* other, int otherIndex,
4085 const Intersections& ts, bool swap) {
4086 Coincidence& coincidence = *fCoincidences.append();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004087 coincidence.fContours[0] = this; // FIXME: no need to store
caryclark@google.comb9738012012-07-03 19:53:30 +00004088 coincidence.fContours[1] = other;
4089 coincidence.fSegments[0] = index;
4090 coincidence.fSegments[1] = otherIndex;
caryclark@google.com32546db2012-08-31 20:55:07 +00004091 if (fSegments[index].verb() == SkPath::kLine_Verb &&
4092 other->fSegments[otherIndex].verb() == SkPath::kLine_Verb) {
4093 // FIXME: coincident lines use legacy Ts instead of coincident Ts
4094 coincidence.fTs[swap][0] = ts.fT[0][0];
4095 coincidence.fTs[swap][1] = ts.fT[0][1];
4096 coincidence.fTs[!swap][0] = ts.fT[1][0];
4097 coincidence.fTs[!swap][1] = ts.fT[1][1];
4098 } else if (fSegments[index].verb() == SkPath::kQuad_Verb &&
4099 other->fSegments[otherIndex].verb() == SkPath::kQuad_Verb) {
4100 coincidence.fTs[swap][0] = ts.fCoincidentT[0][0];
4101 coincidence.fTs[swap][1] = ts.fCoincidentT[0][1];
4102 coincidence.fTs[!swap][0] = ts.fCoincidentT[1][0];
4103 coincidence.fTs[!swap][1] = ts.fCoincidentT[1][1];
4104 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004105 }
4106
4107 void addCross(const Contour* crosser) {
4108#ifdef DEBUG_CROSS
4109 for (int index = 0; index < fCrosses.count(); ++index) {
4110 SkASSERT(fCrosses[index] != crosser);
4111 }
4112#endif
4113 *fCrosses.append() = crosser;
4114 }
4115
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004116 void addCubic(const SkPoint pts[4]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004117 fSegments.push_back().addCubic(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004118 fContainsCurves = true;
4119 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004120
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004121 int addLine(const SkPoint pts[2]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004122 fSegments.push_back().addLine(pts, fOperand, fXor);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004123 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004124 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004125
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004126 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
4127 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
4128 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004129
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004130 int addQuad(const SkPoint pts[3]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004131 fSegments.push_back().addQuad(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004132 fContainsCurves = true;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004133 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004134 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004135
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004136 int addT(int segIndex, double newT, Contour* other, int otherIndex) {
4137 containsIntercepts();
4138 return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex]);
4139 }
4140
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004141 const Bounds& bounds() const {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004142 return fBounds;
4143 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004144
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004145 void complete() {
4146 setBounds();
4147 fContainsIntercepts = false;
4148 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004149
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004150 void containsIntercepts() {
4151 fContainsIntercepts = true;
4152 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004153
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004154 bool crosses(const Contour* crosser) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004155 for (int index = 0; index < fCrosses.count(); ++index) {
4156 if (fCrosses[index] == crosser) {
4157 return true;
4158 }
4159 }
4160 return false;
4161 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004162
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004163 bool done() const {
4164 return fDone;
4165 }
4166
caryclark@google.comf839c032012-10-26 21:03:50 +00004167 const SkPoint& end() const {
4168 const Segment& segment = fSegments.back();
4169 return segment.pts()[segment.verb()];
4170 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004171
caryclark@google.com4eeda372012-12-06 21:47:48 +00004172 void findTooCloseToCall() {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004173 int segmentCount = fSegments.count();
4174 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004175 fSegments[sIndex].findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004176 }
4177 }
4178
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004179 void fixOtherTIndex() {
4180 int segmentCount = fSegments.count();
4181 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4182 fSegments[sIndex].fixOtherTIndex();
4183 }
4184 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004185
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004186 Segment* nonVerticalSegment(int& start, int& end) {
4187 int segmentCount = fSortedSegments.count();
4188 SkASSERT(segmentCount > 0);
4189 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4190 Segment* testSegment = fSortedSegments[sortedIndex];
4191 if (testSegment->done()) {
4192 continue;
4193 }
4194 start = end = 0;
4195 while (testSegment->nextCandidate(start, end)) {
4196 if (!testSegment->isVertical(start, end)) {
4197 return testSegment;
4198 }
4199 }
4200 }
4201 return NULL;
4202 }
4203
caryclark@google.com31143cf2012-11-09 22:14:19 +00004204 bool operand() const {
4205 return fOperand;
4206 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004207
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004208 void reset() {
4209 fSegments.reset();
4210 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004211 fContainsCurves = fContainsIntercepts = fDone = false;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004212 }
caryclark@google.comb9738012012-07-03 19:53:30 +00004213
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004214 void resolveCoincidence(SkTDArray<Contour*>& contourList) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004215 int count = fCoincidences.count();
4216 for (int index = 0; index < count; ++index) {
4217 Coincidence& coincidence = fCoincidences[index];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004218 SkASSERT(coincidence.fContours[0] == this);
caryclark@google.comb9738012012-07-03 19:53:30 +00004219 int thisIndex = coincidence.fSegments[0];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004220 Segment& thisOne = fSegments[thisIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004221 Contour* otherContour = coincidence.fContours[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004222 int otherIndex = coincidence.fSegments[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004223 Segment& other = otherContour->fSegments[otherIndex];
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004224 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004225 continue;
4226 }
caryclark@google.com47580692012-07-23 12:14:49 +00004227 #if DEBUG_CONCIDENT
4228 thisOne.debugShowTs();
4229 other.debugShowTs();
4230 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004231 double startT = coincidence.fTs[0][0];
4232 double endT = coincidence.fTs[0][1];
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004233 bool cancelers = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004234 if (startT > endT) {
4235 SkTSwap<double>(startT, endT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004236 cancelers ^= true; // FIXME: just assign true
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004237 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004238 SkASSERT(!approximately_negative(endT - startT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004239 double oStartT = coincidence.fTs[1][0];
4240 double oEndT = coincidence.fTs[1][1];
4241 if (oStartT > oEndT) {
4242 SkTSwap<double>(oStartT, oEndT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004243 cancelers ^= true;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004244 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004245 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00004246 bool opp = fOperand ^ otherContour->fOperand;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004247 if (cancelers && !opp) {
4248 // make sure startT and endT have t entries
caryclark@google.com2ddff932012-08-07 21:25:27 +00004249 if (startT > 0 || oEndT < 1
4250 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
4251 thisOne.addTPair(startT, other, oEndT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004252 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00004253 if (oStartT > 0 || endT < 1
4254 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
4255 other.addTPair(oStartT, thisOne, endT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004256 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004257 if (!thisOne.done() && !other.done()) {
4258 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4259 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004260 } else {
caryclark@google.com200c2112012-08-03 15:05:04 +00004261 if (startT > 0 || oStartT > 0
4262 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00004263 thisOne.addTPair(startT, other, oStartT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004264 }
caryclark@google.com200c2112012-08-03 15:05:04 +00004265 if (endT < 1 || oEndT < 1
4266 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00004267 other.addTPair(oEndT, thisOne, endT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004268 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004269 if (!thisOne.done() && !other.done()) {
4270 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4271 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004272 }
caryclark@google.com47580692012-07-23 12:14:49 +00004273 #if DEBUG_CONCIDENT
4274 thisOne.debugShowTs();
4275 other.debugShowTs();
4276 #endif
caryclark@google.com729e1c42012-11-21 21:36:34 +00004277 #if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004278 debugShowWindingValues(contourList);
4279 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004280 }
4281 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004282
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004283 // first pass, add missing T values
4284 // second pass, determine winding values of overlaps
4285 void addCoincidentPoints() {
4286 int count = fCoincidences.count();
4287 for (int index = 0; index < count; ++index) {
4288 Coincidence& coincidence = fCoincidences[index];
4289 SkASSERT(coincidence.fContours[0] == this);
4290 int thisIndex = coincidence.fSegments[0];
4291 Segment& thisOne = fSegments[thisIndex];
4292 Contour* otherContour = coincidence.fContours[1];
4293 int otherIndex = coincidence.fSegments[1];
4294 Segment& other = otherContour->fSegments[otherIndex];
4295 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
4296 // OPTIMIZATION: remove from array
4297 continue;
4298 }
4299 #if DEBUG_CONCIDENT
4300 thisOne.debugShowTs();
4301 other.debugShowTs();
4302 #endif
4303 double startT = coincidence.fTs[0][0];
4304 double endT = coincidence.fTs[0][1];
4305 bool cancelers;
4306 if ((cancelers = startT > endT)) {
4307 SkTSwap<double>(startT, endT);
4308 }
4309 SkASSERT(!approximately_negative(endT - startT));
4310 double oStartT = coincidence.fTs[1][0];
4311 double oEndT = coincidence.fTs[1][1];
4312 if (oStartT > oEndT) {
4313 SkTSwap<double>(oStartT, oEndT);
4314 cancelers ^= true;
4315 }
4316 SkASSERT(!approximately_negative(oEndT - oStartT));
4317 bool opp = fOperand ^ otherContour->fOperand;
4318 if (cancelers && !opp) {
4319 // make sure startT and endT have t entries
4320 if (startT > 0 || oEndT < 1
4321 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
4322 thisOne.addTPair(startT, other, oEndT, true);
4323 }
4324 if (oStartT > 0 || endT < 1
4325 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
4326 other.addTPair(oStartT, thisOne, endT, true);
4327 }
4328 } else {
4329 if (startT > 0 || oStartT > 0
4330 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
4331 thisOne.addTPair(startT, other, oStartT, true);
4332 }
4333 if (endT < 1 || oEndT < 1
4334 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
4335 other.addTPair(oEndT, thisOne, endT, true);
4336 }
4337 }
4338 #if DEBUG_CONCIDENT
4339 thisOne.debugShowTs();
4340 other.debugShowTs();
4341 #endif
4342 }
4343 }
4344
4345 void calcCoincidentWinding() {
4346 int count = fCoincidences.count();
4347 for (int index = 0; index < count; ++index) {
4348 Coincidence& coincidence = fCoincidences[index];
4349 SkASSERT(coincidence.fContours[0] == this);
4350 int thisIndex = coincidence.fSegments[0];
4351 Segment& thisOne = fSegments[thisIndex];
4352 if (thisOne.done()) {
4353 continue;
4354 }
4355 Contour* otherContour = coincidence.fContours[1];
4356 int otherIndex = coincidence.fSegments[1];
4357 Segment& other = otherContour->fSegments[otherIndex];
4358 if (other.done()) {
4359 continue;
4360 }
4361 double startT = coincidence.fTs[0][0];
4362 double endT = coincidence.fTs[0][1];
4363 bool cancelers;
4364 if ((cancelers = startT > endT)) {
4365 SkTSwap<double>(startT, endT);
4366 }
4367 SkASSERT(!approximately_negative(endT - startT));
4368 double oStartT = coincidence.fTs[1][0];
4369 double oEndT = coincidence.fTs[1][1];
4370 if (oStartT > oEndT) {
4371 SkTSwap<double>(oStartT, oEndT);
4372 cancelers ^= true;
4373 }
4374 SkASSERT(!approximately_negative(oEndT - oStartT));
4375 bool opp = fOperand ^ otherContour->fOperand;
4376 if (cancelers && !opp) {
4377 // make sure startT and endT have t entries
4378 if (!thisOne.done() && !other.done()) {
4379 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4380 }
4381 } else {
4382 if (!thisOne.done() && !other.done()) {
4383 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4384 }
4385 }
4386 #if DEBUG_CONCIDENT
4387 thisOne.debugShowTs();
4388 other.debugShowTs();
4389 #endif
4390 }
4391 }
4392
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004393 SkTArray<Segment>& segments() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004394 return fSegments;
4395 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004396
caryclark@google.com235f56a2012-09-14 14:19:30 +00004397 void setOperand(bool isOp) {
4398 fOperand = isOp;
4399 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00004400
caryclark@google.com4eeda372012-12-06 21:47:48 +00004401 void setOppXor(bool isOppXor) {
4402 fOppXor = isOppXor;
4403 int segmentCount = fSegments.count();
4404 for (int test = 0; test < segmentCount; ++test) {
4405 fSegments[test].setOppXor(isOppXor);
4406 }
4407 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004408
caryclark@google.com235f56a2012-09-14 14:19:30 +00004409 void setXor(bool isXor) {
4410 fXor = isXor;
4411 }
4412
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004413 void sortSegments() {
4414 int segmentCount = fSegments.count();
4415 fSortedSegments.setReserve(segmentCount);
4416 for (int test = 0; test < segmentCount; ++test) {
4417 *fSortedSegments.append() = &fSegments[test];
4418 }
4419 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4420 fFirstSorted = 0;
4421 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004422
caryclark@google.comf839c032012-10-26 21:03:50 +00004423 const SkPoint& start() const {
4424 return fSegments.front().pts()[0];
4425 }
4426
4427 void toPath(PathWrapper& path) const {
4428 int segmentCount = fSegments.count();
4429 const SkPoint& pt = fSegments.front().pts()[0];
4430 path.deferredMove(pt);
4431 for (int test = 0; test < segmentCount; ++test) {
4432 fSegments[test].addCurveTo(0, 1, path, true);
4433 }
4434 path.close();
4435 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004436
caryclark@google.comf839c032012-10-26 21:03:50 +00004437 void toPartialBackward(PathWrapper& path) const {
4438 int segmentCount = fSegments.count();
4439 for (int test = segmentCount - 1; test >= 0; --test) {
4440 fSegments[test].addCurveTo(1, 0, path, true);
4441 }
4442 }
4443
4444 void toPartialForward(PathWrapper& path) const {
4445 int segmentCount = fSegments.count();
4446 for (int test = 0; test < segmentCount; ++test) {
4447 fSegments[test].addCurveTo(0, 1, path, true);
4448 }
4449 }
4450
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004451 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004452 int segmentCount = fSortedSegments.count();
4453 SkASSERT(segmentCount > 0);
caryclark@google.comf839c032012-10-26 21:03:50 +00004454 int sortedIndex = fFirstSorted;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004455 fDone = true; // may be cleared below
caryclark@google.comf839c032012-10-26 21:03:50 +00004456 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4457 Segment* testSegment = fSortedSegments[sortedIndex];
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004458 if (testSegment->done()) {
caryclark@google.comf839c032012-10-26 21:03:50 +00004459 if (sortedIndex == fFirstSorted) {
4460 ++fFirstSorted;
4461 }
4462 continue;
4463 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004464 fDone = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00004465 SkPoint testXY;
4466 testSegment->activeLeftTop(testXY);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004467 if (topStart) {
4468 if (testXY.fY < topLeft.fY) {
4469 continue;
4470 }
4471 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4472 continue;
4473 }
4474 if (bestXY.fY < testXY.fY) {
4475 continue;
4476 }
4477 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4478 continue;
4479 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004480 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004481 topStart = testSegment;
caryclark@google.comf839c032012-10-26 21:03:50 +00004482 bestXY = testXY;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004483 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004484 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004485
caryclark@google.com24bec792012-08-20 12:43:57 +00004486 Segment* undoneSegment(int& start, int& end) {
4487 int segmentCount = fSegments.count();
4488 for (int test = 0; test < segmentCount; ++test) {
4489 Segment* testSegment = &fSegments[test];
4490 if (testSegment->done()) {
4491 continue;
4492 }
4493 testSegment->undoneSpan(start, end);
4494 return testSegment;
4495 }
4496 return NULL;
4497 }
4498
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004499 int updateSegment(int index, const SkPoint* pts) {
4500 Segment& segment = fSegments[index];
4501 segment.updatePts(pts);
4502 return segment.verb() + 1;
4503 }
4504
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004505#if DEBUG_TEST
4506 SkTArray<Segment>& debugSegments() {
4507 return fSegments;
4508 }
4509#endif
4510
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004511#if DEBUG_DUMP
4512 void dump() {
4513 int i;
4514 const char className[] = "Contour";
4515 const int tab = 4;
4516 SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4517 for (i = 0; i < fSegments.count(); ++i) {
4518 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4519 className, i);
4520 fSegments[i].dump();
4521 }
4522 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4523 tab + sizeof(className), className,
4524 fBounds.fLeft, fBounds.fTop,
4525 fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004526 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4527 className, fContainsIntercepts);
4528 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4529 className, fContainsCurves);
4530 }
4531#endif
4532
caryclark@google.com027de222012-07-12 12:52:50 +00004533#if DEBUG_ACTIVE_SPANS
4534 void debugShowActiveSpans() {
4535 for (int index = 0; index < fSegments.count(); ++index) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004536 fSegments[index].debugShowActiveSpans();
caryclark@google.com027de222012-07-12 12:52:50 +00004537 }
4538 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004539
4540 void validateActiveSpans() {
4541 for (int index = 0; index < fSegments.count(); ++index) {
4542 fSegments[index].validateActiveSpans();
4543 }
4544 }
caryclark@google.com027de222012-07-12 12:52:50 +00004545#endif
4546
caryclark@google.com729e1c42012-11-21 21:36:34 +00004547#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004548 int debugShowWindingValues(int totalSegments, int ofInterest) {
4549 int count = fSegments.count();
4550 int sum = 0;
4551 for (int index = 0; index < count; ++index) {
4552 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4553 }
4554 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4555 return sum;
4556 }
4557
4558 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4559 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4560 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4561 int ofInterest = 1 << 5 | 1 << 8;
4562 int total = 0;
4563 int index;
4564 for (index = 0; index < contourList.count(); ++index) {
4565 total += contourList[index]->segments().count();
4566 }
4567 int sum = 0;
4568 for (index = 0; index < contourList.count(); ++index) {
4569 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4570 }
4571 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4572 }
4573#endif
4574
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004575protected:
4576 void setBounds() {
4577 int count = fSegments.count();
4578 if (count == 0) {
4579 SkDebugf("%s empty contour\n", __FUNCTION__);
4580 SkASSERT(0);
4581 // FIXME: delete empty contour?
4582 return;
4583 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004584 fBounds = fSegments.front().bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004585 for (int index = 1; index < count; ++index) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004586 fBounds.add(fSegments[index].bounds());
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004587 }
4588 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004589
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004590private:
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004591 SkTArray<Segment> fSegments;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004592 SkTDArray<Segment*> fSortedSegments;
4593 int fFirstSorted;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004594 SkTDArray<Coincidence> fCoincidences;
4595 SkTDArray<const Contour*> fCrosses;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004596 Bounds fBounds;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004597 bool fContainsIntercepts;
4598 bool fContainsCurves;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004599 bool fDone;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004600 bool fOperand; // true for the second argument to a binary operator
4601 bool fXor;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004602 bool fOppXor;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004603#if DEBUG_DUMP
4604 int fID;
4605#endif
4606};
4607
4608class EdgeBuilder {
4609public:
4610
caryclark@google.comf839c032012-10-26 21:03:50 +00004611EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
4612 : fPath(path.nativePath())
4613 , fContours(contours)
4614{
4615 init();
4616}
4617
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004618EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
caryclark@google.com235f56a2012-09-14 14:19:30 +00004619 : fPath(&path)
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004620 , fContours(contours)
4621{
caryclark@google.comf839c032012-10-26 21:03:50 +00004622 init();
4623}
4624
4625void init() {
4626 fCurrentContour = NULL;
4627 fOperand = false;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004628 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004629#if DEBUG_DUMP
4630 gContourID = 0;
4631 gSegmentID = 0;
4632#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00004633 fSecondHalf = preFetch();
4634}
4635
4636void addOperand(const SkPath& path) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00004637 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
4638 fPathVerbs.pop();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004639 fPath = &path;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004640 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004641 preFetch();
4642}
4643
4644void finish() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004645 walk();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004646 complete();
4647 if (fCurrentContour && !fCurrentContour->segments().count()) {
4648 fContours.pop_back();
4649 }
4650 // correct pointers in contours since fReducePts may have moved as it grew
4651 int cIndex = 0;
4652 int extraCount = fExtra.count();
4653 SkASSERT(extraCount == 0 || fExtra[0] == -1);
4654 int eIndex = 0;
4655 int rIndex = 0;
4656 while (++eIndex < extraCount) {
4657 int offset = fExtra[eIndex];
4658 if (offset < 0) {
4659 ++cIndex;
4660 continue;
4661 }
4662 fCurrentContour = &fContours[cIndex];
4663 rIndex += fCurrentContour->updateSegment(offset - 1,
4664 &fReducePts[rIndex]);
4665 }
4666 fExtra.reset(); // we're done with this
4667}
4668
4669ShapeOpMask xorMask() const {
caryclark@google.com729e1c42012-11-21 21:36:34 +00004670 return fXorMask[fOperand];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004671}
4672
4673protected:
4674
4675void complete() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004676 if (fCurrentContour && fCurrentContour->segments().count()) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004677 fCurrentContour->complete();
4678 fCurrentContour = NULL;
4679 }
4680}
4681
caryclark@google.com235f56a2012-09-14 14:19:30 +00004682// FIXME:remove once we can access path pts directly
4683int preFetch() {
4684 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004685 SkPoint pts[4];
4686 SkPath::Verb verb;
4687 do {
4688 verb = iter.next(pts);
4689 *fPathVerbs.append() = verb;
4690 if (verb == SkPath::kMove_Verb) {
4691 *fPathPts.append() = pts[0];
4692 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
4693 fPathPts.append(verb, &pts[1]);
4694 }
4695 } while (verb != SkPath::kDone_Verb);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004696 return fPathVerbs.count() - 1;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004697}
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004698
caryclark@google.com235f56a2012-09-14 14:19:30 +00004699void walk() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004700 SkPath::Verb reducedVerb;
4701 uint8_t* verbPtr = fPathVerbs.begin();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004702 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004703 const SkPoint* pointsPtr = fPathPts.begin();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004704 const SkPoint* finalCurveStart = NULL;
4705 const SkPoint* finalCurveEnd = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004706 SkPath::Verb verb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004707 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
4708 switch (verb) {
4709 case SkPath::kMove_Verb:
4710 complete();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004711 if (!fCurrentContour) {
4712 fCurrentContour = fContours.push_back_n(1);
caryclark@google.com235f56a2012-09-14 14:19:30 +00004713 fCurrentContour->setOperand(fOperand);
caryclark@google.com729e1c42012-11-21 21:36:34 +00004714 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004715 *fExtra.append() = -1; // start new contour
4716 }
caryclark@google.com59823f72012-08-09 18:17:47 +00004717 finalCurveEnd = pointsPtr++;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004718 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004719 case SkPath::kLine_Verb:
4720 // skip degenerate points
4721 if (pointsPtr[-1].fX != pointsPtr[0].fX
4722 || pointsPtr[-1].fY != pointsPtr[0].fY) {
4723 fCurrentContour->addLine(&pointsPtr[-1]);
4724 }
4725 break;
4726 case SkPath::kQuad_Verb:
rmistry@google.comd6176b02012-08-23 18:14:13 +00004727
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004728 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
4729 if (reducedVerb == 0) {
4730 break; // skip degenerate points
4731 }
4732 if (reducedVerb == 1) {
rmistry@google.comd6176b02012-08-23 18:14:13 +00004733 *fExtra.append() =
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004734 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004735 break;
4736 }
4737 fCurrentContour->addQuad(&pointsPtr[-1]);
4738 break;
4739 case SkPath::kCubic_Verb:
4740 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
4741 if (reducedVerb == 0) {
4742 break; // skip degenerate points
4743 }
4744 if (reducedVerb == 1) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004745 *fExtra.append() =
4746 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004747 break;
4748 }
4749 if (reducedVerb == 2) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004750 *fExtra.append() =
4751 fCurrentContour->addQuad(fReducePts.end() - 3);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004752 break;
4753 }
4754 fCurrentContour->addCubic(&pointsPtr[-1]);
4755 break;
4756 case SkPath::kClose_Verb:
4757 SkASSERT(fCurrentContour);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004758 if (finalCurveStart && finalCurveEnd
4759 && *finalCurveStart != *finalCurveEnd) {
4760 *fReducePts.append() = *finalCurveStart;
4761 *fReducePts.append() = *finalCurveEnd;
4762 *fExtra.append() =
4763 fCurrentContour->addLine(fReducePts.end() - 2);
4764 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004765 complete();
caryclark@google.com31143cf2012-11-09 22:14:19 +00004766 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004767 default:
4768 SkDEBUGFAIL("bad verb");
4769 return;
4770 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004771 finalCurveStart = &pointsPtr[verb - 1];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004772 pointsPtr += verb;
4773 SkASSERT(fCurrentContour);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004774 nextVerb:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004775 if (verbPtr == endOfFirstHalf) {
4776 fOperand = true;
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004777 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004778 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004779}
4780
4781private:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004782 const SkPath* fPath;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004783 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004784 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004785 Contour* fCurrentContour;
4786 SkTArray<Contour>& fContours;
4787 SkTDArray<SkPoint> fReducePts; // segments created on the fly
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004788 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
caryclark@google.com729e1c42012-11-21 21:36:34 +00004789 ShapeOpMask fXorMask[2];
caryclark@google.com235f56a2012-09-14 14:19:30 +00004790 int fSecondHalf;
4791 bool fOperand;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004792};
4793
4794class Work {
4795public:
4796 enum SegmentType {
4797 kHorizontalLine_Segment = -1,
4798 kVerticalLine_Segment = 0,
4799 kLine_Segment = SkPath::kLine_Verb,
4800 kQuad_Segment = SkPath::kQuad_Verb,
4801 kCubic_Segment = SkPath::kCubic_Verb,
4802 };
rmistry@google.comd6176b02012-08-23 18:14:13 +00004803
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004804 void addCoincident(Work& other, const Intersections& ts, bool swap) {
4805 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
4806 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004807
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004808 // FIXME: does it make sense to write otherIndex now if we're going to
4809 // fix it up later?
4810 void addOtherT(int index, double otherT, int otherIndex) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004811 fContour->addOtherT(fIndex, index, otherT, otherIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004812 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004813
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004814 // Avoid collapsing t values that are close to the same since
4815 // we walk ts to describe consecutive intersections. Since a pair of ts can
4816 // be nearly equal, any problems caused by this should be taken care
4817 // of later.
4818 // On the edge or out of range values are negative; add 2 to get end
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004819 int addT(double newT, const Work& other) {
4820 return fContour->addT(fIndex, newT, other.fContour, other.fIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004821 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004822
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004823 bool advance() {
4824 return ++fIndex < fLast;
4825 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004826
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004827 SkScalar bottom() const {
4828 return bounds().fBottom;
4829 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004830
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004831 const Bounds& bounds() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004832 return fContour->segments()[fIndex].bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004833 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004834
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004835 const SkPoint* cubic() const {
4836 return fCubic;
4837 }
4838
4839 void init(Contour* contour) {
4840 fContour = contour;
4841 fIndex = 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004842 fLast = contour->segments().count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004843 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004844
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00004845 bool isAdjacent(const Work& next) {
4846 return fContour == next.fContour && fIndex + 1 == next.fIndex;
4847 }
4848
4849 bool isFirstLast(const Work& next) {
4850 return fContour == next.fContour && fIndex == 0
4851 && next.fIndex == fLast - 1;
4852 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004853
4854 SkScalar left() const {
4855 return bounds().fLeft;
4856 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004857
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004858 void promoteToCubic() {
4859 fCubic[0] = pts()[0];
4860 fCubic[2] = pts()[1];
4861 fCubic[3] = pts()[2];
4862 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
4863 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
4864 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
4865 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
4866 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004867
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004868 const SkPoint* pts() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004869 return fContour->segments()[fIndex].pts();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004870 }
4871
4872 SkScalar right() const {
4873 return bounds().fRight;
4874 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004875
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004876 ptrdiff_t segmentIndex() const {
4877 return fIndex;
4878 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004879
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004880 SegmentType segmentType() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004881 const Segment& segment = fContour->segments()[fIndex];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004882 SegmentType type = (SegmentType) segment.verb();
4883 if (type != kLine_Segment) {
4884 return type;
4885 }
4886 if (segment.isHorizontal()) {
4887 return kHorizontalLine_Segment;
4888 }
4889 if (segment.isVertical()) {
4890 return kVerticalLine_Segment;
4891 }
4892 return kLine_Segment;
4893 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004894
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004895 bool startAfter(const Work& after) {
4896 fIndex = after.fIndex;
4897 return advance();
4898 }
4899
4900 SkScalar top() const {
4901 return bounds().fTop;
4902 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004903
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004904 SkPath::Verb verb() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004905 return fContour->segments()[fIndex].verb();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004906 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004907
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004908 SkScalar x() const {
4909 return bounds().fLeft;
4910 }
4911
4912 bool xFlipped() const {
4913 return x() != pts()[0].fX;
4914 }
4915
4916 SkScalar y() const {
4917 return bounds().fTop;
4918 }
4919
4920 bool yFlipped() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004921 return y() != pts()[0].fY;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004922 }
4923
4924protected:
4925 Contour* fContour;
4926 SkPoint fCubic[4];
4927 int fIndex;
4928 int fLast;
4929};
4930
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00004931#if DEBUG_ADD_INTERSECTING_TS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004932static void debugShowLineIntersection(int pts, const Work& wt,
4933 const Work& wn, const double wtTs[2], const double wnTs[2]) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004934 return;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004935 if (!pts) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004936 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n",
4937 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
4938 wt.pts()[1].fX, wt.pts()[1].fY, wn.pts()[0].fX, wn.pts()[0].fY,
4939 wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004940 return;
4941 }
4942 SkPoint wtOutPt, wnOutPt;
4943 LineXYAtT(wt.pts(), wtTs[0], &wtOutPt);
4944 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
caryclark@google.coma461ff02012-10-11 12:54:23 +00004945 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004946 __FUNCTION__,
4947 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
4948 wt.pts()[1].fX, wt.pts()[1].fY, wtOutPt.fX, wtOutPt.fY);
4949 if (pts == 2) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00004950 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004951 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00004952 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004953 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
4954 wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
4955 if (pts == 2) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00004956 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
4957 }
4958 SkDebugf("\n");
4959}
4960
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004961static void debugShowQuadLineIntersection(int pts, const Work& wt,
4962 const Work& wn, const double wtTs[2], const double wnTs[2]) {
4963 if (!pts) {
4964 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
caryclark@google.com0b7da432012-10-31 19:00:20 +00004965 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004966 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
4967 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00004968 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004969 return;
4970 }
4971 SkPoint wtOutPt, wnOutPt;
4972 QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
4973 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
4974 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
4975 __FUNCTION__,
4976 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
4977 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
4978 wtOutPt.fX, wtOutPt.fY);
4979 if (pts == 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00004980 QuadXYAtT(wt.pts(), wtTs[1], &wtOutPt);
4981 SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", wtTs[1], wtOutPt.fX, wtOutPt.fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004982 }
4983 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
4984 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
4985 wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
4986 if (pts == 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00004987 LineXYAtT(wn.pts(), wnTs[1], &wnOutPt);
4988 SkDebugf(" wnTs[1]=%1.9g (%1.9g,%1.9g)", wnTs[1], wnOutPt.fX, wnOutPt.fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004989 }
4990 SkDebugf("\n");
4991}
4992
caryclark@google.coma461ff02012-10-11 12:54:23 +00004993static void debugShowQuadIntersection(int pts, const Work& wt,
4994 const Work& wn, const double wtTs[2], const double wnTs[2]) {
4995 if (!pts) {
4996 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
4997 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
4998 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
skia.committer@gmail.com5b6f9162012-10-12 02:01:15 +00004999 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.coma461ff02012-10-11 12:54:23 +00005000 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005001 wn.pts()[2].fX, wn.pts()[2].fY );
caryclark@google.coma461ff02012-10-11 12:54:23 +00005002 return;
5003 }
5004 SkPoint wtOutPt, wnOutPt;
5005 QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5006 QuadXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5007 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5008 __FUNCTION__,
5009 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5010 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
5011 wtOutPt.fX, wtOutPt.fY);
5012 if (pts == 2) {
5013 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
5014 }
5015 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5016 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5017 wn.pts()[1].fX, wn.pts()[1].fY, wn.pts()[2].fX, wn.pts()[2].fY,
5018 wnOutPt.fX, wnOutPt.fY);
5019 if (pts == 2) {
5020 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005021 }
caryclark@google.comb9738012012-07-03 19:53:30 +00005022 SkDebugf("\n");
5023}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005024#else
5025static void debugShowLineIntersection(int , const Work& ,
5026 const Work& , const double [2], const double [2]) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005027}
caryclark@google.coma461ff02012-10-11 12:54:23 +00005028
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005029static void debugShowQuadLineIntersection(int , const Work& ,
5030 const Work& , const double [2], const double [2]) {
5031}
5032
caryclark@google.coma461ff02012-10-11 12:54:23 +00005033static void debugShowQuadIntersection(int , const Work& ,
5034 const Work& , const double [2], const double [2]) {
5035}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005036#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005037
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005038static bool addIntersectTs(Contour* test, Contour* next) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005039
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005040 if (test != next) {
5041 if (test->bounds().fBottom < next->bounds().fTop) {
5042 return false;
5043 }
5044 if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5045 return true;
5046 }
5047 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005048 Work wt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005049 wt.init(test);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005050 bool foundCommonContour = test == next;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005051 do {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005052 Work wn;
5053 wn.init(next);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005054 if (test == next && !wn.startAfter(wt)) {
5055 continue;
5056 }
5057 do {
5058 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5059 continue;
5060 }
5061 int pts;
5062 Intersections ts;
5063 bool swap = false;
5064 switch (wt.segmentType()) {
5065 case Work::kHorizontalLine_Segment:
5066 swap = true;
5067 switch (wn.segmentType()) {
5068 case Work::kHorizontalLine_Segment:
5069 case Work::kVerticalLine_Segment:
5070 case Work::kLine_Segment: {
5071 pts = HLineIntersect(wn.pts(), wt.left(),
5072 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005073 debugShowLineIntersection(pts, wt, wn,
5074 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005075 break;
5076 }
5077 case Work::kQuad_Segment: {
5078 pts = HQuadIntersect(wn.pts(), wt.left(),
5079 wt.right(), wt.y(), wt.xFlipped(), ts);
5080 break;
5081 }
5082 case Work::kCubic_Segment: {
5083 pts = HCubicIntersect(wn.pts(), wt.left(),
5084 wt.right(), wt.y(), wt.xFlipped(), ts);
5085 break;
5086 }
5087 default:
5088 SkASSERT(0);
5089 }
5090 break;
5091 case Work::kVerticalLine_Segment:
5092 swap = true;
5093 switch (wn.segmentType()) {
5094 case Work::kHorizontalLine_Segment:
5095 case Work::kVerticalLine_Segment:
5096 case Work::kLine_Segment: {
5097 pts = VLineIntersect(wn.pts(), wt.top(),
5098 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005099 debugShowLineIntersection(pts, wt, wn,
5100 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005101 break;
5102 }
5103 case Work::kQuad_Segment: {
5104 pts = VQuadIntersect(wn.pts(), wt.top(),
5105 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5106 break;
5107 }
5108 case Work::kCubic_Segment: {
5109 pts = VCubicIntersect(wn.pts(), wt.top(),
5110 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5111 break;
5112 }
5113 default:
5114 SkASSERT(0);
5115 }
5116 break;
5117 case Work::kLine_Segment:
5118 switch (wn.segmentType()) {
5119 case Work::kHorizontalLine_Segment:
5120 pts = HLineIntersect(wt.pts(), wn.left(),
5121 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005122 debugShowLineIntersection(pts, wt, wn,
5123 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005124 break;
5125 case Work::kVerticalLine_Segment:
5126 pts = VLineIntersect(wt.pts(), wn.top(),
5127 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005128 debugShowLineIntersection(pts, wt, wn,
5129 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005130 break;
5131 case Work::kLine_Segment: {
5132 pts = LineIntersect(wt.pts(), wn.pts(), ts);
5133 debugShowLineIntersection(pts, wt, wn,
5134 ts.fT[1], ts.fT[0]);
5135 break;
5136 }
5137 case Work::kQuad_Segment: {
5138 swap = true;
5139 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005140 debugShowQuadLineIntersection(pts, wn, wt,
5141 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005142 break;
5143 }
5144 case Work::kCubic_Segment: {
5145 swap = true;
5146 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
5147 break;
5148 }
5149 default:
5150 SkASSERT(0);
5151 }
5152 break;
5153 case Work::kQuad_Segment:
5154 switch (wn.segmentType()) {
5155 case Work::kHorizontalLine_Segment:
5156 pts = HQuadIntersect(wt.pts(), wn.left(),
5157 wn.right(), wn.y(), wn.xFlipped(), ts);
5158 break;
5159 case Work::kVerticalLine_Segment:
5160 pts = VQuadIntersect(wt.pts(), wn.top(),
5161 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5162 break;
5163 case Work::kLine_Segment: {
5164 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005165 debugShowQuadLineIntersection(pts, wt, wn,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005166 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005167 break;
5168 }
5169 case Work::kQuad_Segment: {
5170 pts = QuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005171 debugShowQuadIntersection(pts, wt, wn,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005172 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005173 break;
5174 }
5175 case Work::kCubic_Segment: {
5176 wt.promoteToCubic();
5177 pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
5178 break;
5179 }
5180 default:
5181 SkASSERT(0);
5182 }
5183 break;
5184 case Work::kCubic_Segment:
5185 switch (wn.segmentType()) {
5186 case Work::kHorizontalLine_Segment:
5187 pts = HCubicIntersect(wt.pts(), wn.left(),
5188 wn.right(), wn.y(), wn.xFlipped(), ts);
5189 break;
5190 case Work::kVerticalLine_Segment:
5191 pts = VCubicIntersect(wt.pts(), wn.top(),
5192 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5193 break;
5194 case Work::kLine_Segment: {
5195 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
5196 break;
5197 }
5198 case Work::kQuad_Segment: {
5199 wn.promoteToCubic();
5200 pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
5201 break;
5202 }
5203 case Work::kCubic_Segment: {
5204 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
5205 break;
5206 }
5207 default:
5208 SkASSERT(0);
5209 }
5210 break;
5211 default:
5212 SkASSERT(0);
5213 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005214 if (!foundCommonContour && pts > 0) {
5215 test->addCross(next);
5216 next->addCross(test);
5217 foundCommonContour = true;
5218 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005219 // in addition to recording T values, record matching segment
caryclark@google.com32546db2012-08-31 20:55:07 +00005220 if (pts == 2) {
5221 if (wn.segmentType() <= Work::kLine_Segment
5222 && wt.segmentType() <= Work::kLine_Segment) {
5223 wt.addCoincident(wn, ts, swap);
5224 continue;
5225 }
5226 if (wn.segmentType() == Work::kQuad_Segment
5227 && wt.segmentType() == Work::kQuad_Segment
5228 && ts.coincidentUsed() == 2) {
5229 wt.addCoincident(wn, ts, swap);
5230 continue;
5231 }
5232
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00005233 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00005234 for (int pt = 0; pt < pts; ++pt) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005235 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5236 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005237 int testTAt = wt.addT(ts.fT[swap][pt], wn);
5238 int nextTAt = wn.addT(ts.fT[!swap][pt], wt);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005239 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
5240 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005241 }
5242 } while (wn.advance());
5243 } while (wt.advance());
5244 return true;
5245}
5246
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005247// resolve any coincident pairs found while intersecting, and
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005248// see if coincidence is formed by clipping non-concident segments
caryclark@google.com4eeda372012-12-06 21:47:48 +00005249static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005250 int contourCount = contourList.count();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005251#if ONE_PASS_COINCIDENCE_CHECK
caryclark@google.comf25edfe2012-06-01 18:20:10 +00005252 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005253 Contour* contour = contourList[cIndex];
caryclark@google.com7ba591e2012-11-20 14:21:54 +00005254 contour->resolveCoincidence(contourList);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005255 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005256#else
5257 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5258 Contour* contour = contourList[cIndex];
5259 contour->addCoincidentPoints();
5260 }
5261 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5262 Contour* contour = contourList[cIndex];
5263 contour->calcCoincidentWinding();
5264 }
5265#endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005266 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5267 Contour* contour = contourList[cIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00005268 contour->findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005269 }
5270}
5271
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005272static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005273 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005274 SkPoint basePt;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005275 double tAtMid = current->tAtMid(index, endIndex, mid);
5276 current->xyAtT(tAtMid, basePt);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005277 int contourCount = contourList.count();
5278 SkScalar bestY = SK_ScalarMin;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005279 Segment* bestSeg = NULL;
5280 int bestTIndex;
5281 bool bestOpp;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005282 bool hitSomething = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005283 for (int cTest = 0; cTest < contourCount; ++cTest) {
5284 Contour* contour = contourList[cTest];
5285 bool testOpp = contour->operand() ^ current->operand() ^ opp;
5286 if (basePt.fY < contour->bounds().fTop) {
5287 continue;
5288 }
5289 if (bestY > contour->bounds().fBottom) {
5290 continue;
5291 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005292 int segmentCount = contour->segments().count();
5293 for (int test = 0; test < segmentCount; ++test) {
5294 Segment* testSeg = &contour->segments()[test];
5295 SkScalar testY = bestY;
5296 double testHit;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005297 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
5298 testOpp, testSeg == current);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005299 if (testTIndex < 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005300 if (testTIndex == SK_MinS32) {
5301 hitSomething = true;
5302 bestSeg = NULL;
5303 goto abortContours; // vertical encountered, return and try different point
5304 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005305 continue;
5306 }
5307 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005308 double baseT = current->t(index);
5309 double endT = current->t(endIndex);
5310 double newMid = (testHit - baseT) / (endT - baseT);
5311#if DEBUG_WINDING
5312 SkPoint midXY, newXY;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005313 double midT = current->tAtMid(index, endIndex, mid);
5314 current->xyAtT(midT, midXY);
5315 double newMidT = current->tAtMid(index, endIndex, newMid);
5316 current->xyAtT(newMidT, newXY);
caryclark@google.com3586ece2012-12-27 18:46:58 +00005317 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
5318 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
5319 current->debugID(), mid, newMid,
5320 baseT, current->xAtT(index), current->yAtT(index),
5321 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
5322 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
5323 endT, current->xAtT(endIndex), current->yAtT(endIndex));
5324#endif
5325 mid = newMid * 2; // calling loop with divide by 2 before continuing
5326 return SK_MinS32;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005327 }
5328 bestSeg = testSeg;
5329 bestHit = testHit;
5330 bestOpp = testOpp;
5331 bestTIndex = testTIndex;
5332 bestY = testY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005333 }
5334 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005335abortContours:
caryclark@google.com10227bf2012-12-28 22:10:41 +00005336 int result;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005337 if (!bestSeg) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00005338 result = hitSomething ? SK_MinS32 : 0;
5339 } else {
5340 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
5341 current = bestSeg;
5342 index = bestTIndex;
5343 endIndex = bestSeg->nextSpan(bestTIndex, 1);
5344 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
5345 tryAgain = true;
5346 return 0;
5347 }
5348 result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
5349 SkASSERT(bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005350 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005351 double baseT = current->t(index);
5352 double endT = current->t(endIndex);
5353 bestHit = baseT + mid * (endT - baseT);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005354 return result;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005355}
5356
caryclark@google.com24bec792012-08-20 12:43:57 +00005357static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
5358 int contourCount = contourList.count();
5359 Segment* result;
5360 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5361 Contour* contour = contourList[cIndex];
5362 result = contour->undoneSegment(start, end);
5363 if (result) {
5364 return result;
5365 }
5366 }
5367 return NULL;
5368}
5369
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005370#define OLD_FIND_CHASE 1
caryclark@google.com24bec792012-08-20 12:43:57 +00005371
caryclark@google.com31143cf2012-11-09 22:14:19 +00005372static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005373 while (chase.count()) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005374 Span* span;
5375 chase.pop(&span);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005376 const Span& backPtr = span->fOther->span(span->fOtherIndex);
5377 Segment* segment = backPtr.fOther;
5378 tIndex = backPtr.fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005379 SkTDArray<Angle> angles;
5380 int done = 0;
5381 if (segment->activeAngle(tIndex, done, angles)) {
5382 Angle* last = angles.end() - 1;
5383 tIndex = last->start();
5384 endIndex = last->end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005385 #if TRY_ROTATE
5386 *chase.insert(0) = span;
5387 #else
5388 *chase.append() = span;
5389 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005390 return last->segment();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005391 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005392 if (done == angles.count()) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00005393 continue;
5394 }
5395 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005396 bool sortable = Segment::SortAngles(angles, sorted);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005397 int angleCount = sorted.count();
caryclark@google.com03f97062012-08-21 13:13:52 +00005398#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005399 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00005400#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005401 if (!sortable) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005402 continue;
5403 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005404 // find first angle, initialize winding to computed fWindSum
5405 int firstIndex = -1;
5406 const Angle* angle;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005407#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005408 int winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005409 do {
5410 angle = sorted[++firstIndex];
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005411 segment = angle->segment();
5412 winding = segment->windSum(angle);
5413 } while (winding == SK_MinS32);
5414 int spanWinding = segment->spanSign(angle->start(), angle->end());
5415 #if DEBUG_WINDING
caryclark@google.com31143cf2012-11-09 22:14:19 +00005416 SkDebugf("%s winding=%d spanWinding=%d\n",
5417 __FUNCTION__, winding, spanWinding);
caryclark@google.com47580692012-07-23 12:14:49 +00005418 #endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005419 // turn span winding into contour winding
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005420 if (spanWinding * winding < 0) {
5421 winding += spanWinding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005422 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005423 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005424 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005425 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005426 // we care about first sign and whether wind sum indicates this
5427 // edge is inside or outside. Maybe need to pass span winding
5428 // or first winding or something into this function?
5429 // advance to first undone angle, then return it and winding
5430 // (to set whether edges are active or not)
5431 int nextIndex = firstIndex + 1;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005432 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005433 angle = sorted[firstIndex];
caryclark@google.com2ddff932012-08-07 21:25:27 +00005434 winding -= angle->segment()->spanSign(angle);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005435#else
5436 do {
5437 angle = sorted[++firstIndex];
5438 segment = angle->segment();
5439 } while (segment->windSum(angle) == SK_MinS32);
5440 #if DEBUG_SORT
5441 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5442 #endif
5443 int sumWinding = segment->updateWindingReverse(angle);
5444 int nextIndex = firstIndex + 1;
5445 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5446 Segment* first = NULL;
5447#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005448 do {
5449 SkASSERT(nextIndex != firstIndex);
5450 if (nextIndex == angleCount) {
5451 nextIndex = 0;
5452 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005453 angle = sorted[nextIndex];
caryclark@google.com9764cc62012-07-12 19:29:45 +00005454 segment = angle->segment();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005455#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005456 int maxWinding = winding;
caryclark@google.com2ddff932012-08-07 21:25:27 +00005457 winding -= segment->spanSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005458 #if DEBUG_SORT
caryclark@google.com2ddff932012-08-07 21:25:27 +00005459 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
5460 segment->debugID(), maxWinding, winding, angle->sign());
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005461 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005462 tIndex = angle->start();
5463 endIndex = angle->end();
5464 int lesser = SkMin32(tIndex, endIndex);
5465 const Span& nextSpan = segment->span(lesser);
5466 if (!nextSpan.fDone) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005467#if 1
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005468 // FIXME: this be wrong? assign startWinding if edge is in
caryclark@google.com9764cc62012-07-12 19:29:45 +00005469 // same direction. If the direction is opposite, winding to
5470 // assign is flipped sign or +/- 1?
caryclark@google.com59823f72012-08-09 18:17:47 +00005471 if (useInnerWinding(maxWinding, winding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005472 maxWinding = winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005473 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005474 segment->markAndChaseWinding(angle, maxWinding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005475#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005476 break;
5477 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005478#else
5479 int start = angle->start();
5480 int end = angle->end();
5481 int maxWinding;
5482 segment->setUpWinding(start, end, maxWinding, sumWinding);
5483 if (!segment->done(angle)) {
5484 if (!first) {
5485 first = segment;
5486 tIndex = start;
5487 endIndex = end;
5488 }
5489 (void) segment->markAngle(maxWinding, sumWinding, true, angle);
5490 }
5491#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005492 } while (++nextIndex != lastIndex);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005493 #if TRY_ROTATE
5494 *chase.insert(0) = span;
5495 #else
5496 *chase.append() = span;
5497 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005498 return segment;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005499 }
5500 return NULL;
5501}
5502
caryclark@google.com027de222012-07-12 12:52:50 +00005503#if DEBUG_ACTIVE_SPANS
5504static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005505 int index;
5506 for (index = 0; index < contourList.count(); ++ index) {
caryclark@google.com027de222012-07-12 12:52:50 +00005507 contourList[index]->debugShowActiveSpans();
5508 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005509 for (index = 0; index < contourList.count(); ++ index) {
5510 contourList[index]->validateActiveSpans();
5511 }
caryclark@google.com027de222012-07-12 12:52:50 +00005512}
5513#endif
5514
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005515static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005516 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005517 Segment* result;
5518 do {
caryclark@google.comf839c032012-10-26 21:03:50 +00005519 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005520 int contourCount = contourList.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00005521 Segment* topStart = NULL;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005522 done = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00005523 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5524 Contour* contour = contourList[cIndex];
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005525 if (contour->done()) {
5526 continue;
5527 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005528 const Bounds& bounds = contour->bounds();
5529 if (bounds.fBottom < topLeft.fY) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005530 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005531 continue;
5532 }
5533 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005534 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005535 continue;
5536 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005537 contour->topSortableSegment(topLeft, bestXY, topStart);
5538 if (!contour->done()) {
5539 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005540 }
5541 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005542 if (!topStart) {
5543 return NULL;
5544 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005545 topLeft = bestXY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005546 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005547 } while (!result);
5548 return result;
5549}
caryclark@google.com31143cf2012-11-09 22:14:19 +00005550
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005551static int rightAngleWinding(SkTDArray<Contour*>& contourList,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005552 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005553 bool opp) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005554 double test = 0.9;
5555 int contourWinding;
5556 do {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005557 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
5558 tryAgain, test, opp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005559 if (contourWinding != SK_MinS32 || tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005560 return contourWinding;
5561 }
5562 test /= 2;
5563 } while (!approximately_negative(test));
5564 SkASSERT(0); // should be OK to comment out, but interested when this hits
5565 return contourWinding;
5566}
5567
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005568static void skipVertical(SkTDArray<Contour*>& contourList,
5569 Segment*& current, int& index, int& endIndex) {
5570 if (!current->isVertical(index, endIndex)) {
5571 return;
5572 }
5573 int contourCount = contourList.count();
5574 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5575 Contour* contour = contourList[cIndex];
5576 if (contour->done()) {
5577 continue;
5578 }
5579 current = contour->nonVerticalSegment(index, endIndex);
5580 if (current) {
5581 return;
5582 }
5583 }
5584}
5585
caryclark@google.com3586ece2012-12-27 18:46:58 +00005586static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005587 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
5588 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
5589 true);
5590 if (!current) {
5591 return NULL;
5592 }
5593 if (firstContour) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005594 current->initWinding(index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005595 firstContour = false;
5596 return current;
5597 }
5598 int minIndex = SkMin32(index, endIndex);
5599 int sumWinding = current->windSum(minIndex);
5600 if (sumWinding != SK_MinS32) {
5601 return current;
5602 }
5603 sumWinding = current->computeSum(index, endIndex, binary);
5604 if (sumWinding != SK_MinS32) {
5605 return current;
5606 }
5607 int contourWinding;
5608 int oppContourWinding = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005609 // the simple upward projection of the unresolved points hit unsortable angles
5610 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005611 bool tryAgain;
5612 double tHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005613 SkScalar hitDx = 0;
5614 SkScalar hitOppDx = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005615 do {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005616 // if current is vertical, find another candidate which is not
5617 // if only remaining candidates are vertical, then they can be marked done
caryclark@google.com10227bf2012-12-28 22:10:41 +00005618 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005619 skipVertical(contourList, current, index, endIndex);
caryclark@google.com10227bf2012-12-28 22:10:41 +00005620 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005621 tryAgain = false;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005622 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005623 tryAgain, false);
5624 if (tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005625 continue;
5626 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005627 if (!binary) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005628 break;
5629 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005630 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005631 tryAgain, true);
5632 } while (tryAgain);
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00005633
caryclark@google.com3586ece2012-12-27 18:46:58 +00005634 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005635 return current;
5636}
5637
5638// rewrite that abandons keeping local track of winding
caryclark@google.com3586ece2012-12-27 18:46:58 +00005639static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005640 bool firstContour = true;
5641 bool unsortable = false;
5642 bool topUnsortable = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005643 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
5644 do {
5645 int index, endIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005646 bool topDone;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005647 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005648 topUnsortable, topDone, false);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005649 if (!current) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005650 if (topUnsortable || !topDone) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005651 topUnsortable = false;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005652 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005653 topLeft.fX = topLeft.fY = SK_ScalarMin;
5654 continue;
5655 }
5656 break;
5657 }
5658 SkTDArray<Span*> chaseArray;
5659 do {
5660 if (current->activeWinding(index, endIndex)) {
5661 do {
5662 #if DEBUG_ACTIVE_SPANS
5663 if (!unsortable && current->done()) {
5664 debugShowActiveSpans(contourList);
5665 }
5666 #endif
5667 SkASSERT(unsortable || !current->done());
5668 int nextStart = index;
5669 int nextEnd = endIndex;
5670 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
5671 unsortable);
5672 if (!next) {
5673 if (!unsortable && simple.hasMove()
5674 && current->verb() != SkPath::kLine_Verb
5675 && !simple.isClosed()) {
5676 current->addCurveTo(index, endIndex, simple, true);
5677 SkASSERT(simple.isClosed());
5678 }
5679 break;
5680 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005681 #if DEBUG_FLOW
5682 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
5683 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
5684 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
5685 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005686 current->addCurveTo(index, endIndex, simple, true);
5687 current = next;
5688 index = nextStart;
5689 endIndex = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005690 } while (!simple.isClosed() && (!unsortable
caryclark@google.com10227bf2012-12-28 22:10:41 +00005691 || !current->done(SkMin32(index, endIndex))));
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005692 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
5693 SkASSERT(unsortable);
5694 int min = SkMin32(index, endIndex);
5695 if (!current->done(min)) {
5696 current->addCurveTo(index, endIndex, simple, true);
5697 current->markDoneUnary(min);
5698 }
5699 }
5700 simple.close();
5701 } else {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005702 Span* last = current->markAndChaseDoneUnary(index, endIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005703 if (last) {
5704 *chaseArray.append() = last;
5705 }
5706 }
5707 current = findChase(chaseArray, index, endIndex);
5708 #if DEBUG_ACTIVE_SPANS
5709 debugShowActiveSpans(contourList);
5710 #endif
5711 if (!current) {
5712 break;
5713 }
5714 } while (true);
5715 } while (true);
5716 return simple.someAssemblyRequired();
5717}
5718
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005719// returns true if all edges were processed
caryclark@google.comf839c032012-10-26 21:03:50 +00005720static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.com24bec792012-08-20 12:43:57 +00005721 Segment* current;
5722 int start, end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005723 bool unsortable = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005724 bool closable = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00005725 while ((current = findUndone(contourList, start, end))) {
caryclark@google.com24bec792012-08-20 12:43:57 +00005726 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005727 #if DEBUG_ACTIVE_SPANS
5728 if (!unsortable && current->done()) {
5729 debugShowActiveSpans(contourList);
5730 }
5731 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005732 SkASSERT(unsortable || !current->done());
caryclark@google.com24bec792012-08-20 12:43:57 +00005733 int nextStart = start;
5734 int nextEnd = end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005735 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
caryclark@google.com24bec792012-08-20 12:43:57 +00005736 if (!next) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005737 if (!unsortable && simple.hasMove()
caryclark@google.comf839c032012-10-26 21:03:50 +00005738 && current->verb() != SkPath::kLine_Verb
5739 && !simple.isClosed()) {
5740 current->addCurveTo(start, end, simple, true);
5741 SkASSERT(simple.isClosed());
caryclark@google.comc899ad92012-08-23 15:24:42 +00005742 }
caryclark@google.com24bec792012-08-20 12:43:57 +00005743 break;
5744 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005745 #if DEBUG_FLOW
5746 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
5747 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
5748 current->xyAtT(end).fX, current->xyAtT(end).fY);
5749 #endif
caryclark@google.comf839c032012-10-26 21:03:50 +00005750 current->addCurveTo(start, end, simple, true);
caryclark@google.com24bec792012-08-20 12:43:57 +00005751 current = next;
5752 start = nextStart;
5753 end = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005754 } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005755 if (!simple.isClosed()) {
5756 SkASSERT(unsortable);
5757 int min = SkMin32(start, end);
5758 if (!current->done(min)) {
5759 current->addCurveTo(start, end, simple, true);
5760 current->markDone(min, 1);
5761 }
5762 closable = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00005763 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005764 simple.close();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005765 #if DEBUG_ACTIVE_SPANS
5766 debugShowActiveSpans(contourList);
5767 #endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00005768 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005769 return closable;
caryclark@google.com24bec792012-08-20 12:43:57 +00005770}
5771
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005772static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
5773 int contourCount = contourList.count();
5774 for (int cTest = 0; cTest < contourCount; ++cTest) {
5775 Contour* contour = contourList[cTest];
5776 contour->fixOtherTIndex();
5777 }
5778}
5779
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005780static void sortSegments(SkTDArray<Contour*>& contourList) {
5781 int contourCount = contourList.count();
5782 for (int cTest = 0; cTest < contourCount; ++cTest) {
5783 Contour* contour = contourList[cTest];
5784 contour->sortSegments();
5785 }
5786}
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005787
caryclark@google.com4eeda372012-12-06 21:47:48 +00005788static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
5789 bool evenOdd, bool oppEvenOdd) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005790 int count = contours.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005791 if (count == 0) {
5792 return;
5793 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005794 for (int index = 0; index < count; ++index) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00005795 Contour& contour = contours[index];
5796 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
5797 *list.append() = &contour;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005798 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005799 QSort<Contour>(list.begin(), list.end() - 1);
5800}
5801
caryclark@google.comf839c032012-10-26 21:03:50 +00005802static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005803 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005804}
5805
caryclark@google.com10227bf2012-12-28 22:10:41 +00005806static bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
5807 return distances[one] < distances[two];
5808}
caryclark@google.comf839c032012-10-26 21:03:50 +00005809 /*
5810 check start and end of each contour
5811 if not the same, record them
5812 match them up
5813 connect closest
5814 reassemble contour pieces into new path
5815 */
5816static void assemble(const PathWrapper& path, PathWrapper& simple) {
5817#if DEBUG_PATH_CONSTRUCTION
5818 SkDebugf("%s\n", __FUNCTION__);
5819#endif
5820 SkTArray<Contour> contours;
5821 EdgeBuilder builder(path, contours);
5822 builder.finish();
5823 int count = contours.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005824 int outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00005825 SkTDArray<int> runs; // indices of partial contours
caryclark@google.com0b7da432012-10-31 19:00:20 +00005826 for (outer = 0; outer < count; ++outer) {
5827 const Contour& eContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00005828 const SkPoint& eStart = eContour.start();
5829 const SkPoint& eEnd = eContour.end();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005830#if DEBUG_ASSEMBLE
5831 SkDebugf("%s contour", __FUNCTION__);
5832 if (!approximatelyEqual(eStart, eEnd)) {
5833 SkDebugf("[%d]", runs.count());
5834 } else {
5835 SkDebugf(" ");
5836 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00005837 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005838 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
5839#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00005840 if (approximatelyEqual(eStart, eEnd)) {
5841 eContour.toPath(simple);
5842 continue;
5843 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00005844 *runs.append() = outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00005845 }
5846 count = runs.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005847 if (count == 0) {
5848 return;
5849 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005850 SkTDArray<int> sLink, eLink;
5851 sLink.setCount(count);
5852 eLink.setCount(count);
caryclark@google.com10227bf2012-12-28 22:10:41 +00005853 int rIndex, iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00005854 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00005855 sLink[rIndex] = eLink[rIndex] = INT_MAX;
caryclark@google.com0b7da432012-10-31 19:00:20 +00005856 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00005857 SkTDArray<double> distances;
5858 const int ends = count * 2; // all starts and ends
5859 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
5860 distances.setCount(entries);
5861 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
5862 outer = runs[rIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00005863 const Contour& oContour = contours[outer];
caryclark@google.com10227bf2012-12-28 22:10:41 +00005864 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
5865 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
5866 * ends - rIndex - 1;
5867 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
5868 int inner = runs[iIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00005869 const Contour& iContour = contours[inner];
caryclark@google.com10227bf2012-12-28 22:10:41 +00005870 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
5871 double dx = iPt.fX - oPt.fX;
5872 double dy = iPt.fY - oPt.fY;
caryclark@google.com0b7da432012-10-31 19:00:20 +00005873 double dist = dx * dx + dy * dy;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005874 distances[row + iIndex] = dist; // oStart distance from iStart
5875 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005876 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00005877 SkTDArray<int> sortedDist;
5878 sortedDist.setCount(entries);
5879 for (rIndex = 0; rIndex < entries; ++rIndex) {
5880 sortedDist[rIndex] = rIndex;
5881 }
5882 QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
5883 int remaining = count; // number of start/end pairs
5884 for (rIndex = 0; rIndex < entries; ++rIndex) {
5885 int pair = sortedDist[rIndex];
5886 int row = pair / ends;
5887 int col = pair - row * ends;
5888 int thingOne = row < col ? row : ends - row - 2;
5889 int ndxOne = thingOne >> 1;
5890 bool endOne = thingOne & 1;
5891 int* linkOne = endOne ? eLink.begin() : sLink.begin();
5892 if (linkOne[ndxOne] != INT_MAX) {
5893 continue;
5894 }
5895 int thingTwo = row < col ? col : ends - row + col - 1;
5896 int ndxTwo = thingTwo >> 1;
5897 bool endTwo = thingTwo & 1;
5898 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
5899 if (linkTwo[ndxTwo] != INT_MAX) {
5900 continue;
5901 }
5902 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
5903 bool flip = endOne == endTwo;
5904 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
5905 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
5906 if (!--remaining) {
5907 break;
5908 }
5909 }
5910 SkASSERT(!remaining);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005911#if DEBUG_ASSEMBLE
5912 for (rIndex = 0; rIndex < count; ++rIndex) {
5913 int s = sLink[rIndex];
5914 int e = eLink[rIndex];
5915 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
5916 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
caryclark@google.comf839c032012-10-26 21:03:50 +00005917 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005918#endif
5919 rIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00005920 do {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005921 bool forward = true;
5922 bool first = true;
5923 int sIndex = sLink[rIndex];
5924 SkASSERT(sIndex != INT_MAX);
5925 sLink[rIndex] = INT_MAX;
5926 int eIndex;
5927 if (sIndex < 0) {
5928 eIndex = sLink[~sIndex];
5929 sLink[~sIndex] = INT_MAX;
5930 } else {
5931 eIndex = eLink[sIndex];
5932 eLink[sIndex] = INT_MAX;
5933 }
5934 SkASSERT(eIndex != INT_MAX);
5935#if DEBUG_ASSEMBLE
5936 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00005937 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
5938 eIndex < 0 ? ~eIndex : eIndex);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005939#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00005940 do {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005941 outer = runs[rIndex];
5942 const Contour& contour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00005943 if (first) {
caryclark@google.comf839c032012-10-26 21:03:50 +00005944 first = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005945 const SkPoint* startPtr = &contour.start();
caryclark@google.comf839c032012-10-26 21:03:50 +00005946 simple.deferredMove(startPtr[0]);
5947 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005948 if (forward) {
5949 contour.toPartialForward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00005950 } else {
5951 contour.toPartialBackward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00005952 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005953#if DEBUG_ASSEMBLE
5954 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00005955 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005956 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
5957#endif
5958 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00005959 simple.close();
caryclark@google.comf839c032012-10-26 21:03:50 +00005960 break;
5961 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005962 if (forward) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005963 eIndex = eLink[rIndex];
5964 SkASSERT(eIndex != INT_MAX);
caryclark@google.comf839c032012-10-26 21:03:50 +00005965 eLink[rIndex] = INT_MAX;
caryclark@google.com0b7da432012-10-31 19:00:20 +00005966 if (eIndex >= 0) {
5967 SkASSERT(sLink[eIndex] == rIndex);
5968 sLink[eIndex] = INT_MAX;
caryclark@google.comf839c032012-10-26 21:03:50 +00005969 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005970 SkASSERT(eLink[~eIndex] == ~rIndex);
5971 eLink[~eIndex] = INT_MAX;
caryclark@google.comf839c032012-10-26 21:03:50 +00005972 }
5973 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005974 eIndex = sLink[rIndex];
5975 SkASSERT(eIndex != INT_MAX);
caryclark@google.comf839c032012-10-26 21:03:50 +00005976 sLink[rIndex] = INT_MAX;
caryclark@google.com0b7da432012-10-31 19:00:20 +00005977 if (eIndex >= 0) {
5978 SkASSERT(eLink[eIndex] == rIndex);
5979 eLink[eIndex] = INT_MAX;
caryclark@google.comf839c032012-10-26 21:03:50 +00005980 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005981 SkASSERT(sLink[~eIndex] == ~rIndex);
5982 sLink[~eIndex] = INT_MAX;
caryclark@google.comf839c032012-10-26 21:03:50 +00005983 }
5984 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00005985 rIndex = eIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00005986 if (rIndex < 0) {
5987 forward ^= 1;
5988 rIndex = ~rIndex;
5989 }
5990 } while (true);
5991 for (rIndex = 0; rIndex < count; ++rIndex) {
5992 if (sLink[rIndex] != INT_MAX) {
5993 break;
5994 }
5995 }
5996 } while (rIndex < count);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005997#if DEBUG_ASSEMBLE
5998 for (rIndex = 0; rIndex < count; ++rIndex) {
5999 SkASSERT(sLink[rIndex] == INT_MAX);
6000 SkASSERT(eLink[rIndex] == INT_MAX);
6001 }
6002#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006003}
6004
6005void simplifyx(const SkPath& path, SkPath& result) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006006 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
caryclark@google.comf839c032012-10-26 21:03:50 +00006007 result.reset();
6008 result.setFillType(SkPath::kEvenOdd_FillType);
6009 PathWrapper simple(result);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006010
6011 // turn path into list of segments
6012 SkTArray<Contour> contours;
6013 // FIXME: add self-intersecting cubics' T values to segment
6014 EdgeBuilder builder(path, contours);
caryclark@google.com235f56a2012-09-14 14:19:30 +00006015 builder.finish();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006016 SkTDArray<Contour*> contourList;
caryclark@google.com4eeda372012-12-06 21:47:48 +00006017 makeContourList(contours, contourList, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006018 Contour** currentPtr = contourList.begin();
6019 if (!currentPtr) {
6020 return;
6021 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006022 Contour** listEnd = contourList.end();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006023 // find all intersections between segments
6024 do {
6025 Contour** nextPtr = currentPtr;
6026 Contour* current = *currentPtr++;
6027 Contour* next;
6028 do {
6029 next = *nextPtr++;
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00006030 } while (addIntersectTs(current, next) && nextPtr != listEnd);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006031 } while (currentPtr != listEnd);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006032 // eat through coincident edges
caryclark@google.com4eeda372012-12-06 21:47:48 +00006033 coincidenceCheck(contourList, 0);
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00006034 fixOtherTIndex(contourList);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006035 sortSegments(contourList);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006036#if DEBUG_ACTIVE_SPANS
6037 debugShowActiveSpans(contourList);
6038#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006039 // construct closed contours
caryclark@google.com3586ece2012-12-27 18:46:58 +00006040 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00006041 : !bridgeXor(contourList, simple))
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006042 { // if some edges could not be resolved, assemble remaining fragments
caryclark@google.comf839c032012-10-26 21:03:50 +00006043 SkPath temp;
6044 temp.setFillType(SkPath::kEvenOdd_FillType);
6045 PathWrapper assembled(temp);
6046 assemble(simple, assembled);
6047 result = *assembled.nativePath();
caryclark@google.com24bec792012-08-20 12:43:57 +00006048 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006049}
6050