blob: 0303022b8d2df9769d5bf4f147289abc00415323 [file] [log] [blame]
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
caryclark@google.comb45a1b42012-05-18 20:50:33 +00007#include "Simplify.h"
caryclark@google.comfa0588f2012-04-26 21:01:06 +00008
9#undef SkASSERT
10#define SkASSERT(cond) while (!(cond)) { sk_throw(); }
11
caryclark@google.com15fa1382012-05-07 20:49:36 +000012// Terminology:
13// A Path contains one of more Contours
14// A Contour is made up of Segment array
caryclark@google.comb45a1b42012-05-18 20:50:33 +000015// A Segment is described by a Verb and a Point array with 2, 3, or 4 points
16// A Verb is one of Line, Quad(ratic), or Cubic
caryclark@google.com15fa1382012-05-07 20:49:36 +000017// A Segment contains a Span array
18// A Span is describes a portion of a Segment using starting and ending T
19// T values range from 0 to 1, where 0 is the first Point in the Segment
caryclark@google.com47580692012-07-23 12:14:49 +000020// An Edge is a Segment generated from a Span
caryclark@google.com15fa1382012-05-07 20:49:36 +000021
caryclark@google.comfa0588f2012-04-26 21:01:06 +000022// FIXME: remove once debugging is complete
caryclark@google.com47580692012-07-23 12:14:49 +000023#ifdef SK_DEBUG
24int gDebugMaxWindSum = SK_MaxS32;
25int gDebugMaxWindValue = SK_MaxS32;
26#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +000027
caryclark@google.comf839c032012-10-26 21:03:50 +000028#define PIN_ADD_T 0
caryclark@google.com0b7da432012-10-31 19:00:20 +000029#define TRY_ROTATE 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000030#define ONE_PASS_COINCIDENCE_CHECK 0
caryclark@google.com73ca6242013-01-17 21:02:47 +000031#define APPROXIMATE_CUBICS 1
caryclark@google.coma461ff02012-10-11 12:54:23 +000032
caryclark@google.com47580692012-07-23 12:14:49 +000033#define DEBUG_UNUSED 0 // set to expose unused functions
caryclark@google.com45a8fc62013-02-14 15:29:11 +000034
caryclark@google.comc83c70e2013-02-22 21:50:07 +000035#define FORCE_RELEASE 0 // set force release to 1 for multiple thread -- no debugging
caryclark@google.comfa0588f2012-04-26 21:01:06 +000036
caryclark@google.com31143cf2012-11-09 22:14:19 +000037#if FORCE_RELEASE || defined SK_RELEASE
caryclark@google.com47580692012-07-23 12:14:49 +000038
39const bool gRunTestsInOneThread = false;
40
caryclark@google.combeda3892013-02-07 13:13:41 +000041#define DEBUG_ACTIVE_OP 0
caryclark@google.com47580692012-07-23 12:14:49 +000042#define DEBUG_ACTIVE_SPANS 0
caryclark@google.com4eeda372012-12-06 21:47:48 +000043#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000044#define DEBUG_ADD_INTERSECTING_TS 0
caryclark@google.com47580692012-07-23 12:14:49 +000045#define DEBUG_ADD_T_PAIR 0
caryclark@google.comc899ad92012-08-23 15:24:42 +000046#define DEBUG_ANGLE 0
caryclark@google.com7ff5c842013-02-26 15:56:05 +000047#define DEBUG_AS_C_CODE 1
caryclark@google.come7bd5f42012-12-13 19:47:53 +000048#define DEBUG_ASSEMBLE 0
caryclark@google.com47580692012-07-23 12:14:49 +000049#define DEBUG_CONCIDENT 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000050#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000051#define DEBUG_FLOW 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000052#define DEBUG_MARK_DONE 0
caryclark@google.comf839c032012-10-26 21:03:50 +000053#define DEBUG_PATH_CONSTRUCTION 0
caryclark@google.com729e1c42012-11-21 21:36:34 +000054#define DEBUG_SHOW_WINDING 0
caryclark@google.comc83c70e2013-02-22 21:50:07 +000055#define DEBUG_SORT 0
caryclark@google.com5e0500f2013-02-20 12:51:37 +000056#define DEBUG_SWAP_TOP 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000057#define DEBUG_UNSORTABLE 0
caryclark@google.comafe56de2012-07-24 18:11:03 +000058#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000059#define DEBUG_WINDING 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000060#define DEBUG_WINDING_AT_T 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000061
62#else
63
caryclark@google.com47580692012-07-23 12:14:49 +000064const bool gRunTestsInOneThread = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +000065
caryclark@google.combeda3892013-02-07 13:13:41 +000066#define DEBUG_ACTIVE_OP 1
caryclark@google.comc91dfe42012-10-16 12:06:27 +000067#define DEBUG_ACTIVE_SPANS 1
caryclark@google.com4eeda372012-12-06 21:47:48 +000068#define DEBUG_ACTIVE_SPANS_SHORT_FORM 1
caryclark@google.com6aea33f2012-10-09 14:11:58 +000069#define DEBUG_ADD_INTERSECTING_TS 1
70#define DEBUG_ADD_T_PAIR 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000071#define DEBUG_ANGLE 1
caryclark@google.com4aaaaea2013-02-28 16:12:39 +000072#define DEBUG_AS_C_CODE 1
caryclark@google.come7bd5f42012-12-13 19:47:53 +000073#define DEBUG_ASSEMBLE 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000074#define DEBUG_CONCIDENT 1
caryclark@google.com534aa5b2012-08-02 20:08:21 +000075#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000076#define DEBUG_FLOW 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000077#define DEBUG_MARK_DONE 1
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000078#define DEBUG_PATH_CONSTRUCTION 1
caryclark@google.com729e1c42012-11-21 21:36:34 +000079#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000080#define DEBUG_SORT 1
caryclark@google.com47d73da2013-02-17 01:41:25 +000081#define DEBUG_SWAP_TOP 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000082#define DEBUG_UNSORTABLE 1
caryclark@google.comafe56de2012-07-24 18:11:03 +000083#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000084#define DEBUG_WINDING 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000085#define DEBUG_WINDING_AT_T 1
caryclark@google.comfa0588f2012-04-26 21:01:06 +000086
87#endif
88
caryclark@google.combeda3892013-02-07 13:13:41 +000089#define DEBUG_DUMP (DEBUG_ACTIVE_OP | DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | \
90 DEBUG_PATH_CONSTRUCTION)
caryclark@google.com027de222012-07-12 12:52:50 +000091
caryclark@google.comfa0588f2012-04-26 21:01:06 +000092#if DEBUG_DUMP
93static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000094// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
caryclark@google.comfa0588f2012-04-26 21:01:06 +000095static int gContourID;
96static int gSegmentID;
97#endif
98
caryclark@google.comc83c70e2013-02-22 21:50:07 +000099#if DEBUG_SORT
caryclark@google.com4aaaaea2013-02-28 16:12:39 +0000100static int gDebugSortCountDefault = SK_MaxS32;
caryclark@google.comc83c70e2013-02-22 21:50:07 +0000101static int gDebugSortCount;
102#endif
103
caryclark@google.com5e0500f2013-02-20 12:51:37 +0000104#if DEBUG_ACTIVE_OP
105static const char* kShapeOpStr[] = {"diff", "sect", "union", "xor"};
106#endif
107
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000108#ifndef DEBUG_TEST
109#define DEBUG_TEST 0
110#endif
111
caryclark@google.com32546db2012-08-31 20:55:07 +0000112#define MAKE_CONST_LINE(line, pts) \
113 const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}
114#define MAKE_CONST_QUAD(quad, pts) \
115 const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
116 {pts[2].fX, pts[2].fY}}
117#define MAKE_CONST_CUBIC(cubic, pts) \
118 const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
119 {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}}
120
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000121static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
122 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000123 MAKE_CONST_LINE(aLine, a);
124 MAKE_CONST_LINE(bLine, b);
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000125 return intersect(aLine, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000126}
127
128static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
129 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000130 MAKE_CONST_QUAD(aQuad, a);
131 MAKE_CONST_LINE(bLine, b);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000132 return intersect(aQuad, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000133}
134
caryclark@google.com32546db2012-08-31 20:55:07 +0000135static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000136 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000137 MAKE_CONST_CUBIC(aCubic, a);
138 MAKE_CONST_LINE(bLine, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000139 return intersect(aCubic, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000140}
141
142static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
143 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000144 MAKE_CONST_QUAD(aQuad, a);
145 MAKE_CONST_QUAD(bQuad, b);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000146#define TRY_QUARTIC_SOLUTION 1
147#if TRY_QUARTIC_SOLUTION
148 intersect2(aQuad, bQuad, intersections);
149#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000150 intersect(aQuad, bQuad, intersections);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000151#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000152 return intersections.fUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000153}
154
caryclark@google.com73ca6242013-01-17 21:02:47 +0000155#if APPROXIMATE_CUBICS
156static int CubicQuadIntersect(const SkPoint a[4], const SkPoint b[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000157 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000158 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000159 MAKE_CONST_QUAD(bQuad, b);
160 return intersect(aCubic, bQuad, intersections);
161}
162#endif
163
164static int CubicIntersect(const SkPoint a[4], const SkPoint b[4], Intersections& intersections) {
165 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com32546db2012-08-31 20:55:07 +0000166 MAKE_CONST_CUBIC(bCubic, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000167#if APPROXIMATE_CUBICS
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000168 intersect3(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000169#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000170 intersect(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000171#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000172 return intersections.fUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000173}
174
caryclark@google.comc83c70e2013-02-22 21:50:07 +0000175static int CubicIntersect(const SkPoint a[4], Intersections& intersections) {
176 MAKE_CONST_CUBIC(aCubic, a);
177 return intersect(aCubic, intersections);
178}
179
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000180static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
181 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000182 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000183 return horizontalIntersect(aLine, left, right, y, flipped, intersections);
184}
185
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000186static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
187 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000188 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000189 return horizontalIntersect(aQuad, left, right, y, flipped, intersections);
190}
191
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000192static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
193 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000194 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000195 return horizontalIntersect(aCubic, left, right, y, flipped, intersections);
196}
197
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000198static int (* const HSegmentIntersect[])(const SkPoint [], SkScalar ,
199 SkScalar , SkScalar , bool , Intersections& ) = {
200 NULL,
201 HLineIntersect,
202 HQuadIntersect,
203 HCubicIntersect
204};
205
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000206static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom,
207 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000208 MAKE_CONST_LINE(aLine, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000209 return verticalIntersect(aLine, top, bottom, x, flipped, intersections);
210}
211
212static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom,
213 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000214 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000215 return verticalIntersect(aQuad, top, bottom, x, flipped, intersections);
216}
217
218static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom,
219 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000220 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000221 return verticalIntersect(aCubic, top, bottom, x, flipped, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000222}
223
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000224static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar ,
225 SkScalar , SkScalar , bool , Intersections& ) = {
226 NULL,
227 VLineIntersect,
228 VQuadIntersect,
229 VCubicIntersect
230};
231
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000232static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000233 MAKE_CONST_LINE(line, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000234 double x, y;
235 xy_at_t(line, t, x, y);
236 out->fX = SkDoubleToScalar(x);
237 out->fY = SkDoubleToScalar(y);
238}
239
caryclark@google.comf9502d72013-02-04 14:06:49 +0000240static void LineXYAtT(const SkPoint a[2], double t, _Point* out) {
241 MAKE_CONST_LINE(line, a);
242 xy_at_t(line, t, out->x, out->y);
243}
244
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000245static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000246 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000247 double x, y;
248 xy_at_t(quad, t, x, y);
249 out->fX = SkDoubleToScalar(x);
250 out->fY = SkDoubleToScalar(y);
251}
252
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000253static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
254 MAKE_CONST_QUAD(quad, a);
255 xy_at_t(quad, t, out->x, out->y);
256}
257
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000258static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000259 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000260 double x, y;
261 xy_at_t(cubic, t, x, y);
262 out->fX = SkDoubleToScalar(x);
263 out->fY = SkDoubleToScalar(y);
264}
265
caryclark@google.comf9502d72013-02-04 14:06:49 +0000266static void CubicXYAtT(const SkPoint a[4], double t, _Point* out) {
267 MAKE_CONST_CUBIC(cubic, a);
268 xy_at_t(cubic, t, out->x, out->y);
269}
270
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000271static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
272 NULL,
273 LineXYAtT,
274 QuadXYAtT,
275 CubicXYAtT
276};
277
caryclark@google.comf9502d72013-02-04 14:06:49 +0000278static void (* const SegmentXYAtT2[])(const SkPoint [], double , _Point* ) = {
279 NULL,
280 LineXYAtT,
281 QuadXYAtT,
282 CubicXYAtT
283};
284
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000285static SkScalar LineXAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000286 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000287 double x;
288 xy_at_t(aLine, t, x, *(double*) 0);
289 return SkDoubleToScalar(x);
290}
291
292static SkScalar QuadXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000293 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000294 double x;
295 xy_at_t(quad, t, x, *(double*) 0);
296 return SkDoubleToScalar(x);
297}
298
299static SkScalar CubicXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000300 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000301 double x;
302 xy_at_t(cubic, t, x, *(double*) 0);
303 return SkDoubleToScalar(x);
304}
305
306static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
307 NULL,
308 LineXAtT,
309 QuadXAtT,
310 CubicXAtT
311};
312
313static SkScalar LineYAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000314 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000315 double y;
316 xy_at_t(aLine, t, *(double*) 0, y);
317 return SkDoubleToScalar(y);
318}
319
320static SkScalar QuadYAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000321 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000322 double y;
323 xy_at_t(quad, t, *(double*) 0, y);
324 return SkDoubleToScalar(y);
325}
326
327static SkScalar CubicYAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000328 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000329 double y;
330 xy_at_t(cubic, t, *(double*) 0, y);
331 return SkDoubleToScalar(y);
332}
333
334static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
335 NULL,
336 LineYAtT,
337 QuadYAtT,
338 CubicYAtT
339};
340
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000341static SkScalar LineDXAtT(const SkPoint a[2], double ) {
342 return a[1].fX - a[0].fX;
343}
344
345static SkScalar QuadDXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000346 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000347 double x = dx_at_t(quad, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000348 return SkDoubleToScalar(x);
349}
350
351static SkScalar CubicDXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000352 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000353 double x = dx_at_t(cubic, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000354 return SkDoubleToScalar(x);
355}
356
357static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
358 NULL,
359 LineDXAtT,
360 QuadDXAtT,
361 CubicDXAtT
362};
363
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000364static SkScalar LineDYAtT(const SkPoint a[2], double ) {
365 return a[1].fY - a[0].fY;
366}
367
368static SkScalar QuadDYAtT(const SkPoint a[3], double t) {
369 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000370 double y = dy_at_t(quad, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000371 return SkDoubleToScalar(y);
372}
373
374static SkScalar CubicDYAtT(const SkPoint a[4], double t) {
375 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000376 double y = dy_at_t(cubic, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000377 return SkDoubleToScalar(y);
378}
379
380static SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = {
381 NULL,
382 LineDYAtT,
383 QuadDYAtT,
384 CubicDYAtT
385};
386
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000387static SkVector LineDXDYAtT(const SkPoint a[2], double ) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000388 return a[1] - a[0];
389}
390
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000391static SkVector QuadDXDYAtT(const SkPoint a[3], double t) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000392 MAKE_CONST_QUAD(quad, a);
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000393 _Vector v = dxdy_at_t(quad, t);
394 return v.asSkVector();
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000395}
396
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000397static SkVector CubicDXDYAtT(const SkPoint a[4], double t) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000398 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000399 _Vector v = dxdy_at_t(cubic, t);
400 return v.asSkVector();
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000401}
402
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000403static SkVector (* const SegmentDXDYAtT[])(const SkPoint [], double ) = {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000404 NULL,
405 LineDXDYAtT,
406 QuadDXDYAtT,
407 CubicDXDYAtT
408};
409
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000410static void LineSubDivide(const SkPoint a[2], double startT, double endT,
411 SkPoint sub[2]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000412 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000413 _Line dst;
414 sub_divide(aLine, startT, endT, dst);
415 sub[0].fX = SkDoubleToScalar(dst[0].x);
416 sub[0].fY = SkDoubleToScalar(dst[0].y);
417 sub[1].fX = SkDoubleToScalar(dst[1].x);
418 sub[1].fY = SkDoubleToScalar(dst[1].y);
419}
420
421static void QuadSubDivide(const SkPoint a[3], double startT, double endT,
422 SkPoint sub[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000423 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000424 Quadratic dst;
425 sub_divide(aQuad, startT, endT, dst);
426 sub[0].fX = SkDoubleToScalar(dst[0].x);
427 sub[0].fY = SkDoubleToScalar(dst[0].y);
428 sub[1].fX = SkDoubleToScalar(dst[1].x);
429 sub[1].fY = SkDoubleToScalar(dst[1].y);
430 sub[2].fX = SkDoubleToScalar(dst[2].x);
431 sub[2].fY = SkDoubleToScalar(dst[2].y);
432}
433
434static void CubicSubDivide(const SkPoint a[4], double startT, double endT,
435 SkPoint sub[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000436 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000437 Cubic dst;
438 sub_divide(aCubic, startT, endT, dst);
439 sub[0].fX = SkDoubleToScalar(dst[0].x);
440 sub[0].fY = SkDoubleToScalar(dst[0].y);
441 sub[1].fX = SkDoubleToScalar(dst[1].x);
442 sub[1].fY = SkDoubleToScalar(dst[1].y);
443 sub[2].fX = SkDoubleToScalar(dst[2].x);
444 sub[2].fY = SkDoubleToScalar(dst[2].y);
445 sub[3].fX = SkDoubleToScalar(dst[3].x);
446 sub[3].fY = SkDoubleToScalar(dst[3].y);
447}
448
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000449static void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
450 SkPoint []) = {
451 NULL,
452 LineSubDivide,
453 QuadSubDivide,
454 CubicSubDivide
455};
456
caryclark@google.comaa358312013-01-29 20:28:49 +0000457static void LineSubDivideHD(const SkPoint a[2], double startT, double endT, _Line& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000458 MAKE_CONST_LINE(aLine, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000459 sub_divide(aLine, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000460}
461
caryclark@google.comaa358312013-01-29 20:28:49 +0000462static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT, Quadratic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000463 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000464 sub_divide(aQuad, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000465}
466
caryclark@google.comaa358312013-01-29 20:28:49 +0000467static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT, Cubic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000468 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000469 sub_divide(aCubic, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000470}
471
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000472static SkPoint QuadTop(const SkPoint a[3], double startT, double endT) {
473 MAKE_CONST_QUAD(quad, a);
474 _Point topPt = top(quad, startT, endT);
475 return topPt.asSkPoint();
476}
477
478static SkPoint CubicTop(const SkPoint a[3], double startT, double endT) {
479 MAKE_CONST_CUBIC(cubic, a);
480 _Point topPt = top(cubic, startT, endT);
481 return topPt.asSkPoint();
482}
483
484static SkPoint (* SegmentTop[])(const SkPoint[], double , double ) = {
485 NULL,
486 NULL,
487 QuadTop,
488 CubicTop
489};
490
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000491#if DEBUG_UNUSED
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000492static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
493 SkRect& bounds) {
494 SkPoint dst[3];
495 QuadSubDivide(a, startT, endT, dst);
496 bounds.fLeft = bounds.fRight = dst[0].fX;
497 bounds.fTop = bounds.fBottom = dst[0].fY;
498 for (int index = 1; index < 3; ++index) {
499 bounds.growToInclude(dst[index].fX, dst[index].fY);
500 }
501}
502
503static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
504 SkRect& bounds) {
505 SkPoint dst[4];
506 CubicSubDivide(a, startT, endT, dst);
507 bounds.fLeft = bounds.fRight = dst[0].fX;
508 bounds.fTop = bounds.fBottom = dst[0].fY;
509 for (int index = 1; index < 4; ++index) {
510 bounds.growToInclude(dst[index].fX, dst[index].fY);
511 }
512}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000513#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000514
caryclark@google.com15fa1382012-05-07 20:49:36 +0000515static SkPath::Verb QuadReduceOrder(const SkPoint a[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000516 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000517 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000518 Quadratic dst;
caryclark@google.com47d73da2013-02-17 01:41:25 +0000519 int order = reduceOrder(aQuad, dst, kReduceOrder_TreatAsFill);
caryclark@google.com24bec792012-08-20 12:43:57 +0000520 if (order == 2) { // quad became line
521 for (int index = 0; index < order; ++index) {
522 SkPoint* pt = reducePts.append();
523 pt->fX = SkDoubleToScalar(dst[index].x);
524 pt->fY = SkDoubleToScalar(dst[index].y);
525 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000526 }
527 return (SkPath::Verb) (order - 1);
528}
529
530static SkPath::Verb CubicReduceOrder(const SkPoint a[4],
531 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000532 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000533 Cubic dst;
caryclark@google.com47d73da2013-02-17 01:41:25 +0000534 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed, kReduceOrder_TreatAsFill);
caryclark@google.com24bec792012-08-20 12:43:57 +0000535 if (order == 2 || order == 3) { // cubic became line or quad
536 for (int index = 0; index < order; ++index) {
537 SkPoint* pt = reducePts.append();
538 pt->fX = SkDoubleToScalar(dst[index].x);
539 pt->fY = SkDoubleToScalar(dst[index].y);
540 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000541 }
542 return (SkPath::Verb) (order - 1);
543}
544
caryclark@google.com15fa1382012-05-07 20:49:36 +0000545static bool QuadIsLinear(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000546 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000547 return isLinear(aQuad, 0, 2);
548}
549
550static bool CubicIsLinear(const SkPoint a[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000551 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000552 return isLinear(aCubic, 0, 3);
553}
554
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000555static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000556 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000557 double x[2];
558 xy_at_t(aLine, startT, x[0], *(double*) 0);
caryclark@google.com495f8e42012-05-31 13:13:11 +0000559 xy_at_t(aLine, endT, x[1], *(double*) 0);
560 return SkMinScalar((float) x[0], (float) x[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000561}
562
563static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000564 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000565 return (float) leftMostT(aQuad, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000566}
567
568static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000569 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000570 return (float) leftMostT(aCubic, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000571}
572
573static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
574 NULL,
575 LineLeftMost,
576 QuadLeftMost,
577 CubicLeftMost
578};
579
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000580#if 0 // currently unused
caryclark@google.com235f56a2012-09-14 14:19:30 +0000581static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
582 Intersections& intersections) {
583 MAKE_CONST_QUAD(aQuad, a);
584 MAKE_CONST_LINE(bLine, b);
585 return intersectRay(aQuad, bLine, intersections);
586}
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000587#endif
588
caryclark@google.comf9502d72013-02-04 14:06:49 +0000589static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000590 MAKE_CONST_QUAD(aQuad, a);
591 return intersectRay(aQuad, bLine, intersections);
592}
caryclark@google.com235f56a2012-09-14 14:19:30 +0000593
caryclark@google.comf9502d72013-02-04 14:06:49 +0000594static int CubicRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
595 MAKE_CONST_CUBIC(aCubic, a);
596 return intersectRay(aCubic, bLine, intersections);
597}
598
599static int (* const SegmentRayIntersect[])(const SkPoint [], const _Line& , Intersections&) = {
600 NULL,
601 NULL,
602 QuadRayIntersect,
603 CubicRayIntersect
604};
605
606
607
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000608static bool LineVertical(const SkPoint a[2], double startT, double endT) {
609 MAKE_CONST_LINE(aLine, a);
610 double x[2];
611 xy_at_t(aLine, startT, x[0], *(double*) 0);
612 xy_at_t(aLine, endT, x[1], *(double*) 0);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000613 return AlmostEqualUlps((float) x[0], (float) x[1]);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000614}
615
616static bool QuadVertical(const SkPoint a[3], double startT, double endT) {
617 SkPoint dst[3];
618 QuadSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000619 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000620}
621
622static bool CubicVertical(const SkPoint a[4], double startT, double endT) {
623 SkPoint dst[4];
624 CubicSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000625 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX)
626 && AlmostEqualUlps(dst[2].fX, dst[3].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000627}
628
629static bool (* const SegmentVertical[])(const SkPoint [], double , double) = {
630 NULL,
631 LineVertical,
632 QuadVertical,
633 CubicVertical
634};
635
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000636class Segment;
637
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000638struct Span {
639 Segment* fOther;
640 mutable SkPoint fPt; // lazily computed as needed
641 double fT;
642 double fOtherT; // value at fOther[fOtherIndex].fT
643 int fOtherIndex; // can't be used during intersection
caryclark@google.com31143cf2012-11-09 22:14:19 +0000644 int fWindSum; // accumulated from contours surrounding this one.
645 int fOppSum; // for binary operators: the opposite winding sum
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000646 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
caryclark@google.com57cff8d2012-11-14 21:14:56 +0000647 int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000648 bool fDone; // if set, this span to next higher T has been processed
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000649 bool fUnsortableStart; // set when start is part of an unsortable pair
650 bool fUnsortableEnd; // set when end is part of an unsortable pair
caryclark@google.comf839c032012-10-26 21:03:50 +0000651 bool fTiny; // if set, span may still be considered once for edge following
caryclark@google.com4aaaaea2013-02-28 16:12:39 +0000652 bool fLoop; // set when a cubic loops back to this point
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000653};
654
caryclark@google.com15fa1382012-05-07 20:49:36 +0000655// sorting angles
656// given angles of {dx dy ddx ddy dddx dddy} sort them
657class Angle {
658public:
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000659 // FIXME: this is bogus for quads and cubics
660 // if the quads and cubics' line from end pt to ctrl pt are coincident,
661 // there's no obvious way to determine the curve ordering from the
662 // derivatives alone. In particular, if one quadratic's coincident tangent
663 // is longer than the other curve, the final control point can place the
664 // longer curve on either side of the shorter one.
665 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
666 // may provide some help, but nothing has been figured out yet.
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000667
caryclark@google.com32546db2012-08-31 20:55:07 +0000668 /*(
669 for quads and cubics, set up a parameterized line (e.g. LineParameters )
670 for points [0] to [1]. See if point [2] is on that line, or on one side
671 or the other. If it both quads' end points are on the same side, choose
672 the shorter tangent. If the tangents are equal, choose the better second
673 tangent angle
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000674
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000675 maybe I could set up LineParameters lazily
caryclark@google.com32546db2012-08-31 20:55:07 +0000676 */
caryclark@google.com15fa1382012-05-07 20:49:36 +0000677 bool operator<(const Angle& rh) const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000678 double y = dy();
679 double ry = rh.dy();
680 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
681 return y < 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000682 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000683 double x = dx();
684 double rx = rh.dx();
685 if (y == 0 && ry == 0 && x * rx < 0) {
686 return x < rx;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000687 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000688 double x_ry = x * ry;
689 double rx_y = rx * y;
690 double cmp = x_ry - rx_y;
caryclark@google.comc899ad92012-08-23 15:24:42 +0000691 if (!approximately_zero(cmp)) {
caryclark@google.com15fa1382012-05-07 20:49:36 +0000692 return cmp < 0;
693 }
caryclark@google.comd1688742012-09-18 20:08:37 +0000694 if (approximately_zero(x_ry) && approximately_zero(rx_y)
695 && !approximately_zero_squared(cmp)) {
696 return cmp < 0;
697 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000698 // at this point, the initial tangent line is coincident
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000699 // see if edges curl away from each other
caryclark@google.com31143cf2012-11-09 22:14:19 +0000700 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
701 || !approximately_zero(rh.fSide))) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000702 // FIXME: running demo will trigger this assertion
703 // (don't know if commenting out will trigger further assertion or not)
704 // commenting it out allows demo to run in release, though
705 // SkASSERT(fSide != rh.fSide);
706 return fSide < rh.fSide;
707 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000708 // see if either curve can be lengthened and try the tangent compare again
709 if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
710 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
711 Angle longer = *this;
712 Angle rhLonger = rh;
713 if (longer.lengthen() | rhLonger.lengthen()) {
714 return longer < rhLonger;
715 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000716 #if 0
caryclark@google.coma461ff02012-10-11 12:54:23 +0000717 // what if we extend in the other direction?
718 longer = *this;
719 rhLonger = rh;
720 if (longer.reverseLengthen() | rhLonger.reverseLengthen()) {
721 return longer < rhLonger;
722 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000723 #endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000724 }
caryclark@google.com185c7c42012-10-19 18:26:24 +0000725 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
caryclark@google.com31143cf2012-11-09 22:14:19 +0000726 || (rh.fVerb == SkPath::kLine_Verb
727 && approximately_zero(rx) && approximately_zero(ry))) {
caryclark@google.com185c7c42012-10-19 18:26:24 +0000728 // See general unsortable comment below. This case can happen when
729 // one line has a non-zero change in t but no change in x and y.
730 fUnsortable = true;
731 rh.fUnsortable = true;
732 return this < &rh; // even with no solution, return a stable sort
733 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000734 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
735 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
736 fUnsortable = true;
737 rh.fUnsortable = true;
738 return this < &rh; // even with no solution, return a stable sort
739 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000740 SkASSERT(fVerb >= SkPath::kQuad_Verb);
741 SkASSERT(rh.fVerb >= SkPath::kQuad_Verb);
skia.committer@gmail.comc1ad0222012-09-19 02:01:47 +0000742 // FIXME: until I can think of something better, project a ray from the
caryclark@google.comd1688742012-09-18 20:08:37 +0000743 // end of the shorter tangent to midway between the end points
744 // through both curves and use the resulting angle to sort
caryclark@google.com235f56a2012-09-14 14:19:30 +0000745 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
746 double len = fTangent1.normalSquared();
747 double rlen = rh.fTangent1.normalSquared();
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000748 _Line ray;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000749 Intersections i, ri;
caryclark@google.comd1688742012-09-18 20:08:37 +0000750 int roots, rroots;
751 bool flip = false;
752 do {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000753 bool useThis = (len < rlen) ^ flip;
754 const Cubic& part = useThis ? fCurvePart : rh.fCurvePart;
755 SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb;
756 ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ?
757 part[2] : part[1];
758 ray[1].x = (part[0].x + part[partVerb].x) / 2;
759 ray[1].y = (part[0].y + part[partVerb].y) / 2;
caryclark@google.comd1688742012-09-18 20:08:37 +0000760 SkASSERT(ray[0] != ray[1]);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000761 roots = (*SegmentRayIntersect[fVerb])(fPts, ray, i);
762 rroots = (*SegmentRayIntersect[rh.fVerb])(rh.fPts, ray, ri);
caryclark@google.comd1688742012-09-18 20:08:37 +0000763 } while ((roots == 0 || rroots == 0) && (flip ^= true));
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000764 if (roots == 0 || rroots == 0) {
765 // FIXME: we don't have a solution in this case. The interim solution
766 // is to mark the edges as unsortable, exclude them from this and
767 // future computations, and allow the returned path to be fragmented
768 fUnsortable = true;
769 rh.fUnsortable = true;
770 return this < &rh; // even with no solution, return a stable sort
771 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000772 _Point loc;
773 double best = SK_ScalarInfinity;
774 double dx, dy, dist;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000775 int index;
776 for (index = 0; index < roots; ++index) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000777 (*SegmentXYAtT2[fVerb])(fPts, i.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000778 dx = loc.x - ray[0].x;
779 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000780 dist = dx * dx + dy * dy;
781 if (best > dist) {
782 best = dist;
783 }
784 }
785 for (index = 0; index < rroots; ++index) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000786 (*SegmentXYAtT2[rh.fVerb])(rh.fPts, ri.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000787 dx = loc.x - ray[0].x;
788 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000789 dist = dx * dx + dy * dy;
790 if (best > dist) {
791 return fSide < 0;
792 }
793 }
794 return fSide > 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000795 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000796
caryclark@google.com47580692012-07-23 12:14:49 +0000797 double dx() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000798 return fTangent1.dx();
caryclark@google.com47580692012-07-23 12:14:49 +0000799 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000800
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000801 double dy() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000802 return fTangent1.dy();
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000803 }
804
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000805 int end() const {
806 return fEnd;
807 }
808
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000809 bool isHorizontal() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000810 return dy() == 0 && fVerb == SkPath::kLine_Verb;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000811 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000812
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000813 bool lengthen() {
814 int newEnd = fEnd;
815 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
816 fEnd = newEnd;
817 setSpans();
818 return true;
819 }
820 return false;
821 }
822
caryclark@google.coma461ff02012-10-11 12:54:23 +0000823 bool reverseLengthen() {
824 if (fReversed) {
825 return false;
826 }
827 int newEnd = fStart;
828 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
829 fEnd = newEnd;
830 fReversed = true;
831 setSpans();
832 return true;
833 }
834 return false;
835 }
836
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000837 void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000838 int start, int end, const SkTDArray<Span>& spans) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000839 fSegment = segment;
840 fStart = start;
841 fEnd = end;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000842 fPts = orig;
843 fVerb = verb;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000844 fSpans = &spans;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000845 fReversed = false;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000846 fUnsortable = false;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000847 setSpans();
848 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000849
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000850
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000851 void setSpans() {
852 double startT = (*fSpans)[fStart].fT;
853 double endT = (*fSpans)[fEnd].fT;
854 switch (fVerb) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000855 case SkPath::kLine_Verb:
856 _Line l;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000857 LineSubDivideHD(fPts, startT, endT, l);
caryclark@google.com32546db2012-08-31 20:55:07 +0000858 // OPTIMIZATION: for pure line compares, we never need fTangent1.c
859 fTangent1.lineEndPoints(l);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000860 fSide = 0;
caryclark@google.com32546db2012-08-31 20:55:07 +0000861 break;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000862 case SkPath::kQuad_Verb: {
863 Quadratic& quad = (Quadratic&)fCurvePart;
864 QuadSubDivideHD(fPts, startT, endT, quad);
865 fTangent1.quadEndPoints(quad, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000866 if (dx() == 0 && dy() == 0) {
caryclark@google.combeda3892013-02-07 13:13:41 +0000867 // SkDebugf("*** %s quad is line\n", __FUNCTION__);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000868 fTangent1.quadEndPoints(quad);
caryclark@google.comaa358312013-01-29 20:28:49 +0000869 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000870 fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- compare sign only
871 } break;
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000872 case SkPath::kCubic_Verb: {
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000873 int nextC = 2;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000874 CubicSubDivideHD(fPts, startT, endT, fCurvePart);
875 fTangent1.cubicEndPoints(fCurvePart, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000876 if (dx() == 0 && dy() == 0) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000877 fTangent1.cubicEndPoints(fCurvePart, 0, 2);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000878 nextC = 3;
caryclark@google.comaa358312013-01-29 20:28:49 +0000879 if (dx() == 0 && dy() == 0) {
caryclark@google.com4aaaaea2013-02-28 16:12:39 +0000880 // SkDebugf("*** %s cubic is line\n", __FUNCTION__);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000881 fTangent1.cubicEndPoints(fCurvePart, 0, 3);
caryclark@google.comaa358312013-01-29 20:28:49 +0000882 }
caryclark@google.comaa358312013-01-29 20:28:49 +0000883 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000884 fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign only
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000885 if (nextC == 2 && approximately_zero(fSide)) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000886 fSide = -fTangent1.pointDistance(fCurvePart[3]);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000887 }
888 } break;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000889 default:
890 SkASSERT(0);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000891 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000892 fUnsortable = dx() == 0 && dy() == 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000893 if (fUnsortable) {
894 return;
895 }
896 SkASSERT(fStart != fEnd);
897 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
898 for (int index = fStart; index != fEnd; index += step) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000899#if 1
900 const Span& thisSpan = (*fSpans)[index];
901 const Span& nextSpan = (*fSpans)[index + step];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000902 if (thisSpan.fTiny || precisely_equal(thisSpan.fT, nextSpan.fT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000903 continue;
caryclark@google.comf839c032012-10-26 21:03:50 +0000904 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000905 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
906#if DEBUG_UNSORTABLE
907 if (fUnsortable) {
908 SkPoint iPt, ePt;
909 (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt);
910 (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt);
911 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
912 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
913 }
914#endif
915 return;
916#else
917 if ((*fSpans)[index].fUnsortableStart) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000918 fUnsortable = true;
919 return;
920 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000921#endif
caryclark@google.comf839c032012-10-26 21:03:50 +0000922 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000923#if 1
924#if DEBUG_UNSORTABLE
925 SkPoint iPt, ePt;
926 (*SegmentXYAtT[fVerb])(fPts, startT, &iPt);
927 (*SegmentXYAtT[fVerb])(fPts, endT, &ePt);
928 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
929 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
930#endif
931 fUnsortable = true;
932#endif
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000933 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000934
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000935 Segment* segment() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000936 return const_cast<Segment*>(fSegment);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000937 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000938
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000939 int sign() const {
caryclark@google.com495f8e42012-05-31 13:13:11 +0000940 return SkSign32(fStart - fEnd);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000941 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000942
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000943 const SkTDArray<Span>* spans() const {
944 return fSpans;
945 }
946
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000947 int start() const {
948 return fStart;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000949 }
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +0000950
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000951 bool unsortable() const {
952 return fUnsortable;
953 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000954
caryclark@google.comc899ad92012-08-23 15:24:42 +0000955#if DEBUG_ANGLE
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000956 const SkPoint* pts() const {
957 return fPts;
958 }
959
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000960 SkPath::Verb verb() const {
961 return fVerb;
962 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000963
caryclark@google.comc899ad92012-08-23 15:24:42 +0000964 void debugShow(const SkPoint& a) const {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000965 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
caryclark@google.comc899ad92012-08-23 15:24:42 +0000966 }
967#endif
968
caryclark@google.com15fa1382012-05-07 20:49:36 +0000969private:
caryclark@google.com235f56a2012-09-14 14:19:30 +0000970 const SkPoint* fPts;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000971 Cubic fCurvePart;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000972 SkPath::Verb fVerb;
973 double fSide;
974 LineParameters fTangent1;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000975 const SkTDArray<Span>* fSpans;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000976 const Segment* fSegment;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000977 int fStart;
978 int fEnd;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000979 bool fReversed;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000980 mutable bool fUnsortable; // this alone is editable by the less than operator
caryclark@google.com15fa1382012-05-07 20:49:36 +0000981};
982
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000983// Bounds, unlike Rect, does not consider a line to be empty.
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000984struct Bounds : public SkRect {
985 static bool Intersects(const Bounds& a, const Bounds& b) {
986 return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
987 a.fTop <= b.fBottom && b.fTop <= a.fBottom;
988 }
989
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000990 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
991 if (left < fLeft) {
992 fLeft = left;
993 }
994 if (top < fTop) {
995 fTop = top;
996 }
997 if (right > fRight) {
998 fRight = right;
999 }
1000 if (bottom > fBottom) {
1001 fBottom = bottom;
1002 }
1003 }
1004
1005 void add(const Bounds& toAdd) {
1006 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
1007 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001008
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001009 void add(const SkPoint& pt) {
1010 if (pt.fX < fLeft) fLeft = pt.fX;
1011 if (pt.fY < fTop) fTop = pt.fY;
1012 if (pt.fX > fRight) fRight = pt.fX;
1013 if (pt.fY > fBottom) fBottom = pt.fY;
1014 }
1015
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001016 bool isEmpty() {
1017 return fLeft > fRight || fTop > fBottom
caryclark@google.com235f56a2012-09-14 14:19:30 +00001018 || (fLeft == fRight && fTop == fBottom)
caryclark@google.combeda3892013-02-07 13:13:41 +00001019 || sk_double_isnan(fLeft) || sk_double_isnan(fRight)
1020 || sk_double_isnan(fTop) || sk_double_isnan(fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001021 }
1022
1023 void setCubicBounds(const SkPoint a[4]) {
1024 _Rect dRect;
caryclark@google.com32546db2012-08-31 20:55:07 +00001025 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001026 dRect.setBounds(cubic);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001027 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1028 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001029 }
1030
1031 void setQuadBounds(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +00001032 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001033 _Rect dRect;
1034 dRect.setBounds(quad);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001035 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1036 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001037 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001038
1039 void setPoint(const SkPoint& pt) {
1040 fLeft = fRight = pt.fX;
1041 fTop = fBottom = pt.fY;
1042 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001043};
1044
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001045// OPTIMIZATION: does the following also work, and is it any faster?
1046// return outerWinding * innerWinding > 0
1047// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
caryclark@google.com2ddff932012-08-07 21:25:27 +00001048static bool useInnerWinding(int outerWinding, int innerWinding) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001049 SkASSERT(outerWinding != SK_MaxS32);
1050 SkASSERT(innerWinding != SK_MaxS32);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001051 int absOut = abs(outerWinding);
1052 int absIn = abs(innerWinding);
1053 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
caryclark@google.com5e0500f2013-02-20 12:51:37 +00001054#if 0 && DEBUG_WINDING
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001055 if (outerWinding * innerWinding < 0) {
caryclark@google.com24bec792012-08-20 12:43:57 +00001056 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
caryclark@google.com2ddff932012-08-07 21:25:27 +00001057 outerWinding, innerWinding, result ? "true" : "false");
caryclark@google.com2ddff932012-08-07 21:25:27 +00001058 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001059#endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001060 return result;
1061}
1062
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001063#define F (false) // discard the edge
1064#define T (true) // keep the edge
1065
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001066static const bool gUnaryActiveEdge[2][2] = {
1067// from=0 from=1
1068// to=0,1 to=0,1
1069 {F, T}, {T, F},
1070};
1071
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001072static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
1073// miFrom=0 miFrom=1
1074// miTo=0 miTo=1 miTo=0 miTo=1
1075// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
1076// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
1077 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
1078 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
1079 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
1080 {{{{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 +00001081};
1082
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001083#undef F
1084#undef T
caryclark@google.com235f56a2012-09-14 14:19:30 +00001085
caryclark@google.comf839c032012-10-26 21:03:50 +00001086// wrap path to keep track of whether the contour is initialized and non-empty
1087class PathWrapper {
1088public:
1089 PathWrapper(SkPath& path)
1090 : fPathPtr(&path)
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001091 , fCloses(0)
1092 , fMoves(0)
caryclark@google.comf839c032012-10-26 21:03:50 +00001093 {
1094 init();
1095 }
1096
1097 void close() {
1098 if (!fHasMove) {
1099 return;
1100 }
1101 bool callClose = isClosed();
1102 lineTo();
1103 if (fEmpty) {
1104 return;
1105 }
1106 if (callClose) {
1107 #if DEBUG_PATH_CONSTRUCTION
1108 SkDebugf("path.close();\n");
1109 #endif
1110 fPathPtr->close();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001111 fCloses++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001112 }
1113 init();
1114 }
1115
1116 void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
1117 lineTo();
1118 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001119 fDefer[1] = pt3;
1120 nudge();
1121 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001122#if DEBUG_PATH_CONSTRUCTION
1123 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001124 pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001125#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001126 fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001127 fEmpty = false;
1128 }
1129
1130 void deferredLine(const SkPoint& pt) {
1131 if (pt == fDefer[1]) {
1132 return;
1133 }
1134 if (changedSlopes(pt)) {
1135 lineTo();
1136 fDefer[0] = fDefer[1];
1137 }
1138 fDefer[1] = pt;
1139 }
1140
1141 void deferredMove(const SkPoint& pt) {
1142 fMoved = true;
1143 fHasMove = true;
1144 fEmpty = true;
1145 fDefer[0] = fDefer[1] = pt;
1146 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001147
caryclark@google.comf839c032012-10-26 21:03:50 +00001148 void deferredMoveLine(const SkPoint& pt) {
1149 if (!fHasMove) {
1150 deferredMove(pt);
1151 }
1152 deferredLine(pt);
1153 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001154
caryclark@google.comf839c032012-10-26 21:03:50 +00001155 bool hasMove() const {
1156 return fHasMove;
1157 }
1158
1159 void init() {
1160 fEmpty = true;
1161 fHasMove = false;
1162 fMoved = false;
1163 }
1164
1165 bool isClosed() const {
1166 return !fEmpty && fFirstPt == fDefer[1];
1167 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001168
caryclark@google.comf839c032012-10-26 21:03:50 +00001169 void lineTo() {
1170 if (fDefer[0] == fDefer[1]) {
1171 return;
1172 }
1173 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001174 nudge();
caryclark@google.comf839c032012-10-26 21:03:50 +00001175 fEmpty = false;
1176#if DEBUG_PATH_CONSTRUCTION
1177 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
1178#endif
1179 fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
1180 fDefer[0] = fDefer[1];
1181 }
1182
1183 const SkPath* nativePath() const {
1184 return fPathPtr;
1185 }
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +00001186
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001187 void nudge() {
1188 if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX)
1189 || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) {
1190 return;
1191 }
1192 fDefer[1] = fFirstPt;
1193 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001194
1195 void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
1196 lineTo();
1197 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001198 fDefer[1] = pt2;
1199 nudge();
1200 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001201#if DEBUG_PATH_CONSTRUCTION
1202 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001203 pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001204#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001205 fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001206 fEmpty = false;
1207 }
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00001208
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001209 bool someAssemblyRequired() const {
1210 return fCloses < fMoves;
1211 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001212
1213protected:
1214 bool changedSlopes(const SkPoint& pt) const {
1215 if (fDefer[0] == fDefer[1]) {
1216 return false;
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001217 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001218 SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
1219 SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
1220 SkScalar lineDx = pt.fX - fDefer[1].fX;
1221 SkScalar lineDy = pt.fY - fDefer[1].fY;
1222 return deferDx * lineDy != deferDy * lineDx;
1223 }
1224
1225 void moveTo() {
1226 if (!fMoved) {
1227 return;
1228 }
1229 fFirstPt = fDefer[0];
1230#if DEBUG_PATH_CONSTRUCTION
1231 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
1232#endif
1233 fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
1234 fMoved = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001235 fMoves++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001236 }
1237
1238private:
1239 SkPath* fPathPtr;
1240 SkPoint fDefer[2];
1241 SkPoint fFirstPt;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001242 int fCloses;
1243 int fMoves;
caryclark@google.comf839c032012-10-26 21:03:50 +00001244 bool fEmpty;
1245 bool fHasMove;
1246 bool fMoved;
1247};
1248
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001249class Segment {
1250public:
1251 Segment() {
1252#if DEBUG_DUMP
1253 fID = ++gSegmentID;
1254#endif
1255 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00001256
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001257 bool operator<(const Segment& rh) const {
1258 return fBounds.fTop < rh.fBounds.fTop;
1259 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001260
caryclark@google.com4eeda372012-12-06 21:47:48 +00001261 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001262 if (activeAngleInner(index, done, angles)) {
1263 return true;
1264 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001265 int lesser = index;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001266 while (--lesser >= 0 && equalPoints(index, lesser)) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001267 if (activeAngleOther(lesser, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001268 return true;
1269 }
1270 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001271 lesser = index;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001272 do {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001273 if (activeAngleOther(index, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001274 return true;
1275 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001276 } while (++index < fTs.count() && equalPoints(index, lesser));
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001277 return false;
1278 }
1279
caryclark@google.com4eeda372012-12-06 21:47:48 +00001280 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001281 Span* span = &fTs[index];
1282 Segment* other = span->fOther;
1283 int oIndex = span->fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001284 return other->activeAngleInner(oIndex, done, angles);
1285 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001286
caryclark@google.com4eeda372012-12-06 21:47:48 +00001287 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001288 int next = nextExactSpan(index, 1);
caryclark@google.com9764cc62012-07-12 19:29:45 +00001289 if (next > 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001290 Span& upSpan = fTs[index];
1291 if (upSpan.fWindValue || upSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001292 addAngle(angles, index, next);
caryclark@google.comf839c032012-10-26 21:03:50 +00001293 if (upSpan.fDone || upSpan.fUnsortableEnd) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001294 done++;
1295 } else if (upSpan.fWindSum != SK_MinS32) {
1296 return true;
1297 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001298 } else if (!upSpan.fDone) {
1299 upSpan.fDone = true;
1300 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001301 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001302 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001303 int prev = nextExactSpan(index, -1);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001304 // edge leading into junction
caryclark@google.com9764cc62012-07-12 19:29:45 +00001305 if (prev >= 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001306 Span& downSpan = fTs[prev];
1307 if (downSpan.fWindValue || downSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001308 addAngle(angles, index, prev);
1309 if (downSpan.fDone) {
1310 done++;
1311 } else if (downSpan.fWindSum != SK_MinS32) {
1312 return true;
1313 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001314 } else if (!downSpan.fDone) {
1315 downSpan.fDone = true;
1316 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001317 }
1318 }
1319 return false;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001320 }
1321
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001322 SkPoint activeLeftTop(bool onlySortable, int* firstT) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001323 SkASSERT(!done());
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001324 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001325 int count = fTs.count();
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001326 // see if either end is not done since we want smaller Y of the pair
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001327 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00001328 bool lastUnsortable = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001329 double lastT = -1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001330 for (int index = 0; index < count; ++index) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001331 const Span& span = fTs[index];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001332 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001333 goto next;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001334 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001335 if (span.fDone && lastDone) {
1336 goto next;
1337 }
1338 if (approximately_negative(span.fT - lastT)) {
1339 goto next;
1340 }
1341 {
1342 const SkPoint& xy = xyAtT(&span);
1343 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
1344 topPt = xy;
1345 if (firstT) {
1346 *firstT = index;
1347 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001348 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001349 if (fVerb != SkPath::kLine_Verb && !lastDone) {
1350 SkPoint curveTop = (*SegmentTop[fVerb])(fPts, lastT, span.fT);
1351 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
1352 && topPt.fX > curveTop.fX)) {
1353 topPt = curveTop;
1354 if (firstT) {
1355 *firstT = index;
1356 }
1357 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001358 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001359 lastT = span.fT;
caryclark@google.comf839c032012-10-26 21:03:50 +00001360 }
1361 next:
1362 lastDone = span.fDone;
1363 lastUnsortable = span.fUnsortableEnd;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001364 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001365 return topPt;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001366 }
1367
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001368 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
1369 int sumMiWinding = updateWinding(endIndex, index);
1370 int sumSuWinding = updateOppWinding(endIndex, index);
1371 if (fOperand) {
1372 SkTSwap<int>(sumMiWinding, sumSuWinding);
1373 }
1374 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1375 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001376 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001377 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001378
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001379 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00001380 int& sumMiWinding, int& sumSuWinding,
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001381 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
1382 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1383 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001384 bool miFrom;
1385 bool miTo;
1386 bool suFrom;
1387 bool suTo;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001388 if (operand()) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001389 miFrom = (oppMaxWinding & xorMiMask) != 0;
1390 miTo = (oppSumWinding & xorMiMask) != 0;
1391 suFrom = (maxWinding & xorSuMask) != 0;
1392 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001393 } else {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001394 miFrom = (maxWinding & xorMiMask) != 0;
1395 miTo = (sumWinding & xorMiMask) != 0;
1396 suFrom = (oppMaxWinding & xorSuMask) != 0;
1397 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001398 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001399 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
caryclark@google.combeda3892013-02-07 13:13:41 +00001400#if DEBUG_ACTIVE_OP
1401 SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__,
1402 kShapeOpStr[op], miFrom, miTo, suFrom, suTo, result);
1403#endif
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001404 SkASSERT(result != -1);
1405 return result;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001406 }
1407
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001408 bool activeWinding(int index, int endIndex) {
1409 int sumWinding = updateWinding(endIndex, index);
1410 int maxWinding;
1411 return activeWinding(index, endIndex, maxWinding, sumWinding);
1412 }
1413
1414 bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
1415 setUpWinding(index, endIndex, maxWinding, sumWinding);
1416 bool from = maxWinding != 0;
1417 bool to = sumWinding != 0;
1418 bool result = gUnaryActiveEdge[from][to];
1419 SkASSERT(result != -1);
1420 return result;
1421 }
1422
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001423 void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001424 SkASSERT(start != end);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001425 Angle* angle = angles.append();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001426#if DEBUG_ANGLE
caryclark@google.com31143cf2012-11-09 22:14:19 +00001427 if (angles.count() > 1 && !fTs[start].fTiny) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001428 SkPoint angle0Pt, newPt;
1429 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
1430 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
1431 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
caryclark@google.com6d0032a2013-01-04 19:41:13 +00001432 SkASSERT(AlmostEqualUlps(angle0Pt.fX, newPt.fX));
1433 SkASSERT(AlmostEqualUlps(angle0Pt.fY, newPt.fY));
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001434 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001435#endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001436 angle->set(fPts, fVerb, this, start, end, fTs);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001437 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001438
caryclark@google.com2ddff932012-08-07 21:25:27 +00001439 void addCancelOutsides(double tStart, double oStart, Segment& other,
caryclark@google.comcc905052012-07-25 20:59:42 +00001440 double oEnd) {
1441 int tIndex = -1;
1442 int tCount = fTs.count();
1443 int oIndex = -1;
1444 int oCount = other.fTs.count();
caryclark@google.comcc905052012-07-25 20:59:42 +00001445 do {
1446 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001447 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001448 int tIndexStart = tIndex;
1449 do {
1450 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001451 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001452 int oIndexStart = oIndex;
1453 double nextT;
1454 do {
1455 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001456 } while (nextT < 1 && approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001457 double oNextT;
1458 do {
1459 oNextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001460 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001461 // at this point, spans before and after are at:
1462 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1463 // if tIndexStart == 0, no prior span
1464 // if nextT == 1, no following span
rmistry@google.comd6176b02012-08-23 18:14:13 +00001465
caryclark@google.comcc905052012-07-25 20:59:42 +00001466 // advance the span with zero winding
1467 // if the following span exists (not past the end, non-zero winding)
1468 // connect the two edges
1469 if (!fTs[tIndexStart].fWindValue) {
1470 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1471 #if DEBUG_CONCIDENT
1472 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1473 __FUNCTION__, fID, other.fID, tIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001474 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
1475 xyAtT(tIndexStart).fY);
caryclark@google.comcc905052012-07-25 20:59:42 +00001476 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001477 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false,
1478 fTs[tIndexStart].fPt);
caryclark@google.comcc905052012-07-25 20:59:42 +00001479 }
1480 if (nextT < 1 && fTs[tIndex].fWindValue) {
1481 #if DEBUG_CONCIDENT
1482 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1483 __FUNCTION__, fID, other.fID, tIndex,
1484 fTs[tIndex].fT, xyAtT(tIndex).fX,
1485 xyAtT(tIndex).fY);
1486 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001487 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false, fTs[tIndex].fPt);
caryclark@google.comcc905052012-07-25 20:59:42 +00001488 }
1489 } else {
1490 SkASSERT(!other.fTs[oIndexStart].fWindValue);
1491 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1492 #if DEBUG_CONCIDENT
1493 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1494 __FUNCTION__, fID, other.fID, oIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001495 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
1496 other.xyAtT(oIndexStart).fY);
1497 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
caryclark@google.comcc905052012-07-25 20:59:42 +00001498 #endif
caryclark@google.comcc905052012-07-25 20:59:42 +00001499 }
1500 if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1501 #if DEBUG_CONCIDENT
1502 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1503 __FUNCTION__, fID, other.fID, oIndex,
1504 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1505 other.xyAtT(oIndex).fY);
1506 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1507 #endif
1508 }
1509 }
1510 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001511
caryclark@google.comcc905052012-07-25 20:59:42 +00001512 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1513 double oEnd) {
1514 // walk this to outsideTs[0]
1515 // walk other to outsideTs[1]
1516 // if either is > 0, add a pointer to the other, copying adjacent winding
1517 int tIndex = -1;
1518 int oIndex = -1;
1519 double tStart = outsideTs[0];
1520 double oStart = outsideTs[1];
1521 do {
1522 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001523 } while (!approximately_negative(tStart - fTs[tIndex].fT));
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001524 SkPoint ptStart = fTs[tIndex].fPt;
caryclark@google.comcc905052012-07-25 20:59:42 +00001525 do {
1526 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001527 } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001528 if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001529 addTPair(tStart, other, oStart, false, ptStart);
caryclark@google.comcc905052012-07-25 20:59:42 +00001530 }
1531 tStart = fTs[tIndex].fT;
1532 oStart = other.fTs[oIndex].fT;
1533 do {
1534 double nextT;
1535 do {
1536 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001537 } while (approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001538 tStart = nextT;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001539 ptStart = fTs[tIndex].fPt;
caryclark@google.comcc905052012-07-25 20:59:42 +00001540 do {
1541 nextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001542 } while (approximately_negative(nextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001543 oStart = nextT;
caryclark@google.com4eeda372012-12-06 21:47:48 +00001544 if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001545 break;
1546 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001547 addTPair(tStart, other, oStart, false, ptStart);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001548 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001549 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001550
caryclark@google.com4eeda372012-12-06 21:47:48 +00001551 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
1552 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001553 fBounds.setCubicBounds(pts);
1554 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001555
caryclark@google.comf839c032012-10-26 21:03:50 +00001556 /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001557 SkPoint edge[4];
caryclark@google.comf839c032012-10-26 21:03:50 +00001558 const SkPoint* ePtr;
1559 int lastT = fTs.count() - 1;
1560 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1561 ePtr = fPts;
1562 } else {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001563 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001564 subDivide(start, end, edge);
caryclark@google.comf839c032012-10-26 21:03:50 +00001565 ePtr = edge;
1566 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001567 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001568 bool reverse = ePtr == fPts && start != 0;
1569 if (reverse) {
1570 path.deferredMoveLine(ePtr[fVerb]);
1571 switch (fVerb) {
1572 case SkPath::kLine_Verb:
1573 path.deferredLine(ePtr[0]);
1574 break;
1575 case SkPath::kQuad_Verb:
1576 path.quadTo(ePtr[1], ePtr[0]);
1577 break;
1578 case SkPath::kCubic_Verb:
1579 path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1580 break;
1581 default:
1582 SkASSERT(0);
1583 }
1584 // return ePtr[0];
1585 } else {
1586 path.deferredMoveLine(ePtr[0]);
1587 switch (fVerb) {
1588 case SkPath::kLine_Verb:
1589 path.deferredLine(ePtr[1]);
1590 break;
1591 case SkPath::kQuad_Verb:
1592 path.quadTo(ePtr[1], ePtr[2]);
1593 break;
1594 case SkPath::kCubic_Verb:
1595 path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1596 break;
1597 default:
1598 SkASSERT(0);
1599 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001600 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001601 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001602 // return ePtr[fVerb];
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001603 }
1604
caryclark@google.com4eeda372012-12-06 21:47:48 +00001605 void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
1606 init(pts, SkPath::kLine_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001607 fBounds.set(pts, 2);
1608 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001609
caryclark@google.comf839c032012-10-26 21:03:50 +00001610#if 0
1611 const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001612 const SkPoint& pt = xyAtT(tIndex);
1613 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001614 path.deferredMove(pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001615 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00001616 return pt;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001617 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001618#endif
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001619
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001620 // add 2 to edge or out of range values to get T extremes
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001621 void addOtherT(int index, double otherT, int otherIndex) {
1622 Span& span = fTs[index];
caryclark@google.comf839c032012-10-26 21:03:50 +00001623 #if PIN_ADD_T
caryclark@google.com185c7c42012-10-19 18:26:24 +00001624 if (precisely_less_than_zero(otherT)) {
1625 otherT = 0;
1626 } else if (precisely_greater_than_one(otherT)) {
1627 otherT = 1;
1628 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001629 #endif
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001630 span.fOtherT = otherT;
1631 span.fOtherIndex = otherIndex;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001632 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001633
caryclark@google.com4eeda372012-12-06 21:47:48 +00001634 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
1635 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001636 fBounds.setQuadBounds(pts);
1637 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001638
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001639 // Defer all coincident edge processing until
1640 // after normal intersections have been computed
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001641
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001642// no need to be tricky; insert in normal T order
1643// resolve overlapping ts when considering coincidence later
1644
1645 // add non-coincident intersection. Resulting edges are sorted in T.
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001646 int addT(Segment* other, const SkPoint& pt, double& newT) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001647 // FIXME: in the pathological case where there is a ton of intercepts,
1648 // binary search?
1649 int insertedAt = -1;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001650 size_t tCount = fTs.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00001651 #if PIN_ADD_T
caryclark@google.comc899ad92012-08-23 15:24:42 +00001652 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
caryclark@google.com185c7c42012-10-19 18:26:24 +00001653 if (precisely_less_than_zero(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001654 newT = 0;
caryclark@google.com185c7c42012-10-19 18:26:24 +00001655 } else if (precisely_greater_than_one(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001656 newT = 1;
1657 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001658 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001659 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001660 // OPTIMIZATION: if there are three or more identical Ts, then
1661 // the fourth and following could be further insertion-sorted so
1662 // that all the edges are clockwise or counterclockwise.
1663 // This could later limit segment tests to the two adjacent
1664 // neighbors, although it doesn't help with determining which
1665 // circular direction to go in.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001666 if (newT < fTs[index].fT) {
1667 insertedAt = index;
1668 break;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001669 }
1670 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001671 Span* span;
1672 if (insertedAt >= 0) {
1673 span = fTs.insert(insertedAt);
1674 } else {
1675 insertedAt = tCount;
1676 span = fTs.append();
1677 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001678 span->fT = newT;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001679 span->fOther = other;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001680 span->fPt = pt;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001681 span->fWindSum = SK_MinS32;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001682 span->fOppSum = SK_MinS32;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001683 span->fWindValue = 1;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001684 span->fOppValue = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00001685 span->fTiny = false;
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00001686 span->fLoop = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001687 if ((span->fDone = newT == 1)) {
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00001688 ++fDoneSpans;
rmistry@google.comd6176b02012-08-23 18:14:13 +00001689 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001690 span->fUnsortableStart = false;
1691 span->fUnsortableEnd = false;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001692 int less = -1;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001693 while (&span[less + 1] - fTs.begin() > 0 && xyAtT(&span[less]) == xyAtT(span)) {
1694#if 1
1695 if (span[less].fDone) {
1696 break;
1697 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001698 double tInterval = newT - span[less].fT;
1699 if (precisely_negative(tInterval)) {
1700 break;
1701 }
1702 if (fVerb == SkPath::kCubic_Verb) {
1703 double tMid = newT - tInterval / 2;
1704 _Point midPt;
1705 CubicXYAtT(fPts, tMid, &midPt);
1706 if (!midPt.approximatelyEqual(xyAtT(span))) {
1707 break;
1708 }
1709 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001710 span[less].fTiny = true;
1711 span[less].fDone = true;
1712 if (approximately_negative(newT - span[less].fT)) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00001713 if (approximately_greater_than_one(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001714 span[less].fUnsortableStart = true;
1715 span[less - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001716 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001717 if (approximately_less_than_zero(span[less].fT)) {
1718 span[less + 1].fUnsortableStart = true;
1719 span[less].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001720 }
1721 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001722 ++fDoneSpans;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001723#else
1724 double tInterval = newT - span[less].fT;
1725 if (precisely_negative(tInterval)) {
1726 break;
1727 }
1728 if (fVerb == SkPath::kCubic_Verb) {
1729 double tMid = newT - tInterval / 2;
1730 _Point midPt;
1731 CubicXYAtT(fPts, tMid, &midPt);
1732 if (!midPt.approximatelyEqual(xyAtT(span))) {
1733 break;
1734 }
1735 }
1736 SkASSERT(span[less].fDone == span->fDone);
1737 if (span[less].fT == 0) {
1738 span->fT = newT = 0;
1739 } else {
1740 setSpanT(less, newT);
1741 }
1742#endif
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001743 --less;
caryclark@google.comf839c032012-10-26 21:03:50 +00001744 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001745 int more = 1;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001746 while (fTs.end() - &span[more - 1] > 1 && xyAtT(&span[more]) == xyAtT(span)) {
1747#if 1
1748 if (span[more - 1].fDone) {
1749 break;
1750 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001751 double tEndInterval = span[more].fT - newT;
1752 if (precisely_negative(tEndInterval)) {
1753 break;
1754 }
1755 if (fVerb == SkPath::kCubic_Verb) {
1756 double tMid = newT - tEndInterval / 2;
1757 _Point midEndPt;
1758 CubicXYAtT(fPts, tMid, &midEndPt);
1759 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
1760 break;
1761 }
1762 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001763 span[more - 1].fTiny = true;
1764 span[more - 1].fDone = true;
1765 if (approximately_negative(span[more].fT - newT)) {
1766 if (approximately_greater_than_one(span[more].fT)) {
1767 span[more + 1].fUnsortableStart = true;
1768 span[more].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001769 }
1770 if (approximately_less_than_zero(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001771 span[more].fUnsortableStart = true;
1772 span[more - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001773 }
1774 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001775 ++fDoneSpans;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001776#else
1777 double tEndInterval = span[more].fT - newT;
1778 if (precisely_negative(tEndInterval)) {
1779 break;
1780 }
1781 if (fVerb == SkPath::kCubic_Verb) {
1782 double tMid = newT - tEndInterval / 2;
1783 _Point midEndPt;
1784 CubicXYAtT(fPts, tMid, &midEndPt);
1785 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
1786 break;
1787 }
1788 }
1789 SkASSERT(span[more - 1].fDone == span[more].fDone);
1790 if (newT == 0) {
1791 setSpanT(more, 0);
1792 } else {
1793 span->fT = newT = span[more].fT;
1794 }
1795#endif
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001796 ++more;
caryclark@google.comf839c032012-10-26 21:03:50 +00001797 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001798 return insertedAt;
1799 }
1800
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001801 // set spans from start to end to decrement by one
1802 // note this walks other backwards
1803 // FIMXE: there's probably an edge case that can be constructed where
1804 // two span in one segment are separated by float epsilon on one span but
1805 // not the other, if one segment is very small. For this
1806 // case the counts asserted below may or may not be enough to separate the
caryclark@google.com2ddff932012-08-07 21:25:27 +00001807 // spans. Even if the counts work out, what if the spans aren't correctly
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001808 // sorted? It feels better in such a case to match the span's other span
1809 // pointer since both coincident segments must contain the same spans.
1810 void addTCancel(double startT, double endT, Segment& other,
1811 double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001812 SkASSERT(!approximately_negative(endT - startT));
1813 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00001814 bool binary = fOperand != other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001815 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001816 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001817 ++index;
1818 }
caryclark@google.comb9738012012-07-03 19:53:30 +00001819 int oIndex = other.fTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001820 while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001821 ;
caryclark@google.com59823f72012-08-09 18:17:47 +00001822 double tRatio = (oEndT - oStartT) / (endT - startT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001823 Span* test = &fTs[index];
1824 Span* oTest = &other.fTs[oIndex];
caryclark@google.com18063442012-07-25 12:05:18 +00001825 SkTDArray<double> outsideTs;
1826 SkTDArray<double> oOutsideTs;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001827 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001828 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
caryclark@google.comcc905052012-07-25 20:59:42 +00001829 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.com200c2112012-08-03 15:05:04 +00001830 double testT = test->fT;
1831 double oTestT = oTest->fT;
1832 Span* span = test;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001833 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001834 if (decrement) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001835 decrementSpan(span);
caryclark@google.com200c2112012-08-03 15:05:04 +00001836 } else if (track && span->fT < 1 && oTestT < 1) {
1837 TrackOutside(outsideTs, span->fT, oTestT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001838 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001839 span = &fTs[++index];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001840 } while (approximately_negative(span->fT - testT));
caryclark@google.com200c2112012-08-03 15:05:04 +00001841 Span* oSpan = oTest;
caryclark@google.com59823f72012-08-09 18:17:47 +00001842 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1843 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1844 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001845 while (approximately_negative(otherTMatchStart - oSpan->fT)
1846 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
caryclark@google.com03f97062012-08-21 13:13:52 +00001847 #ifdef SK_DEBUG
caryclark@google.com59823f72012-08-09 18:17:47 +00001848 SkASSERT(originalWindValue == oSpan->fWindValue);
caryclark@google.com03f97062012-08-21 13:13:52 +00001849 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001850 if (decrement) {
caryclark@google.com200c2112012-08-03 15:05:04 +00001851 other.decrementSpan(oSpan);
1852 } else if (track && oSpan->fT < 1 && testT < 1) {
1853 TrackOutside(oOutsideTs, oSpan->fT, testT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001854 }
1855 if (!oIndex) {
1856 break;
1857 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001858 oSpan = &other.fTs[--oIndex];
rmistry@google.comd6176b02012-08-23 18:14:13 +00001859 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001860 test = span;
1861 oTest = oSpan;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001862 } while (!approximately_negative(endT - test->fT));
1863 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
caryclark@google.com18063442012-07-25 12:05:18 +00001864 // FIXME: determine if canceled edges need outside ts added
caryclark@google.comcc905052012-07-25 20:59:42 +00001865 if (!done() && outsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001866 double tStart = outsideTs[0];
1867 double oStart = outsideTs[1];
1868 addCancelOutsides(tStart, oStart, other, oEndT);
1869 int count = outsideTs.count();
1870 if (count > 2) {
1871 double tStart = outsideTs[count - 2];
1872 double oStart = outsideTs[count - 1];
1873 addCancelOutsides(tStart, oStart, other, oEndT);
1874 }
caryclark@google.com18063442012-07-25 12:05:18 +00001875 }
caryclark@google.comcc905052012-07-25 20:59:42 +00001876 if (!other.done() && oOutsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001877 double tStart = oOutsideTs[0];
1878 double oStart = oOutsideTs[1];
1879 other.addCancelOutsides(tStart, oStart, *this, endT);
caryclark@google.com18063442012-07-25 12:05:18 +00001880 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001881 }
skia.committer@gmail.com631cdcb2013-03-01 12:12:55 +00001882
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00001883 int addSelfT(Segment* other, const SkPoint& pt, double& newT) {
1884 int result = addT(other, pt, newT);
1885 Span* span = &fTs[result];
1886 span->fLoop = true;
1887 return result;
1888 }
skia.committer@gmail.com15dd3002013-01-18 07:07:28 +00001889
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001890 int addUnsortableT(Segment* other, bool start, const SkPoint& pt, double& newT) {
1891 int result = addT(other, pt, newT);
caryclark@google.com73ca6242013-01-17 21:02:47 +00001892 Span* span = &fTs[result];
1893 if (start) {
1894 if (result > 0) {
1895 span[result - 1].fUnsortableEnd = true;
1896 }
1897 span[result].fUnsortableStart = true;
1898 } else {
1899 span[result].fUnsortableEnd = true;
1900 if (result + 1 < fTs.count()) {
1901 span[result + 1].fUnsortableStart = true;
1902 }
1903 }
1904 return result;
1905 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00001906
caryclark@google.com4eeda372012-12-06 21:47:48 +00001907 int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1908 SkTDArray<double>& outsideTs) {
1909 int oWindValue = oTest->fWindValue;
1910 int oOppValue = oTest->fOppValue;
1911 if (opp) {
1912 SkTSwap<int>(oWindValue, oOppValue);
1913 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001914 Span* const test = &fTs[index];
1915 Span* end = test;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001916 const double oStartT = oTest->fT;
1917 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001918 if (bumpSpan(end, oWindValue, oOppValue)) {
1919 TrackOutside(outsideTs, end->fT, oStartT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001920 }
1921 end = &fTs[++index];
1922 } while (approximately_negative(end->fT - test->fT));
1923 return index;
1924 }
1925
1926 // because of the order in which coincidences are resolved, this and other
1927 // may not have the same intermediate points. Compute the corresponding
1928 // intermediate T values (using this as the master, other as the follower)
1929 // and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com4eeda372012-12-06 21:47:48 +00001930 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1931 SkTDArray<double>& oOutsideTs) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001932 Span* const oTest = &fTs[oIndex];
1933 Span* oEnd = oTest;
1934 const double startT = test->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001935 const double oStartT = oTest->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001936 while (!approximately_negative(oEndT - oEnd->fT)
caryclark@google.com4eeda372012-12-06 21:47:48 +00001937 && approximately_negative(oEnd->fT - oStartT)) {
1938 zeroSpan(oEnd);
1939 TrackOutside(oOutsideTs, oEnd->fT, startT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001940 oEnd = &fTs[++oIndex];
1941 }
1942 return oIndex;
1943 }
1944
1945 // FIXME: need to test this case:
1946 // contourA has two segments that are coincident
1947 // contourB has two segments that are coincident in the same place
1948 // each ends up with +2/0 pairs for winding count
1949 // since logic below doesn't transfer count (only increments/decrements) can this be
1950 // resolved to +4/0 ?
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001951
1952 // set spans from start to end to increment the greater by one and decrement
1953 // the lesser
caryclark@google.com4eeda372012-12-06 21:47:48 +00001954 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001955 SkASSERT(!approximately_negative(endT - startT));
1956 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001957 bool opp = fOperand ^ other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001958 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001959 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001960 ++index;
1961 }
1962 int oIndex = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001963 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001964 ++oIndex;
1965 }
1966 Span* test = &fTs[index];
1967 Span* oTest = &other.fTs[oIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001968 SkTDArray<double> outsideTs;
1969 SkTDArray<double> oOutsideTs;
1970 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001971 // if either span has an opposite value and the operands don't match, resolve first
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001972 // SkASSERT(!test->fDone || !oTest->fDone);
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001973 if (test->fDone || oTest->fDone) {
1974 index = advanceCoincidentThis(oTest, opp, index);
1975 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
1976 } else {
1977 index = bumpCoincidentThis(oTest, opp, index, outsideTs);
1978 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
1979 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001980 test = &fTs[index];
1981 oTest = &other.fTs[oIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001982 } while (!approximately_negative(endT - test->fT));
1983 SkASSERT(approximately_negative(oTest->fT - oEndT));
1984 SkASSERT(approximately_negative(oEndT - oTest->fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001985 if (!done() && outsideTs.count()) {
1986 addCoinOutsides(outsideTs, other, oEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001987 }
1988 if (!other.done() && oOutsideTs.count()) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001989 other.addCoinOutsides(oOutsideTs, *this, endT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001990 }
1991 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001992
caryclark@google.comcc905052012-07-25 20:59:42 +00001993 // FIXME: this doesn't prevent the same span from being added twice
caryclark@google.comaa358312013-01-29 20:28:49 +00001994 // fix in caller, SkASSERT here?
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001995 void addTPair(double t, Segment& other, double otherT, bool borrowWind, const SkPoint& pt) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001996 int tCount = fTs.count();
1997 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1998 const Span& span = fTs[tIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001999 if (!approximately_negative(span.fT - t)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00002000 break;
2001 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00002002 if (approximately_negative(span.fT - t) && span.fOther == &other
2003 && approximately_equal(span.fOtherT, otherT)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00002004#if DEBUG_ADD_T_PAIR
2005 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
2006 __FUNCTION__, fID, t, other.fID, otherT);
2007#endif
2008 return;
2009 }
2010 }
caryclark@google.com47580692012-07-23 12:14:49 +00002011#if DEBUG_ADD_T_PAIR
2012 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
2013 __FUNCTION__, fID, t, other.fID, otherT);
2014#endif
caryclark@google.com7ff5c842013-02-26 15:56:05 +00002015 int insertedAt = addT(&other, pt, t);
2016 int otherInsertedAt = other.addT(this, pt, otherT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002017 addOtherT(insertedAt, otherT, otherInsertedAt);
caryclark@google.comb9738012012-07-03 19:53:30 +00002018 other.addOtherT(otherInsertedAt, t, insertedAt);
caryclark@google.com2ddff932012-08-07 21:25:27 +00002019 matchWindingValue(insertedAt, t, borrowWind);
2020 other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002021 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002022
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002023 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002024 // add edge leading into junction
caryclark@google.com4eeda372012-12-06 21:47:48 +00002025 int min = SkMin32(end, start);
2026 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002027 addAngle(angles, end, start);
2028 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002029 // add edge leading away from junction
caryclark@google.com495f8e42012-05-31 13:13:11 +00002030 int step = SkSign32(end - start);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002031 int tIndex = nextExactSpan(end, step);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002032 min = SkMin32(end, tIndex);
2033 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002034 addAngle(angles, end, tIndex);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002035 }
2036 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002037
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002038 int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
2039 Span* const test = &fTs[index];
2040 Span* end = test;
2041 do {
2042 end = &fTs[++index];
2043 } while (approximately_negative(end->fT - test->fT));
2044 return index;
2045 }
2046
2047 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
2048 Span* const oTest = &fTs[oIndex];
2049 Span* oEnd = oTest;
2050 const double oStartT = oTest->fT;
2051 while (!approximately_negative(oEndT - oEnd->fT)
2052 && approximately_negative(oEnd->fT - oStartT)) {
2053 oEnd = &fTs[++oIndex];
2054 }
2055 return oIndex;
2056 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00002057
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002058 bool betweenTs(int lesser, double testT, int greater) {
2059 if (lesser > greater) {
2060 SkTSwap<int>(lesser, greater);
2061 }
2062 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
2063 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002064
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002065 const Bounds& bounds() const {
2066 return fBounds;
2067 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002068
caryclark@google.com31143cf2012-11-09 22:14:19 +00002069 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002070 double referenceT = fTs[index].fT;
2071 int lesser = index;
caryclark@google.com31143cf2012-11-09 22:14:19 +00002072 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
2073 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00002074 buildAnglesInner(lesser, angles);
2075 }
2076 do {
2077 buildAnglesInner(index, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002078 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
2079 && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002080 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002081
2082 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
2083 Span* span = &fTs[index];
2084 Segment* other = span->fOther;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002085 // if there is only one live crossing, and no coincidence, continue
2086 // in the same direction
2087 // if there is coincidence, the only choice may be to reverse direction
2088 // find edge on either side of intersection
2089 int oIndex = span->fOtherIndex;
2090 // if done == -1, prior span has already been processed
2091 int step = 1;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002092 int next = other->nextExactSpan(oIndex, step);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002093 if (next < 0) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002094 step = -step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002095 next = other->nextExactSpan(oIndex, step);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002096 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002097 // add candidate into and away from junction
2098 other->addTwoAngles(next, oIndex, angles);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002099 }
2100
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002101 int computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002102 SkTDArray<Angle> angles;
2103 addTwoAngles(startIndex, endIndex, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002104 buildAngles(endIndex, angles, false);
caryclark@google.comd1688742012-09-18 20:08:37 +00002105 // OPTIMIZATION: check all angles to see if any have computed wind sum
2106 // before sorting (early exit if none)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002107 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002108 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002109#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002110 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002111#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002112 if (!sortable) {
2113 return SK_MinS32;
2114 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002115 int angleCount = angles.count();
2116 const Angle* angle;
2117 const Segment* base;
2118 int winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002119 int oWinding;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002120 int firstIndex = 0;
2121 do {
2122 angle = sorted[firstIndex];
2123 base = angle->segment();
2124 winding = base->windSum(angle);
2125 if (winding != SK_MinS32) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002126 oWinding = base->oppSum(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002127 break;
2128 }
2129 if (++firstIndex == angleCount) {
2130 return SK_MinS32;
2131 }
2132 } while (true);
2133 // turn winding into contourWinding
caryclark@google.com2ddff932012-08-07 21:25:27 +00002134 int spanWinding = base->spanSign(angle);
2135 bool inner = useInnerWinding(winding + spanWinding, winding);
2136 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00002137 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
caryclark@google.com59823f72012-08-09 18:17:47 +00002138 spanWinding, winding, angle->sign(), inner,
caryclark@google.com2ddff932012-08-07 21:25:27 +00002139 inner ? winding + spanWinding : winding);
2140 #endif
2141 if (inner) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002142 winding += spanWinding;
2143 }
2144 #if DEBUG_SORT
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002145 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002146 #endif
2147 int nextIndex = firstIndex + 1;
2148 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com2ddff932012-08-07 21:25:27 +00002149 winding -= base->spanSign(angle);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002150 oWinding -= base->oppSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002151 do {
2152 if (nextIndex == angleCount) {
2153 nextIndex = 0;
2154 }
2155 angle = sorted[nextIndex];
2156 Segment* segment = angle->segment();
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002157 bool opp = base->fOperand ^ segment->fOperand;
2158 int maxWinding, oMaxWinding;
2159 int spanSign = segment->spanSign(angle);
2160 int oppoSign = segment->oppSign(angle);
2161 if (opp) {
2162 oMaxWinding = oWinding;
2163 oWinding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002164 maxWinding = winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002165 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002166 winding -= oppoSign;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002167 }
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002168 } else {
2169 maxWinding = winding;
2170 winding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002171 oMaxWinding = oWinding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002172 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002173 oWinding -= oppoSign;
2174 }
2175 }
2176 if (segment->windSum(angle) == SK_MinS32) {
2177 if (opp) {
2178 if (useInnerWinding(oMaxWinding, oWinding)) {
2179 oMaxWinding = oWinding;
2180 }
2181 if (oppoSign && useInnerWinding(maxWinding, winding)) {
2182 maxWinding = winding;
2183 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002184 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002185 } else {
2186 if (useInnerWinding(maxWinding, winding)) {
2187 maxWinding = winding;
2188 }
2189 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
2190 oMaxWinding = oWinding;
2191 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002192 (void) segment->markAndChaseWinding(angle, maxWinding,
2193 binary ? oMaxWinding : 0);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002194 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002195 }
2196 } while (++nextIndex != lastIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002197 int minIndex = SkMin32(startIndex, endIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002198 return windSum(minIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002199 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002200
caryclark@google.com3586ece2012-12-27 18:46:58 +00002201 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
caryclark@google.com10227bf2012-12-28 22:10:41 +00002202 double mid, bool opp, bool current) const {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002203 SkScalar bottom = fBounds.fBottom;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002204 int bestTIndex = -1;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002205 if (bottom <= bestY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002206 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002207 }
2208 SkScalar top = fBounds.fTop;
2209 if (top >= basePt.fY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002210 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002211 }
2212 if (fBounds.fLeft > basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002213 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002214 }
2215 if (fBounds.fRight < basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002216 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002217 }
2218 if (fBounds.fLeft == fBounds.fRight) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002219 // if vertical, and directly above test point, wait for another one
caryclark@google.com6d0032a2013-01-04 19:41:13 +00002220 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002221 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002222 // intersect ray starting at basePt with edge
2223 Intersections intersections;
2224 // OPTIMIZE: use specialty function that intersects ray with curve,
2225 // returning t values only for curve (we don't care about t on ray)
2226 int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
2227 if (pts == 0 || (current && pts == 1)) {
2228 return bestTIndex;
2229 }
2230 if (current) {
2231 SkASSERT(pts > 1);
2232 int closestIdx = 0;
2233 double closest = fabs(intersections.fT[0][0] - mid);
2234 for (int idx = 1; idx < pts; ++idx) {
2235 double test = fabs(intersections.fT[0][idx] - mid);
2236 if (closest > test) {
2237 closestIdx = idx;
2238 closest = test;
2239 }
2240 }
2241 if (closestIdx < pts - 1) {
2242 intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
2243 }
2244 --pts;
2245 }
2246 double bestT = -1;
2247 for (int index = 0; index < pts; ++index) {
2248 double foundT = intersections.fT[0][index];
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002249 if (approximately_less_than_zero(foundT)
2250 || approximately_greater_than_one(foundT)) {
2251 continue;
2252 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002253 SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
2254 if (approximately_negative(testY - bestY)
2255 || approximately_negative(basePt.fY - testY)) {
caryclark@google.com47580692012-07-23 12:14:49 +00002256 continue;
2257 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002258 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002259 return SK_MinS32; // if the intersection is edge on, wait for another one
caryclark@google.com10227bf2012-12-28 22:10:41 +00002260 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002261 if (fVerb > SkPath::kLine_Verb) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002262 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
2263 if (approximately_zero(dx)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002264 return SK_MinS32; // hit vertical, wait for another one
caryclark@google.com3586ece2012-12-27 18:46:58 +00002265 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00002266 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002267 bestY = testY;
2268 bestT = foundT;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002269 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002270 if (bestT < 0) {
2271 return bestTIndex;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002272 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002273 SkASSERT(bestT >= 0);
2274 SkASSERT(bestT <= 1);
2275 int start;
2276 int end = 0;
2277 do {
2278 start = end;
2279 end = nextSpan(start, 1);
2280 } while (fTs[end].fT < bestT);
2281 // FIXME: see next candidate for a better pattern to find the next start/end pair
2282 while (start + 1 < end && fTs[start].fDone) {
2283 ++start;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002284 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002285 if (!isCanceled(start)) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002286 hitT = bestT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002287 bestTIndex = start;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002288 hitSomething = true;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002289 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002290 return bestTIndex;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002291 }
caryclark@google.com18063442012-07-25 12:05:18 +00002292
caryclark@google.com4eeda372012-12-06 21:47:48 +00002293 void decrementSpan(Span* span) {
caryclark@google.com18063442012-07-25 12:05:18 +00002294 SkASSERT(span->fWindValue > 0);
2295 if (--(span->fWindValue) == 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002296 if (!span->fOppValue && !span->fDone) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002297 span->fDone = true;
2298 ++fDoneSpans;
2299 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002300 }
2301 }
2302
2303 bool bumpSpan(Span* span, int windDelta, int oppDelta) {
2304 SkASSERT(!span->fDone);
2305 span->fWindValue += windDelta;
2306 SkASSERT(span->fWindValue >= 0);
2307 span->fOppValue += oppDelta;
2308 SkASSERT(span->fOppValue >= 0);
2309 if (fXor) {
2310 span->fWindValue &= 1;
2311 }
2312 if (fOppXor) {
2313 span->fOppValue &= 1;
2314 }
2315 if (!span->fWindValue && !span->fOppValue) {
2316 span->fDone = true;
2317 ++fDoneSpans;
caryclark@google.com18063442012-07-25 12:05:18 +00002318 return true;
2319 }
2320 return false;
2321 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002322
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002323 // OPTIMIZE
2324 // when the edges are initially walked, they don't automatically get the prior and next
2325 // 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 +00002326 // and would additionally remove the need for similar checks in condition edges. It would
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002327 // also allow intersection code to assume end of segment intersections (maybe?)
2328 bool complete() const {
2329 int count = fTs.count();
2330 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
2331 }
caryclark@google.com18063442012-07-25 12:05:18 +00002332
caryclark@google.com15fa1382012-05-07 20:49:36 +00002333 bool done() const {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002334 SkASSERT(fDoneSpans <= fTs.count());
2335 return fDoneSpans == fTs.count();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002336 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002337
caryclark@google.comf839c032012-10-26 21:03:50 +00002338 bool done(int min) const {
2339 return fTs[min].fDone;
2340 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002341
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002342 bool done(const Angle* angle) const {
2343 return done(SkMin32(angle->start(), angle->end()));
caryclark@google.com47580692012-07-23 12:14:49 +00002344 }
skia.committer@gmail.com044679e2013-02-15 07:16:57 +00002345
caryclark@google.com7ff5c842013-02-26 15:56:05 +00002346 SkVector dxdy(int index) const {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002347 return (*SegmentDXDYAtT[fVerb])(fPts, fTs[index].fT);
2348 }
2349
2350 SkScalar dy(int index) const {
2351 return (*SegmentDYAtT[fVerb])(fPts, fTs[index].fT);
2352 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00002353
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002354 bool equalPoints(int greaterTIndex, int lesserTIndex) {
2355 SkASSERT(greaterTIndex >= lesserTIndex);
2356 double greaterT = fTs[greaterTIndex].fT;
2357 double lesserT = fTs[lesserTIndex].fT;
2358 if (greaterT == lesserT) {
2359 return true;
2360 }
2361 if (!approximately_negative(greaterT - lesserT)) {
2362 return false;
2363 }
2364 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2365 }
2366
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002367 /*
2368 The M and S variable name parts stand for the operators.
2369 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2370 Su stands for Subtrahend
2371 The Opp variable name part designates that the value is for the Opposite operator.
2372 Opposite values result from combining coincident spans.
2373 */
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002374
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002375 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2376 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002377 const int startIndex = nextStart;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002378 const int endIndex = nextEnd;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002379 SkASSERT(startIndex != endIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002380 const int count = fTs.count();
2381 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2382 const int step = SkSign32(endIndex - startIndex);
2383 const int end = nextExactSpan(startIndex, step);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002384 SkASSERT(end >= 0);
2385 Span* endSpan = &fTs[end];
2386 Segment* other;
2387 if (isSimple(end)) {
2388 // mark the smaller of startIndex, endIndex done, and all adjacent
2389 // spans with the same T value (but not 'other' spans)
2390 #if DEBUG_WINDING
2391 SkDebugf("%s simple\n", __FUNCTION__);
2392 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002393 int min = SkMin32(startIndex, endIndex);
2394 if (fTs[min].fDone) {
2395 return NULL;
2396 }
2397 markDoneBinary(min);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002398 other = endSpan->fOther;
2399 nextStart = endSpan->fOtherIndex;
2400 double startT = other->fTs[nextStart].fT;
2401 nextEnd = nextStart;
2402 do {
2403 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002404 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002405 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002406 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2407 return other;
2408 }
2409 // more than one viable candidate -- measure angles to find best
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, true);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002415 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002416 bool sortable = SortAngles(angles, sorted);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002417 int angleCount = angles.count();
2418 int firstIndex = findStartingEdge(sorted, startIndex, end);
2419 SkASSERT(firstIndex >= 0);
2420 #if DEBUG_SORT
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002421 debugShowSort(__FUNCTION__, sorted, firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002422 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002423 if (!sortable) {
2424 unsortable = true;
2425 return NULL;
2426 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002427 SkASSERT(sorted[firstIndex]->segment() == this);
2428 #if DEBUG_WINDING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002429 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2430 sorted[firstIndex]->sign());
caryclark@google.com235f56a2012-09-14 14:19:30 +00002431 #endif
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002432 int sumMiWinding = updateWinding(endIndex, startIndex);
2433 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2434 if (operand()) {
2435 SkTSwap<int>(sumMiWinding, sumSuWinding);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002436 }
2437 int nextIndex = firstIndex + 1;
2438 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2439 const Angle* foundAngle = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002440 bool foundDone = false;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002441 // iterate through the angle, and compute everyone's winding
caryclark@google.com235f56a2012-09-14 14:19:30 +00002442 Segment* nextSegment;
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00002443 int activeCount = 0;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002444 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002445 SkASSERT(nextIndex != firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002446 if (nextIndex == angleCount) {
2447 nextIndex = 0;
2448 }
2449 const Angle* nextAngle = sorted[nextIndex];
2450 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002451 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2452 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2453 nextAngle->end(), op, sumMiWinding, sumSuWinding,
2454 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00002455 if (activeAngle) {
2456 ++activeCount;
2457 if (!foundAngle || (foundDone && activeCount & 1)) {
2458 if (nextSegment->tiny(nextAngle)) {
2459 unsortable = true;
2460 return NULL;
2461 }
2462 foundAngle = nextAngle;
2463 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
2464 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002465 }
2466 if (nextSegment->done()) {
2467 continue;
2468 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002469 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2470 continue;
2471 }
2472 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2473 oppSumWinding, activeAngle, nextAngle);
2474 if (last) {
2475 *chase.append() = last;
2476#if DEBUG_WINDING
2477 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2478 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2479#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002480 }
2481 } while (++nextIndex != lastIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002482 markDoneBinary(SkMin32(startIndex, endIndex));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002483 if (!foundAngle) {
2484 return NULL;
2485 }
2486 nextStart = foundAngle->start();
2487 nextEnd = foundAngle->end();
2488 nextSegment = foundAngle->segment();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002489
caryclark@google.com235f56a2012-09-14 14:19:30 +00002490 #if DEBUG_WINDING
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002491 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2492 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002493 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002494 return nextSegment;
2495 }
caryclark@google.com47580692012-07-23 12:14:49 +00002496
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002497 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2498 bool& unsortable) {
2499 const int startIndex = nextStart;
2500 const int endIndex = nextEnd;
2501 SkASSERT(startIndex != endIndex);
2502 const int count = fTs.count();
2503 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2504 const int step = SkSign32(endIndex - startIndex);
2505 const int end = nextExactSpan(startIndex, step);
2506 SkASSERT(end >= 0);
2507 Span* endSpan = &fTs[end];
2508 Segment* other;
2509 if (isSimple(end)) {
2510 // mark the smaller of startIndex, endIndex done, and all adjacent
2511 // spans with the same T value (but not 'other' spans)
2512 #if DEBUG_WINDING
2513 SkDebugf("%s simple\n", __FUNCTION__);
2514 #endif
2515 int min = SkMin32(startIndex, endIndex);
2516 if (fTs[min].fDone) {
2517 return NULL;
2518 }
2519 markDoneUnary(min);
2520 other = endSpan->fOther;
2521 nextStart = endSpan->fOtherIndex;
2522 double startT = other->fTs[nextStart].fT;
2523 nextEnd = nextStart;
2524 do {
2525 nextEnd += step;
2526 }
2527 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2528 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2529 return other;
2530 }
2531 // more than one viable candidate -- measure angles to find best
2532 SkTDArray<Angle> angles;
2533 SkASSERT(startIndex - endIndex != 0);
2534 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2535 addTwoAngles(startIndex, end, angles);
2536 buildAngles(end, angles, true);
2537 SkTDArray<Angle*> sorted;
2538 bool sortable = SortAngles(angles, sorted);
2539 int angleCount = angles.count();
2540 int firstIndex = findStartingEdge(sorted, startIndex, end);
2541 SkASSERT(firstIndex >= 0);
2542 #if DEBUG_SORT
2543 debugShowSort(__FUNCTION__, sorted, firstIndex);
2544 #endif
2545 if (!sortable) {
2546 unsortable = true;
2547 return NULL;
2548 }
2549 SkASSERT(sorted[firstIndex]->segment() == this);
2550 #if DEBUG_WINDING
2551 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2552 sorted[firstIndex]->sign());
2553 #endif
2554 int sumWinding = updateWinding(endIndex, startIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002555 int nextIndex = firstIndex + 1;
2556 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2557 const Angle* foundAngle = NULL;
2558 bool foundDone = false;
2559 // iterate through the angle, and compute everyone's winding
2560 Segment* nextSegment;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002561 int activeCount = 0;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002562 do {
2563 SkASSERT(nextIndex != firstIndex);
2564 if (nextIndex == angleCount) {
2565 nextIndex = 0;
2566 }
2567 const Angle* nextAngle = sorted[nextIndex];
2568 nextSegment = nextAngle->segment();
2569 int maxWinding;
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00002570 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002571 maxWinding, sumWinding);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002572 if (activeAngle) {
2573 ++activeCount;
2574 if (!foundAngle || (foundDone && activeCount & 1)) {
2575 if (nextSegment->tiny(nextAngle)) {
2576 unsortable = true;
2577 return NULL;
2578 }
2579 foundAngle = nextAngle;
2580 foundDone = nextSegment->done(nextAngle);
2581 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002582 }
2583 if (nextSegment->done()) {
2584 continue;
2585 }
2586 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2587 continue;
2588 }
2589 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2590 if (last) {
2591 *chase.append() = last;
2592#if DEBUG_WINDING
2593 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2594 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2595#endif
2596 }
2597 } while (++nextIndex != lastIndex);
2598 markDoneUnary(SkMin32(startIndex, endIndex));
2599 if (!foundAngle) {
2600 return NULL;
2601 }
2602 nextStart = foundAngle->start();
2603 nextEnd = foundAngle->end();
2604 nextSegment = foundAngle->segment();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002605 #if DEBUG_WINDING
2606 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2607 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2608 #endif
2609 return nextSegment;
2610 }
2611
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002612 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002613 const int startIndex = nextStart;
2614 const int endIndex = nextEnd;
2615 SkASSERT(startIndex != endIndex);
2616 int count = fTs.count();
2617 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2618 : startIndex > 0);
2619 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002620 int end = nextExactSpan(startIndex, step);
caryclark@google.com24bec792012-08-20 12:43:57 +00002621 SkASSERT(end >= 0);
2622 Span* endSpan = &fTs[end];
2623 Segment* other;
caryclark@google.com24bec792012-08-20 12:43:57 +00002624 if (isSimple(end)) {
2625 #if DEBUG_WINDING
2626 SkDebugf("%s simple\n", __FUNCTION__);
2627 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002628 int min = SkMin32(startIndex, endIndex);
2629 if (fTs[min].fDone) {
2630 return NULL;
2631 }
2632 markDone(min, 1);
caryclark@google.com24bec792012-08-20 12:43:57 +00002633 other = endSpan->fOther;
2634 nextStart = endSpan->fOtherIndex;
2635 double startT = other->fTs[nextStart].fT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002636 #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 +00002637 SkDEBUGCODE(bool firstLoop = true;)
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002638 if ((approximately_less_than_zero(startT) && step < 0)
2639 || (approximately_greater_than_one(startT) && step > 0)) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002640 step = -step;
2641 SkDEBUGCODE(firstLoop = false;)
2642 }
2643 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002644 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002645 nextEnd = nextStart;
2646 do {
2647 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002648 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002649 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002650 #if 01
caryclark@google.com24bec792012-08-20 12:43:57 +00002651 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2652 break;
2653 }
caryclark@google.com03f97062012-08-21 13:13:52 +00002654 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00002655 SkASSERT(firstLoop);
caryclark@google.com03f97062012-08-21 13:13:52 +00002656 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002657 SkDEBUGCODE(firstLoop = false;)
2658 step = -step;
2659 } while (true);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002660 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002661 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2662 return other;
2663 }
2664 SkTDArray<Angle> angles;
2665 SkASSERT(startIndex - endIndex != 0);
2666 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2667 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002668 buildAngles(end, angles, false);
caryclark@google.com24bec792012-08-20 12:43:57 +00002669 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002670 bool sortable = SortAngles(angles, sorted);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002671 if (!sortable) {
2672 unsortable = true;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002673 #if DEBUG_SORT
2674 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
2675 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002676 return NULL;
2677 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002678 int angleCount = angles.count();
2679 int firstIndex = findStartingEdge(sorted, startIndex, end);
2680 SkASSERT(firstIndex >= 0);
2681 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002682 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
caryclark@google.com24bec792012-08-20 12:43:57 +00002683 #endif
2684 SkASSERT(sorted[firstIndex]->segment() == this);
2685 int nextIndex = firstIndex + 1;
2686 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002687 const Angle* foundAngle = NULL;
2688 bool foundDone = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002689 Segment* nextSegment;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002690 int activeCount = 0;
caryclark@google.com24bec792012-08-20 12:43:57 +00002691 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002692 SkASSERT(nextIndex != firstIndex);
caryclark@google.com24bec792012-08-20 12:43:57 +00002693 if (nextIndex == angleCount) {
2694 nextIndex = 0;
2695 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002696 const Angle* nextAngle = sorted[nextIndex];
caryclark@google.com24bec792012-08-20 12:43:57 +00002697 nextSegment = nextAngle->segment();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002698 ++activeCount;
2699 if (!foundAngle || (foundDone && activeCount & 1)) {
2700 if (nextSegment->tiny(nextAngle)) {
2701 unsortable = true;
2702 return NULL;
2703 }
2704 foundAngle = nextAngle;
2705 foundDone = nextSegment->done(nextAngle);
2706 }
2707 if (nextSegment->done()) {
2708 continue;
caryclark@google.com24bec792012-08-20 12:43:57 +00002709 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002710 } while (++nextIndex != lastIndex);
2711 markDone(SkMin32(startIndex, endIndex), 1);
2712 if (!foundAngle) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002713 return NULL;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002714 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002715 nextStart = foundAngle->start();
2716 nextEnd = foundAngle->end();
2717 nextSegment = foundAngle->segment();
2718 #if DEBUG_WINDING
2719 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2720 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2721 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002722 return nextSegment;
2723 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002724
2725 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2726 int angleCount = sorted.count();
2727 int firstIndex = -1;
2728 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2729 const Angle* angle = sorted[angleIndex];
2730 if (angle->segment() == this && angle->start() == end &&
2731 angle->end() == start) {
2732 firstIndex = angleIndex;
2733 break;
2734 }
2735 }
2736 return firstIndex;
2737 }
2738
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002739 // FIXME: this is tricky code; needs its own unit test
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002740 // note that fOtherIndex isn't computed yet, so it can't be used here
caryclark@google.com4eeda372012-12-06 21:47:48 +00002741 void findTooCloseToCall() {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002742 int count = fTs.count();
2743 if (count < 3) { // require t=0, x, 1 at minimum
2744 return;
2745 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002746 int matchIndex = 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002747 int moCount;
2748 Span* match;
2749 Segment* mOther;
2750 do {
2751 match = &fTs[matchIndex];
2752 mOther = match->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002753 // FIXME: allow quads, cubics to be near coincident?
2754 if (mOther->fVerb == SkPath::kLine_Verb) {
2755 moCount = mOther->fTs.count();
2756 if (moCount >= 3) {
2757 break;
2758 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002759 }
2760 if (++matchIndex >= count) {
2761 return;
2762 }
2763 } while (true); // require t=0, x, 1 at minimum
caryclark@google.com15fa1382012-05-07 20:49:36 +00002764 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002765 const SkPoint* matchPt = &xyAtT(match);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002766 // look for a pair of nearby T values that map to the same (x,y) value
2767 // if found, see if the pair of other segments share a common point. If
2768 // so, the span from here to there is coincident.
caryclark@google.com15fa1382012-05-07 20:49:36 +00002769 for (int index = matchIndex + 1; index < count; ++index) {
2770 Span* test = &fTs[index];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002771 if (test->fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002772 continue;
2773 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002774 Segment* tOther = test->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002775 if (tOther->fVerb != SkPath::kLine_Verb) {
2776 continue; // FIXME: allow quads, cubics to be near coincident?
2777 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002778 int toCount = tOther->fTs.count();
2779 if (toCount < 3) { // require t=0, x, 1 at minimum
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002780 continue;
2781 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002782 const SkPoint* testPt = &xyAtT(test);
2783 if (*matchPt != *testPt) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002784 matchIndex = index;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002785 moCount = toCount;
2786 match = test;
2787 mOther = tOther;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002788 matchPt = testPt;
2789 continue;
2790 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002791 int moStart = -1;
2792 int moEnd = -1;
2793 double moStartT, moEndT;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002794 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002795 Span& moSpan = mOther->fTs[moIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002796 if (moSpan.fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002797 continue;
2798 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002799 if (moSpan.fOther == this) {
2800 if (moSpan.fOtherT == match->fT) {
2801 moStart = moIndex;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002802 moStartT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002803 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002804 continue;
2805 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002806 if (moSpan.fOther == tOther) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002807 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002808 moStart = -1;
2809 break;
2810 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002811 SkASSERT(moEnd == -1);
2812 moEnd = moIndex;
2813 moEndT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002814 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002815 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002816 if (moStart < 0 || moEnd < 0) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002817 continue;
2818 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002819 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002820 if (approximately_equal(moStartT, moEndT)) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002821 continue;
2822 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002823 int toStart = -1;
2824 int toEnd = -1;
2825 double toStartT, toEndT;
2826 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2827 Span& toSpan = tOther->fTs[toIndex];
caryclark@google.comc899ad92012-08-23 15:24:42 +00002828 if (toSpan.fDone) {
2829 continue;
2830 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002831 if (toSpan.fOther == this) {
2832 if (toSpan.fOtherT == test->fT) {
2833 toStart = toIndex;
2834 toStartT = toSpan.fT;
2835 }
2836 continue;
2837 }
2838 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002839 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002840 moStart = -1;
2841 break;
2842 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002843 SkASSERT(toEnd == -1);
2844 toEnd = toIndex;
2845 toEndT = toSpan.fT;
2846 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002847 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002848 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2849 if (toStart <= 0 || toEnd <= 0) {
2850 continue;
2851 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002852 if (approximately_equal(toStartT, toEndT)) {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002853 continue;
2854 }
2855 // test to see if the segment between there and here is linear
2856 if (!mOther->isLinear(moStart, moEnd)
2857 || !tOther->isLinear(toStart, toEnd)) {
2858 continue;
2859 }
caryclark@google.comc899ad92012-08-23 15:24:42 +00002860 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002861 if (flipped) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002862 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002863 } else {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002864 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002865 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002866 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002867 }
2868
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002869 // FIXME: either:
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002870 // a) mark spans with either end unsortable as done, or
2871 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2872 // when encountering an unsortable span
2873
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002874 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2875 // and use more concise logic like the old edge walker code?
2876 // FIXME: this needs to deal with coincident edges
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002877 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002878 // iterate through T intersections and return topmost
2879 // topmost tangent from y-min to first pt is closer to horizontal
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002880 SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002881 int firstT = -1;
caryclark@google.comd0a19eb2013-02-19 12:49:33 +00002882 /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002883 SkASSERT(firstT >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002884 // sort the edges to find the leftmost
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002885 int step = 1;
2886 int end = nextSpan(firstT, step);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002887 if (end == -1) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002888 step = -1;
2889 end = nextSpan(firstT, step);
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00002890 SkASSERT(end != -1);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002891 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002892 // if the topmost T is not on end, or is three-way or more, find left
2893 // look for left-ness from tLeft to firstT (matching y of other)
2894 SkTDArray<Angle> angles;
2895 SkASSERT(firstT - end != 0);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002896 addTwoAngles(end, firstT, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002897 buildAngles(firstT, angles, true);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002898 SkTDArray<Angle*> sorted;
caryclark@google.comf839c032012-10-26 21:03:50 +00002899 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002900 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002901 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002902 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002903 if (onlySortable && !sortable) {
2904 unsortable = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002905 return NULL;
2906 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002907 // skip edges that have already been processed
2908 firstT = -1;
2909 Segment* leftSegment;
2910 do {
2911 const Angle* angle = sorted[++firstT];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002912 SkASSERT(!onlySortable || !angle->unsortable());
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002913 leftSegment = angle->segment();
2914 tIndex = angle->end();
2915 endIndex = angle->start();
2916 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002917 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002918 bool bumpsUp = leftSegment->bumpsUp(tIndex, endIndex);
2919 SkPoint xyE = leftSegment->xyAtT(endIndex);
2920 SkPoint xyS = leftSegment->xyAtT(tIndex);
caryclark@google.com7ff5c842013-02-26 15:56:05 +00002921 SkVector dxyE = leftSegment->dxdy(endIndex);
2922 SkVector dxyS = leftSegment->dxdy(tIndex);
caryclark@google.com47d73da2013-02-17 01:41:25 +00002923 double cross = dxyE.cross(dxyS);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00002924 bool bumpCheck = bumpsUp && xyE.fY < xyS.fY && dxyE.fX < 0;
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00002925 if (xyE == xyS){
2926 SkDebugf("%s ignore loops\n", __FUNCTION__);
2927 cross = 0;
2928 }
caryclark@google.com47d73da2013-02-17 01:41:25 +00002929 #if DEBUG_SWAP_TOP
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002930 SkDebugf("%s xyE=(%1.9g,%1.9g) xyS=(%1.9g,%1.9g)\n", __FUNCTION__,
2931 xyE.fX, xyE.fY, xyS.fX, xyS.fY);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00002932 SkDebugf("%s dxyE=(%1.9g,%1.9g) dxyS=(%1.9g,%1.9g) cross=%1.9g bumpsUp=%s\n",
2933 __FUNCTION__,
2934 dxyE.fX, dxyE.fY, dxyS.fX, dxyS.fY, cross, bumpsUp ? "true" : "false");
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002935 if ((cross > 0) ^ bumpCheck) {
2936 leftSegment->bumpsUp(tIndex, endIndex);
2937 SkDebugf("%s cross bump disagree\n", __FUNCTION__);
2938 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00002939 #endif
2940 if (cross > 0 || bumpCheck) {
caryclark@google.com47d73da2013-02-17 01:41:25 +00002941 #if DEBUG_SWAP_TOP
2942 SkDebugf("%s swap\n", __FUNCTION__);
2943 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002944 SkTSwap(tIndex, endIndex);
2945 }
2946 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002947 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002948 return leftSegment;
2949 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002950
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002951 // FIXME: not crazy about this
2952 // when the intersections are performed, the other index is into an
2953 // incomplete array. as the array grows, the indices become incorrect
2954 // while the following fixes the indices up again, it isn't smart about
2955 // skipping segments whose indices are already correct
2956 // assuming we leave the code that wrote the index in the first place
2957 void fixOtherTIndex() {
2958 int iCount = fTs.count();
2959 for (int i = 0; i < iCount; ++i) {
2960 Span& iSpan = fTs[i];
2961 double oT = iSpan.fOtherT;
2962 Segment* other = iSpan.fOther;
2963 int oCount = other->fTs.count();
2964 for (int o = 0; o < oCount; ++o) {
2965 Span& oSpan = other->fTs[o];
2966 if (oT == oSpan.fT && this == oSpan.fOther) {
2967 iSpan.fOtherIndex = o;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002968 break;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002969 }
2970 }
2971 }
2972 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002973
caryclark@google.com4eeda372012-12-06 21:47:48 +00002974 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002975 fDoneSpans = 0;
2976 fOperand = operand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00002977 fXor = evenOdd;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002978 fPts = pts;
2979 fVerb = verb;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002980 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00002981
caryclark@google.com3586ece2012-12-27 18:46:58 +00002982 void initWinding(int start, int end) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002983 int local = spanSign(start, end);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002984 int oppLocal = oppSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002985 (void) markAndChaseWinding(start, end, local, oppLocal);
caryclark@google.com73ca6242013-01-17 21:02:47 +00002986 // OPTIMIZATION: the reverse mark and chase could skip the first marking
2987 (void) markAndChaseWinding(end, start, local, oppLocal);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002988 }
2989
caryclark@google.com3586ece2012-12-27 18:46:58 +00002990 void initWinding(int start, int end, int winding, int oppWinding) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002991 int local = spanSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002992 if (local * winding >= 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002993 winding += local;
2994 }
2995 int oppLocal = oppSign(start, end);
2996 if (oppLocal * oppWinding >= 0) {
2997 oppWinding += oppLocal;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002998 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002999 (void) markAndChaseWinding(start, end, winding, oppWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003000 }
3001
caryclark@google.com3586ece2012-12-27 18:46:58 +00003002/*
3003when we start with a vertical intersect, we try to use the dx to determine if the edge is to
3004the 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 +00003005sign or not. However, this isn't enough.
3006If 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 +00003007If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
3008from 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 +00003009the same winding is shared by both.
caryclark@google.com3586ece2012-12-27 18:46:58 +00003010*/
3011 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
3012 SkScalar hitOppDx) {
3013 SkASSERT(hitDx || !winding);
3014 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
3015 SkASSERT(dx);
3016 int windVal = windValue(SkMin32(start, end));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003017 #if DEBUG_WINDING_AT_T
3018 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
3019 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
3020 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00003021 if (!winding) {
3022 winding = dx < 0 ? windVal : -windVal;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003023 } else if (winding * dx < 0) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00003024 int sideWind = winding + (dx < 0 ? windVal : -windVal);
3025 if (abs(winding) < abs(sideWind)) {
3026 winding = sideWind;
3027 }
3028 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003029 #if DEBUG_WINDING_AT_T
3030 SkDebugf(" winding=%d\n", winding);
3031 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00003032 int oppLocal = oppSign(start, end);
3033 SkASSERT(hitOppDx || !oppWind || !oppLocal);
3034 int oppWindVal = oppValue(SkMin32(start, end));
3035 if (!oppWind) {
3036 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
3037 } else if (hitOppDx * dx >= 0) {
3038 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
3039 if (abs(oppWind) < abs(oppSideWind)) {
3040 oppWind = oppSideWind;
3041 }
3042 }
3043 (void) markAndChaseWinding(start, end, winding, oppWind);
3044 }
3045
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003046 bool intersected() const {
3047 return fTs.count() > 0;
3048 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00003049
caryclark@google.com10227bf2012-12-28 22:10:41 +00003050 bool isCanceled(int tIndex) const {
3051 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
3052 }
3053
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00003054 bool isConnected(int startIndex, int endIndex) const {
3055 return fTs[startIndex].fWindSum != SK_MinS32
3056 || fTs[endIndex].fWindSum != SK_MinS32;
3057 }
3058
caryclark@google.com235f56a2012-09-14 14:19:30 +00003059 bool isHorizontal() const {
3060 return fBounds.fTop == fBounds.fBottom;
3061 }
3062
caryclark@google.com15fa1382012-05-07 20:49:36 +00003063 bool isLinear(int start, int end) const {
3064 if (fVerb == SkPath::kLine_Verb) {
3065 return true;
3066 }
3067 if (fVerb == SkPath::kQuad_Verb) {
3068 SkPoint qPart[3];
3069 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
3070 return QuadIsLinear(qPart);
3071 } else {
3072 SkASSERT(fVerb == SkPath::kCubic_Verb);
3073 SkPoint cPart[4];
3074 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
3075 return CubicIsLinear(cPart);
3076 }
3077 }
caryclark@google.comb9738012012-07-03 19:53:30 +00003078
3079 // OPTIMIZE: successive calls could start were the last leaves off
3080 // or calls could specialize to walk forwards or backwards
3081 bool isMissing(double startT) const {
3082 size_t tCount = fTs.count();
3083 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003084 if (approximately_zero(startT - fTs[index].fT)) {
caryclark@google.comb9738012012-07-03 19:53:30 +00003085 return false;
3086 }
3087 }
3088 return true;
3089 }
3090
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003091 bool isSimple(int end) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003092 int count = fTs.count();
3093 if (count == 2) {
3094 return true;
3095 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003096 double t = fTs[end].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003097 if (approximately_less_than_zero(t)) {
3098 return !approximately_less_than_zero(fTs[1].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003099 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003100 if (approximately_greater_than_one(t)) {
3101 return !approximately_greater_than_one(fTs[count - 2].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003102 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003103 return false;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003104 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003105
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003106 bool isVertical() const {
3107 return fBounds.fLeft == fBounds.fRight;
3108 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003109
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003110 bool isVertical(int start, int end) const {
3111 return (*SegmentVertical[fVerb])(fPts, start, end);
3112 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003113
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003114 SkScalar leftMost(int start, int end) const {
3115 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
3116 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003117
caryclark@google.com495f8e42012-05-31 13:13:11 +00003118 // this span is excluded by the winding rule -- chase the ends
3119 // as long as they are unambiguous to mark connections as done
3120 // and give them the same winding value
caryclark@google.com59823f72012-08-09 18:17:47 +00003121 Span* markAndChaseDone(const Angle* angle, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003122 int index = angle->start();
3123 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003124 return markAndChaseDone(index, endIndex, winding);
3125 }
3126
caryclark@google.com31143cf2012-11-09 22:14:19 +00003127 Span* markAndChaseDone(int index, int endIndex, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003128 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003129 int min = SkMin32(index, endIndex);
3130 markDone(min, winding);
3131 Span* last;
3132 Segment* other = this;
3133 while ((other = other->nextChase(index, step, min, last))) {
3134 other->markDone(min, winding);
3135 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003136 return last;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003137 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003138
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003139 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
3140 int index = angle->start();
3141 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003142 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003143 int min = SkMin32(index, endIndex);
3144 markDoneBinary(min, winding, oppWinding);
3145 Span* last;
3146 Segment* other = this;
3147 while ((other = other->nextChase(index, step, min, last))) {
3148 other->markDoneBinary(min, winding, oppWinding);
3149 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003150 return last;
3151 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003152
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003153 Span* markAndChaseDoneBinary(int index, int endIndex) {
3154 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003155 int min = SkMin32(index, endIndex);
3156 markDoneBinary(min);
3157 Span* last;
3158 Segment* other = this;
3159 while ((other = other->nextChase(index, step, min, last))) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003160 if (other->done()) {
3161 return NULL;
3162 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003163 other->markDoneBinary(min);
3164 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003165 return last;
3166 }
3167
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003168 Span* markAndChaseDoneUnary(int index, int endIndex) {
3169 int step = SkSign32(endIndex - index);
3170 int min = SkMin32(index, endIndex);
3171 markDoneUnary(min);
3172 Span* last;
3173 Segment* other = this;
3174 while ((other = other->nextChase(index, step, min, last))) {
3175 if (other->done()) {
3176 return NULL;
3177 }
3178 other->markDoneUnary(min);
3179 }
3180 return last;
3181 }
3182
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003183 Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
3184 int index = angle->start();
3185 int endIndex = angle->end();
3186 return markAndChaseDone(index, endIndex, winding);
3187 }
3188
caryclark@google.com4eeda372012-12-06 21:47:48 +00003189 Span* markAndChaseWinding(const Angle* angle, const int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003190 int index = angle->start();
3191 int endIndex = angle->end();
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003192 int step = SkSign32(endIndex - index);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003193 int min = SkMin32(index, endIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00003194 markWinding(min, winding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003195 Span* last;
3196 Segment* other = this;
3197 while ((other = other->nextChase(index, step, min, last))) {
3198 if (other->fTs[min].fWindSum != SK_MinS32) {
3199 SkASSERT(other->fTs[min].fWindSum == winding);
3200 return NULL;
3201 }
3202 other->markWinding(min, winding);
3203 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003204 return last;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003205 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003206
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003207 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003208 int min = SkMin32(index, endIndex);
3209 int step = SkSign32(endIndex - index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003210 markWinding(min, winding, oppWinding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003211 Span* last;
3212 Segment* other = this;
3213 while ((other = other->nextChase(index, step, min, last))) {
3214 if (other->fTs[min].fWindSum != SK_MinS32) {
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00003215 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003216 return NULL;
3217 }
3218 other->markWinding(min, winding, oppWinding);
3219 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003220 return last;
3221 }
3222
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003223 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
3224 int start = angle->start();
3225 int end = angle->end();
3226 return markAndChaseWinding(start, end, winding, oppWinding);
3227 }
3228
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003229 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
3230 SkASSERT(angle->segment() == this);
3231 if (useInnerWinding(maxWinding, sumWinding)) {
3232 maxWinding = sumWinding;
3233 }
3234 Span* last;
3235 if (activeAngle) {
3236 last = markAndChaseWinding(angle, maxWinding);
3237 } else {
3238 last = markAndChaseDoneUnary(angle, maxWinding);
3239 }
3240 return last;
3241 }
3242
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003243 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
3244 bool activeAngle, const Angle* angle) {
3245 SkASSERT(angle->segment() == this);
3246 if (useInnerWinding(maxWinding, sumWinding)) {
3247 maxWinding = sumWinding;
3248 }
3249 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
3250 oppMaxWinding = oppSumWinding;
3251 }
3252 Span* last;
3253 if (activeAngle) {
3254 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3255 } else {
3256 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
3257 }
3258 return last;
3259 }
3260
caryclark@google.com495f8e42012-05-31 13:13:11 +00003261 // FIXME: this should also mark spans with equal (x,y)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003262 // This may be called when the segment is already marked done. While this
3263 // wastes time, it shouldn't do any more than spin through the T spans.
rmistry@google.comd6176b02012-08-23 18:14:13 +00003264 // OPTIMIZATION: abort on first done found (assuming that this code is
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003265 // always called to mark segments done).
caryclark@google.com59823f72012-08-09 18:17:47 +00003266 void markDone(int index, int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003267 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003268 SkASSERT(winding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003269 double referenceT = fTs[index].fT;
3270 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003271 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3272 markOneDone(__FUNCTION__, lesser, winding);
3273 }
3274 do {
3275 markOneDone(__FUNCTION__, index, winding);
3276 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003277 }
3278
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003279 void markDoneBinary(int index, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003280 // SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003281 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003282 double referenceT = fTs[index].fT;
3283 int lesser = index;
3284 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003285 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003286 }
3287 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003288 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
3289 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3290 }
3291
3292 void markDoneBinary(int index) {
3293 double referenceT = fTs[index].fT;
3294 int lesser = index;
3295 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3296 markOneDoneBinary(__FUNCTION__, lesser);
3297 }
3298 do {
3299 markOneDoneBinary(__FUNCTION__, index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003300 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003301 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00003302
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003303 void markDoneUnary(int index, int winding) {
3304 // SkASSERT(!done());
3305 SkASSERT(winding);
3306 double referenceT = fTs[index].fT;
3307 int lesser = index;
3308 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3309 markOneDoneUnary(__FUNCTION__, lesser, winding);
3310 }
3311 do {
3312 markOneDoneUnary(__FUNCTION__, index, winding);
3313 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3314 }
3315
3316 void markDoneUnary(int index) {
3317 double referenceT = fTs[index].fT;
3318 int lesser = index;
3319 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3320 markOneDoneUnary(__FUNCTION__, lesser);
3321 }
3322 do {
3323 markOneDoneUnary(__FUNCTION__, index);
3324 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3325 }
3326
caryclark@google.com24bec792012-08-20 12:43:57 +00003327 void markOneDone(const char* funName, int tIndex, int winding) {
3328 Span* span = markOneWinding(funName, tIndex, winding);
3329 if (!span) {
3330 return;
3331 }
3332 span->fDone = true;
3333 fDoneSpans++;
3334 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003335
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003336 void markOneDoneBinary(const char* funName, int tIndex) {
3337 Span* span = verifyOneWinding(funName, tIndex);
3338 if (!span) {
3339 return;
3340 }
3341 span->fDone = true;
3342 fDoneSpans++;
3343 }
3344
3345 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003346 Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
3347 if (!span) {
3348 return;
3349 }
3350 span->fDone = true;
3351 fDoneSpans++;
3352 }
3353
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003354 void markOneDoneUnary(const char* funName, int tIndex) {
3355 Span* span = verifyOneWindingU(funName, tIndex);
3356 if (!span) {
3357 return;
3358 }
3359 span->fDone = true;
3360 fDoneSpans++;
3361 }
3362
3363 void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3364 Span* span = markOneWinding(funName, tIndex, winding);
3365 if (!span) {
3366 return;
3367 }
3368 span->fDone = true;
3369 fDoneSpans++;
3370 }
3371
caryclark@google.com24bec792012-08-20 12:43:57 +00003372 Span* markOneWinding(const char* funName, int tIndex, int winding) {
3373 Span& span = fTs[tIndex];
3374 if (span.fDone) {
3375 return NULL;
3376 }
3377 #if DEBUG_MARK_DONE
3378 debugShowNewWinding(funName, span, winding);
3379 #endif
3380 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com03f97062012-08-21 13:13:52 +00003381 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00003382 SkASSERT(abs(winding) <= gDebugMaxWindSum);
caryclark@google.com03f97062012-08-21 13:13:52 +00003383 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00003384 span.fWindSum = winding;
3385 return &span;
3386 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003387
caryclark@google.com31143cf2012-11-09 22:14:19 +00003388 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
3389 Span& span = fTs[tIndex];
3390 if (span.fDone) {
3391 return NULL;
3392 }
3393 #if DEBUG_MARK_DONE
3394 debugShowNewWinding(funName, span, winding, oppWinding);
3395 #endif
3396 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3397 #ifdef SK_DEBUG
3398 SkASSERT(abs(winding) <= gDebugMaxWindSum);
3399 #endif
3400 span.fWindSum = winding;
3401 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3402 #ifdef SK_DEBUG
3403 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
3404 #endif
3405 span.fOppSum = oppWinding;
3406 return &span;
3407 }
3408
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003409 bool bumpsUp(int tStart, int tEnd) const {
3410 SkPoint edge[4];
caryclark@google.comc83c70e2013-02-22 21:50:07 +00003411 subDivide(tStart, tEnd, edge);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003412 switch (fVerb) {
3413 case SkPath::kLine_Verb:
3414 SkASSERT(0); // shouldn't call in for lines
3415 return true;
3416 case SkPath::kQuad_Verb:
3417 return approximately_greater(edge[0].fY, edge[1].fY)
3418 && approximately_lesser(edge[1].fY, edge[2].fY);
3419 case SkPath::kCubic_Verb:
3420 return (approximately_greater(edge[0].fY, edge[1].fY)
3421 && approximately_lesser(edge[1].fY, edge[3].fY))
3422 || (approximately_greater(edge[0].fY, edge[2].fY)
3423 && approximately_lesser(edge[2].fY, edge[3].fY));
3424 default:
3425 SkASSERT(0);
3426 return false;
3427 }
3428 }
3429
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003430 Span* verifyOneWinding(const char* funName, int tIndex) {
3431 Span& span = fTs[tIndex];
3432 if (span.fDone) {
3433 return NULL;
3434 }
3435 #if DEBUG_MARK_DONE
3436 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3437 #endif
3438 SkASSERT(span.fWindSum != SK_MinS32);
3439 SkASSERT(span.fOppSum != SK_MinS32);
3440 return &span;
3441 }
3442
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003443 Span* verifyOneWindingU(const char* funName, int tIndex) {
3444 Span& span = fTs[tIndex];
3445 if (span.fDone) {
3446 return NULL;
3447 }
3448 #if DEBUG_MARK_DONE
3449 debugShowNewWinding(funName, span, span.fWindSum);
3450 #endif
3451 SkASSERT(span.fWindSum != SK_MinS32);
3452 return &span;
3453 }
3454
caryclark@google.comf839c032012-10-26 21:03:50 +00003455 // note that just because a span has one end that is unsortable, that's
3456 // not enough to mark it done. The other end may be sortable, allowing the
3457 // span to be added.
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003458 // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003459 void markUnsortable(int start, int end) {
3460 Span* span = &fTs[start];
3461 if (start < end) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003462#if DEBUG_UNSORTABLE
3463 SkDebugf("%s start id=%d [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fID, start,
3464 xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003465#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003466 span->fUnsortableStart = true;
3467 } else {
3468 --span;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003469#if DEBUG_UNSORTABLE
3470 SkDebugf("%s end id=%d [%d] (%1.9g,%1.9g) next:(%1.9g,%1.9g)\n", __FUNCTION__, fID,
3471 start - 1, xAtT(start - 1), yAtT(start - 1), xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003472#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003473 span->fUnsortableEnd = true;
3474 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003475 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003476 return;
3477 }
3478 span->fDone = true;
3479 fDoneSpans++;
3480 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003481
caryclark@google.com59823f72012-08-09 18:17:47 +00003482 void markWinding(int index, int winding) {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003483 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003484 SkASSERT(winding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003485 double referenceT = fTs[index].fT;
3486 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003487 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3488 markOneWinding(__FUNCTION__, lesser, winding);
3489 }
3490 do {
3491 markOneWinding(__FUNCTION__, index, winding);
3492 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003493 }
3494
3495 void markWinding(int index, int winding, int oppWinding) {
3496 // SkASSERT(!done());
caryclark@google.com4eeda372012-12-06 21:47:48 +00003497 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003498 double referenceT = fTs[index].fT;
3499 int lesser = index;
3500 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3501 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003502 }
3503 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003504 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3505 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003506 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003507
caryclark@google.com2ddff932012-08-07 21:25:27 +00003508 void matchWindingValue(int tIndex, double t, bool borrowWind) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003509 int nextDoorWind = SK_MaxS32;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003510 int nextOppWind = SK_MaxS32;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003511 if (tIndex > 0) {
3512 const Span& below = fTs[tIndex - 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003513 if (approximately_negative(t - below.fT)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003514 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003515 nextOppWind = below.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003516 }
3517 }
3518 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3519 const Span& above = fTs[tIndex + 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003520 if (approximately_negative(above.fT - t)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003521 nextDoorWind = above.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003522 nextOppWind = above.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003523 }
3524 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003525 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3526 const Span& below = fTs[tIndex - 1];
3527 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003528 nextOppWind = below.fOppValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003529 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003530 if (nextDoorWind != SK_MaxS32) {
3531 Span& newSpan = fTs[tIndex];
3532 newSpan.fWindValue = nextDoorWind;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003533 newSpan.fOppValue = nextOppWind;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003534 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003535 newSpan.fDone = true;
3536 ++fDoneSpans;
3537 }
3538 }
3539 }
3540
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003541 bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3542 // find bounds
3543 Bounds bounds;
3544 bounds.setPoint(xyAtT(index));
3545 bounds.add(xyAtT(endIndex));
3546 SkScalar width = bounds.width();
3547 SkScalar height = bounds.height();
3548 if (width > height) {
3549 if (approximately_negative(width)) {
3550 unsortable = true; // edge is too small to resolve meaningfully
3551 }
3552 return false;
3553 } else {
3554 if (approximately_negative(height)) {
3555 unsortable = true; // edge is too small to resolve meaningfully
3556 }
3557 return true;
3558 }
3559 }
3560
caryclark@google.com9764cc62012-07-12 19:29:45 +00003561 // return span if when chasing, two or more radiating spans are not done
3562 // OPTIMIZATION: ? multiple spans is detected when there is only one valid
3563 // candidate and the remaining spans have windValue == 0 (canceled by
3564 // coincidence). The coincident edges could either be removed altogether,
3565 // or this code could be more complicated in detecting this case. Worth it?
3566 bool multipleSpans(int end) const {
3567 return end > 0 && end < fTs.count() - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00003568 }
3569
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003570 bool nextCandidate(int& start, int& end) const {
caryclark@google.com10227bf2012-12-28 22:10:41 +00003571 while (fTs[end].fDone) {
3572 if (fTs[end].fT == 1) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003573 return false;
3574 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00003575 ++end;
3576 }
3577 start = end;
3578 end = nextExactSpan(start, 1);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003579 return true;
3580 }
3581
caryclark@google.com4eeda372012-12-06 21:47:48 +00003582 Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
3583 int end = nextExactSpan(index, step);
3584 SkASSERT(end >= 0);
3585 if (multipleSpans(end)) {
3586 last = &fTs[end];
3587 return NULL;
3588 }
3589 const Span& endSpan = fTs[end];
3590 Segment* other = endSpan.fOther;
3591 index = endSpan.fOtherIndex;
caryclark@google.comaa358312013-01-29 20:28:49 +00003592 SkASSERT(index >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003593 int otherEnd = other->nextExactSpan(index, step);
caryclark@google.comaa358312013-01-29 20:28:49 +00003594 SkASSERT(otherEnd >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003595 min = SkMin32(index, otherEnd);
3596 return other;
3597 }
3598
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003599 // This has callers for two different situations: one establishes the end
3600 // of the current span, and one establishes the beginning of the next span
3601 // (thus the name). When this is looking for the end of the current span,
3602 // coincidence is found when the beginning Ts contain -step and the end
3603 // contains step. When it is looking for the beginning of the next, the
3604 // first Ts found can be ignored and the last Ts should contain -step.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003605 // OPTIMIZATION: probably should split into two functions
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003606 int nextSpan(int from, int step) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003607 const Span& fromSpan = fTs[from];
caryclark@google.com495f8e42012-05-31 13:13:11 +00003608 int count = fTs.count();
3609 int to = from;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003610 while (step > 0 ? ++to < count : --to >= 0) {
3611 const Span& span = fTs[to];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003612 if (approximately_zero(span.fT - fromSpan.fT)) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003613 continue;
3614 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003615 return to;
3616 }
3617 return -1;
3618 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +00003619
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003620 // FIXME
3621 // this returns at any difference in T, vs. a preset minimum. It may be
3622 // that all callers to nextSpan should use this instead.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003623 // OPTIMIZATION splitting this into separate loops for up/down steps
3624 // would allow using precisely_negative instead of precisely_zero
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003625 int nextExactSpan(int from, int step) const {
3626 const Span& fromSpan = fTs[from];
3627 int count = fTs.count();
3628 int to = from;
3629 while (step > 0 ? ++to < count : --to >= 0) {
3630 const Span& span = fTs[to];
caryclark@google.coma461ff02012-10-11 12:54:23 +00003631 if (precisely_zero(span.fT - fromSpan.fT)) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003632 continue;
3633 }
3634 return to;
3635 }
3636 return -1;
3637 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003638
caryclark@google.com235f56a2012-09-14 14:19:30 +00003639 bool operand() const {
3640 return fOperand;
3641 }
3642
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003643 int oppSign(const Angle* angle) const {
3644 SkASSERT(angle->segment() == this);
3645 return oppSign(angle->start(), angle->end());
3646 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003647
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003648 int oppSign(int startIndex, int endIndex) const {
3649 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3650 : fTs[endIndex].fOppValue;
3651#if DEBUG_WIND_BUMP
3652 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3653#endif
3654 return result;
3655 }
3656
caryclark@google.com31143cf2012-11-09 22:14:19 +00003657 int oppSum(int tIndex) const {
3658 return fTs[tIndex].fOppSum;
3659 }
3660
3661 int oppSum(const Angle* angle) const {
3662 int lesser = SkMin32(angle->start(), angle->end());
3663 return fTs[lesser].fOppSum;
caryclark@google.com235f56a2012-09-14 14:19:30 +00003664 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003665
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003666 int oppValue(int tIndex) const {
3667 return fTs[tIndex].fOppValue;
3668 }
3669
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003670 int oppValue(const Angle* angle) const {
3671 int lesser = SkMin32(angle->start(), angle->end());
3672 return fTs[lesser].fOppValue;
3673 }
3674
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003675 const SkPoint* pts() const {
3676 return fPts;
3677 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003678
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003679 void reset() {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003680 init(NULL, (SkPath::Verb) -1, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003681 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3682 fTs.reset();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003683 }
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +00003684
caryclark@google.com4eeda372012-12-06 21:47:48 +00003685 void setOppXor(bool isOppXor) {
3686 fOppXor = isOppXor;
3687 }
skia.committer@gmail.com12eea2b2013-02-27 07:10:10 +00003688
caryclark@google.com7ff5c842013-02-26 15:56:05 +00003689 void setSpanT(int index, double t) {
3690 Span& span = fTs[index];
3691 span.fT = t;
3692 span.fOther->fTs[span.fOtherIndex].fOtherT = t;
3693 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003694
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003695 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3696 int deltaSum = spanSign(index, endIndex);
3697 maxWinding = sumWinding;
3698 sumWinding = sumWinding -= deltaSum;
3699 }
3700
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003701 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3702 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3703 int deltaSum = spanSign(index, endIndex);
3704 int oppDeltaSum = oppSign(index, endIndex);
3705 if (operand()) {
3706 maxWinding = sumSuWinding;
3707 sumWinding = sumSuWinding -= deltaSum;
3708 oppMaxWinding = sumMiWinding;
3709 oppSumWinding = sumMiWinding -= oppDeltaSum;
3710 } else {
3711 maxWinding = sumMiWinding;
3712 sumWinding = sumMiWinding -= deltaSum;
3713 oppMaxWinding = sumSuWinding;
3714 oppSumWinding = sumSuWinding -= oppDeltaSum;
3715 }
3716 }
3717
caryclark@google.comf839c032012-10-26 21:03:50 +00003718 // This marks all spans unsortable so that this info is available for early
3719 // exclusion in find top and others. This could be optimized to only mark
3720 // adjacent spans that unsortable. However, this makes it difficult to later
3721 // determine starting points for edge detection in find top and the like.
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003722 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
caryclark@google.comf839c032012-10-26 21:03:50 +00003723 bool sortable = true;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003724 int angleCount = angles.count();
3725 int angleIndex;
3726 angleList.setReserve(angleCount);
3727 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003728 Angle& angle = angles[angleIndex];
caryclark@google.comf839c032012-10-26 21:03:50 +00003729 *angleList.append() = &angle;
3730 sortable &= !angle.unsortable();
3731 }
3732 if (sortable) {
3733 QSort<Angle>(angleList.begin(), angleList.end() - 1);
3734 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3735 if (angles[angleIndex].unsortable()) {
3736 sortable = false;
3737 break;
3738 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003739 }
3740 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003741 if (!sortable) {
3742 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3743 Angle& angle = angles[angleIndex];
3744 angle.segment()->markUnsortable(angle.start(), angle.end());
3745 }
3746 }
3747 return sortable;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003748 }
3749
caryclark@google.com1577e8f2012-05-22 17:01:14 +00003750 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003751 const Span& span(int tIndex) const {
3752 return fTs[tIndex];
3753 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003754
caryclark@google.com235f56a2012-09-14 14:19:30 +00003755 int spanSign(const Angle* angle) const {
3756 SkASSERT(angle->segment() == this);
3757 return spanSign(angle->start(), angle->end());
3758 }
3759
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003760 int spanSign(int startIndex, int endIndex) const {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003761 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3762 : fTs[endIndex].fWindValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003763#if DEBUG_WIND_BUMP
3764 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3765#endif
3766 return result;
3767 }
skia.committer@gmail.com58433de2013-02-23 07:02:45 +00003768
caryclark@google.comc83c70e2013-02-22 21:50:07 +00003769 void subDivide(int start, int end, SkPoint edge[4]) const {
3770 edge[0] = fTs[start].fPt;
3771 edge[fVerb] = fTs[end].fPt;
3772 if (fVerb == SkPath::kQuad_Verb || fVerb == SkPath::kCubic_Verb) {
3773 _Point sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[fVerb].fX, edge[fVerb].fY }};
3774 if (fVerb == SkPath::kQuad_Verb) {
3775 MAKE_CONST_QUAD(aQuad, fPts);
3776 edge[1] = sub_divide(aQuad, sub[0], sub[1], fTs[start].fT, fTs[end].fT).asSkPoint();
3777 } else {
3778 MAKE_CONST_CUBIC(aCubic, fPts);
3779 sub_divide(aCubic, sub[0], sub[1], fTs[start].fT, fTs[end].fT, sub);
3780 edge[1] = sub[0].asSkPoint();
3781 edge[2] = sub[1].asSkPoint();
3782 }
3783 }
3784 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003785
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003786 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003787 double t(int tIndex) const {
3788 return fTs[tIndex].fT;
3789 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003790
caryclark@google.com10227bf2012-12-28 22:10:41 +00003791 double tAtMid(int start, int end, double mid) const {
3792 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
3793 }
3794
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003795 bool tiny(const Angle* angle) const {
3796 int start = angle->start();
3797 int end = angle->end();
caryclark@google.comf839c032012-10-26 21:03:50 +00003798 const Span& mSpan = fTs[SkMin32(start, end)];
3799 return mSpan.fTiny;
3800 }
3801
caryclark@google.com18063442012-07-25 12:05:18 +00003802 static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3803 double start) {
3804 int outCount = outsideTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003805 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
caryclark@google.com18063442012-07-25 12:05:18 +00003806 *outsideTs.append() = end;
3807 *outsideTs.append() = start;
3808 }
3809 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003810
caryclark@google.com24bec792012-08-20 12:43:57 +00003811 void undoneSpan(int& start, int& end) {
3812 size_t tCount = fTs.count();
3813 size_t index;
3814 for (index = 0; index < tCount; ++index) {
3815 if (!fTs[index].fDone) {
3816 break;
3817 }
3818 }
3819 SkASSERT(index < tCount - 1);
3820 start = index;
3821 double startT = fTs[index].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003822 while (approximately_negative(fTs[++index].fT - startT))
caryclark@google.com24bec792012-08-20 12:43:57 +00003823 SkASSERT(index < tCount);
3824 SkASSERT(index < tCount);
3825 end = index;
3826 }
caryclark@google.com18063442012-07-25 12:05:18 +00003827
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003828 bool unsortable(int index) const {
3829 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3830 }
3831
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003832 void updatePts(const SkPoint pts[]) {
3833 fPts = pts;
3834 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003835
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003836 int updateOppWinding(int index, int endIndex) const {
3837 int lesser = SkMin32(index, endIndex);
3838 int oppWinding = oppSum(lesser);
3839 int oppSpanWinding = oppSign(index, endIndex);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003840 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)
3841 && oppWinding != SK_MaxS32) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003842 oppWinding -= oppSpanWinding;
3843 }
3844 return oppWinding;
3845 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003846
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003847 int updateOppWinding(const Angle* angle) const {
3848 int startIndex = angle->start();
3849 int endIndex = angle->end();
3850 return updateOppWinding(endIndex, startIndex);
3851 }
3852
3853 int updateOppWindingReverse(const Angle* angle) const {
3854 int startIndex = angle->start();
3855 int endIndex = angle->end();
3856 return updateOppWinding(startIndex, endIndex);
3857 }
3858
3859 int updateWinding(int index, int endIndex) const {
3860 int lesser = SkMin32(index, endIndex);
3861 int winding = windSum(lesser);
3862 int spanWinding = spanSign(index, endIndex);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003863 if (winding && useInnerWinding(winding - spanWinding, winding) && winding != SK_MaxS32) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003864 winding -= spanWinding;
3865 }
3866 return winding;
3867 }
3868
3869 int updateWinding(const Angle* angle) const {
3870 int startIndex = angle->start();
3871 int endIndex = angle->end();
3872 return updateWinding(endIndex, startIndex);
3873 }
3874
3875 int updateWindingReverse(const Angle* angle) const {
3876 int startIndex = angle->start();
3877 int endIndex = angle->end();
3878 return updateWinding(startIndex, endIndex);
3879 }
3880
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003881 SkPath::Verb verb() const {
3882 return fVerb;
3883 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003884
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003885 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003886 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3887 return SK_MinS32;
3888 }
3889 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3890 SkASSERT(winding != SK_MinS32);
3891 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003892 #if DEBUG_WINDING_AT_T
3893 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003894 #endif
3895 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark@google.com3586ece2012-12-27 18:46:58 +00003896 dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003897 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3898 dx = fPts[2].fX - fPts[1].fX - dx;
3899 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003900 if (dx == 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003901 #if DEBUG_WINDING_AT_T
3902 SkDebugf(" dx=0 winding=SK_MinS32\n");
3903 #endif
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003904 return SK_MinS32;
3905 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003906 if (winding * dx > 0) { // if same signs, result is negative
3907 winding += dx > 0 ? -windVal : windVal;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003908 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003909 #if DEBUG_WINDING_AT_T
3910 SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding);
3911 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003912 return winding;
3913 }
3914
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003915 int windSum(int tIndex) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003916 return fTs[tIndex].fWindSum;
3917 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003918
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003919 int windSum(const Angle* angle) const {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003920 int start = angle->start();
3921 int end = angle->end();
3922 int index = SkMin32(start, end);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003923 return windSum(index);
caryclark@google.com495f8e42012-05-31 13:13:11 +00003924 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003925
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003926 int windValue(int tIndex) const {
3927 return fTs[tIndex].fWindValue;
3928 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003929
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003930 int windValue(const Angle* angle) const {
3931 int start = angle->start();
3932 int end = angle->end();
3933 int index = SkMin32(start, end);
3934 return windValue(index);
3935 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00003936
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003937 int windValueAt(double t) const {
3938 int count = fTs.count();
3939 for (int index = 0; index < count; ++index) {
3940 if (fTs[index].fT == t) {
3941 return fTs[index].fWindValue;
3942 }
3943 }
3944 SkASSERT(0);
3945 return 0;
3946 }
3947
caryclark@google.com3586ece2012-12-27 18:46:58 +00003948 SkScalar xAtT(int index) const {
3949 return xAtT(&fTs[index]);
3950 }
3951
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003952 SkScalar xAtT(const Span* span) const {
3953 return xyAtT(span).fX;
3954 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003955
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003956 const SkPoint& xyAtT(int index) const {
3957 return xyAtT(&fTs[index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003958 }
3959
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003960 const SkPoint& xyAtT(const Span* span) const {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003961 if (SkScalarIsNaN(span->fPt.fX)) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00003962 SkASSERT(0); // make sure this path is never used
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003963 if (span->fT == 0) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003964 span->fPt = fPts[0];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003965 } else if (span->fT == 1) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003966 span->fPt = fPts[fVerb];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003967 } else {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003968 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003969 }
3970 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00003971 return span->fPt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003972 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003973
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003974 // used only by right angle winding finding
caryclark@google.com10227bf2012-12-28 22:10:41 +00003975 void xyAtT(double mid, SkPoint& pt) const {
3976 (*SegmentXYAtT[fVerb])(fPts, mid, &pt);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003977 }
3978
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003979 SkScalar yAtT(int index) const {
3980 return yAtT(&fTs[index]);
3981 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003982
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003983 SkScalar yAtT(const Span* span) const {
3984 return xyAtT(span).fY;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003985 }
3986
caryclark@google.com4eeda372012-12-06 21:47:48 +00003987 void zeroCoincidentOpp(Span* oTest, int index) {
3988 Span* const test = &fTs[index];
3989 Span* end = test;
3990 do {
3991 end->fOppValue = 0;
3992 end = &fTs[++index];
3993 } while (approximately_negative(end->fT - test->fT));
3994 }
3995
3996 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
3997 Span* const oTest = &fTs[oIndex];
3998 Span* oEnd = oTest;
3999 const double startT = test->fT;
4000 const double oStartT = oTest->fT;
4001 double otherTMatch = (test->fT - startT) * tRatio + oStartT;
4002 while (!approximately_negative(oEndT - oEnd->fT)
4003 && approximately_negative(oEnd->fT - otherTMatch)) {
4004 oEnd->fOppValue = 0;
4005 oEnd = &fTs[++oIndex];
4006 }
4007 }
4008
4009 void zeroSpan(Span* span) {
4010 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
caryclark@google.com6ec15262012-11-16 20:16:50 +00004011 span->fWindValue = 0;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004012 span->fOppValue = 0;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004013 SkASSERT(!span->fDone);
4014 span->fDone = true;
4015 ++fDoneSpans;
caryclark@google.com6ec15262012-11-16 20:16:50 +00004016 }
4017
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004018#if DEBUG_DUMP
4019 void dump() const {
4020 const char className[] = "Segment";
4021 const int tab = 4;
4022 for (int i = 0; i < fTs.count(); ++i) {
4023 SkPoint out;
4024 (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
4025 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004026 " otherT=%1.9g windSum=%d\n",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004027 tab + sizeof(className), className, fID,
4028 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004029 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004030 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00004031 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004032 tab + sizeof(className), className, fID,
caryclark@google.com15fa1382012-05-07 20:49:36 +00004033 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004034 }
4035#endif
4036
caryclark@google.com47580692012-07-23 12:14:49 +00004037#if DEBUG_CONCIDENT
caryclark@google.comaa358312013-01-29 20:28:49 +00004038 // SkASSERT if pair has not already been added
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004039 void debugAddTPair(double t, const Segment& other, double otherT) const {
caryclark@google.comcc905052012-07-25 20:59:42 +00004040 for (int i = 0; i < fTs.count(); ++i) {
4041 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
4042 return;
4043 }
4044 }
4045 SkASSERT(0);
4046 }
4047#endif
4048
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004049#if DEBUG_DUMP
4050 int debugID() const {
4051 return fID;
4052 }
4053#endif
4054
caryclark@google.com24bec792012-08-20 12:43:57 +00004055#if DEBUG_WINDING
4056 void debugShowSums() const {
4057 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
4058 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
4059 for (int i = 0; i < fTs.count(); ++i) {
4060 const Span& span = fTs[i];
4061 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
4062 if (span.fWindSum == SK_MinS32) {
4063 SkDebugf("?");
4064 } else {
4065 SkDebugf("%d", span.fWindSum);
4066 }
4067 SkDebugf("]");
4068 }
4069 SkDebugf("\n");
4070 }
4071#endif
4072
caryclark@google.comcc905052012-07-25 20:59:42 +00004073#if DEBUG_CONCIDENT
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004074 void debugShowTs() const {
caryclark@google.com24bec792012-08-20 12:43:57 +00004075 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com4eeda372012-12-06 21:47:48 +00004076 int lastWind = -1;
4077 int lastOpp = -1;
4078 double lastT = -1;
4079 int i;
4080 for (i = 0; i < fTs.count(); ++i) {
4081 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
4082 || lastOpp != fTs[i].fOppValue;
4083 if (change && lastWind >= 0) {
4084 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
4085 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
4086 }
4087 if (change) {
4088 SkDebugf(" [o=%d", fTs[i].fOther->fID);
4089 lastWind = fTs[i].fWindValue;
4090 lastOpp = fTs[i].fOppValue;
4091 lastT = fTs[i].fT;
4092 } else {
4093 SkDebugf(",%d", fTs[i].fOther->fID);
4094 }
4095 }
4096 if (i <= 0) {
4097 return;
4098 }
4099 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
4100 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
4101 if (fOperand) {
4102 SkDebugf(" operand");
4103 }
4104 if (done()) {
4105 SkDebugf(" done");
caryclark@google.com47580692012-07-23 12:14:49 +00004106 }
4107 SkDebugf("\n");
4108 }
4109#endif
4110
caryclark@google.com027de222012-07-12 12:52:50 +00004111#if DEBUG_ACTIVE_SPANS
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004112 void debugShowActiveSpans() const {
caryclark@google.com027de222012-07-12 12:52:50 +00004113 if (done()) {
4114 return;
4115 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004116#if DEBUG_ACTIVE_SPANS_SHORT_FORM
4117 int lastId = -1;
4118 double lastT = -1;
4119#endif
caryclark@google.com027de222012-07-12 12:52:50 +00004120 for (int i = 0; i < fTs.count(); ++i) {
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004121 SkASSERT(&fTs[i] == &fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOther->
4122 fTs[fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOtherIndex]);
caryclark@google.com027de222012-07-12 12:52:50 +00004123 if (fTs[i].fDone) {
4124 continue;
4125 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004126#if DEBUG_ACTIVE_SPANS_SHORT_FORM
4127 if (lastId == fID && lastT == fTs[i].fT) {
4128 continue;
4129 }
4130 lastId = fID;
4131 lastT = fTs[i].fT;
4132#endif
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004133 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com027de222012-07-12 12:52:50 +00004134 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4135 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4136 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4137 }
4138 const Span* span = &fTs[i];
rmistry@google.comd6176b02012-08-23 18:14:13 +00004139 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
caryclark@google.com0c803d02012-08-06 11:15:47 +00004140 xAtT(span), yAtT(span));
caryclark@google.com47d73da2013-02-17 01:41:25 +00004141 int iEnd = i + 1;
4142 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) {
4143 ++iEnd;
4144 }
4145 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT);
caryclark@google.com027de222012-07-12 12:52:50 +00004146 const Segment* other = fTs[i].fOther;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004147 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
4148 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
4149 if (fTs[i].fWindSum == SK_MinS32) {
4150 SkDebugf("?");
4151 } else {
4152 SkDebugf("%d", fTs[i].fWindSum);
4153 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004154 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
caryclark@google.com027de222012-07-12 12:52:50 +00004155 }
4156 }
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +00004157
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004158 // This isn't useful yet -- but leaving it in for now in case i think of something
4159 // to use it for
4160 void validateActiveSpans() const {
4161 if (done()) {
4162 return;
4163 }
4164 int tCount = fTs.count();
4165 for (int index = 0; index < tCount; ++index) {
4166 if (fTs[index].fDone) {
4167 continue;
4168 }
4169 // count number of connections which are not done
4170 int first = index;
4171 double baseT = fTs[index].fT;
4172 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
4173 --first;
4174 }
4175 int last = index;
4176 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
4177 ++last;
4178 }
4179 int connections = 0;
4180 connections += first > 0 && !fTs[first - 1].fDone;
4181 for (int test = first; test <= last; ++test) {
4182 connections += !fTs[test].fDone;
4183 const Segment* other = fTs[test].fOther;
4184 int oIndex = fTs[test].fOtherIndex;
4185 connections += !other->fTs[oIndex].fDone;
4186 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
4187 }
4188 // SkASSERT(!(connections & 1));
4189 }
4190 }
caryclark@google.com027de222012-07-12 12:52:50 +00004191#endif
4192
caryclark@google.com0c803d02012-08-06 11:15:47 +00004193#if DEBUG_MARK_DONE
4194 void debugShowNewWinding(const char* fun, const Span& span, int winding) {
4195 const SkPoint& pt = xyAtT(&span);
4196 SkDebugf("%s id=%d", fun, fID);
4197 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4198 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4199 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4200 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004201 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4202 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4203 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d windSum=",
4204 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, winding);
caryclark@google.com0c803d02012-08-06 11:15:47 +00004205 if (span.fWindSum == SK_MinS32) {
4206 SkDebugf("?");
4207 } else {
4208 SkDebugf("%d", span.fWindSum);
4209 }
4210 SkDebugf(" windValue=%d\n", span.fWindValue);
4211 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004212
4213 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
4214 const SkPoint& pt = xyAtT(&span);
4215 SkDebugf("%s id=%d", fun, fID);
4216 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4217 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4218 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4219 }
4220 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4221 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4222 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=",
4223 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
4224 winding, oppWinding);
4225 if (span.fOppSum == SK_MinS32) {
4226 SkDebugf("?");
4227 } else {
4228 SkDebugf("%d", span.fOppSum);
4229 }
4230 SkDebugf(" windSum=");
4231 if (span.fWindSum == SK_MinS32) {
4232 SkDebugf("?");
4233 } else {
4234 SkDebugf("%d", span.fWindSum);
4235 }
4236 SkDebugf(" windValue=%d\n", span.fWindValue);
4237 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00004238#endif
4239
caryclark@google.com47580692012-07-23 12:14:49 +00004240#if DEBUG_SORT
caryclark@google.com03f97062012-08-21 13:13:52 +00004241 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
caryclark@google.com31143cf2012-11-09 22:14:19 +00004242 const int contourWinding, const int oppContourWinding) const {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004243 if (--gDebugSortCount < 0) {
4244 return;
4245 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004246 SkASSERT(angles[first]->segment() == this);
caryclark@google.com200c2112012-08-03 15:05:04 +00004247 SkASSERT(angles.count() > 1);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004248 int lastSum = contourWinding;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004249 int oppLastSum = oppContourWinding;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004250 const Angle* firstAngle = angles[first];
4251 int windSum = lastSum - spanSign(firstAngle);
4252 int oppoSign = oppSign(firstAngle);
4253 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004254 #define WIND_AS_STRING(x) char x##Str[12]; if (!valid_wind(x)) strcpy(x##Str, "?"); \
4255 else snprintf(x##Str, sizeof(x##Str), "%d", x)
4256 WIND_AS_STRING(contourWinding);
4257 WIND_AS_STRING(oppContourWinding);
4258 SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FUNCTION__,
4259 contourWindingStr, oppContourWindingStr, spanSign(angles[first]));
caryclark@google.comafe56de2012-07-24 18:11:03 +00004260 int index = first;
4261 bool firstTime = true;
caryclark@google.com47580692012-07-23 12:14:49 +00004262 do {
4263 const Angle& angle = *angles[index];
4264 const Segment& segment = *angle.segment();
4265 int start = angle.start();
4266 int end = angle.end();
4267 const Span& sSpan = segment.fTs[start];
4268 const Span& eSpan = segment.fTs[end];
4269 const Span& mSpan = segment.fTs[SkMin32(start, end)];
caryclark@google.com31143cf2012-11-09 22:14:19 +00004270 bool opp = segment.fOperand ^ fOperand;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004271 if (!firstTime) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004272 oppoSign = segment.oppSign(&angle);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004273 if (opp) {
4274 oppLastSum = oppWindSum;
4275 oppWindSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004276 if (oppoSign) {
4277 lastSum = windSum;
4278 windSum -= oppoSign;
4279 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004280 } else {
4281 lastSum = windSum;
4282 windSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004283 if (oppoSign) {
4284 oppLastSum = oppWindSum;
4285 oppWindSum -= oppoSign;
4286 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004287 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004288 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004289 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 +00004290 " sign=%d windValue=%d windSum=",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004291 __FUNCTION__, index, angle.unsortable() ? "*** UNSORTABLE *** " : "",
caryclark@google.comc91dfe42012-10-16 12:06:27 +00004292 segment.fID, kLVerbStr[segment.fVerb],
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004293 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
4294 segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(),
4295 mSpan.fWindValue);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004296 winding_printf(mSpan.fWindSum);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004297 int last, wind;
4298 if (opp) {
4299 last = oppLastSum;
4300 wind = oppWindSum;
4301 } else {
4302 last = lastSum;
4303 wind = windSum;
4304 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004305 bool useInner = valid_wind(last) && valid_wind(wind) && useInnerWinding(last, wind);
4306 WIND_AS_STRING(last);
4307 WIND_AS_STRING(wind);
4308 WIND_AS_STRING(lastSum);
4309 WIND_AS_STRING(oppLastSum);
4310 WIND_AS_STRING(windSum);
4311 WIND_AS_STRING(oppWindSum);
4312 #undef WIND_AS_STRING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004313 if (!oppoSign) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004314 SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr : lastStr);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004315 } else {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004316 SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : oppLastSumStr,
4317 opp ? windSumStr : oppWindSumStr);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004318 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004319 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004320#if false && DEBUG_ANGLE
caryclark@google.comc899ad92012-08-23 15:24:42 +00004321 angle.debugShow(segment.xyAtT(&sSpan));
4322#endif
caryclark@google.com47580692012-07-23 12:14:49 +00004323 ++index;
4324 if (index == angles.count()) {
4325 index = 0;
4326 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004327 if (firstTime) {
4328 firstTime = false;
4329 }
caryclark@google.com47580692012-07-23 12:14:49 +00004330 } while (index != first);
4331 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00004332
4333 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
4334 const Angle* firstAngle = angles[first];
4335 const Segment* segment = firstAngle->segment();
4336 int winding = segment->updateWinding(firstAngle);
4337 int oppWinding = segment->updateOppWinding(firstAngle);
4338 debugShowSort(fun, angles, first, winding, oppWinding);
4339 }
4340
caryclark@google.com47580692012-07-23 12:14:49 +00004341#endif
4342
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004343#if DEBUG_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004344 static char as_digit(int value) {
4345 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
4346 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004347#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004348
caryclark@google.com729e1c42012-11-21 21:36:34 +00004349#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004350 int debugShowWindingValues(int slotCount, int ofInterest) const {
4351 if (!(1 << fID & ofInterest)) {
4352 return 0;
4353 }
4354 int sum = 0;
4355 SkTDArray<char> slots;
4356 slots.setCount(slotCount * 2);
4357 memset(slots.begin(), ' ', slotCount * 2);
4358 for (int i = 0; i < fTs.count(); ++i) {
4359 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
4360 // continue;
4361 // }
4362 sum += fTs[i].fWindValue;
4363 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
4364 sum += fTs[i].fOppValue;
4365 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
4366 }
4367 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
4368 slots.begin() + slotCount);
4369 return sum;
4370 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004371#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004372
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004373private:
4374 const SkPoint* fPts;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004375 Bounds fBounds;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004376 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
caryclark@google.com4eeda372012-12-06 21:47:48 +00004377 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
caryclark@google.com24bec792012-08-20 12:43:57 +00004378 int fDoneSpans; // quick check that segment is finished
caryclark@google.com4eeda372012-12-06 21:47:48 +00004379 // OPTIMIZATION: force the following to be byte-sized
4380 SkPath::Verb fVerb;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004381 bool fOperand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004382 bool fXor; // set if original contour had even-odd fill
4383 bool fOppXor; // set if opposite operand had even-odd fill
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004384#if DEBUG_DUMP
4385 int fID;
4386#endif
4387};
4388
caryclark@google.comb9738012012-07-03 19:53:30 +00004389class Contour;
4390
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004391struct Coincidence {
caryclark@google.comb9738012012-07-03 19:53:30 +00004392 Contour* fContours[2];
4393 int fSegments[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004394 double fTs[2][2];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004395 SkPoint fPts[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004396};
4397
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004398class Contour {
4399public:
4400 Contour() {
4401 reset();
4402#if DEBUG_DUMP
4403 fID = ++gContourID;
4404#endif
4405 }
4406
4407 bool operator<(const Contour& rh) const {
4408 return fBounds.fTop == rh.fBounds.fTop
4409 ? fBounds.fLeft < rh.fBounds.fLeft
4410 : fBounds.fTop < rh.fBounds.fTop;
4411 }
4412
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004413 void addCoincident(int index, Contour* other, int otherIndex,
4414 const Intersections& ts, bool swap) {
4415 Coincidence& coincidence = *fCoincidences.append();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004416 coincidence.fContours[0] = this; // FIXME: no need to store
caryclark@google.comb9738012012-07-03 19:53:30 +00004417 coincidence.fContours[1] = other;
4418 coincidence.fSegments[0] = index;
4419 coincidence.fSegments[1] = otherIndex;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004420 coincidence.fTs[swap][0] = ts.fT[0][0];
4421 coincidence.fTs[swap][1] = ts.fT[0][1];
4422 coincidence.fTs[!swap][0] = ts.fT[1][0];
4423 coincidence.fTs[!swap][1] = ts.fT[1][1];
4424 coincidence.fPts[0] = ts.fPt[0].asSkPoint();
4425 coincidence.fPts[1] = ts.fPt[1].asSkPoint();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004426 }
4427
4428 void addCross(const Contour* crosser) {
4429#ifdef DEBUG_CROSS
4430 for (int index = 0; index < fCrosses.count(); ++index) {
4431 SkASSERT(fCrosses[index] != crosser);
4432 }
4433#endif
4434 *fCrosses.append() = crosser;
4435 }
4436
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004437 void addCubic(const SkPoint pts[4]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004438 fSegments.push_back().addCubic(pts, fOperand, fXor);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004439 fContainsCurves = fContainsCubics = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004440 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004441
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004442 int addLine(const SkPoint pts[2]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004443 fSegments.push_back().addLine(pts, fOperand, fXor);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004444 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004445 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004446
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004447 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
4448 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
4449 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004450
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004451 int addQuad(const SkPoint pts[3]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004452 fSegments.push_back().addQuad(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004453 fContainsCurves = true;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004454 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004455 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004456
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004457 int addT(int segIndex, Contour* other, int otherIndex, const SkPoint& pt, double& newT) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004458 setContainsIntercepts();
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004459 return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004460 }
4461
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00004462 int addSelfT(int segIndex, Contour* other, int otherIndex, const SkPoint& pt, double& newT) {
4463 setContainsIntercepts();
4464 return fSegments[segIndex].addSelfT(&other->fSegments[otherIndex], pt, newT);
4465 }
4466
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004467 int addUnsortableT(int segIndex, Contour* other, int otherIndex, bool start,
4468 const SkPoint& pt, double& newT) {
4469 return fSegments[segIndex].addUnsortableT(&other->fSegments[otherIndex], start, pt, newT);
caryclark@google.com73ca6242013-01-17 21:02:47 +00004470 }
4471
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004472 const Bounds& bounds() const {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004473 return fBounds;
4474 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004475
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004476 void complete() {
4477 setBounds();
4478 fContainsIntercepts = false;
4479 }
skia.committer@gmail.com58433de2013-02-23 07:02:45 +00004480
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004481 bool containsCubics() const {
4482 return fContainsCubics;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004483 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004484
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004485 bool crosses(const Contour* crosser) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004486 for (int index = 0; index < fCrosses.count(); ++index) {
4487 if (fCrosses[index] == crosser) {
4488 return true;
4489 }
4490 }
4491 return false;
4492 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004493
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004494 bool done() const {
4495 return fDone;
4496 }
4497
caryclark@google.comf839c032012-10-26 21:03:50 +00004498 const SkPoint& end() const {
4499 const Segment& segment = fSegments.back();
4500 return segment.pts()[segment.verb()];
4501 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004502
caryclark@google.com4eeda372012-12-06 21:47:48 +00004503 void findTooCloseToCall() {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004504 int segmentCount = fSegments.count();
4505 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004506 fSegments[sIndex].findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004507 }
4508 }
4509
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004510 void fixOtherTIndex() {
4511 int segmentCount = fSegments.count();
4512 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4513 fSegments[sIndex].fixOtherTIndex();
4514 }
4515 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004516
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004517 Segment* nonVerticalSegment(int& start, int& end) {
4518 int segmentCount = fSortedSegments.count();
4519 SkASSERT(segmentCount > 0);
4520 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4521 Segment* testSegment = fSortedSegments[sortedIndex];
4522 if (testSegment->done()) {
4523 continue;
4524 }
4525 start = end = 0;
4526 while (testSegment->nextCandidate(start, end)) {
4527 if (!testSegment->isVertical(start, end)) {
4528 return testSegment;
4529 }
4530 }
4531 }
4532 return NULL;
4533 }
4534
caryclark@google.com31143cf2012-11-09 22:14:19 +00004535 bool operand() const {
4536 return fOperand;
4537 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004538
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004539 void reset() {
4540 fSegments.reset();
4541 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004542 fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004543 }
caryclark@google.comb9738012012-07-03 19:53:30 +00004544
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004545 void resolveCoincidence(SkTDArray<Contour*>& contourList) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004546 int count = fCoincidences.count();
4547 for (int index = 0; index < count; ++index) {
4548 Coincidence& coincidence = fCoincidences[index];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004549 SkASSERT(coincidence.fContours[0] == this);
caryclark@google.comb9738012012-07-03 19:53:30 +00004550 int thisIndex = coincidence.fSegments[0];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004551 Segment& thisOne = fSegments[thisIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004552 Contour* otherContour = coincidence.fContours[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004553 int otherIndex = coincidence.fSegments[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004554 Segment& other = otherContour->fSegments[otherIndex];
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004555 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004556 continue;
4557 }
caryclark@google.com47580692012-07-23 12:14:49 +00004558 #if DEBUG_CONCIDENT
4559 thisOne.debugShowTs();
4560 other.debugShowTs();
4561 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004562 double startT = coincidence.fTs[0][0];
4563 double endT = coincidence.fTs[0][1];
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004564 bool cancelers = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004565 if (startT > endT) {
4566 SkTSwap<double>(startT, endT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004567 cancelers ^= true; // FIXME: just assign true
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004568 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004569 SkASSERT(!approximately_negative(endT - startT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004570 double oStartT = coincidence.fTs[1][0];
4571 double oEndT = coincidence.fTs[1][1];
4572 if (oStartT > oEndT) {
4573 SkTSwap<double>(oStartT, oEndT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004574 cancelers ^= true;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004575 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004576 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00004577 bool opp = fOperand ^ otherContour->fOperand;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004578 if (cancelers && !opp) {
4579 // make sure startT and endT have t entries
caryclark@google.com2ddff932012-08-07 21:25:27 +00004580 if (startT > 0 || oEndT < 1
4581 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004582 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004583 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00004584 if (oStartT > 0 || endT < 1
4585 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004586 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004587 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004588 if (!thisOne.done() && !other.done()) {
4589 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4590 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004591 } else {
caryclark@google.com200c2112012-08-03 15:05:04 +00004592 if (startT > 0 || oStartT > 0
4593 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004594 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004595 }
caryclark@google.com200c2112012-08-03 15:05:04 +00004596 if (endT < 1 || oEndT < 1
4597 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004598 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004599 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004600 if (!thisOne.done() && !other.done()) {
4601 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4602 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004603 }
caryclark@google.com47580692012-07-23 12:14:49 +00004604 #if DEBUG_CONCIDENT
4605 thisOne.debugShowTs();
4606 other.debugShowTs();
4607 #endif
caryclark@google.com729e1c42012-11-21 21:36:34 +00004608 #if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004609 debugShowWindingValues(contourList);
4610 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004611 }
4612 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004613
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004614 // first pass, add missing T values
4615 // second pass, determine winding values of overlaps
4616 void addCoincidentPoints() {
4617 int count = fCoincidences.count();
4618 for (int index = 0; index < count; ++index) {
4619 Coincidence& coincidence = fCoincidences[index];
4620 SkASSERT(coincidence.fContours[0] == this);
4621 int thisIndex = coincidence.fSegments[0];
4622 Segment& thisOne = fSegments[thisIndex];
4623 Contour* otherContour = coincidence.fContours[1];
4624 int otherIndex = coincidence.fSegments[1];
4625 Segment& other = otherContour->fSegments[otherIndex];
4626 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
4627 // OPTIMIZATION: remove from array
4628 continue;
4629 }
4630 #if DEBUG_CONCIDENT
4631 thisOne.debugShowTs();
4632 other.debugShowTs();
4633 #endif
4634 double startT = coincidence.fTs[0][0];
4635 double endT = coincidence.fTs[0][1];
4636 bool cancelers;
4637 if ((cancelers = startT > endT)) {
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004638 SkTSwap(startT, endT);
4639 SkTSwap(coincidence.fPts[0], coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004640 }
4641 SkASSERT(!approximately_negative(endT - startT));
4642 double oStartT = coincidence.fTs[1][0];
4643 double oEndT = coincidence.fTs[1][1];
4644 if (oStartT > oEndT) {
4645 SkTSwap<double>(oStartT, oEndT);
4646 cancelers ^= true;
4647 }
4648 SkASSERT(!approximately_negative(oEndT - oStartT));
4649 bool opp = fOperand ^ otherContour->fOperand;
4650 if (cancelers && !opp) {
4651 // make sure startT and endT have t entries
4652 if (startT > 0 || oEndT < 1
4653 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004654 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004655 }
4656 if (oStartT > 0 || endT < 1
4657 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004658 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004659 }
4660 } else {
4661 if (startT > 0 || oStartT > 0
4662 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004663 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004664 }
4665 if (endT < 1 || oEndT < 1
4666 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004667 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004668 }
4669 }
4670 #if DEBUG_CONCIDENT
4671 thisOne.debugShowTs();
4672 other.debugShowTs();
4673 #endif
4674 }
4675 }
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00004676
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004677 void calcCoincidentWinding() {
4678 int count = fCoincidences.count();
4679 for (int index = 0; index < count; ++index) {
4680 Coincidence& coincidence = fCoincidences[index];
4681 SkASSERT(coincidence.fContours[0] == this);
4682 int thisIndex = coincidence.fSegments[0];
4683 Segment& thisOne = fSegments[thisIndex];
4684 if (thisOne.done()) {
4685 continue;
4686 }
4687 Contour* otherContour = coincidence.fContours[1];
4688 int otherIndex = coincidence.fSegments[1];
4689 Segment& other = otherContour->fSegments[otherIndex];
4690 if (other.done()) {
4691 continue;
4692 }
4693 double startT = coincidence.fTs[0][0];
4694 double endT = coincidence.fTs[0][1];
4695 bool cancelers;
4696 if ((cancelers = startT > endT)) {
4697 SkTSwap<double>(startT, endT);
4698 }
4699 SkASSERT(!approximately_negative(endT - startT));
4700 double oStartT = coincidence.fTs[1][0];
4701 double oEndT = coincidence.fTs[1][1];
4702 if (oStartT > oEndT) {
4703 SkTSwap<double>(oStartT, oEndT);
4704 cancelers ^= true;
4705 }
4706 SkASSERT(!approximately_negative(oEndT - oStartT));
4707 bool opp = fOperand ^ otherContour->fOperand;
4708 if (cancelers && !opp) {
4709 // make sure startT and endT have t entries
4710 if (!thisOne.done() && !other.done()) {
4711 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4712 }
4713 } else {
4714 if (!thisOne.done() && !other.done()) {
4715 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4716 }
4717 }
4718 #if DEBUG_CONCIDENT
4719 thisOne.debugShowTs();
4720 other.debugShowTs();
4721 #endif
4722 }
4723 }
4724
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004725 SkTArray<Segment>& segments() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004726 return fSegments;
4727 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004728
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004729 void setContainsIntercepts() {
4730 fContainsIntercepts = true;
4731 }
4732
caryclark@google.com235f56a2012-09-14 14:19:30 +00004733 void setOperand(bool isOp) {
4734 fOperand = isOp;
4735 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00004736
caryclark@google.com4eeda372012-12-06 21:47:48 +00004737 void setOppXor(bool isOppXor) {
4738 fOppXor = isOppXor;
4739 int segmentCount = fSegments.count();
4740 for (int test = 0; test < segmentCount; ++test) {
4741 fSegments[test].setOppXor(isOppXor);
4742 }
4743 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004744
caryclark@google.com235f56a2012-09-14 14:19:30 +00004745 void setXor(bool isXor) {
4746 fXor = isXor;
4747 }
4748
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004749 void sortSegments() {
4750 int segmentCount = fSegments.count();
4751 fSortedSegments.setReserve(segmentCount);
4752 for (int test = 0; test < segmentCount; ++test) {
4753 *fSortedSegments.append() = &fSegments[test];
4754 }
4755 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4756 fFirstSorted = 0;
4757 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004758
caryclark@google.comf839c032012-10-26 21:03:50 +00004759 const SkPoint& start() const {
4760 return fSegments.front().pts()[0];
4761 }
4762
4763 void toPath(PathWrapper& path) const {
4764 int segmentCount = fSegments.count();
4765 const SkPoint& pt = fSegments.front().pts()[0];
4766 path.deferredMove(pt);
4767 for (int test = 0; test < segmentCount; ++test) {
4768 fSegments[test].addCurveTo(0, 1, path, true);
4769 }
4770 path.close();
4771 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004772
caryclark@google.comf839c032012-10-26 21:03:50 +00004773 void toPartialBackward(PathWrapper& path) const {
4774 int segmentCount = fSegments.count();
4775 for (int test = segmentCount - 1; test >= 0; --test) {
4776 fSegments[test].addCurveTo(1, 0, path, true);
4777 }
4778 }
4779
4780 void toPartialForward(PathWrapper& path) const {
4781 int segmentCount = fSegments.count();
4782 for (int test = 0; test < segmentCount; ++test) {
4783 fSegments[test].addCurveTo(0, 1, path, true);
4784 }
4785 }
4786
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004787 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004788 int segmentCount = fSortedSegments.count();
4789 SkASSERT(segmentCount > 0);
caryclark@google.comf839c032012-10-26 21:03:50 +00004790 int sortedIndex = fFirstSorted;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004791 fDone = true; // may be cleared below
caryclark@google.comf839c032012-10-26 21:03:50 +00004792 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4793 Segment* testSegment = fSortedSegments[sortedIndex];
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004794 if (testSegment->done()) {
caryclark@google.comf839c032012-10-26 21:03:50 +00004795 if (sortedIndex == fFirstSorted) {
4796 ++fFirstSorted;
4797 }
4798 continue;
4799 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004800 fDone = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004801 SkPoint testXY = testSegment->activeLeftTop(true, NULL);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004802 if (topStart) {
4803 if (testXY.fY < topLeft.fY) {
4804 continue;
4805 }
4806 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4807 continue;
4808 }
4809 if (bestXY.fY < testXY.fY) {
4810 continue;
4811 }
4812 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4813 continue;
4814 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004815 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004816 topStart = testSegment;
caryclark@google.comf839c032012-10-26 21:03:50 +00004817 bestXY = testXY;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004818 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004819 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004820
caryclark@google.com24bec792012-08-20 12:43:57 +00004821 Segment* undoneSegment(int& start, int& end) {
4822 int segmentCount = fSegments.count();
4823 for (int test = 0; test < segmentCount; ++test) {
4824 Segment* testSegment = &fSegments[test];
4825 if (testSegment->done()) {
4826 continue;
4827 }
4828 testSegment->undoneSpan(start, end);
4829 return testSegment;
4830 }
4831 return NULL;
4832 }
4833
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004834 int updateSegment(int index, const SkPoint* pts) {
4835 Segment& segment = fSegments[index];
4836 segment.updatePts(pts);
4837 return segment.verb() + 1;
4838 }
4839
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004840#if DEBUG_TEST
4841 SkTArray<Segment>& debugSegments() {
4842 return fSegments;
4843 }
4844#endif
4845
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004846#if DEBUG_DUMP
4847 void dump() {
4848 int i;
4849 const char className[] = "Contour";
4850 const int tab = 4;
4851 SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4852 for (i = 0; i < fSegments.count(); ++i) {
4853 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4854 className, i);
4855 fSegments[i].dump();
4856 }
4857 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4858 tab + sizeof(className), className,
4859 fBounds.fLeft, fBounds.fTop,
4860 fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004861 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4862 className, fContainsIntercepts);
4863 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4864 className, fContainsCurves);
4865 }
4866#endif
4867
caryclark@google.com027de222012-07-12 12:52:50 +00004868#if DEBUG_ACTIVE_SPANS
4869 void debugShowActiveSpans() {
4870 for (int index = 0; index < fSegments.count(); ++index) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004871 fSegments[index].debugShowActiveSpans();
caryclark@google.com027de222012-07-12 12:52:50 +00004872 }
4873 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004874
4875 void validateActiveSpans() {
4876 for (int index = 0; index < fSegments.count(); ++index) {
4877 fSegments[index].validateActiveSpans();
4878 }
4879 }
caryclark@google.com027de222012-07-12 12:52:50 +00004880#endif
4881
caryclark@google.com729e1c42012-11-21 21:36:34 +00004882#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004883 int debugShowWindingValues(int totalSegments, int ofInterest) {
4884 int count = fSegments.count();
4885 int sum = 0;
4886 for (int index = 0; index < count; ++index) {
4887 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4888 }
4889 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4890 return sum;
4891 }
4892
4893 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4894 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4895 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4896 int ofInterest = 1 << 5 | 1 << 8;
4897 int total = 0;
4898 int index;
4899 for (index = 0; index < contourList.count(); ++index) {
4900 total += contourList[index]->segments().count();
4901 }
4902 int sum = 0;
4903 for (index = 0; index < contourList.count(); ++index) {
4904 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4905 }
4906 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4907 }
4908#endif
4909
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004910protected:
4911 void setBounds() {
4912 int count = fSegments.count();
4913 if (count == 0) {
4914 SkDebugf("%s empty contour\n", __FUNCTION__);
4915 SkASSERT(0);
4916 // FIXME: delete empty contour?
4917 return;
4918 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004919 fBounds = fSegments.front().bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004920 for (int index = 1; index < count; ++index) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004921 fBounds.add(fSegments[index].bounds());
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004922 }
4923 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004924
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004925private:
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004926 SkTArray<Segment> fSegments;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004927 SkTDArray<Segment*> fSortedSegments;
4928 int fFirstSorted;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004929 SkTDArray<Coincidence> fCoincidences;
4930 SkTDArray<const Contour*> fCrosses;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004931 Bounds fBounds;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004932 bool fContainsIntercepts; // FIXME: is this used by anybody?
4933 bool fContainsCubics;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004934 bool fContainsCurves;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004935 bool fDone;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004936 bool fOperand; // true for the second argument to a binary operator
4937 bool fXor;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004938 bool fOppXor;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004939#if DEBUG_DUMP
4940 int fID;
4941#endif
4942};
4943
4944class EdgeBuilder {
4945public:
4946
caryclark@google.comf839c032012-10-26 21:03:50 +00004947EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
4948 : fPath(path.nativePath())
4949 , fContours(contours)
4950{
4951 init();
4952}
4953
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004954EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
caryclark@google.com235f56a2012-09-14 14:19:30 +00004955 : fPath(&path)
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004956 , fContours(contours)
4957{
caryclark@google.comf839c032012-10-26 21:03:50 +00004958 init();
4959}
4960
4961void init() {
4962 fCurrentContour = NULL;
4963 fOperand = false;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004964 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004965#if DEBUG_DUMP
4966 gContourID = 0;
4967 gSegmentID = 0;
4968#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00004969 fSecondHalf = preFetch();
4970}
4971
4972void addOperand(const SkPath& path) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00004973 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
4974 fPathVerbs.pop();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004975 fPath = &path;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004976 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004977 preFetch();
4978}
4979
4980void finish() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004981 walk();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004982 complete();
4983 if (fCurrentContour && !fCurrentContour->segments().count()) {
4984 fContours.pop_back();
4985 }
4986 // correct pointers in contours since fReducePts may have moved as it grew
4987 int cIndex = 0;
4988 int extraCount = fExtra.count();
4989 SkASSERT(extraCount == 0 || fExtra[0] == -1);
4990 int eIndex = 0;
4991 int rIndex = 0;
4992 while (++eIndex < extraCount) {
4993 int offset = fExtra[eIndex];
4994 if (offset < 0) {
4995 ++cIndex;
4996 continue;
4997 }
4998 fCurrentContour = &fContours[cIndex];
4999 rIndex += fCurrentContour->updateSegment(offset - 1,
5000 &fReducePts[rIndex]);
5001 }
5002 fExtra.reset(); // we're done with this
5003}
5004
5005ShapeOpMask xorMask() const {
caryclark@google.com729e1c42012-11-21 21:36:34 +00005006 return fXorMask[fOperand];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005007}
5008
5009protected:
5010
5011void complete() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005012 if (fCurrentContour && fCurrentContour->segments().count()) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005013 fCurrentContour->complete();
5014 fCurrentContour = NULL;
5015 }
5016}
5017
caryclark@google.com235f56a2012-09-14 14:19:30 +00005018// FIXME:remove once we can access path pts directly
5019int preFetch() {
5020 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005021 SkPoint pts[4];
5022 SkPath::Verb verb;
5023 do {
5024 verb = iter.next(pts);
5025 *fPathVerbs.append() = verb;
5026 if (verb == SkPath::kMove_Verb) {
5027 *fPathPts.append() = pts[0];
5028 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
5029 fPathPts.append(verb, &pts[1]);
5030 }
5031 } while (verb != SkPath::kDone_Verb);
caryclark@google.com31143cf2012-11-09 22:14:19 +00005032 return fPathVerbs.count() - 1;
caryclark@google.com235f56a2012-09-14 14:19:30 +00005033}
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005034
caryclark@google.com235f56a2012-09-14 14:19:30 +00005035void walk() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005036 SkPath::Verb reducedVerb;
5037 uint8_t* verbPtr = fPathVerbs.begin();
caryclark@google.com235f56a2012-09-14 14:19:30 +00005038 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005039 const SkPoint* pointsPtr = fPathPts.begin();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005040 const SkPoint* finalCurveStart = NULL;
5041 const SkPoint* finalCurveEnd = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00005042 SkPath::Verb verb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005043 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
5044 switch (verb) {
5045 case SkPath::kMove_Verb:
5046 complete();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005047 if (!fCurrentContour) {
5048 fCurrentContour = fContours.push_back_n(1);
caryclark@google.com235f56a2012-09-14 14:19:30 +00005049 fCurrentContour->setOperand(fOperand);
caryclark@google.com729e1c42012-11-21 21:36:34 +00005050 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005051 *fExtra.append() = -1; // start new contour
5052 }
caryclark@google.com59823f72012-08-09 18:17:47 +00005053 finalCurveEnd = pointsPtr++;
caryclark@google.com31143cf2012-11-09 22:14:19 +00005054 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005055 case SkPath::kLine_Verb:
5056 // skip degenerate points
5057 if (pointsPtr[-1].fX != pointsPtr[0].fX
5058 || pointsPtr[-1].fY != pointsPtr[0].fY) {
5059 fCurrentContour->addLine(&pointsPtr[-1]);
5060 }
5061 break;
5062 case SkPath::kQuad_Verb:
rmistry@google.comd6176b02012-08-23 18:14:13 +00005063
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005064 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
5065 if (reducedVerb == 0) {
5066 break; // skip degenerate points
5067 }
5068 if (reducedVerb == 1) {
rmistry@google.comd6176b02012-08-23 18:14:13 +00005069 *fExtra.append() =
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005070 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005071 break;
5072 }
5073 fCurrentContour->addQuad(&pointsPtr[-1]);
5074 break;
5075 case SkPath::kCubic_Verb:
5076 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
5077 if (reducedVerb == 0) {
5078 break; // skip degenerate points
5079 }
5080 if (reducedVerb == 1) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005081 *fExtra.append() =
5082 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005083 break;
5084 }
5085 if (reducedVerb == 2) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005086 *fExtra.append() =
5087 fCurrentContour->addQuad(fReducePts.end() - 3);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005088 break;
5089 }
5090 fCurrentContour->addCubic(&pointsPtr[-1]);
5091 break;
5092 case SkPath::kClose_Verb:
5093 SkASSERT(fCurrentContour);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005094 if (finalCurveStart && finalCurveEnd
5095 && *finalCurveStart != *finalCurveEnd) {
5096 *fReducePts.append() = *finalCurveStart;
5097 *fReducePts.append() = *finalCurveEnd;
5098 *fExtra.append() =
5099 fCurrentContour->addLine(fReducePts.end() - 2);
5100 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005101 complete();
caryclark@google.com31143cf2012-11-09 22:14:19 +00005102 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005103 default:
5104 SkDEBUGFAIL("bad verb");
5105 return;
5106 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005107 finalCurveStart = &pointsPtr[verb - 1];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005108 pointsPtr += verb;
5109 SkASSERT(fCurrentContour);
caryclark@google.com31143cf2012-11-09 22:14:19 +00005110 nextVerb:
caryclark@google.com235f56a2012-09-14 14:19:30 +00005111 if (verbPtr == endOfFirstHalf) {
5112 fOperand = true;
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00005113 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005114 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005115}
5116
5117private:
caryclark@google.com235f56a2012-09-14 14:19:30 +00005118 const SkPath* fPath;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005119 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005120 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005121 Contour* fCurrentContour;
5122 SkTArray<Contour>& fContours;
5123 SkTDArray<SkPoint> fReducePts; // segments created on the fly
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005124 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
caryclark@google.com729e1c42012-11-21 21:36:34 +00005125 ShapeOpMask fXorMask[2];
caryclark@google.com235f56a2012-09-14 14:19:30 +00005126 int fSecondHalf;
5127 bool fOperand;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005128};
5129
5130class Work {
5131public:
5132 enum SegmentType {
5133 kHorizontalLine_Segment = -1,
5134 kVerticalLine_Segment = 0,
5135 kLine_Segment = SkPath::kLine_Verb,
5136 kQuad_Segment = SkPath::kQuad_Verb,
5137 kCubic_Segment = SkPath::kCubic_Verb,
5138 };
rmistry@google.comd6176b02012-08-23 18:14:13 +00005139
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005140 void addCoincident(Work& other, const Intersections& ts, bool swap) {
5141 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
5142 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005143
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005144 // FIXME: does it make sense to write otherIndex now if we're going to
5145 // fix it up later?
5146 void addOtherT(int index, double otherT, int otherIndex) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005147 fContour->addOtherT(fIndex, index, otherT, otherIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005148 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005149
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005150 // Avoid collapsing t values that are close to the same since
5151 // we walk ts to describe consecutive intersections. Since a pair of ts can
5152 // be nearly equal, any problems caused by this should be taken care
5153 // of later.
5154 // On the edge or out of range values are negative; add 2 to get end
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005155 int addT(const Work& other, const SkPoint& pt, double& newT) {
5156 return fContour->addT(fIndex, other.fContour, other.fIndex, pt, newT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005157 }
skia.committer@gmail.com631cdcb2013-03-01 12:12:55 +00005158
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00005159 int addSelfT(const Work& other, const SkPoint& pt, double& newT) {
5160 return fContour->addSelfT(fIndex, other.fContour, other.fIndex, pt, newT);
5161 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005162
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005163 int addUnsortableT(const Work& other, bool start, const SkPoint& pt, double& newT) {
5164 return fContour->addUnsortableT(fIndex, other.fContour, other.fIndex, start, pt, newT);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005165 }
5166
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005167 bool advance() {
5168 return ++fIndex < fLast;
5169 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005170
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005171 SkScalar bottom() const {
5172 return bounds().fBottom;
5173 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005174
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005175 const Bounds& bounds() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005176 return fContour->segments()[fIndex].bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005177 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00005178
caryclark@google.com73ca6242013-01-17 21:02:47 +00005179#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005180 const SkPoint* cubic() const {
5181 return fCubic;
5182 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005183#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005184
5185 void init(Contour* contour) {
5186 fContour = contour;
5187 fIndex = 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005188 fLast = contour->segments().count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005189 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00005190
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00005191 bool isAdjacent(const Work& next) {
5192 return fContour == next.fContour && fIndex + 1 == next.fIndex;
5193 }
5194
5195 bool isFirstLast(const Work& next) {
5196 return fContour == next.fContour && fIndex == 0
5197 && next.fIndex == fLast - 1;
5198 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005199
5200 SkScalar left() const {
5201 return bounds().fLeft;
5202 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005203
caryclark@google.com73ca6242013-01-17 21:02:47 +00005204#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005205 void promoteToCubic() {
5206 fCubic[0] = pts()[0];
5207 fCubic[2] = pts()[1];
5208 fCubic[3] = pts()[2];
5209 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
5210 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
5211 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
5212 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
5213 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005214#endif
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005215
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005216 const SkPoint* pts() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005217 return fContour->segments()[fIndex].pts();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005218 }
5219
5220 SkScalar right() const {
5221 return bounds().fRight;
5222 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005223
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005224 ptrdiff_t segmentIndex() const {
5225 return fIndex;
5226 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005227
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005228 SegmentType segmentType() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005229 const Segment& segment = fContour->segments()[fIndex];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005230 SegmentType type = (SegmentType) segment.verb();
5231 if (type != kLine_Segment) {
5232 return type;
5233 }
5234 if (segment.isHorizontal()) {
5235 return kHorizontalLine_Segment;
5236 }
5237 if (segment.isVertical()) {
5238 return kVerticalLine_Segment;
5239 }
5240 return kLine_Segment;
5241 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005242
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005243 bool startAfter(const Work& after) {
5244 fIndex = after.fIndex;
5245 return advance();
5246 }
5247
5248 SkScalar top() const {
5249 return bounds().fTop;
5250 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005251
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005252 SkPath::Verb verb() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005253 return fContour->segments()[fIndex].verb();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005254 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005255
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005256 SkScalar x() const {
5257 return bounds().fLeft;
5258 }
5259
5260 bool xFlipped() const {
5261 return x() != pts()[0].fX;
5262 }
5263
5264 SkScalar y() const {
5265 return bounds().fTop;
5266 }
5267
5268 bool yFlipped() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005269 return y() != pts()[0].fY;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005270 }
5271
5272protected:
5273 Contour* fContour;
caryclark@google.com73ca6242013-01-17 21:02:47 +00005274#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005275 SkPoint fCubic[4];
caryclark@google.com73ca6242013-01-17 21:02:47 +00005276#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005277 int fIndex;
5278 int fLast;
5279};
5280
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005281#if DEBUG_ADD_INTERSECTING_TS
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005282
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005283#if DEBUG_AS_C_CODE
5284#define CUBIC_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}}"
5285#define QUAD_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}}"
5286#define LINE_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}}"
5287#define PT_DEBUG_STR "{{%1.17g,%1.17g}}"
5288#else
5289#define CUBIC_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5290#define QUAD_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5291#define LINE_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g)"
5292#define PT_DEBUG_STR "(%1.9g,%1.9g)"
5293#endif
5294#define T_DEBUG_STR(t, n) #t "[" #n "]=%1.9g"
5295#define TX_DEBUG_STR(t) #t "[%d]=%1.9g"
5296#define CUBIC_DEBUG_DATA(c) c[0].fX, c[0].fY, c[1].fX, c[1].fY, c[2].fX, c[2].fY, c[3].fX, c[3].fY
5297#define QUAD_DEBUG_DATA(q) q[0].fX, q[0].fY, q[1].fX, q[1].fY, q[2].fX, q[2].fY
5298#define LINE_DEBUG_DATA(l) l[0].fX, l[0].fY, l[1].fX, l[1].fY
5299#define PT_DEBUG_DATA(i, n) i.fPt[n].x, i.fPt[n].y
5300
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005301static void debugShowLineIntersection(int pts, const Work& wt, const Work& wn,
5302 const Intersections& i) {
5303 SkASSERT(i.used() == pts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005304 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005305 SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n",
5306 __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005307 return;
5308 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005309 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " LINE_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5310 i.fT[0][0], LINE_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005311 if (pts == 2) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005312 SkDebugf(" " T_DEBUG_STR(wtTs, 1) " " PT_DEBUG_STR, i.fT[0][1], PT_DEBUG_DATA(i, 1));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005313 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005314 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005315 if (pts == 2) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005316 SkDebugf(" " T_DEBUG_STR(wnTs, 1), i.fT[1][1]);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005317 }
5318 SkDebugf("\n");
5319}
5320
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005321static void debugShowQuadLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005322 const Work& wn, const Intersections& i) {
5323 SkASSERT(i.used() == pts);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005324 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005325 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " LINE_DEBUG_STR "\n",
5326 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005327 return;
5328 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005329 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5330 i.fT[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5331 for (int n = 1; n < pts; ++n) {
5332 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005333 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005334 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
5335 for (int n = 1; n < pts; ++n) {
5336 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005337 }
5338 SkDebugf("\n");
5339}
5340
caryclark@google.coma461ff02012-10-11 12:54:23 +00005341static void debugShowQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005342 const Work& wn, const Intersections& i) {
5343 SkASSERT(i.used() == pts);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005344 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005345 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " QUAD_DEBUG_STR "\n",
5346 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
caryclark@google.coma461ff02012-10-11 12:54:23 +00005347 return;
5348 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005349 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5350 i.fT[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5351 for (int n = 1; n < pts; ++n) {
5352 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
caryclark@google.coma461ff02012-10-11 12:54:23 +00005353 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005354 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i.fT[1][0], QUAD_DEBUG_DATA(wn.pts()));
5355 for (int n = 1; n < pts; ++n) {
5356 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005357 }
caryclark@google.comb9738012012-07-03 19:53:30 +00005358 SkDebugf("\n");
5359}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005360
5361static void debugShowCubicLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005362 const Work& wn, const Intersections& i) {
5363 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005364 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005365 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " LINE_DEBUG_STR "\n",
5366 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005367 return;
5368 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005369 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5370 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5371 for (int n = 1; n < pts; ++n) {
5372 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005373 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005374 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
5375 for (int n = 1; n < pts; ++n) {
5376 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005377 }
5378 SkDebugf("\n");
5379}
5380
caryclark@google.com73ca6242013-01-17 21:02:47 +00005381static void debugShowCubicQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005382 const Work& wn, const Intersections& i) {
5383 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005384 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005385 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " QUAD_DEBUG_STR "\n",
5386 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005387 return;
5388 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005389 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5390 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5391 for (int n = 1; n < pts; ++n) {
5392 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005393 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005394 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i.fT[1][0], QUAD_DEBUG_DATA(wn.pts()));
5395 for (int n = 1; n < pts; ++n) {
5396 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005397 }
5398 SkDebugf("\n");
5399}
5400
caryclark@google.com73ca6242013-01-17 21:02:47 +00005401static void debugShowCubicIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005402 const Work& wn, const Intersections& i) {
5403 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005404 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005405 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " CUBIC_DEBUG_STR "\n",
5406 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), CUBIC_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005407 return;
5408 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005409 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5410 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5411 for (int n = 1; n < pts; ++n) {
5412 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005413 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005414 SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i.fT[1][0], CUBIC_DEBUG_DATA(wn.pts()));
5415 for (int n = 1; n < pts; ++n) {
5416 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005417 }
5418 SkDebugf("\n");
5419}
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005420
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005421static void debugShowCubicIntersection(int pts, const Work& wt, const Intersections& i) {
5422 SkASSERT(i.used() == pts);
5423 if (!pts) {
5424 SkDebugf("%s no self intersect " CUBIC_DEBUG_STR "\n", __FUNCTION__,
5425 CUBIC_DEBUG_DATA(wt.pts()));
5426 return;
5427 }
5428 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5429 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5430 SkDebugf(" " T_DEBUG_STR(wtTs, 1), i.fT[1][0]);
5431 SkDebugf("\n");
5432}
5433
5434#undef CUBIC_DEBUG_STR
5435#undef QUAD_DEBUG_STR
5436#undef LINE_DEBUG_STR
5437#undef PT_DEBUG_STR
5438#undef T_DEBUG_STR
5439#undef CUBIC_DEBUG_DATA
5440#undef QUAD_DEBUG_DATA
5441#undef LINE_DEBUG_DATA
5442#undef PT_DEBUG_DATA
5443
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005444#else
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005445static void debugShowLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005446}
caryclark@google.coma461ff02012-10-11 12:54:23 +00005447
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005448static void debugShowQuadLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005449}
5450
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005451static void debugShowQuadIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005452}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005453
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005454static void debugShowCubicLineIntersection(int , const Work& , const Work& ,
5455 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005456}
5457
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005458static void debugShowCubicQuadIntersection(int , const Work& , const Work& ,
5459 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005460}
5461
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005462static void debugShowCubicIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005463}
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005464
5465static void debugShowCubicIntersection(int , const Work& , const Intersections& ) {
5466}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005467#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005468
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005469static bool addIntersectTs(Contour* test, Contour* next) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005470
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005471 if (test != next) {
5472 if (test->bounds().fBottom < next->bounds().fTop) {
5473 return false;
5474 }
5475 if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5476 return true;
5477 }
5478 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005479 Work wt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005480 wt.init(test);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005481 bool foundCommonContour = test == next;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005482 do {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005483 Work wn;
5484 wn.init(next);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005485 if (test == next && !wn.startAfter(wt)) {
5486 continue;
5487 }
5488 do {
5489 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5490 continue;
5491 }
5492 int pts;
5493 Intersections ts;
5494 bool swap = false;
5495 switch (wt.segmentType()) {
5496 case Work::kHorizontalLine_Segment:
5497 swap = true;
5498 switch (wn.segmentType()) {
5499 case Work::kHorizontalLine_Segment:
5500 case Work::kVerticalLine_Segment:
5501 case Work::kLine_Segment: {
5502 pts = HLineIntersect(wn.pts(), wt.left(),
5503 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005504 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005505 break;
5506 }
5507 case Work::kQuad_Segment: {
5508 pts = HQuadIntersect(wn.pts(), wt.left(),
5509 wt.right(), wt.y(), wt.xFlipped(), ts);
5510 break;
5511 }
5512 case Work::kCubic_Segment: {
5513 pts = HCubicIntersect(wn.pts(), wt.left(),
5514 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005515 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005516 break;
5517 }
5518 default:
5519 SkASSERT(0);
5520 }
5521 break;
5522 case Work::kVerticalLine_Segment:
5523 swap = true;
5524 switch (wn.segmentType()) {
5525 case Work::kHorizontalLine_Segment:
5526 case Work::kVerticalLine_Segment:
5527 case Work::kLine_Segment: {
5528 pts = VLineIntersect(wn.pts(), wt.top(),
5529 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005530 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005531 break;
5532 }
5533 case Work::kQuad_Segment: {
5534 pts = VQuadIntersect(wn.pts(), wt.top(),
5535 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5536 break;
5537 }
5538 case Work::kCubic_Segment: {
5539 pts = VCubicIntersect(wn.pts(), wt.top(),
5540 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005541 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005542 break;
5543 }
5544 default:
5545 SkASSERT(0);
5546 }
5547 break;
5548 case Work::kLine_Segment:
5549 switch (wn.segmentType()) {
5550 case Work::kHorizontalLine_Segment:
5551 pts = HLineIntersect(wt.pts(), wn.left(),
5552 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005553 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005554 break;
5555 case Work::kVerticalLine_Segment:
5556 pts = VLineIntersect(wt.pts(), wn.top(),
5557 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005558 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005559 break;
5560 case Work::kLine_Segment: {
5561 pts = LineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005562 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005563 break;
5564 }
5565 case Work::kQuad_Segment: {
5566 swap = true;
5567 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005568 debugShowQuadLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005569 break;
5570 }
5571 case Work::kCubic_Segment: {
5572 swap = true;
5573 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005574 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005575 break;
5576 }
5577 default:
5578 SkASSERT(0);
5579 }
5580 break;
5581 case Work::kQuad_Segment:
5582 switch (wn.segmentType()) {
5583 case Work::kHorizontalLine_Segment:
5584 pts = HQuadIntersect(wt.pts(), wn.left(),
5585 wn.right(), wn.y(), wn.xFlipped(), ts);
5586 break;
5587 case Work::kVerticalLine_Segment:
5588 pts = VQuadIntersect(wt.pts(), wn.top(),
5589 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5590 break;
5591 case Work::kLine_Segment: {
5592 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005593 debugShowQuadLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005594 break;
5595 }
5596 case Work::kQuad_Segment: {
5597 pts = QuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005598 debugShowQuadIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005599 break;
5600 }
5601 case Work::kCubic_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005602 #if APPROXIMATE_CUBICS
5603 swap = true;
5604 pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005605 debugShowCubicQuadIntersection(pts, wn, wt, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005606 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005607 wt.promoteToCubic();
5608 pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005609 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005610 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005611 break;
5612 }
5613 default:
5614 SkASSERT(0);
5615 }
5616 break;
5617 case Work::kCubic_Segment:
5618 switch (wn.segmentType()) {
5619 case Work::kHorizontalLine_Segment:
5620 pts = HCubicIntersect(wt.pts(), wn.left(),
5621 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005622 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005623 break;
5624 case Work::kVerticalLine_Segment:
5625 pts = VCubicIntersect(wt.pts(), wn.top(),
5626 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005627 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005628 break;
5629 case Work::kLine_Segment: {
5630 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005631 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005632 break;
5633 }
5634 case Work::kQuad_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005635 #if APPROXIMATE_CUBICS
5636 pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005637 debugShowCubicQuadIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005638 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005639 wn.promoteToCubic();
5640 pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005641 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005642 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005643 break;
5644 }
5645 case Work::kCubic_Segment: {
5646 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005647 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005648 break;
5649 }
5650 default:
5651 SkASSERT(0);
5652 }
5653 break;
5654 default:
5655 SkASSERT(0);
5656 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005657 if (!foundCommonContour && pts > 0) {
5658 test->addCross(next);
5659 next->addCross(test);
5660 foundCommonContour = true;
5661 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005662 // in addition to recording T values, record matching segment
caryclark@google.com73ca6242013-01-17 21:02:47 +00005663 if (ts.unsortable()) {
5664 bool start = true;
5665 for (int pt = 0; pt < ts.used(); ++pt) {
5666 // FIXME: if unsortable, the other points to the original. This logic is
5667 // untested downstream.
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005668 SkPoint point = ts.fPt[pt].asSkPoint();
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005669 int testTAt = wt.addUnsortableT(wt, start, point, ts.fT[swap][pt]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005670 wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt);
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005671 testTAt = wn.addUnsortableT(wn, start ^ ts.fFlip, point, ts.fT[!swap][pt]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005672 wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt);
5673 start ^= true;
5674 }
5675 continue;
5676 }
caryclark@google.com32546db2012-08-31 20:55:07 +00005677 if (pts == 2) {
5678 if (wn.segmentType() <= Work::kLine_Segment
5679 && wt.segmentType() <= Work::kLine_Segment) {
5680 wt.addCoincident(wn, ts, swap);
5681 continue;
5682 }
caryclark@google.combeda3892013-02-07 13:13:41 +00005683 if (wn.segmentType() >= Work::kQuad_Segment
5684 && wt.segmentType() >= Work::kQuad_Segment
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005685 && ts.fIsCoincident[0]) {
5686 SkASSERT(ts.coincidentUsed() == 2);
caryclark@google.com32546db2012-08-31 20:55:07 +00005687 wt.addCoincident(wn, ts, swap);
5688 continue;
5689 }
5690
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00005691 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00005692 for (int pt = 0; pt < pts; ++pt) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005693 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5694 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005695 SkPoint point = ts.fPt[pt].asSkPoint();
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005696 int testTAt = wt.addT(wn, point, ts.fT[swap][pt]);
5697 int nextTAt = wn.addT(wt, point, ts.fT[!swap][pt]);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005698 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
5699 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005700 }
5701 } while (wn.advance());
5702 } while (wt.advance());
5703 return true;
5704}
5705
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005706static void addSelfIntersectTs(Contour* test) {
5707 Work wt;
5708 wt.init(test);
5709 do {
5710 if (wt.segmentType() != Work::kCubic_Segment) {
5711 continue;
5712 }
5713 Intersections ts;
5714 int pts = CubicIntersect(wt.pts(), ts);
5715 debugShowCubicIntersection(pts, wt, ts);
5716 if (!pts) {
5717 continue;
5718 }
5719 SkASSERT(pts == 1);
5720 SkASSERT(ts.fT[0][0] >= 0 && ts.fT[0][0] <= 1);
5721 SkASSERT(ts.fT[1][0] >= 0 && ts.fT[1][0] <= 1);
5722 SkPoint point = ts.fPt[0].asSkPoint();
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00005723 int testTAt = wt.addSelfT(wt, point, ts.fT[0][0]);
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005724 int nextTAt = wt.addT(wt, point, ts.fT[1][0]);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005725 wt.addOtherT(testTAt, ts.fT[1][0], nextTAt);
5726 wt.addOtherT(nextTAt, ts.fT[0][0], testTAt);
5727 } while (wt.advance());
5728}
5729
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005730// resolve any coincident pairs found while intersecting, and
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005731// see if coincidence is formed by clipping non-concident segments
caryclark@google.com4eeda372012-12-06 21:47:48 +00005732static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005733 int contourCount = contourList.count();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005734#if ONE_PASS_COINCIDENCE_CHECK
caryclark@google.comf25edfe2012-06-01 18:20:10 +00005735 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005736 Contour* contour = contourList[cIndex];
caryclark@google.com7ba591e2012-11-20 14:21:54 +00005737 contour->resolveCoincidence(contourList);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005738 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005739#else
5740 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5741 Contour* contour = contourList[cIndex];
5742 contour->addCoincidentPoints();
5743 }
5744 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5745 Contour* contour = contourList[cIndex];
5746 contour->calcCoincidentWinding();
5747 }
5748#endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005749 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5750 Contour* contour = contourList[cIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00005751 contour->findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005752 }
5753}
5754
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005755static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005756 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005757 SkPoint basePt;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005758 double tAtMid = current->tAtMid(index, endIndex, mid);
5759 current->xyAtT(tAtMid, basePt);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005760 int contourCount = contourList.count();
5761 SkScalar bestY = SK_ScalarMin;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005762 Segment* bestSeg = NULL;
5763 int bestTIndex;
5764 bool bestOpp;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005765 bool hitSomething = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005766 for (int cTest = 0; cTest < contourCount; ++cTest) {
5767 Contour* contour = contourList[cTest];
5768 bool testOpp = contour->operand() ^ current->operand() ^ opp;
5769 if (basePt.fY < contour->bounds().fTop) {
5770 continue;
5771 }
5772 if (bestY > contour->bounds().fBottom) {
5773 continue;
5774 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005775 int segmentCount = contour->segments().count();
5776 for (int test = 0; test < segmentCount; ++test) {
5777 Segment* testSeg = &contour->segments()[test];
5778 SkScalar testY = bestY;
5779 double testHit;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005780 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
5781 testOpp, testSeg == current);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005782 if (testTIndex < 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005783 if (testTIndex == SK_MinS32) {
5784 hitSomething = true;
5785 bestSeg = NULL;
5786 goto abortContours; // vertical encountered, return and try different point
5787 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005788 continue;
5789 }
5790 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005791 double baseT = current->t(index);
5792 double endT = current->t(endIndex);
5793 double newMid = (testHit - baseT) / (endT - baseT);
5794#if DEBUG_WINDING
5795 SkPoint midXY, newXY;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005796 double midT = current->tAtMid(index, endIndex, mid);
5797 current->xyAtT(midT, midXY);
5798 double newMidT = current->tAtMid(index, endIndex, newMid);
5799 current->xyAtT(newMidT, newXY);
caryclark@google.com3586ece2012-12-27 18:46:58 +00005800 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
5801 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
5802 current->debugID(), mid, newMid,
5803 baseT, current->xAtT(index), current->yAtT(index),
5804 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
5805 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
5806 endT, current->xAtT(endIndex), current->yAtT(endIndex));
5807#endif
5808 mid = newMid * 2; // calling loop with divide by 2 before continuing
5809 return SK_MinS32;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005810 }
5811 bestSeg = testSeg;
5812 bestHit = testHit;
5813 bestOpp = testOpp;
5814 bestTIndex = testTIndex;
5815 bestY = testY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005816 }
5817 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005818abortContours:
caryclark@google.com10227bf2012-12-28 22:10:41 +00005819 int result;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005820 if (!bestSeg) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00005821 result = hitSomething ? SK_MinS32 : 0;
5822 } else {
5823 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
5824 current = bestSeg;
5825 index = bestTIndex;
5826 endIndex = bestSeg->nextSpan(bestTIndex, 1);
5827 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
5828 tryAgain = true;
5829 return 0;
5830 }
5831 result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
5832 SkASSERT(bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005833 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005834 double baseT = current->t(index);
5835 double endT = current->t(endIndex);
5836 bestHit = baseT + mid * (endT - baseT);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005837 return result;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005838}
5839
caryclark@google.com24bec792012-08-20 12:43:57 +00005840static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
5841 int contourCount = contourList.count();
5842 Segment* result;
5843 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5844 Contour* contour = contourList[cIndex];
5845 result = contour->undoneSegment(start, end);
5846 if (result) {
5847 return result;
5848 }
5849 }
5850 return NULL;
5851}
5852
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005853#define OLD_FIND_CHASE 1
caryclark@google.com24bec792012-08-20 12:43:57 +00005854
caryclark@google.com31143cf2012-11-09 22:14:19 +00005855static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005856 while (chase.count()) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005857 Span* span;
5858 chase.pop(&span);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005859 const Span& backPtr = span->fOther->span(span->fOtherIndex);
5860 Segment* segment = backPtr.fOther;
5861 tIndex = backPtr.fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005862 SkTDArray<Angle> angles;
5863 int done = 0;
5864 if (segment->activeAngle(tIndex, done, angles)) {
5865 Angle* last = angles.end() - 1;
5866 tIndex = last->start();
5867 endIndex = last->end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005868 #if TRY_ROTATE
5869 *chase.insert(0) = span;
5870 #else
5871 *chase.append() = span;
5872 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005873 return last->segment();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005874 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005875 if (done == angles.count()) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00005876 continue;
5877 }
5878 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005879 bool sortable = Segment::SortAngles(angles, sorted);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005880 int angleCount = sorted.count();
caryclark@google.com03f97062012-08-21 13:13:52 +00005881#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005882 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00005883#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005884 if (!sortable) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005885 continue;
5886 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005887 // find first angle, initialize winding to computed fWindSum
5888 int firstIndex = -1;
5889 const Angle* angle;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005890#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005891 int winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005892 do {
5893 angle = sorted[++firstIndex];
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005894 segment = angle->segment();
5895 winding = segment->windSum(angle);
5896 } while (winding == SK_MinS32);
5897 int spanWinding = segment->spanSign(angle->start(), angle->end());
5898 #if DEBUG_WINDING
caryclark@google.com31143cf2012-11-09 22:14:19 +00005899 SkDebugf("%s winding=%d spanWinding=%d\n",
5900 __FUNCTION__, winding, spanWinding);
caryclark@google.com47580692012-07-23 12:14:49 +00005901 #endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005902 // turn span winding into contour winding
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005903 if (spanWinding * winding < 0) {
5904 winding += spanWinding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005905 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005906 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005907 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005908 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005909 // we care about first sign and whether wind sum indicates this
5910 // edge is inside or outside. Maybe need to pass span winding
5911 // or first winding or something into this function?
5912 // advance to first undone angle, then return it and winding
5913 // (to set whether edges are active or not)
5914 int nextIndex = firstIndex + 1;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005915 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005916 angle = sorted[firstIndex];
caryclark@google.com2ddff932012-08-07 21:25:27 +00005917 winding -= angle->segment()->spanSign(angle);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005918#else
5919 do {
5920 angle = sorted[++firstIndex];
5921 segment = angle->segment();
5922 } while (segment->windSum(angle) == SK_MinS32);
5923 #if DEBUG_SORT
5924 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5925 #endif
5926 int sumWinding = segment->updateWindingReverse(angle);
5927 int nextIndex = firstIndex + 1;
5928 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5929 Segment* first = NULL;
5930#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005931 do {
5932 SkASSERT(nextIndex != firstIndex);
5933 if (nextIndex == angleCount) {
5934 nextIndex = 0;
5935 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005936 angle = sorted[nextIndex];
caryclark@google.com9764cc62012-07-12 19:29:45 +00005937 segment = angle->segment();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005938#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005939 int maxWinding = winding;
caryclark@google.com2ddff932012-08-07 21:25:27 +00005940 winding -= segment->spanSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005941 #if DEBUG_SORT
caryclark@google.com2ddff932012-08-07 21:25:27 +00005942 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
5943 segment->debugID(), maxWinding, winding, angle->sign());
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005944 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005945 tIndex = angle->start();
5946 endIndex = angle->end();
5947 int lesser = SkMin32(tIndex, endIndex);
5948 const Span& nextSpan = segment->span(lesser);
5949 if (!nextSpan.fDone) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005950#if 1
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005951 // FIXME: this be wrong? assign startWinding if edge is in
caryclark@google.com9764cc62012-07-12 19:29:45 +00005952 // same direction. If the direction is opposite, winding to
5953 // assign is flipped sign or +/- 1?
caryclark@google.com59823f72012-08-09 18:17:47 +00005954 if (useInnerWinding(maxWinding, winding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005955 maxWinding = winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005956 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005957 segment->markAndChaseWinding(angle, maxWinding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005958#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005959 break;
5960 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005961#else
5962 int start = angle->start();
5963 int end = angle->end();
5964 int maxWinding;
5965 segment->setUpWinding(start, end, maxWinding, sumWinding);
5966 if (!segment->done(angle)) {
5967 if (!first) {
5968 first = segment;
5969 tIndex = start;
5970 endIndex = end;
5971 }
5972 (void) segment->markAngle(maxWinding, sumWinding, true, angle);
5973 }
5974#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005975 } while (++nextIndex != lastIndex);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005976 #if TRY_ROTATE
5977 *chase.insert(0) = span;
5978 #else
5979 *chase.append() = span;
5980 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005981 return segment;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005982 }
5983 return NULL;
5984}
5985
caryclark@google.com027de222012-07-12 12:52:50 +00005986#if DEBUG_ACTIVE_SPANS
5987static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005988 int index;
5989 for (index = 0; index < contourList.count(); ++ index) {
caryclark@google.com027de222012-07-12 12:52:50 +00005990 contourList[index]->debugShowActiveSpans();
5991 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005992 for (index = 0; index < contourList.count(); ++ index) {
5993 contourList[index]->validateActiveSpans();
5994 }
caryclark@google.com027de222012-07-12 12:52:50 +00005995}
5996#endif
5997
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005998static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005999 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006000 Segment* result;
6001 do {
caryclark@google.comf839c032012-10-26 21:03:50 +00006002 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006003 int contourCount = contourList.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00006004 Segment* topStart = NULL;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006005 done = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00006006 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
6007 Contour* contour = contourList[cIndex];
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006008 if (contour->done()) {
6009 continue;
6010 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006011 const Bounds& bounds = contour->bounds();
6012 if (bounds.fBottom < topLeft.fY) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006013 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00006014 continue;
6015 }
6016 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006017 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00006018 continue;
6019 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006020 contour->topSortableSegment(topLeft, bestXY, topStart);
6021 if (!contour->done()) {
6022 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00006023 }
6024 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006025 if (!topStart) {
6026 return NULL;
6027 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006028 topLeft = bestXY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006029 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006030 } while (!result);
6031 return result;
6032}
caryclark@google.com31143cf2012-11-09 22:14:19 +00006033
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006034static int rightAngleWinding(SkTDArray<Contour*>& contourList,
caryclark@google.com3586ece2012-12-27 18:46:58 +00006035 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006036 bool opp) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006037 double test = 0.9;
6038 int contourWinding;
6039 do {
caryclark@google.com3586ece2012-12-27 18:46:58 +00006040 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
6041 tryAgain, test, opp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006042 if (contourWinding != SK_MinS32 || tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006043 return contourWinding;
6044 }
6045 test /= 2;
6046 } while (!approximately_negative(test));
6047 SkASSERT(0); // should be OK to comment out, but interested when this hits
6048 return contourWinding;
6049}
6050
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006051static void skipVertical(SkTDArray<Contour*>& contourList,
6052 Segment*& current, int& index, int& endIndex) {
6053 if (!current->isVertical(index, endIndex)) {
6054 return;
6055 }
6056 int contourCount = contourList.count();
6057 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
6058 Contour* contour = contourList[cIndex];
6059 if (contour->done()) {
6060 continue;
6061 }
6062 current = contour->nonVerticalSegment(index, endIndex);
6063 if (current) {
6064 return;
6065 }
6066 }
6067}
6068
caryclark@google.com3586ece2012-12-27 18:46:58 +00006069static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006070 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
6071 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
6072 true);
6073 if (!current) {
6074 return NULL;
6075 }
6076 if (firstContour) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00006077 current->initWinding(index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006078 firstContour = false;
6079 return current;
6080 }
6081 int minIndex = SkMin32(index, endIndex);
6082 int sumWinding = current->windSum(minIndex);
6083 if (sumWinding != SK_MinS32) {
6084 return current;
6085 }
6086 sumWinding = current->computeSum(index, endIndex, binary);
6087 if (sumWinding != SK_MinS32) {
6088 return current;
6089 }
6090 int contourWinding;
6091 int oppContourWinding = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006092 // the simple upward projection of the unresolved points hit unsortable angles
6093 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006094 bool tryAgain;
6095 double tHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006096 SkScalar hitDx = 0;
6097 SkScalar hitOppDx = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006098 do {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006099 // if current is vertical, find another candidate which is not
6100 // if only remaining candidates are vertical, then they can be marked done
caryclark@google.com10227bf2012-12-28 22:10:41 +00006101 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006102 skipVertical(contourList, current, index, endIndex);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006103 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006104 tryAgain = false;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006105 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006106 tryAgain, false);
6107 if (tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006108 continue;
6109 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006110 if (!binary) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006111 break;
6112 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00006113 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006114 tryAgain, true);
6115 } while (tryAgain);
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00006116
caryclark@google.com3586ece2012-12-27 18:46:58 +00006117 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006118 return current;
6119}
6120
6121// rewrite that abandons keeping local track of winding
caryclark@google.com3586ece2012-12-27 18:46:58 +00006122static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006123 bool firstContour = true;
6124 bool unsortable = false;
6125 bool topUnsortable = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006126 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
6127 do {
6128 int index, endIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006129 bool topDone;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006130 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006131 topUnsortable, topDone, false);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006132 if (!current) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006133 if (topUnsortable || !topDone) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006134 topUnsortable = false;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006135 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006136 topLeft.fX = topLeft.fY = SK_ScalarMin;
6137 continue;
6138 }
6139 break;
6140 }
6141 SkTDArray<Span*> chaseArray;
6142 do {
6143 if (current->activeWinding(index, endIndex)) {
6144 do {
6145 #if DEBUG_ACTIVE_SPANS
6146 if (!unsortable && current->done()) {
6147 debugShowActiveSpans(contourList);
6148 }
6149 #endif
6150 SkASSERT(unsortable || !current->done());
6151 int nextStart = index;
6152 int nextEnd = endIndex;
6153 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
6154 unsortable);
6155 if (!next) {
6156 if (!unsortable && simple.hasMove()
6157 && current->verb() != SkPath::kLine_Verb
6158 && !simple.isClosed()) {
6159 current->addCurveTo(index, endIndex, simple, true);
6160 SkASSERT(simple.isClosed());
6161 }
6162 break;
6163 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006164 #if DEBUG_FLOW
6165 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6166 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
6167 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
6168 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006169 current->addCurveTo(index, endIndex, simple, true);
6170 current = next;
6171 index = nextStart;
6172 endIndex = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006173 } while (!simple.isClosed() && (!unsortable
caryclark@google.com10227bf2012-12-28 22:10:41 +00006174 || !current->done(SkMin32(index, endIndex))));
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006175 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
6176 SkASSERT(unsortable);
6177 int min = SkMin32(index, endIndex);
6178 if (!current->done(min)) {
6179 current->addCurveTo(index, endIndex, simple, true);
6180 current->markDoneUnary(min);
6181 }
6182 }
6183 simple.close();
6184 } else {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006185 Span* last = current->markAndChaseDoneUnary(index, endIndex);
caryclark@google.com4aaaaea2013-02-28 16:12:39 +00006186 if (last && !last->fLoop) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006187 *chaseArray.append() = last;
6188 }
6189 }
6190 current = findChase(chaseArray, index, endIndex);
6191 #if DEBUG_ACTIVE_SPANS
6192 debugShowActiveSpans(contourList);
6193 #endif
6194 if (!current) {
6195 break;
6196 }
6197 } while (true);
6198 } while (true);
6199 return simple.someAssemblyRequired();
6200}
6201
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006202// returns true if all edges were processed
caryclark@google.comf839c032012-10-26 21:03:50 +00006203static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006204 Segment* current;
6205 int start, end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006206 bool unsortable = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006207 bool closable = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00006208 while ((current = findUndone(contourList, start, end))) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006209 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006210 #if DEBUG_ACTIVE_SPANS
6211 if (!unsortable && current->done()) {
6212 debugShowActiveSpans(contourList);
6213 }
6214 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006215 SkASSERT(unsortable || !current->done());
caryclark@google.com24bec792012-08-20 12:43:57 +00006216 int nextStart = start;
6217 int nextEnd = end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006218 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
caryclark@google.com24bec792012-08-20 12:43:57 +00006219 if (!next) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006220 if (!unsortable && simple.hasMove()
caryclark@google.comf839c032012-10-26 21:03:50 +00006221 && current->verb() != SkPath::kLine_Verb
6222 && !simple.isClosed()) {
6223 current->addCurveTo(start, end, simple, true);
6224 SkASSERT(simple.isClosed());
caryclark@google.comc899ad92012-08-23 15:24:42 +00006225 }
caryclark@google.com24bec792012-08-20 12:43:57 +00006226 break;
6227 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006228 #if DEBUG_FLOW
6229 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6230 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
6231 current->xyAtT(end).fX, current->xyAtT(end).fY);
6232 #endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006233 current->addCurveTo(start, end, simple, true);
caryclark@google.com24bec792012-08-20 12:43:57 +00006234 current = next;
6235 start = nextStart;
6236 end = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006237 } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006238 if (!simple.isClosed()) {
6239 SkASSERT(unsortable);
6240 int min = SkMin32(start, end);
6241 if (!current->done(min)) {
6242 current->addCurveTo(start, end, simple, true);
6243 current->markDone(min, 1);
6244 }
6245 closable = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00006246 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006247 simple.close();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00006248 #if DEBUG_ACTIVE_SPANS
6249 debugShowActiveSpans(contourList);
6250 #endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00006251 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006252 return closable;
caryclark@google.com24bec792012-08-20 12:43:57 +00006253}
6254
caryclark@google.comb45a1b42012-05-18 20:50:33 +00006255static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
6256 int contourCount = contourList.count();
6257 for (int cTest = 0; cTest < contourCount; ++cTest) {
6258 Contour* contour = contourList[cTest];
6259 contour->fixOtherTIndex();
6260 }
6261}
6262
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006263static void sortSegments(SkTDArray<Contour*>& contourList) {
6264 int contourCount = contourList.count();
6265 for (int cTest = 0; cTest < contourCount; ++cTest) {
6266 Contour* contour = contourList[cTest];
6267 contour->sortSegments();
6268 }
6269}
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006270
caryclark@google.com4eeda372012-12-06 21:47:48 +00006271static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
6272 bool evenOdd, bool oppEvenOdd) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006273 int count = contours.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006274 if (count == 0) {
6275 return;
6276 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006277 for (int index = 0; index < count; ++index) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00006278 Contour& contour = contours[index];
6279 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
6280 *list.append() = &contour;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006281 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006282 QSort<Contour>(list.begin(), list.end() - 1);
6283}
6284
caryclark@google.comf839c032012-10-26 21:03:50 +00006285static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006286 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006287}
6288
caryclark@google.com10227bf2012-12-28 22:10:41 +00006289static bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
6290 return distances[one] < distances[two];
6291}
caryclark@google.comf839c032012-10-26 21:03:50 +00006292 /*
6293 check start and end of each contour
6294 if not the same, record them
6295 match them up
6296 connect closest
6297 reassemble contour pieces into new path
6298 */
6299static void assemble(const PathWrapper& path, PathWrapper& simple) {
6300#if DEBUG_PATH_CONSTRUCTION
6301 SkDebugf("%s\n", __FUNCTION__);
6302#endif
6303 SkTArray<Contour> contours;
6304 EdgeBuilder builder(path, contours);
6305 builder.finish();
6306 int count = contours.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006307 int outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006308 SkTDArray<int> runs; // indices of partial contours
caryclark@google.com0b7da432012-10-31 19:00:20 +00006309 for (outer = 0; outer < count; ++outer) {
6310 const Contour& eContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006311 const SkPoint& eStart = eContour.start();
6312 const SkPoint& eEnd = eContour.end();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006313#if DEBUG_ASSEMBLE
6314 SkDebugf("%s contour", __FUNCTION__);
6315 if (!approximatelyEqual(eStart, eEnd)) {
6316 SkDebugf("[%d]", runs.count());
6317 } else {
6318 SkDebugf(" ");
6319 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006320 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006321 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
6322#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006323 if (approximatelyEqual(eStart, eEnd)) {
6324 eContour.toPath(simple);
6325 continue;
6326 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006327 *runs.append() = outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006328 }
6329 count = runs.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006330 if (count == 0) {
6331 return;
6332 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006333 SkTDArray<int> sLink, eLink;
6334 sLink.setCount(count);
6335 eLink.setCount(count);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006336 int rIndex, iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006337 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006338 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006339 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006340 SkTDArray<double> distances;
6341 const int ends = count * 2; // all starts and ends
6342 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
6343 distances.setCount(entries);
6344 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
6345 outer = runs[rIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006346 const Contour& oContour = contours[outer];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006347 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
6348 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
6349 * ends - rIndex - 1;
6350 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
6351 int inner = runs[iIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006352 const Contour& iContour = contours[inner];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006353 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
6354 double dx = iPt.fX - oPt.fX;
6355 double dy = iPt.fY - oPt.fY;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006356 double dist = dx * dx + dy * dy;
caryclark@google.com10227bf2012-12-28 22:10:41 +00006357 distances[row + iIndex] = dist; // oStart distance from iStart
6358 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006359 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006360 SkTDArray<int> sortedDist;
6361 sortedDist.setCount(entries);
6362 for (rIndex = 0; rIndex < entries; ++rIndex) {
6363 sortedDist[rIndex] = rIndex;
6364 }
6365 QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
6366 int remaining = count; // number of start/end pairs
6367 for (rIndex = 0; rIndex < entries; ++rIndex) {
6368 int pair = sortedDist[rIndex];
6369 int row = pair / ends;
6370 int col = pair - row * ends;
6371 int thingOne = row < col ? row : ends - row - 2;
6372 int ndxOne = thingOne >> 1;
6373 bool endOne = thingOne & 1;
6374 int* linkOne = endOne ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006375 if (linkOne[ndxOne] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006376 continue;
6377 }
6378 int thingTwo = row < col ? col : ends - row + col - 1;
6379 int ndxTwo = thingTwo >> 1;
6380 bool endTwo = thingTwo & 1;
6381 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006382 if (linkTwo[ndxTwo] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006383 continue;
6384 }
6385 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
6386 bool flip = endOne == endTwo;
6387 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
6388 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
6389 if (!--remaining) {
6390 break;
6391 }
6392 }
6393 SkASSERT(!remaining);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006394#if DEBUG_ASSEMBLE
6395 for (rIndex = 0; rIndex < count; ++rIndex) {
6396 int s = sLink[rIndex];
6397 int e = eLink[rIndex];
6398 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
6399 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
caryclark@google.comf839c032012-10-26 21:03:50 +00006400 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006401#endif
6402 rIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00006403 do {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006404 bool forward = true;
6405 bool first = true;
6406 int sIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006407 SkASSERT(sIndex != SK_MaxS32);
6408 sLink[rIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006409 int eIndex;
6410 if (sIndex < 0) {
6411 eIndex = sLink[~sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006412 sLink[~sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006413 } else {
6414 eIndex = eLink[sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006415 eLink[sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006416 }
caryclark@google.comaa358312013-01-29 20:28:49 +00006417 SkASSERT(eIndex != SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006418#if DEBUG_ASSEMBLE
6419 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006420 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
6421 eIndex < 0 ? ~eIndex : eIndex);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006422#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006423 do {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006424 outer = runs[rIndex];
6425 const Contour& contour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006426 if (first) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006427 first = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006428 const SkPoint* startPtr = &contour.start();
caryclark@google.comf839c032012-10-26 21:03:50 +00006429 simple.deferredMove(startPtr[0]);
6430 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006431 if (forward) {
6432 contour.toPartialForward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006433 } else {
6434 contour.toPartialBackward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006435 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006436#if DEBUG_ASSEMBLE
6437 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006438 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006439 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
6440#endif
6441 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006442 simple.close();
caryclark@google.comf839c032012-10-26 21:03:50 +00006443 break;
6444 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006445 if (forward) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006446 eIndex = eLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006447 SkASSERT(eIndex != SK_MaxS32);
6448 eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006449 if (eIndex >= 0) {
6450 SkASSERT(sLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006451 sLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006452 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006453 SkASSERT(eLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006454 eLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006455 }
6456 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006457 eIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006458 SkASSERT(eIndex != SK_MaxS32);
6459 sLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006460 if (eIndex >= 0) {
6461 SkASSERT(eLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006462 eLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006463 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006464 SkASSERT(sLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006465 sLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006466 }
6467 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006468 rIndex = eIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006469 if (rIndex < 0) {
6470 forward ^= 1;
6471 rIndex = ~rIndex;
6472 }
6473 } while (true);
6474 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006475 if (sLink[rIndex] != SK_MaxS32) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006476 break;
6477 }
6478 }
6479 } while (rIndex < count);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006480#if DEBUG_ASSEMBLE
6481 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006482 SkASSERT(sLink[rIndex] == SK_MaxS32);
6483 SkASSERT(eLink[rIndex] == SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006484 }
6485#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006486}
6487
6488void simplifyx(const SkPath& path, SkPath& result) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00006489#if DEBUG_SORT
6490 gDebugSortCount = gDebugSortCountDefault;
6491#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006492 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
caryclark@google.comf839c032012-10-26 21:03:50 +00006493 result.reset();
6494 result.setFillType(SkPath::kEvenOdd_FillType);
6495 PathWrapper simple(result);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006496
6497 // turn path into list of segments
6498 SkTArray<Contour> contours;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006499 EdgeBuilder builder(path, contours);
caryclark@google.com235f56a2012-09-14 14:19:30 +00006500 builder.finish();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006501 SkTDArray<Contour*> contourList;
caryclark@google.com4eeda372012-12-06 21:47:48 +00006502 makeContourList(contours, contourList, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006503 Contour** currentPtr = contourList.begin();
6504 if (!currentPtr) {
6505 return;
6506 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006507 Contour** listEnd = contourList.end();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006508 // find all intersections between segments
6509 do {
6510 Contour** nextPtr = currentPtr;
6511 Contour* current = *currentPtr++;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00006512 if (current->containsCubics()) {
6513 addSelfIntersectTs(current);
6514 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006515 Contour* next;
6516 do {
6517 next = *nextPtr++;
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00006518 } while (addIntersectTs(current, next) && nextPtr != listEnd);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006519 } while (currentPtr != listEnd);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006520 // eat through coincident edges
caryclark@google.com4eeda372012-12-06 21:47:48 +00006521 coincidenceCheck(contourList, 0);
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00006522 fixOtherTIndex(contourList);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006523 sortSegments(contourList);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006524#if DEBUG_ACTIVE_SPANS
6525 debugShowActiveSpans(contourList);
6526#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006527 // construct closed contours
caryclark@google.com3586ece2012-12-27 18:46:58 +00006528 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00006529 : !bridgeXor(contourList, simple))
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006530 { // if some edges could not be resolved, assemble remaining fragments
caryclark@google.comf839c032012-10-26 21:03:50 +00006531 SkPath temp;
6532 temp.setFillType(SkPath::kEvenOdd_FillType);
6533 PathWrapper assembled(temp);
6534 assemble(simple, assembled);
6535 result = *assembled.nativePath();
caryclark@google.com24bec792012-08-20 12:43:57 +00006536 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006537}