blob: f4d887579415cb17dbddc607ac33a3029297cde6 [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.come7bd5f42012-12-13 19:47:53 +000047#define DEBUG_ASSEMBLE 0
caryclark@google.com47580692012-07-23 12:14:49 +000048#define DEBUG_CONCIDENT 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000049#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000050#define DEBUG_FLOW 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000051#define DEBUG_MARK_DONE 0
caryclark@google.comf839c032012-10-26 21:03:50 +000052#define DEBUG_PATH_CONSTRUCTION 0
caryclark@google.com729e1c42012-11-21 21:36:34 +000053#define DEBUG_SHOW_WINDING 0
caryclark@google.comc83c70e2013-02-22 21:50:07 +000054#define DEBUG_SORT 0
caryclark@google.com5e0500f2013-02-20 12:51:37 +000055#define DEBUG_SWAP_TOP 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000056#define DEBUG_UNSORTABLE 0
caryclark@google.comafe56de2012-07-24 18:11:03 +000057#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000058#define DEBUG_WINDING 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000059#define DEBUG_WINDING_AT_T 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000060
61#else
62
caryclark@google.com47580692012-07-23 12:14:49 +000063const bool gRunTestsInOneThread = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +000064
caryclark@google.combeda3892013-02-07 13:13:41 +000065#define DEBUG_ACTIVE_OP 1
caryclark@google.comc91dfe42012-10-16 12:06:27 +000066#define DEBUG_ACTIVE_SPANS 1
caryclark@google.com4eeda372012-12-06 21:47:48 +000067#define DEBUG_ACTIVE_SPANS_SHORT_FORM 1
caryclark@google.com6aea33f2012-10-09 14:11:58 +000068#define DEBUG_ADD_INTERSECTING_TS 1
69#define DEBUG_ADD_T_PAIR 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000070#define DEBUG_ANGLE 1
caryclark@google.come7bd5f42012-12-13 19:47:53 +000071#define DEBUG_ASSEMBLE 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000072#define DEBUG_CONCIDENT 1
caryclark@google.com534aa5b2012-08-02 20:08:21 +000073#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000074#define DEBUG_FLOW 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000075#define DEBUG_MARK_DONE 1
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000076#define DEBUG_PATH_CONSTRUCTION 1
caryclark@google.com729e1c42012-11-21 21:36:34 +000077#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000078#define DEBUG_SORT 1
caryclark@google.com47d73da2013-02-17 01:41:25 +000079#define DEBUG_SWAP_TOP 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000080#define DEBUG_UNSORTABLE 1
caryclark@google.comafe56de2012-07-24 18:11:03 +000081#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000082#define DEBUG_WINDING 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000083#define DEBUG_WINDING_AT_T 1
caryclark@google.comfa0588f2012-04-26 21:01:06 +000084
85#endif
86
caryclark@google.combeda3892013-02-07 13:13:41 +000087#define DEBUG_DUMP (DEBUG_ACTIVE_OP | DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | \
88 DEBUG_PATH_CONSTRUCTION)
caryclark@google.com027de222012-07-12 12:52:50 +000089
caryclark@google.comfa0588f2012-04-26 21:01:06 +000090#if DEBUG_DUMP
91static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000092// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
caryclark@google.comfa0588f2012-04-26 21:01:06 +000093static int gContourID;
94static int gSegmentID;
95#endif
96
caryclark@google.comc83c70e2013-02-22 21:50:07 +000097#if DEBUG_SORT
98static int gDebugSortCountDefault = 3; // SK_MaxS32;
99static int gDebugSortCount;
100#endif
101
caryclark@google.com5e0500f2013-02-20 12:51:37 +0000102#if DEBUG_ACTIVE_OP
103static const char* kShapeOpStr[] = {"diff", "sect", "union", "xor"};
104#endif
105
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000106#ifndef DEBUG_TEST
107#define DEBUG_TEST 0
108#endif
109
caryclark@google.com32546db2012-08-31 20:55:07 +0000110#define MAKE_CONST_LINE(line, pts) \
111 const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}
112#define MAKE_CONST_QUAD(quad, pts) \
113 const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
114 {pts[2].fX, pts[2].fY}}
115#define MAKE_CONST_CUBIC(cubic, pts) \
116 const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
117 {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}}
118
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000119static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
120 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000121 MAKE_CONST_LINE(aLine, a);
122 MAKE_CONST_LINE(bLine, b);
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000123 return intersect(aLine, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000124}
125
126static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
127 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000128 MAKE_CONST_QUAD(aQuad, a);
129 MAKE_CONST_LINE(bLine, b);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000130 return intersect(aQuad, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000131}
132
caryclark@google.com32546db2012-08-31 20:55:07 +0000133static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000134 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000135 MAKE_CONST_CUBIC(aCubic, a);
136 MAKE_CONST_LINE(bLine, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000137 return intersect(aCubic, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000138}
139
140static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
141 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000142 MAKE_CONST_QUAD(aQuad, a);
143 MAKE_CONST_QUAD(bQuad, b);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000144#define TRY_QUARTIC_SOLUTION 1
145#if TRY_QUARTIC_SOLUTION
146 intersect2(aQuad, bQuad, intersections);
147#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000148 intersect(aQuad, bQuad, intersections);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000149#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000150 return intersections.fUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000151}
152
caryclark@google.com73ca6242013-01-17 21:02:47 +0000153#if APPROXIMATE_CUBICS
154static int CubicQuadIntersect(const SkPoint a[4], const SkPoint b[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000155 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000156 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000157 MAKE_CONST_QUAD(bQuad, b);
158 return intersect(aCubic, bQuad, intersections);
159}
160#endif
161
162static int CubicIntersect(const SkPoint a[4], const SkPoint b[4], Intersections& intersections) {
163 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com32546db2012-08-31 20:55:07 +0000164 MAKE_CONST_CUBIC(bCubic, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000165#if APPROXIMATE_CUBICS
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000166 intersect3(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000167#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000168 intersect(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000169#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000170 return intersections.fUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000171}
172
caryclark@google.comc83c70e2013-02-22 21:50:07 +0000173static int CubicIntersect(const SkPoint a[4], Intersections& intersections) {
174 MAKE_CONST_CUBIC(aCubic, a);
175 return intersect(aCubic, intersections);
176}
177
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000178static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
179 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000180 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000181 return horizontalIntersect(aLine, left, right, y, flipped, intersections);
182}
183
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000184static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
185 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000186 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000187 return horizontalIntersect(aQuad, left, right, y, flipped, intersections);
188}
189
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000190static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
191 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000192 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000193 return horizontalIntersect(aCubic, left, right, y, flipped, intersections);
194}
195
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000196static int (* const HSegmentIntersect[])(const SkPoint [], SkScalar ,
197 SkScalar , SkScalar , bool , Intersections& ) = {
198 NULL,
199 HLineIntersect,
200 HQuadIntersect,
201 HCubicIntersect
202};
203
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000204static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom,
205 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000206 MAKE_CONST_LINE(aLine, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000207 return verticalIntersect(aLine, top, bottom, x, flipped, intersections);
208}
209
210static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom,
211 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000212 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000213 return verticalIntersect(aQuad, top, bottom, x, flipped, intersections);
214}
215
216static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom,
217 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000218 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000219 return verticalIntersect(aCubic, top, bottom, x, flipped, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000220}
221
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000222static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar ,
223 SkScalar , SkScalar , bool , Intersections& ) = {
224 NULL,
225 VLineIntersect,
226 VQuadIntersect,
227 VCubicIntersect
228};
229
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000230static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000231 MAKE_CONST_LINE(line, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000232 double x, y;
233 xy_at_t(line, t, x, y);
234 out->fX = SkDoubleToScalar(x);
235 out->fY = SkDoubleToScalar(y);
236}
237
caryclark@google.comf9502d72013-02-04 14:06:49 +0000238static void LineXYAtT(const SkPoint a[2], double t, _Point* out) {
239 MAKE_CONST_LINE(line, a);
240 xy_at_t(line, t, out->x, out->y);
241}
242
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000243static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000244 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000245 double x, y;
246 xy_at_t(quad, t, x, y);
247 out->fX = SkDoubleToScalar(x);
248 out->fY = SkDoubleToScalar(y);
249}
250
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000251static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
252 MAKE_CONST_QUAD(quad, a);
253 xy_at_t(quad, t, out->x, out->y);
254}
255
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000256static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000257 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000258 double x, y;
259 xy_at_t(cubic, t, x, y);
260 out->fX = SkDoubleToScalar(x);
261 out->fY = SkDoubleToScalar(y);
262}
263
caryclark@google.comf9502d72013-02-04 14:06:49 +0000264static void CubicXYAtT(const SkPoint a[4], double t, _Point* out) {
265 MAKE_CONST_CUBIC(cubic, a);
266 xy_at_t(cubic, t, out->x, out->y);
267}
268
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000269static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
270 NULL,
271 LineXYAtT,
272 QuadXYAtT,
273 CubicXYAtT
274};
275
caryclark@google.comf9502d72013-02-04 14:06:49 +0000276static void (* const SegmentXYAtT2[])(const SkPoint [], double , _Point* ) = {
277 NULL,
278 LineXYAtT,
279 QuadXYAtT,
280 CubicXYAtT
281};
282
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000283static SkScalar LineXAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000284 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000285 double x;
286 xy_at_t(aLine, t, x, *(double*) 0);
287 return SkDoubleToScalar(x);
288}
289
290static SkScalar QuadXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000291 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000292 double x;
293 xy_at_t(quad, t, x, *(double*) 0);
294 return SkDoubleToScalar(x);
295}
296
297static SkScalar CubicXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000298 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000299 double x;
300 xy_at_t(cubic, t, x, *(double*) 0);
301 return SkDoubleToScalar(x);
302}
303
304static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
305 NULL,
306 LineXAtT,
307 QuadXAtT,
308 CubicXAtT
309};
310
311static SkScalar LineYAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000312 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000313 double y;
314 xy_at_t(aLine, t, *(double*) 0, y);
315 return SkDoubleToScalar(y);
316}
317
318static SkScalar QuadYAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000319 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000320 double y;
321 xy_at_t(quad, t, *(double*) 0, y);
322 return SkDoubleToScalar(y);
323}
324
325static SkScalar CubicYAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000326 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000327 double y;
328 xy_at_t(cubic, t, *(double*) 0, y);
329 return SkDoubleToScalar(y);
330}
331
332static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
333 NULL,
334 LineYAtT,
335 QuadYAtT,
336 CubicYAtT
337};
338
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000339static SkScalar LineDXAtT(const SkPoint a[2], double ) {
340 return a[1].fX - a[0].fX;
341}
342
343static SkScalar QuadDXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000344 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000345 double x = dx_at_t(quad, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000346 return SkDoubleToScalar(x);
347}
348
349static SkScalar CubicDXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000350 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000351 double x = dx_at_t(cubic, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000352 return SkDoubleToScalar(x);
353}
354
355static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
356 NULL,
357 LineDXAtT,
358 QuadDXAtT,
359 CubicDXAtT
360};
361
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000362static SkScalar LineDYAtT(const SkPoint a[2], double ) {
363 return a[1].fY - a[0].fY;
364}
365
366static SkScalar QuadDYAtT(const SkPoint a[3], double t) {
367 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000368 double y = dy_at_t(quad, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000369 return SkDoubleToScalar(y);
370}
371
372static SkScalar CubicDYAtT(const SkPoint a[4], double t) {
373 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000374 double y = dy_at_t(cubic, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000375 return SkDoubleToScalar(y);
376}
377
378static SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = {
379 NULL,
380 LineDYAtT,
381 QuadDYAtT,
382 CubicDYAtT
383};
384
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000385static SkPoint LineDXDYAtT(const SkPoint a[2], double ) {
386 return a[1] - a[0];
387}
388
389static SkPoint QuadDXDYAtT(const SkPoint a[3], double t) {
390 MAKE_CONST_QUAD(quad, a);
391 _Point pt;
392 dxdy_at_t(quad, t, pt);
393 return pt.asSkPoint();
394}
395
396static SkPoint CubicDXDYAtT(const SkPoint a[4], double t) {
397 MAKE_CONST_CUBIC(cubic, a);
398 _Point pt;
399 dxdy_at_t(cubic, t, pt);
400 return pt.asSkPoint();
401}
402
403static SkPoint (* const SegmentDXDYAtT[])(const SkPoint [], double ) = {
404 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.com6aea33f2012-10-09 14:11:58 +0000652};
653
caryclark@google.com15fa1382012-05-07 20:49:36 +0000654// sorting angles
655// given angles of {dx dy ddx ddy dddx dddy} sort them
656class Angle {
657public:
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000658 // FIXME: this is bogus for quads and cubics
659 // if the quads and cubics' line from end pt to ctrl pt are coincident,
660 // there's no obvious way to determine the curve ordering from the
661 // derivatives alone. In particular, if one quadratic's coincident tangent
662 // is longer than the other curve, the final control point can place the
663 // longer curve on either side of the shorter one.
664 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
665 // may provide some help, but nothing has been figured out yet.
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000666
caryclark@google.com32546db2012-08-31 20:55:07 +0000667 /*(
668 for quads and cubics, set up a parameterized line (e.g. LineParameters )
669 for points [0] to [1]. See if point [2] is on that line, or on one side
670 or the other. If it both quads' end points are on the same side, choose
671 the shorter tangent. If the tangents are equal, choose the better second
672 tangent angle
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000673
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000674 maybe I could set up LineParameters lazily
caryclark@google.com32546db2012-08-31 20:55:07 +0000675 */
caryclark@google.com15fa1382012-05-07 20:49:36 +0000676 bool operator<(const Angle& rh) const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000677 double y = dy();
678 double ry = rh.dy();
679 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
680 return y < 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000681 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000682 double x = dx();
683 double rx = rh.dx();
684 if (y == 0 && ry == 0 && x * rx < 0) {
685 return x < rx;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000686 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000687 double x_ry = x * ry;
688 double rx_y = rx * y;
689 double cmp = x_ry - rx_y;
caryclark@google.comc899ad92012-08-23 15:24:42 +0000690 if (!approximately_zero(cmp)) {
caryclark@google.com15fa1382012-05-07 20:49:36 +0000691 return cmp < 0;
692 }
caryclark@google.comd1688742012-09-18 20:08:37 +0000693 if (approximately_zero(x_ry) && approximately_zero(rx_y)
694 && !approximately_zero_squared(cmp)) {
695 return cmp < 0;
696 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000697 // at this point, the initial tangent line is coincident
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000698 // see if edges curl away from each other
caryclark@google.com31143cf2012-11-09 22:14:19 +0000699 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
700 || !approximately_zero(rh.fSide))) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000701 // FIXME: running demo will trigger this assertion
702 // (don't know if commenting out will trigger further assertion or not)
703 // commenting it out allows demo to run in release, though
704 // SkASSERT(fSide != rh.fSide);
705 return fSide < rh.fSide;
706 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000707 // see if either curve can be lengthened and try the tangent compare again
708 if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
709 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
710 Angle longer = *this;
711 Angle rhLonger = rh;
712 if (longer.lengthen() | rhLonger.lengthen()) {
713 return longer < rhLonger;
714 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000715 #if 0
caryclark@google.coma461ff02012-10-11 12:54:23 +0000716 // what if we extend in the other direction?
717 longer = *this;
718 rhLonger = rh;
719 if (longer.reverseLengthen() | rhLonger.reverseLengthen()) {
720 return longer < rhLonger;
721 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000722 #endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000723 }
caryclark@google.com185c7c42012-10-19 18:26:24 +0000724 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
caryclark@google.com31143cf2012-11-09 22:14:19 +0000725 || (rh.fVerb == SkPath::kLine_Verb
726 && approximately_zero(rx) && approximately_zero(ry))) {
caryclark@google.com185c7c42012-10-19 18:26:24 +0000727 // See general unsortable comment below. This case can happen when
728 // one line has a non-zero change in t but no change in x and y.
729 fUnsortable = true;
730 rh.fUnsortable = true;
731 return this < &rh; // even with no solution, return a stable sort
732 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000733 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
734 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
735 fUnsortable = true;
736 rh.fUnsortable = true;
737 return this < &rh; // even with no solution, return a stable sort
738 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000739 SkASSERT(fVerb >= SkPath::kQuad_Verb);
740 SkASSERT(rh.fVerb >= SkPath::kQuad_Verb);
skia.committer@gmail.comc1ad0222012-09-19 02:01:47 +0000741 // FIXME: until I can think of something better, project a ray from the
caryclark@google.comd1688742012-09-18 20:08:37 +0000742 // end of the shorter tangent to midway between the end points
743 // through both curves and use the resulting angle to sort
caryclark@google.com235f56a2012-09-14 14:19:30 +0000744 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
745 double len = fTangent1.normalSquared();
746 double rlen = rh.fTangent1.normalSquared();
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000747 _Line ray;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000748 Intersections i, ri;
caryclark@google.comd1688742012-09-18 20:08:37 +0000749 int roots, rroots;
750 bool flip = false;
751 do {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000752 bool useThis = (len < rlen) ^ flip;
753 const Cubic& part = useThis ? fCurvePart : rh.fCurvePart;
754 SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb;
755 ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ?
756 part[2] : part[1];
757 ray[1].x = (part[0].x + part[partVerb].x) / 2;
758 ray[1].y = (part[0].y + part[partVerb].y) / 2;
caryclark@google.comd1688742012-09-18 20:08:37 +0000759 SkASSERT(ray[0] != ray[1]);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000760 roots = (*SegmentRayIntersect[fVerb])(fPts, ray, i);
761 rroots = (*SegmentRayIntersect[rh.fVerb])(rh.fPts, ray, ri);
caryclark@google.comd1688742012-09-18 20:08:37 +0000762 } while ((roots == 0 || rroots == 0) && (flip ^= true));
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000763 if (roots == 0 || rroots == 0) {
764 // FIXME: we don't have a solution in this case. The interim solution
765 // is to mark the edges as unsortable, exclude them from this and
766 // future computations, and allow the returned path to be fragmented
767 fUnsortable = true;
768 rh.fUnsortable = true;
769 return this < &rh; // even with no solution, return a stable sort
770 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000771 _Point loc;
772 double best = SK_ScalarInfinity;
773 double dx, dy, dist;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000774 int index;
775 for (index = 0; index < roots; ++index) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000776 (*SegmentXYAtT2[fVerb])(fPts, i.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000777 dx = loc.x - ray[0].x;
778 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000779 dist = dx * dx + dy * dy;
780 if (best > dist) {
781 best = dist;
782 }
783 }
784 for (index = 0; index < rroots; ++index) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000785 (*SegmentXYAtT2[rh.fVerb])(rh.fPts, ri.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000786 dx = loc.x - ray[0].x;
787 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000788 dist = dx * dx + dy * dy;
789 if (best > dist) {
790 return fSide < 0;
791 }
792 }
793 return fSide > 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000794 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000795
caryclark@google.com47580692012-07-23 12:14:49 +0000796 double dx() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000797 return fTangent1.dx();
caryclark@google.com47580692012-07-23 12:14:49 +0000798 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000799
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000800 double dy() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000801 return fTangent1.dy();
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000802 }
803
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000804 int end() const {
805 return fEnd;
806 }
807
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000808 bool isHorizontal() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000809 return dy() == 0 && fVerb == SkPath::kLine_Verb;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000810 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000811
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000812 bool lengthen() {
813 int newEnd = fEnd;
814 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
815 fEnd = newEnd;
816 setSpans();
817 return true;
818 }
819 return false;
820 }
821
caryclark@google.coma461ff02012-10-11 12:54:23 +0000822 bool reverseLengthen() {
823 if (fReversed) {
824 return false;
825 }
826 int newEnd = fStart;
827 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
828 fEnd = newEnd;
829 fReversed = true;
830 setSpans();
831 return true;
832 }
833 return false;
834 }
835
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000836 void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000837 int start, int end, const SkTDArray<Span>& spans) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000838 fSegment = segment;
839 fStart = start;
840 fEnd = end;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000841 fPts = orig;
842 fVerb = verb;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000843 fSpans = &spans;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000844 fReversed = false;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000845 fUnsortable = false;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000846 setSpans();
847 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000848
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000849
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000850 void setSpans() {
851 double startT = (*fSpans)[fStart].fT;
852 double endT = (*fSpans)[fEnd].fT;
853 switch (fVerb) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000854 case SkPath::kLine_Verb:
855 _Line l;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000856 LineSubDivideHD(fPts, startT, endT, l);
caryclark@google.com32546db2012-08-31 20:55:07 +0000857 // OPTIMIZATION: for pure line compares, we never need fTangent1.c
858 fTangent1.lineEndPoints(l);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000859 fSide = 0;
caryclark@google.com32546db2012-08-31 20:55:07 +0000860 break;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000861 case SkPath::kQuad_Verb: {
862 Quadratic& quad = (Quadratic&)fCurvePart;
863 QuadSubDivideHD(fPts, startT, endT, quad);
864 fTangent1.quadEndPoints(quad, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000865 #if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
866 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 }
870 #endif
caryclark@google.comf9502d72013-02-04 14:06:49 +0000871 fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- compare sign only
872 } break;
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000873 case SkPath::kCubic_Verb: {
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000874 int nextC = 2;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000875 CubicSubDivideHD(fPts, startT, endT, fCurvePart);
876 fTangent1.cubicEndPoints(fCurvePart, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000877 if (dx() == 0 && dy() == 0) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000878 fTangent1.cubicEndPoints(fCurvePart, 0, 2);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000879 nextC = 3;
caryclark@google.comaa358312013-01-29 20:28:49 +0000880 #if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
881 if (dx() == 0 && dy() == 0) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000882 SkDebugf("*** %s cubic is line\n", __FUNCTION__);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000883 fTangent1.cubicEndPoints(fCurvePart, 0, 3);
caryclark@google.comaa358312013-01-29 20:28:49 +0000884 }
885 #endif
886 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000887 fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign only
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000888 if (nextC == 2 && approximately_zero(fSide)) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000889 fSide = -fTangent1.pointDistance(fCurvePart[3]);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000890 }
891 } break;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000892 default:
893 SkASSERT(0);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000894 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000895 fUnsortable = dx() == 0 && dy() == 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000896 if (fUnsortable) {
897 return;
898 }
899 SkASSERT(fStart != fEnd);
900 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
901 for (int index = fStart; index != fEnd; index += step) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000902#if 1
903 const Span& thisSpan = (*fSpans)[index];
904 const Span& nextSpan = (*fSpans)[index + step];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000905 if (thisSpan.fTiny || precisely_equal(thisSpan.fT, nextSpan.fT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000906 continue;
caryclark@google.comf839c032012-10-26 21:03:50 +0000907 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000908 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
909#if DEBUG_UNSORTABLE
910 if (fUnsortable) {
911 SkPoint iPt, ePt;
912 (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt);
913 (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt);
914 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
915 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
916 }
917#endif
918 return;
919#else
920 if ((*fSpans)[index].fUnsortableStart) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000921 fUnsortable = true;
922 return;
923 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000924#endif
caryclark@google.comf839c032012-10-26 21:03:50 +0000925 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000926#if 1
927#if DEBUG_UNSORTABLE
928 SkPoint iPt, ePt;
929 (*SegmentXYAtT[fVerb])(fPts, startT, &iPt);
930 (*SegmentXYAtT[fVerb])(fPts, endT, &ePt);
931 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
932 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
933#endif
934 fUnsortable = true;
935#endif
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000936 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000937
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000938 Segment* segment() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000939 return const_cast<Segment*>(fSegment);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000940 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000941
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000942 int sign() const {
caryclark@google.com495f8e42012-05-31 13:13:11 +0000943 return SkSign32(fStart - fEnd);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000944 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000945
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000946 const SkTDArray<Span>* spans() const {
947 return fSpans;
948 }
949
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000950 int start() const {
951 return fStart;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000952 }
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +0000953
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000954 bool unsortable() const {
955 return fUnsortable;
956 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000957
caryclark@google.comc899ad92012-08-23 15:24:42 +0000958#if DEBUG_ANGLE
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000959 const SkPoint* pts() const {
960 return fPts;
961 }
962
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000963 SkPath::Verb verb() const {
964 return fVerb;
965 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000966
caryclark@google.comc899ad92012-08-23 15:24:42 +0000967 void debugShow(const SkPoint& a) const {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000968 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
caryclark@google.comc899ad92012-08-23 15:24:42 +0000969 }
970#endif
971
caryclark@google.com15fa1382012-05-07 20:49:36 +0000972private:
caryclark@google.com235f56a2012-09-14 14:19:30 +0000973 const SkPoint* fPts;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000974 Cubic fCurvePart;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000975 SkPath::Verb fVerb;
976 double fSide;
977 LineParameters fTangent1;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000978 const SkTDArray<Span>* fSpans;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000979 const Segment* fSegment;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000980 int fStart;
981 int fEnd;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000982 bool fReversed;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000983 mutable bool fUnsortable; // this alone is editable by the less than operator
caryclark@google.com15fa1382012-05-07 20:49:36 +0000984};
985
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000986// Bounds, unlike Rect, does not consider a line to be empty.
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000987struct Bounds : public SkRect {
988 static bool Intersects(const Bounds& a, const Bounds& b) {
989 return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
990 a.fTop <= b.fBottom && b.fTop <= a.fBottom;
991 }
992
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000993 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
994 if (left < fLeft) {
995 fLeft = left;
996 }
997 if (top < fTop) {
998 fTop = top;
999 }
1000 if (right > fRight) {
1001 fRight = right;
1002 }
1003 if (bottom > fBottom) {
1004 fBottom = bottom;
1005 }
1006 }
1007
1008 void add(const Bounds& toAdd) {
1009 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
1010 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001011
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001012 void add(const SkPoint& pt) {
1013 if (pt.fX < fLeft) fLeft = pt.fX;
1014 if (pt.fY < fTop) fTop = pt.fY;
1015 if (pt.fX > fRight) fRight = pt.fX;
1016 if (pt.fY > fBottom) fBottom = pt.fY;
1017 }
1018
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001019 bool isEmpty() {
1020 return fLeft > fRight || fTop > fBottom
caryclark@google.com235f56a2012-09-14 14:19:30 +00001021 || (fLeft == fRight && fTop == fBottom)
caryclark@google.combeda3892013-02-07 13:13:41 +00001022 || sk_double_isnan(fLeft) || sk_double_isnan(fRight)
1023 || sk_double_isnan(fTop) || sk_double_isnan(fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001024 }
1025
1026 void setCubicBounds(const SkPoint a[4]) {
1027 _Rect dRect;
caryclark@google.com32546db2012-08-31 20:55:07 +00001028 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001029 dRect.setBounds(cubic);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001030 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1031 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001032 }
1033
1034 void setQuadBounds(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +00001035 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001036 _Rect dRect;
1037 dRect.setBounds(quad);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001038 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1039 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001040 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001041
1042 void setPoint(const SkPoint& pt) {
1043 fLeft = fRight = pt.fX;
1044 fTop = fBottom = pt.fY;
1045 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001046};
1047
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001048// OPTIMIZATION: does the following also work, and is it any faster?
1049// return outerWinding * innerWinding > 0
1050// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
caryclark@google.com2ddff932012-08-07 21:25:27 +00001051static bool useInnerWinding(int outerWinding, int innerWinding) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001052 SkASSERT(outerWinding != SK_MaxS32);
1053 SkASSERT(innerWinding != SK_MaxS32);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001054 int absOut = abs(outerWinding);
1055 int absIn = abs(innerWinding);
1056 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
caryclark@google.com5e0500f2013-02-20 12:51:37 +00001057#if 0 && DEBUG_WINDING
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001058 if (outerWinding * innerWinding < 0) {
caryclark@google.com24bec792012-08-20 12:43:57 +00001059 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
caryclark@google.com2ddff932012-08-07 21:25:27 +00001060 outerWinding, innerWinding, result ? "true" : "false");
caryclark@google.com2ddff932012-08-07 21:25:27 +00001061 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001062#endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001063 return result;
1064}
1065
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001066#define F (false) // discard the edge
1067#define T (true) // keep the edge
1068
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001069static const bool gUnaryActiveEdge[2][2] = {
1070// from=0 from=1
1071// to=0,1 to=0,1
1072 {F, T}, {T, F},
1073};
1074
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001075static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
1076// miFrom=0 miFrom=1
1077// miTo=0 miTo=1 miTo=0 miTo=1
1078// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
1079// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
1080 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
1081 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
1082 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
1083 {{{{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 +00001084};
1085
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001086#undef F
1087#undef T
caryclark@google.com235f56a2012-09-14 14:19:30 +00001088
caryclark@google.comf839c032012-10-26 21:03:50 +00001089// wrap path to keep track of whether the contour is initialized and non-empty
1090class PathWrapper {
1091public:
1092 PathWrapper(SkPath& path)
1093 : fPathPtr(&path)
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001094 , fCloses(0)
1095 , fMoves(0)
caryclark@google.comf839c032012-10-26 21:03:50 +00001096 {
1097 init();
1098 }
1099
1100 void close() {
1101 if (!fHasMove) {
1102 return;
1103 }
1104 bool callClose = isClosed();
1105 lineTo();
1106 if (fEmpty) {
1107 return;
1108 }
1109 if (callClose) {
1110 #if DEBUG_PATH_CONSTRUCTION
1111 SkDebugf("path.close();\n");
1112 #endif
1113 fPathPtr->close();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001114 fCloses++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001115 }
1116 init();
1117 }
1118
1119 void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
1120 lineTo();
1121 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001122 fDefer[1] = pt3;
1123 nudge();
1124 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001125#if DEBUG_PATH_CONSTRUCTION
1126 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001127 pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001128#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001129 fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001130 fEmpty = false;
1131 }
1132
1133 void deferredLine(const SkPoint& pt) {
1134 if (pt == fDefer[1]) {
1135 return;
1136 }
1137 if (changedSlopes(pt)) {
1138 lineTo();
1139 fDefer[0] = fDefer[1];
1140 }
1141 fDefer[1] = pt;
1142 }
1143
1144 void deferredMove(const SkPoint& pt) {
1145 fMoved = true;
1146 fHasMove = true;
1147 fEmpty = true;
1148 fDefer[0] = fDefer[1] = pt;
1149 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001150
caryclark@google.comf839c032012-10-26 21:03:50 +00001151 void deferredMoveLine(const SkPoint& pt) {
1152 if (!fHasMove) {
1153 deferredMove(pt);
1154 }
1155 deferredLine(pt);
1156 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001157
caryclark@google.comf839c032012-10-26 21:03:50 +00001158 bool hasMove() const {
1159 return fHasMove;
1160 }
1161
1162 void init() {
1163 fEmpty = true;
1164 fHasMove = false;
1165 fMoved = false;
1166 }
1167
1168 bool isClosed() const {
1169 return !fEmpty && fFirstPt == fDefer[1];
1170 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001171
caryclark@google.comf839c032012-10-26 21:03:50 +00001172 void lineTo() {
1173 if (fDefer[0] == fDefer[1]) {
1174 return;
1175 }
1176 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001177 nudge();
caryclark@google.comf839c032012-10-26 21:03:50 +00001178 fEmpty = false;
1179#if DEBUG_PATH_CONSTRUCTION
1180 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
1181#endif
1182 fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
1183 fDefer[0] = fDefer[1];
1184 }
1185
1186 const SkPath* nativePath() const {
1187 return fPathPtr;
1188 }
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +00001189
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001190 void nudge() {
1191 if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX)
1192 || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) {
1193 return;
1194 }
1195 fDefer[1] = fFirstPt;
1196 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001197
1198 void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
1199 lineTo();
1200 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001201 fDefer[1] = pt2;
1202 nudge();
1203 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001204#if DEBUG_PATH_CONSTRUCTION
1205 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001206 pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001207#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001208 fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001209 fEmpty = false;
1210 }
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00001211
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001212 bool someAssemblyRequired() const {
1213 return fCloses < fMoves;
1214 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001215
1216protected:
1217 bool changedSlopes(const SkPoint& pt) const {
1218 if (fDefer[0] == fDefer[1]) {
1219 return false;
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001220 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001221 SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
1222 SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
1223 SkScalar lineDx = pt.fX - fDefer[1].fX;
1224 SkScalar lineDy = pt.fY - fDefer[1].fY;
1225 return deferDx * lineDy != deferDy * lineDx;
1226 }
1227
1228 void moveTo() {
1229 if (!fMoved) {
1230 return;
1231 }
1232 fFirstPt = fDefer[0];
1233#if DEBUG_PATH_CONSTRUCTION
1234 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
1235#endif
1236 fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
1237 fMoved = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001238 fMoves++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001239 }
1240
1241private:
1242 SkPath* fPathPtr;
1243 SkPoint fDefer[2];
1244 SkPoint fFirstPt;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001245 int fCloses;
1246 int fMoves;
caryclark@google.comf839c032012-10-26 21:03:50 +00001247 bool fEmpty;
1248 bool fHasMove;
1249 bool fMoved;
1250};
1251
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001252class Segment {
1253public:
1254 Segment() {
1255#if DEBUG_DUMP
1256 fID = ++gSegmentID;
1257#endif
1258 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00001259
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001260 bool operator<(const Segment& rh) const {
1261 return fBounds.fTop < rh.fBounds.fTop;
1262 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001263
caryclark@google.com4eeda372012-12-06 21:47:48 +00001264 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001265 if (activeAngleInner(index, done, angles)) {
1266 return true;
1267 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001268 int lesser = index;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001269 while (--lesser >= 0 && equalPoints(index, lesser)) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001270 if (activeAngleOther(lesser, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001271 return true;
1272 }
1273 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001274 lesser = index;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001275 do {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001276 if (activeAngleOther(index, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001277 return true;
1278 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001279 } while (++index < fTs.count() && equalPoints(index, lesser));
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001280 return false;
1281 }
1282
caryclark@google.com4eeda372012-12-06 21:47:48 +00001283 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001284 Span* span = &fTs[index];
1285 Segment* other = span->fOther;
1286 int oIndex = span->fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001287 return other->activeAngleInner(oIndex, done, angles);
1288 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001289
caryclark@google.com4eeda372012-12-06 21:47:48 +00001290 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001291 int next = nextExactSpan(index, 1);
caryclark@google.com9764cc62012-07-12 19:29:45 +00001292 if (next > 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001293 Span& upSpan = fTs[index];
1294 if (upSpan.fWindValue || upSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001295 addAngle(angles, index, next);
caryclark@google.comf839c032012-10-26 21:03:50 +00001296 if (upSpan.fDone || upSpan.fUnsortableEnd) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001297 done++;
1298 } else if (upSpan.fWindSum != SK_MinS32) {
1299 return true;
1300 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001301 } else if (!upSpan.fDone) {
1302 upSpan.fDone = true;
1303 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001304 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001305 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001306 int prev = nextExactSpan(index, -1);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001307 // edge leading into junction
caryclark@google.com9764cc62012-07-12 19:29:45 +00001308 if (prev >= 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001309 Span& downSpan = fTs[prev];
1310 if (downSpan.fWindValue || downSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001311 addAngle(angles, index, prev);
1312 if (downSpan.fDone) {
1313 done++;
1314 } else if (downSpan.fWindSum != SK_MinS32) {
1315 return true;
1316 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001317 } else if (!downSpan.fDone) {
1318 downSpan.fDone = true;
1319 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001320 }
1321 }
1322 return false;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001323 }
1324
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001325 SkPoint activeLeftTop(bool onlySortable, int* firstT) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001326 SkASSERT(!done());
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001327 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001328 int count = fTs.count();
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001329 // see if either end is not done since we want smaller Y of the pair
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001330 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00001331 bool lastUnsortable = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001332 double lastT = -1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001333 for (int index = 0; index < count; ++index) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001334 const Span& span = fTs[index];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001335 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001336 goto next;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001337 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001338 if (span.fDone && lastDone) {
1339 goto next;
1340 }
1341 if (approximately_negative(span.fT - lastT)) {
1342 goto next;
1343 }
1344 {
1345 const SkPoint& xy = xyAtT(&span);
1346 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
1347 topPt = xy;
1348 if (firstT) {
1349 *firstT = index;
1350 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001351 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001352 if (fVerb != SkPath::kLine_Verb && !lastDone) {
1353 SkPoint curveTop = (*SegmentTop[fVerb])(fPts, lastT, span.fT);
1354 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
1355 && topPt.fX > curveTop.fX)) {
1356 topPt = curveTop;
1357 if (firstT) {
1358 *firstT = index;
1359 }
1360 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001361 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001362 lastT = span.fT;
caryclark@google.comf839c032012-10-26 21:03:50 +00001363 }
1364 next:
1365 lastDone = span.fDone;
1366 lastUnsortable = span.fUnsortableEnd;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001367 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001368 return topPt;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001369 }
1370
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001371 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
1372 int sumMiWinding = updateWinding(endIndex, index);
1373 int sumSuWinding = updateOppWinding(endIndex, index);
1374 if (fOperand) {
1375 SkTSwap<int>(sumMiWinding, sumSuWinding);
1376 }
1377 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1378 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001379 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001380 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001381
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001382 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00001383 int& sumMiWinding, int& sumSuWinding,
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001384 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
1385 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1386 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001387 bool miFrom;
1388 bool miTo;
1389 bool suFrom;
1390 bool suTo;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001391 if (operand()) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001392 miFrom = (oppMaxWinding & xorMiMask) != 0;
1393 miTo = (oppSumWinding & xorMiMask) != 0;
1394 suFrom = (maxWinding & xorSuMask) != 0;
1395 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001396 } else {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001397 miFrom = (maxWinding & xorMiMask) != 0;
1398 miTo = (sumWinding & xorMiMask) != 0;
1399 suFrom = (oppMaxWinding & xorSuMask) != 0;
1400 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001401 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001402 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
caryclark@google.combeda3892013-02-07 13:13:41 +00001403#if DEBUG_ACTIVE_OP
1404 SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__,
1405 kShapeOpStr[op], miFrom, miTo, suFrom, suTo, result);
1406#endif
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001407 SkASSERT(result != -1);
1408 return result;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001409 }
1410
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001411 bool activeWinding(int index, int endIndex) {
1412 int sumWinding = updateWinding(endIndex, index);
1413 int maxWinding;
1414 return activeWinding(index, endIndex, maxWinding, sumWinding);
1415 }
1416
1417 bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
1418 setUpWinding(index, endIndex, maxWinding, sumWinding);
1419 bool from = maxWinding != 0;
1420 bool to = sumWinding != 0;
1421 bool result = gUnaryActiveEdge[from][to];
1422 SkASSERT(result != -1);
1423 return result;
1424 }
1425
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001426 void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001427 SkASSERT(start != end);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001428 Angle* angle = angles.append();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001429#if DEBUG_ANGLE
caryclark@google.com31143cf2012-11-09 22:14:19 +00001430 if (angles.count() > 1 && !fTs[start].fTiny) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001431 SkPoint angle0Pt, newPt;
1432 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
1433 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
1434 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
caryclark@google.com6d0032a2013-01-04 19:41:13 +00001435 SkASSERT(AlmostEqualUlps(angle0Pt.fX, newPt.fX));
1436 SkASSERT(AlmostEqualUlps(angle0Pt.fY, newPt.fY));
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001437 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001438#endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001439 angle->set(fPts, fVerb, this, start, end, fTs);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001440 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001441
caryclark@google.com2ddff932012-08-07 21:25:27 +00001442 void addCancelOutsides(double tStart, double oStart, Segment& other,
caryclark@google.comcc905052012-07-25 20:59:42 +00001443 double oEnd) {
1444 int tIndex = -1;
1445 int tCount = fTs.count();
1446 int oIndex = -1;
1447 int oCount = other.fTs.count();
caryclark@google.comcc905052012-07-25 20:59:42 +00001448 do {
1449 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001450 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001451 int tIndexStart = tIndex;
1452 do {
1453 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001454 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001455 int oIndexStart = oIndex;
1456 double nextT;
1457 do {
1458 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001459 } while (nextT < 1 && approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001460 double oNextT;
1461 do {
1462 oNextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001463 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001464 // at this point, spans before and after are at:
1465 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1466 // if tIndexStart == 0, no prior span
1467 // if nextT == 1, no following span
rmistry@google.comd6176b02012-08-23 18:14:13 +00001468
caryclark@google.comcc905052012-07-25 20:59:42 +00001469 // advance the span with zero winding
1470 // if the following span exists (not past the end, non-zero winding)
1471 // connect the two edges
1472 if (!fTs[tIndexStart].fWindValue) {
1473 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1474 #if DEBUG_CONCIDENT
1475 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1476 __FUNCTION__, fID, other.fID, tIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001477 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
1478 xyAtT(tIndexStart).fY);
caryclark@google.comcc905052012-07-25 20:59:42 +00001479 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001480 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false,
1481 fTs[tIndexStart].fPt);
caryclark@google.comcc905052012-07-25 20:59:42 +00001482 }
1483 if (nextT < 1 && fTs[tIndex].fWindValue) {
1484 #if DEBUG_CONCIDENT
1485 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1486 __FUNCTION__, fID, other.fID, tIndex,
1487 fTs[tIndex].fT, xyAtT(tIndex).fX,
1488 xyAtT(tIndex).fY);
1489 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001490 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false, fTs[tIndex].fPt);
caryclark@google.comcc905052012-07-25 20:59:42 +00001491 }
1492 } else {
1493 SkASSERT(!other.fTs[oIndexStart].fWindValue);
1494 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1495 #if DEBUG_CONCIDENT
1496 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1497 __FUNCTION__, fID, other.fID, oIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001498 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
1499 other.xyAtT(oIndexStart).fY);
1500 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
caryclark@google.comcc905052012-07-25 20:59:42 +00001501 #endif
caryclark@google.comcc905052012-07-25 20:59:42 +00001502 }
1503 if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1504 #if DEBUG_CONCIDENT
1505 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1506 __FUNCTION__, fID, other.fID, oIndex,
1507 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1508 other.xyAtT(oIndex).fY);
1509 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1510 #endif
1511 }
1512 }
1513 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001514
caryclark@google.comcc905052012-07-25 20:59:42 +00001515 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1516 double oEnd) {
1517 // walk this to outsideTs[0]
1518 // walk other to outsideTs[1]
1519 // if either is > 0, add a pointer to the other, copying adjacent winding
1520 int tIndex = -1;
1521 int oIndex = -1;
1522 double tStart = outsideTs[0];
1523 double oStart = outsideTs[1];
1524 do {
1525 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001526 } while (!approximately_negative(tStart - fTs[tIndex].fT));
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001527 SkPoint ptStart = fTs[tIndex].fPt;
caryclark@google.comcc905052012-07-25 20:59:42 +00001528 do {
1529 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001530 } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001531 if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001532 addTPair(tStart, other, oStart, false, ptStart);
caryclark@google.comcc905052012-07-25 20:59:42 +00001533 }
1534 tStart = fTs[tIndex].fT;
1535 oStart = other.fTs[oIndex].fT;
1536 do {
1537 double nextT;
1538 do {
1539 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001540 } while (approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001541 tStart = nextT;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001542 ptStart = fTs[tIndex].fPt;
caryclark@google.comcc905052012-07-25 20:59:42 +00001543 do {
1544 nextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001545 } while (approximately_negative(nextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001546 oStart = nextT;
caryclark@google.com4eeda372012-12-06 21:47:48 +00001547 if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001548 break;
1549 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001550 addTPair(tStart, other, oStart, false, ptStart);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001551 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001552 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001553
caryclark@google.com4eeda372012-12-06 21:47:48 +00001554 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
1555 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001556 fBounds.setCubicBounds(pts);
1557 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001558
caryclark@google.comf839c032012-10-26 21:03:50 +00001559 /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001560 SkPoint edge[4];
caryclark@google.comf839c032012-10-26 21:03:50 +00001561 const SkPoint* ePtr;
1562 int lastT = fTs.count() - 1;
1563 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1564 ePtr = fPts;
1565 } else {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001566 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001567 subDivide(start, end, edge);
caryclark@google.comf839c032012-10-26 21:03:50 +00001568 ePtr = edge;
1569 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001570 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001571 bool reverse = ePtr == fPts && start != 0;
1572 if (reverse) {
1573 path.deferredMoveLine(ePtr[fVerb]);
1574 switch (fVerb) {
1575 case SkPath::kLine_Verb:
1576 path.deferredLine(ePtr[0]);
1577 break;
1578 case SkPath::kQuad_Verb:
1579 path.quadTo(ePtr[1], ePtr[0]);
1580 break;
1581 case SkPath::kCubic_Verb:
1582 path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1583 break;
1584 default:
1585 SkASSERT(0);
1586 }
1587 // return ePtr[0];
1588 } else {
1589 path.deferredMoveLine(ePtr[0]);
1590 switch (fVerb) {
1591 case SkPath::kLine_Verb:
1592 path.deferredLine(ePtr[1]);
1593 break;
1594 case SkPath::kQuad_Verb:
1595 path.quadTo(ePtr[1], ePtr[2]);
1596 break;
1597 case SkPath::kCubic_Verb:
1598 path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1599 break;
1600 default:
1601 SkASSERT(0);
1602 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001603 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001604 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001605 // return ePtr[fVerb];
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001606 }
1607
caryclark@google.com4eeda372012-12-06 21:47:48 +00001608 void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
1609 init(pts, SkPath::kLine_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001610 fBounds.set(pts, 2);
1611 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001612
caryclark@google.comf839c032012-10-26 21:03:50 +00001613#if 0
1614 const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001615 const SkPoint& pt = xyAtT(tIndex);
1616 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001617 path.deferredMove(pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001618 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00001619 return pt;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001620 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001621#endif
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001622
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001623 // add 2 to edge or out of range values to get T extremes
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001624 void addOtherT(int index, double otherT, int otherIndex) {
1625 Span& span = fTs[index];
caryclark@google.comf839c032012-10-26 21:03:50 +00001626 #if PIN_ADD_T
caryclark@google.com185c7c42012-10-19 18:26:24 +00001627 if (precisely_less_than_zero(otherT)) {
1628 otherT = 0;
1629 } else if (precisely_greater_than_one(otherT)) {
1630 otherT = 1;
1631 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001632 #endif
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001633 span.fOtherT = otherT;
1634 span.fOtherIndex = otherIndex;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001635 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001636
caryclark@google.com4eeda372012-12-06 21:47:48 +00001637 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
1638 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001639 fBounds.setQuadBounds(pts);
1640 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001641
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001642 // Defer all coincident edge processing until
1643 // after normal intersections have been computed
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001644
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001645// no need to be tricky; insert in normal T order
1646// resolve overlapping ts when considering coincidence later
1647
1648 // add non-coincident intersection. Resulting edges are sorted in T.
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001649 int addT(double newT, Segment* other, const SkPoint& pt) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001650 // FIXME: in the pathological case where there is a ton of intercepts,
1651 // binary search?
1652 int insertedAt = -1;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001653 size_t tCount = fTs.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00001654 #if PIN_ADD_T
caryclark@google.comc899ad92012-08-23 15:24:42 +00001655 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
caryclark@google.com185c7c42012-10-19 18:26:24 +00001656 if (precisely_less_than_zero(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001657 newT = 0;
caryclark@google.com185c7c42012-10-19 18:26:24 +00001658 } else if (precisely_greater_than_one(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001659 newT = 1;
1660 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001661 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001662 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001663 // OPTIMIZATION: if there are three or more identical Ts, then
1664 // the fourth and following could be further insertion-sorted so
1665 // that all the edges are clockwise or counterclockwise.
1666 // This could later limit segment tests to the two adjacent
1667 // neighbors, although it doesn't help with determining which
1668 // circular direction to go in.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001669 if (newT < fTs[index].fT) {
1670 insertedAt = index;
1671 break;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001672 }
1673 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001674 Span* span;
1675 if (insertedAt >= 0) {
1676 span = fTs.insert(insertedAt);
1677 } else {
1678 insertedAt = tCount;
1679 span = fTs.append();
1680 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001681 span->fT = newT;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001682 span->fOther = other;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001683 span->fPt = pt;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001684 span->fWindSum = SK_MinS32;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001685 span->fOppSum = SK_MinS32;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001686 span->fWindValue = 1;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001687 span->fOppValue = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00001688 span->fTiny = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001689 if ((span->fDone = newT == 1)) {
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00001690 ++fDoneSpans;
rmistry@google.comd6176b02012-08-23 18:14:13 +00001691 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001692 span->fUnsortableStart = false;
1693 span->fUnsortableEnd = false;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001694 int less = -1;
1695 while (&span[less + 1] - fTs.begin() > 0 && !span[less].fDone
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001696 && xyAtT(&span[less]) == xyAtT(span)) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001697 double tInterval = newT - span[less].fT;
1698 if (precisely_negative(tInterval)) {
1699 break;
1700 }
1701 if (fVerb == SkPath::kCubic_Verb) {
1702 double tMid = newT - tInterval / 2;
1703 _Point midPt;
1704 CubicXYAtT(fPts, tMid, &midPt);
1705 if (!midPt.approximatelyEqual(xyAtT(span))) {
1706 break;
1707 }
1708 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001709 span[less].fTiny = true;
1710 span[less].fDone = true;
1711 if (approximately_negative(newT - span[less].fT)) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00001712 if (approximately_greater_than_one(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001713 span[less].fUnsortableStart = true;
1714 span[less - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001715 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001716 if (approximately_less_than_zero(span[less].fT)) {
1717 span[less + 1].fUnsortableStart = true;
1718 span[less].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001719 }
1720 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001721 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001722 --less;
caryclark@google.comf839c032012-10-26 21:03:50 +00001723 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001724 int more = 1;
1725 while (fTs.end() - &span[more - 1] > 1 && !span[more - 1].fDone
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001726 && xyAtT(&span[more]) == xyAtT(span)) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001727 double tEndInterval = span[more].fT - newT;
1728 if (precisely_negative(tEndInterval)) {
1729 break;
1730 }
1731 if (fVerb == SkPath::kCubic_Verb) {
1732 double tMid = newT - tEndInterval / 2;
1733 _Point midEndPt;
1734 CubicXYAtT(fPts, tMid, &midEndPt);
1735 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
1736 break;
1737 }
1738 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001739 span[more - 1].fTiny = true;
1740 span[more - 1].fDone = true;
1741 if (approximately_negative(span[more].fT - newT)) {
1742 if (approximately_greater_than_one(span[more].fT)) {
1743 span[more + 1].fUnsortableStart = true;
1744 span[more].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001745 }
1746 if (approximately_less_than_zero(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001747 span[more].fUnsortableStart = true;
1748 span[more - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001749 }
1750 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001751 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001752 ++more;
caryclark@google.comf839c032012-10-26 21:03:50 +00001753 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001754 return insertedAt;
1755 }
1756
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001757 // set spans from start to end to decrement by one
1758 // note this walks other backwards
1759 // FIMXE: there's probably an edge case that can be constructed where
1760 // two span in one segment are separated by float epsilon on one span but
1761 // not the other, if one segment is very small. For this
1762 // case the counts asserted below may or may not be enough to separate the
caryclark@google.com2ddff932012-08-07 21:25:27 +00001763 // spans. Even if the counts work out, what if the spans aren't correctly
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001764 // sorted? It feels better in such a case to match the span's other span
1765 // pointer since both coincident segments must contain the same spans.
1766 void addTCancel(double startT, double endT, Segment& other,
1767 double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001768 SkASSERT(!approximately_negative(endT - startT));
1769 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00001770 bool binary = fOperand != other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001771 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001772 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001773 ++index;
1774 }
caryclark@google.comb9738012012-07-03 19:53:30 +00001775 int oIndex = other.fTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001776 while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001777 ;
caryclark@google.com59823f72012-08-09 18:17:47 +00001778 double tRatio = (oEndT - oStartT) / (endT - startT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001779 Span* test = &fTs[index];
1780 Span* oTest = &other.fTs[oIndex];
caryclark@google.com18063442012-07-25 12:05:18 +00001781 SkTDArray<double> outsideTs;
1782 SkTDArray<double> oOutsideTs;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001783 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001784 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
caryclark@google.comcc905052012-07-25 20:59:42 +00001785 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.com200c2112012-08-03 15:05:04 +00001786 double testT = test->fT;
1787 double oTestT = oTest->fT;
1788 Span* span = test;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001789 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001790 if (decrement) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001791 decrementSpan(span);
caryclark@google.com200c2112012-08-03 15:05:04 +00001792 } else if (track && span->fT < 1 && oTestT < 1) {
1793 TrackOutside(outsideTs, span->fT, oTestT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001794 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001795 span = &fTs[++index];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001796 } while (approximately_negative(span->fT - testT));
caryclark@google.com200c2112012-08-03 15:05:04 +00001797 Span* oSpan = oTest;
caryclark@google.com59823f72012-08-09 18:17:47 +00001798 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1799 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1800 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001801 while (approximately_negative(otherTMatchStart - oSpan->fT)
1802 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
caryclark@google.com03f97062012-08-21 13:13:52 +00001803 #ifdef SK_DEBUG
caryclark@google.com59823f72012-08-09 18:17:47 +00001804 SkASSERT(originalWindValue == oSpan->fWindValue);
caryclark@google.com03f97062012-08-21 13:13:52 +00001805 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001806 if (decrement) {
caryclark@google.com200c2112012-08-03 15:05:04 +00001807 other.decrementSpan(oSpan);
1808 } else if (track && oSpan->fT < 1 && testT < 1) {
1809 TrackOutside(oOutsideTs, oSpan->fT, testT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001810 }
1811 if (!oIndex) {
1812 break;
1813 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001814 oSpan = &other.fTs[--oIndex];
rmistry@google.comd6176b02012-08-23 18:14:13 +00001815 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001816 test = span;
1817 oTest = oSpan;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001818 } while (!approximately_negative(endT - test->fT));
1819 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
caryclark@google.com18063442012-07-25 12:05:18 +00001820 // FIXME: determine if canceled edges need outside ts added
caryclark@google.comcc905052012-07-25 20:59:42 +00001821 if (!done() && outsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001822 double tStart = outsideTs[0];
1823 double oStart = outsideTs[1];
1824 addCancelOutsides(tStart, oStart, other, oEndT);
1825 int count = outsideTs.count();
1826 if (count > 2) {
1827 double tStart = outsideTs[count - 2];
1828 double oStart = outsideTs[count - 1];
1829 addCancelOutsides(tStart, oStart, other, oEndT);
1830 }
caryclark@google.com18063442012-07-25 12:05:18 +00001831 }
caryclark@google.comcc905052012-07-25 20:59:42 +00001832 if (!other.done() && oOutsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001833 double tStart = oOutsideTs[0];
1834 double oStart = oOutsideTs[1];
1835 other.addCancelOutsides(tStart, oStart, *this, endT);
caryclark@google.com18063442012-07-25 12:05:18 +00001836 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001837 }
skia.committer@gmail.com15dd3002013-01-18 07:07:28 +00001838
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001839 int addUnsortableT(double newT, Segment* other, bool start, const SkPoint& pt) {
1840 int result = addT(newT, other, pt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00001841 Span* span = &fTs[result];
1842 if (start) {
1843 if (result > 0) {
1844 span[result - 1].fUnsortableEnd = true;
1845 }
1846 span[result].fUnsortableStart = true;
1847 } else {
1848 span[result].fUnsortableEnd = true;
1849 if (result + 1 < fTs.count()) {
1850 span[result + 1].fUnsortableStart = true;
1851 }
1852 }
1853 return result;
1854 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00001855
caryclark@google.com4eeda372012-12-06 21:47:48 +00001856 int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1857 SkTDArray<double>& outsideTs) {
1858 int oWindValue = oTest->fWindValue;
1859 int oOppValue = oTest->fOppValue;
1860 if (opp) {
1861 SkTSwap<int>(oWindValue, oOppValue);
1862 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001863 Span* const test = &fTs[index];
1864 Span* end = test;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001865 const double oStartT = oTest->fT;
1866 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001867 if (bumpSpan(end, oWindValue, oOppValue)) {
1868 TrackOutside(outsideTs, end->fT, oStartT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001869 }
1870 end = &fTs[++index];
1871 } while (approximately_negative(end->fT - test->fT));
1872 return index;
1873 }
1874
1875 // because of the order in which coincidences are resolved, this and other
1876 // may not have the same intermediate points. Compute the corresponding
1877 // intermediate T values (using this as the master, other as the follower)
1878 // and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com4eeda372012-12-06 21:47:48 +00001879 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1880 SkTDArray<double>& oOutsideTs) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001881 Span* const oTest = &fTs[oIndex];
1882 Span* oEnd = oTest;
1883 const double startT = test->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001884 const double oStartT = oTest->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001885 while (!approximately_negative(oEndT - oEnd->fT)
caryclark@google.com4eeda372012-12-06 21:47:48 +00001886 && approximately_negative(oEnd->fT - oStartT)) {
1887 zeroSpan(oEnd);
1888 TrackOutside(oOutsideTs, oEnd->fT, startT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001889 oEnd = &fTs[++oIndex];
1890 }
1891 return oIndex;
1892 }
1893
1894 // FIXME: need to test this case:
1895 // contourA has two segments that are coincident
1896 // contourB has two segments that are coincident in the same place
1897 // each ends up with +2/0 pairs for winding count
1898 // since logic below doesn't transfer count (only increments/decrements) can this be
1899 // resolved to +4/0 ?
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001900
1901 // set spans from start to end to increment the greater by one and decrement
1902 // the lesser
caryclark@google.com4eeda372012-12-06 21:47:48 +00001903 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001904 SkASSERT(!approximately_negative(endT - startT));
1905 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001906 bool opp = fOperand ^ other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001907 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001908 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001909 ++index;
1910 }
1911 int oIndex = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001912 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001913 ++oIndex;
1914 }
1915 Span* test = &fTs[index];
1916 Span* oTest = &other.fTs[oIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001917 SkTDArray<double> outsideTs;
1918 SkTDArray<double> oOutsideTs;
1919 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001920 // if either span has an opposite value and the operands don't match, resolve first
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001921 // SkASSERT(!test->fDone || !oTest->fDone);
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001922 if (test->fDone || oTest->fDone) {
1923 index = advanceCoincidentThis(oTest, opp, index);
1924 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
1925 } else {
1926 index = bumpCoincidentThis(oTest, opp, index, outsideTs);
1927 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
1928 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001929 test = &fTs[index];
1930 oTest = &other.fTs[oIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001931 } while (!approximately_negative(endT - test->fT));
1932 SkASSERT(approximately_negative(oTest->fT - oEndT));
1933 SkASSERT(approximately_negative(oEndT - oTest->fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001934 if (!done() && outsideTs.count()) {
1935 addCoinOutsides(outsideTs, other, oEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001936 }
1937 if (!other.done() && oOutsideTs.count()) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001938 other.addCoinOutsides(oOutsideTs, *this, endT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001939 }
1940 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001941
caryclark@google.comcc905052012-07-25 20:59:42 +00001942 // FIXME: this doesn't prevent the same span from being added twice
caryclark@google.comaa358312013-01-29 20:28:49 +00001943 // fix in caller, SkASSERT here?
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001944 void addTPair(double t, Segment& other, double otherT, bool borrowWind, const SkPoint& pt) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001945 int tCount = fTs.count();
1946 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1947 const Span& span = fTs[tIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001948 if (!approximately_negative(span.fT - t)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001949 break;
1950 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001951 if (approximately_negative(span.fT - t) && span.fOther == &other
1952 && approximately_equal(span.fOtherT, otherT)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001953#if DEBUG_ADD_T_PAIR
1954 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1955 __FUNCTION__, fID, t, other.fID, otherT);
1956#endif
1957 return;
1958 }
1959 }
caryclark@google.com47580692012-07-23 12:14:49 +00001960#if DEBUG_ADD_T_PAIR
1961 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1962 __FUNCTION__, fID, t, other.fID, otherT);
1963#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001964 int insertedAt = addT(t, &other, pt);
1965 int otherInsertedAt = other.addT(otherT, this, pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001966 addOtherT(insertedAt, otherT, otherInsertedAt);
caryclark@google.comb9738012012-07-03 19:53:30 +00001967 other.addOtherT(otherInsertedAt, t, insertedAt);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001968 matchWindingValue(insertedAt, t, borrowWind);
1969 other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001970 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001971
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001972 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001973 // add edge leading into junction
caryclark@google.com4eeda372012-12-06 21:47:48 +00001974 int min = SkMin32(end, start);
1975 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001976 addAngle(angles, end, start);
1977 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001978 // add edge leading away from junction
caryclark@google.com495f8e42012-05-31 13:13:11 +00001979 int step = SkSign32(end - start);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001980 int tIndex = nextExactSpan(end, step);
caryclark@google.com4eeda372012-12-06 21:47:48 +00001981 min = SkMin32(end, tIndex);
1982 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001983 addAngle(angles, end, tIndex);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001984 }
1985 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001986
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001987 int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
1988 Span* const test = &fTs[index];
1989 Span* end = test;
1990 do {
1991 end = &fTs[++index];
1992 } while (approximately_negative(end->fT - test->fT));
1993 return index;
1994 }
1995
1996 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
1997 Span* const oTest = &fTs[oIndex];
1998 Span* oEnd = oTest;
1999 const double oStartT = oTest->fT;
2000 while (!approximately_negative(oEndT - oEnd->fT)
2001 && approximately_negative(oEnd->fT - oStartT)) {
2002 oEnd = &fTs[++oIndex];
2003 }
2004 return oIndex;
2005 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00002006
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002007 bool betweenTs(int lesser, double testT, int greater) {
2008 if (lesser > greater) {
2009 SkTSwap<int>(lesser, greater);
2010 }
2011 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
2012 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002013
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002014 const Bounds& bounds() const {
2015 return fBounds;
2016 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002017
caryclark@google.com31143cf2012-11-09 22:14:19 +00002018 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002019 double referenceT = fTs[index].fT;
2020 int lesser = index;
caryclark@google.com31143cf2012-11-09 22:14:19 +00002021 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
2022 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00002023 buildAnglesInner(lesser, angles);
2024 }
2025 do {
2026 buildAnglesInner(index, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002027 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
2028 && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002029 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002030
2031 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
2032 Span* span = &fTs[index];
2033 Segment* other = span->fOther;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002034 // if there is only one live crossing, and no coincidence, continue
2035 // in the same direction
2036 // if there is coincidence, the only choice may be to reverse direction
2037 // find edge on either side of intersection
2038 int oIndex = span->fOtherIndex;
2039 // if done == -1, prior span has already been processed
2040 int step = 1;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002041 int next = other->nextExactSpan(oIndex, step);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002042 if (next < 0) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002043 step = -step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002044 next = other->nextExactSpan(oIndex, step);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002045 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002046 // add candidate into and away from junction
2047 other->addTwoAngles(next, oIndex, angles);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002048 }
2049
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002050 int computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002051 SkTDArray<Angle> angles;
2052 addTwoAngles(startIndex, endIndex, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002053 buildAngles(endIndex, angles, false);
caryclark@google.comd1688742012-09-18 20:08:37 +00002054 // OPTIMIZATION: check all angles to see if any have computed wind sum
2055 // before sorting (early exit if none)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002056 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002057 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002058#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002059 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002060#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002061 if (!sortable) {
2062 return SK_MinS32;
2063 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002064 int angleCount = angles.count();
2065 const Angle* angle;
2066 const Segment* base;
2067 int winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002068 int oWinding;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002069 int firstIndex = 0;
2070 do {
2071 angle = sorted[firstIndex];
2072 base = angle->segment();
2073 winding = base->windSum(angle);
2074 if (winding != SK_MinS32) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002075 oWinding = base->oppSum(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002076 break;
2077 }
2078 if (++firstIndex == angleCount) {
2079 return SK_MinS32;
2080 }
2081 } while (true);
2082 // turn winding into contourWinding
caryclark@google.com2ddff932012-08-07 21:25:27 +00002083 int spanWinding = base->spanSign(angle);
2084 bool inner = useInnerWinding(winding + spanWinding, winding);
2085 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00002086 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
caryclark@google.com59823f72012-08-09 18:17:47 +00002087 spanWinding, winding, angle->sign(), inner,
caryclark@google.com2ddff932012-08-07 21:25:27 +00002088 inner ? winding + spanWinding : winding);
2089 #endif
2090 if (inner) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002091 winding += spanWinding;
2092 }
2093 #if DEBUG_SORT
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002094 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002095 #endif
2096 int nextIndex = firstIndex + 1;
2097 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com2ddff932012-08-07 21:25:27 +00002098 winding -= base->spanSign(angle);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002099 oWinding -= base->oppSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002100 do {
2101 if (nextIndex == angleCount) {
2102 nextIndex = 0;
2103 }
2104 angle = sorted[nextIndex];
2105 Segment* segment = angle->segment();
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002106 bool opp = base->fOperand ^ segment->fOperand;
2107 int maxWinding, oMaxWinding;
2108 int spanSign = segment->spanSign(angle);
2109 int oppoSign = segment->oppSign(angle);
2110 if (opp) {
2111 oMaxWinding = oWinding;
2112 oWinding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002113 maxWinding = winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002114 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002115 winding -= oppoSign;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002116 }
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002117 } else {
2118 maxWinding = winding;
2119 winding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002120 oMaxWinding = oWinding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002121 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002122 oWinding -= oppoSign;
2123 }
2124 }
2125 if (segment->windSum(angle) == SK_MinS32) {
2126 if (opp) {
2127 if (useInnerWinding(oMaxWinding, oWinding)) {
2128 oMaxWinding = oWinding;
2129 }
2130 if (oppoSign && useInnerWinding(maxWinding, winding)) {
2131 maxWinding = winding;
2132 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002133 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002134 } else {
2135 if (useInnerWinding(maxWinding, winding)) {
2136 maxWinding = winding;
2137 }
2138 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
2139 oMaxWinding = oWinding;
2140 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002141 (void) segment->markAndChaseWinding(angle, maxWinding,
2142 binary ? oMaxWinding : 0);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002143 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002144 }
2145 } while (++nextIndex != lastIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002146 int minIndex = SkMin32(startIndex, endIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002147 return windSum(minIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002148 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002149
caryclark@google.com3586ece2012-12-27 18:46:58 +00002150 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
caryclark@google.com10227bf2012-12-28 22:10:41 +00002151 double mid, bool opp, bool current) const {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002152 SkScalar bottom = fBounds.fBottom;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002153 int bestTIndex = -1;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002154 if (bottom <= bestY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002155 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002156 }
2157 SkScalar top = fBounds.fTop;
2158 if (top >= basePt.fY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002159 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002160 }
2161 if (fBounds.fLeft > basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002162 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002163 }
2164 if (fBounds.fRight < basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002165 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002166 }
2167 if (fBounds.fLeft == fBounds.fRight) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002168 // if vertical, and directly above test point, wait for another one
caryclark@google.com6d0032a2013-01-04 19:41:13 +00002169 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002170 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002171 // intersect ray starting at basePt with edge
2172 Intersections intersections;
2173 // OPTIMIZE: use specialty function that intersects ray with curve,
2174 // returning t values only for curve (we don't care about t on ray)
2175 int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
2176 if (pts == 0 || (current && pts == 1)) {
2177 return bestTIndex;
2178 }
2179 if (current) {
2180 SkASSERT(pts > 1);
2181 int closestIdx = 0;
2182 double closest = fabs(intersections.fT[0][0] - mid);
2183 for (int idx = 1; idx < pts; ++idx) {
2184 double test = fabs(intersections.fT[0][idx] - mid);
2185 if (closest > test) {
2186 closestIdx = idx;
2187 closest = test;
2188 }
2189 }
2190 if (closestIdx < pts - 1) {
2191 intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
2192 }
2193 --pts;
2194 }
2195 double bestT = -1;
2196 for (int index = 0; index < pts; ++index) {
2197 double foundT = intersections.fT[0][index];
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002198 if (approximately_less_than_zero(foundT)
2199 || approximately_greater_than_one(foundT)) {
2200 continue;
2201 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002202 SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
2203 if (approximately_negative(testY - bestY)
2204 || approximately_negative(basePt.fY - testY)) {
caryclark@google.com47580692012-07-23 12:14:49 +00002205 continue;
2206 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002207 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002208 return SK_MinS32; // if the intersection is edge on, wait for another one
caryclark@google.com10227bf2012-12-28 22:10:41 +00002209 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002210 if (fVerb > SkPath::kLine_Verb) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002211 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
2212 if (approximately_zero(dx)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002213 return SK_MinS32; // hit vertical, wait for another one
caryclark@google.com3586ece2012-12-27 18:46:58 +00002214 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00002215 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002216 bestY = testY;
2217 bestT = foundT;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002218 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002219 if (bestT < 0) {
2220 return bestTIndex;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002221 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002222 SkASSERT(bestT >= 0);
2223 SkASSERT(bestT <= 1);
2224 int start;
2225 int end = 0;
2226 do {
2227 start = end;
2228 end = nextSpan(start, 1);
2229 } while (fTs[end].fT < bestT);
2230 // FIXME: see next candidate for a better pattern to find the next start/end pair
2231 while (start + 1 < end && fTs[start].fDone) {
2232 ++start;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002233 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002234 if (!isCanceled(start)) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002235 hitT = bestT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002236 bestTIndex = start;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002237 hitSomething = true;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002238 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002239 return bestTIndex;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002240 }
caryclark@google.com18063442012-07-25 12:05:18 +00002241
caryclark@google.com4eeda372012-12-06 21:47:48 +00002242 void decrementSpan(Span* span) {
caryclark@google.com18063442012-07-25 12:05:18 +00002243 SkASSERT(span->fWindValue > 0);
2244 if (--(span->fWindValue) == 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002245 if (!span->fOppValue && !span->fDone) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002246 span->fDone = true;
2247 ++fDoneSpans;
2248 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002249 }
2250 }
2251
2252 bool bumpSpan(Span* span, int windDelta, int oppDelta) {
2253 SkASSERT(!span->fDone);
2254 span->fWindValue += windDelta;
2255 SkASSERT(span->fWindValue >= 0);
2256 span->fOppValue += oppDelta;
2257 SkASSERT(span->fOppValue >= 0);
2258 if (fXor) {
2259 span->fWindValue &= 1;
2260 }
2261 if (fOppXor) {
2262 span->fOppValue &= 1;
2263 }
2264 if (!span->fWindValue && !span->fOppValue) {
2265 span->fDone = true;
2266 ++fDoneSpans;
caryclark@google.com18063442012-07-25 12:05:18 +00002267 return true;
2268 }
2269 return false;
2270 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002271
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002272 // OPTIMIZE
2273 // when the edges are initially walked, they don't automatically get the prior and next
2274 // 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 +00002275 // and would additionally remove the need for similar checks in condition edges. It would
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002276 // also allow intersection code to assume end of segment intersections (maybe?)
2277 bool complete() const {
2278 int count = fTs.count();
2279 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
2280 }
caryclark@google.com18063442012-07-25 12:05:18 +00002281
caryclark@google.com15fa1382012-05-07 20:49:36 +00002282 bool done() const {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002283 SkASSERT(fDoneSpans <= fTs.count());
2284 return fDoneSpans == fTs.count();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002285 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002286
caryclark@google.comf839c032012-10-26 21:03:50 +00002287 bool done(int min) const {
2288 return fTs[min].fDone;
2289 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002290
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002291 bool done(const Angle* angle) const {
2292 return done(SkMin32(angle->start(), angle->end()));
caryclark@google.com47580692012-07-23 12:14:49 +00002293 }
skia.committer@gmail.com044679e2013-02-15 07:16:57 +00002294
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002295 SkPoint dxdy(int index) const {
2296 return (*SegmentDXDYAtT[fVerb])(fPts, fTs[index].fT);
2297 }
2298
2299 SkScalar dy(int index) const {
2300 return (*SegmentDYAtT[fVerb])(fPts, fTs[index].fT);
2301 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00002302
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002303 bool equalPoints(int greaterTIndex, int lesserTIndex) {
2304 SkASSERT(greaterTIndex >= lesserTIndex);
2305 double greaterT = fTs[greaterTIndex].fT;
2306 double lesserT = fTs[lesserTIndex].fT;
2307 if (greaterT == lesserT) {
2308 return true;
2309 }
2310 if (!approximately_negative(greaterT - lesserT)) {
2311 return false;
2312 }
2313 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2314 }
2315
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002316 /*
2317 The M and S variable name parts stand for the operators.
2318 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2319 Su stands for Subtrahend
2320 The Opp variable name part designates that the value is for the Opposite operator.
2321 Opposite values result from combining coincident spans.
2322 */
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002323
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002324 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2325 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002326 const int startIndex = nextStart;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002327 const int endIndex = nextEnd;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002328 SkASSERT(startIndex != endIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002329 const int count = fTs.count();
2330 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2331 const int step = SkSign32(endIndex - startIndex);
2332 const int end = nextExactSpan(startIndex, step);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002333 SkASSERT(end >= 0);
2334 Span* endSpan = &fTs[end];
2335 Segment* other;
2336 if (isSimple(end)) {
2337 // mark the smaller of startIndex, endIndex done, and all adjacent
2338 // spans with the same T value (but not 'other' spans)
2339 #if DEBUG_WINDING
2340 SkDebugf("%s simple\n", __FUNCTION__);
2341 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002342 int min = SkMin32(startIndex, endIndex);
2343 if (fTs[min].fDone) {
2344 return NULL;
2345 }
2346 markDoneBinary(min);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002347 other = endSpan->fOther;
2348 nextStart = endSpan->fOtherIndex;
2349 double startT = other->fTs[nextStart].fT;
2350 nextEnd = nextStart;
2351 do {
2352 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002353 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002354 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002355 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2356 return other;
2357 }
2358 // more than one viable candidate -- measure angles to find best
2359 SkTDArray<Angle> angles;
2360 SkASSERT(startIndex - endIndex != 0);
2361 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2362 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002363 buildAngles(end, angles, true);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002364 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002365 bool sortable = SortAngles(angles, sorted);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002366 int angleCount = angles.count();
2367 int firstIndex = findStartingEdge(sorted, startIndex, end);
2368 SkASSERT(firstIndex >= 0);
2369 #if DEBUG_SORT
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002370 debugShowSort(__FUNCTION__, sorted, firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002371 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002372 if (!sortable) {
2373 unsortable = true;
2374 return NULL;
2375 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002376 SkASSERT(sorted[firstIndex]->segment() == this);
2377 #if DEBUG_WINDING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002378 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2379 sorted[firstIndex]->sign());
caryclark@google.com235f56a2012-09-14 14:19:30 +00002380 #endif
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002381 int sumMiWinding = updateWinding(endIndex, startIndex);
2382 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2383 if (operand()) {
2384 SkTSwap<int>(sumMiWinding, sumSuWinding);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002385 }
2386 int nextIndex = firstIndex + 1;
2387 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2388 const Angle* foundAngle = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002389 bool foundDone = false;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002390 // iterate through the angle, and compute everyone's winding
caryclark@google.com235f56a2012-09-14 14:19:30 +00002391 Segment* nextSegment;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002392 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002393 SkASSERT(nextIndex != firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002394 if (nextIndex == angleCount) {
2395 nextIndex = 0;
2396 }
2397 const Angle* nextAngle = sorted[nextIndex];
2398 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002399 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2400 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2401 nextAngle->end(), op, sumMiWinding, sumSuWinding,
2402 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
2403 if (activeAngle && (!foundAngle || foundDone)) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002404 foundAngle = nextAngle;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002405 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002406 }
2407 if (nextSegment->done()) {
2408 continue;
2409 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002410 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2411 continue;
2412 }
2413 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2414 oppSumWinding, activeAngle, nextAngle);
2415 if (last) {
2416 *chase.append() = last;
2417#if DEBUG_WINDING
2418 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2419 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2420#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002421 }
2422 } while (++nextIndex != lastIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002423 markDoneBinary(SkMin32(startIndex, endIndex));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002424 if (!foundAngle) {
2425 return NULL;
2426 }
2427 nextStart = foundAngle->start();
2428 nextEnd = foundAngle->end();
2429 nextSegment = foundAngle->segment();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002430
caryclark@google.com235f56a2012-09-14 14:19:30 +00002431 #if DEBUG_WINDING
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002432 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2433 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002434 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002435 return nextSegment;
2436 }
caryclark@google.com47580692012-07-23 12:14:49 +00002437
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002438 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2439 bool& unsortable) {
2440 const int startIndex = nextStart;
2441 const int endIndex = nextEnd;
2442 SkASSERT(startIndex != endIndex);
2443 const int count = fTs.count();
2444 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2445 const int step = SkSign32(endIndex - startIndex);
2446 const int end = nextExactSpan(startIndex, step);
2447 SkASSERT(end >= 0);
2448 Span* endSpan = &fTs[end];
2449 Segment* other;
2450 if (isSimple(end)) {
2451 // mark the smaller of startIndex, endIndex done, and all adjacent
2452 // spans with the same T value (but not 'other' spans)
2453 #if DEBUG_WINDING
2454 SkDebugf("%s simple\n", __FUNCTION__);
2455 #endif
2456 int min = SkMin32(startIndex, endIndex);
2457 if (fTs[min].fDone) {
2458 return NULL;
2459 }
2460 markDoneUnary(min);
2461 other = endSpan->fOther;
2462 nextStart = endSpan->fOtherIndex;
2463 double startT = other->fTs[nextStart].fT;
2464 nextEnd = nextStart;
2465 do {
2466 nextEnd += step;
2467 }
2468 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2469 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2470 return other;
2471 }
2472 // more than one viable candidate -- measure angles to find best
2473 SkTDArray<Angle> angles;
2474 SkASSERT(startIndex - endIndex != 0);
2475 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2476 addTwoAngles(startIndex, end, angles);
2477 buildAngles(end, angles, true);
2478 SkTDArray<Angle*> sorted;
2479 bool sortable = SortAngles(angles, sorted);
2480 int angleCount = angles.count();
2481 int firstIndex = findStartingEdge(sorted, startIndex, end);
2482 SkASSERT(firstIndex >= 0);
2483 #if DEBUG_SORT
2484 debugShowSort(__FUNCTION__, sorted, firstIndex);
2485 #endif
2486 if (!sortable) {
2487 unsortable = true;
2488 return NULL;
2489 }
2490 SkASSERT(sorted[firstIndex]->segment() == this);
2491 #if DEBUG_WINDING
2492 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2493 sorted[firstIndex]->sign());
2494 #endif
2495 int sumWinding = updateWinding(endIndex, startIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002496 int nextIndex = firstIndex + 1;
2497 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2498 const Angle* foundAngle = NULL;
2499 bool foundDone = false;
2500 // iterate through the angle, and compute everyone's winding
2501 Segment* nextSegment;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002502 int activeCount = 0;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002503 do {
2504 SkASSERT(nextIndex != firstIndex);
2505 if (nextIndex == angleCount) {
2506 nextIndex = 0;
2507 }
2508 const Angle* nextAngle = sorted[nextIndex];
2509 nextSegment = nextAngle->segment();
2510 int maxWinding;
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00002511 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002512 maxWinding, sumWinding);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002513 if (activeAngle) {
2514 ++activeCount;
2515 if (!foundAngle || (foundDone && activeCount & 1)) {
2516 if (nextSegment->tiny(nextAngle)) {
2517 unsortable = true;
2518 return NULL;
2519 }
2520 foundAngle = nextAngle;
2521 foundDone = nextSegment->done(nextAngle);
2522 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002523 }
2524 if (nextSegment->done()) {
2525 continue;
2526 }
2527 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2528 continue;
2529 }
2530 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2531 if (last) {
2532 *chase.append() = last;
2533#if DEBUG_WINDING
2534 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2535 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2536#endif
2537 }
2538 } while (++nextIndex != lastIndex);
2539 markDoneUnary(SkMin32(startIndex, endIndex));
2540 if (!foundAngle) {
2541 return NULL;
2542 }
2543 nextStart = foundAngle->start();
2544 nextEnd = foundAngle->end();
2545 nextSegment = foundAngle->segment();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002546 #if DEBUG_WINDING
2547 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2548 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2549 #endif
2550 return nextSegment;
2551 }
2552
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002553 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002554 const int startIndex = nextStart;
2555 const int endIndex = nextEnd;
2556 SkASSERT(startIndex != endIndex);
2557 int count = fTs.count();
2558 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2559 : startIndex > 0);
2560 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002561 int end = nextExactSpan(startIndex, step);
caryclark@google.com24bec792012-08-20 12:43:57 +00002562 SkASSERT(end >= 0);
2563 Span* endSpan = &fTs[end];
2564 Segment* other;
caryclark@google.com24bec792012-08-20 12:43:57 +00002565 if (isSimple(end)) {
2566 #if DEBUG_WINDING
2567 SkDebugf("%s simple\n", __FUNCTION__);
2568 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002569 int min = SkMin32(startIndex, endIndex);
2570 if (fTs[min].fDone) {
2571 return NULL;
2572 }
2573 markDone(min, 1);
caryclark@google.com24bec792012-08-20 12:43:57 +00002574 other = endSpan->fOther;
2575 nextStart = endSpan->fOtherIndex;
2576 double startT = other->fTs[nextStart].fT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002577 #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 +00002578 SkDEBUGCODE(bool firstLoop = true;)
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002579 if ((approximately_less_than_zero(startT) && step < 0)
2580 || (approximately_greater_than_one(startT) && step > 0)) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002581 step = -step;
2582 SkDEBUGCODE(firstLoop = false;)
2583 }
2584 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002585 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002586 nextEnd = nextStart;
2587 do {
2588 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002589 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002590 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002591 #if 01
caryclark@google.com24bec792012-08-20 12:43:57 +00002592 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2593 break;
2594 }
caryclark@google.com03f97062012-08-21 13:13:52 +00002595 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00002596 SkASSERT(firstLoop);
caryclark@google.com03f97062012-08-21 13:13:52 +00002597 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002598 SkDEBUGCODE(firstLoop = false;)
2599 step = -step;
2600 } while (true);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002601 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002602 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2603 return other;
2604 }
2605 SkTDArray<Angle> angles;
2606 SkASSERT(startIndex - endIndex != 0);
2607 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2608 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002609 buildAngles(end, angles, false);
caryclark@google.com24bec792012-08-20 12:43:57 +00002610 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002611 bool sortable = SortAngles(angles, sorted);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002612 if (!sortable) {
2613 unsortable = true;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002614 #if DEBUG_SORT
2615 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
2616 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002617 return NULL;
2618 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002619 int angleCount = angles.count();
2620 int firstIndex = findStartingEdge(sorted, startIndex, end);
2621 SkASSERT(firstIndex >= 0);
2622 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002623 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
caryclark@google.com24bec792012-08-20 12:43:57 +00002624 #endif
2625 SkASSERT(sorted[firstIndex]->segment() == this);
2626 int nextIndex = firstIndex + 1;
2627 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002628 const Angle* foundAngle = NULL;
2629 bool foundDone = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002630 Segment* nextSegment;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002631 int activeCount = 0;
caryclark@google.com24bec792012-08-20 12:43:57 +00002632 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002633 SkASSERT(nextIndex != firstIndex);
caryclark@google.com24bec792012-08-20 12:43:57 +00002634 if (nextIndex == angleCount) {
2635 nextIndex = 0;
2636 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002637 const Angle* nextAngle = sorted[nextIndex];
caryclark@google.com24bec792012-08-20 12:43:57 +00002638 nextSegment = nextAngle->segment();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002639 ++activeCount;
2640 if (!foundAngle || (foundDone && activeCount & 1)) {
2641 if (nextSegment->tiny(nextAngle)) {
2642 unsortable = true;
2643 return NULL;
2644 }
2645 foundAngle = nextAngle;
2646 foundDone = nextSegment->done(nextAngle);
2647 }
2648 if (nextSegment->done()) {
2649 continue;
caryclark@google.com24bec792012-08-20 12:43:57 +00002650 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002651 } while (++nextIndex != lastIndex);
2652 markDone(SkMin32(startIndex, endIndex), 1);
2653 if (!foundAngle) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002654 return NULL;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002655 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002656 nextStart = foundAngle->start();
2657 nextEnd = foundAngle->end();
2658 nextSegment = foundAngle->segment();
2659 #if DEBUG_WINDING
2660 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2661 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2662 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002663 return nextSegment;
2664 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002665
2666 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2667 int angleCount = sorted.count();
2668 int firstIndex = -1;
2669 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2670 const Angle* angle = sorted[angleIndex];
2671 if (angle->segment() == this && angle->start() == end &&
2672 angle->end() == start) {
2673 firstIndex = angleIndex;
2674 break;
2675 }
2676 }
2677 return firstIndex;
2678 }
2679
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002680 // FIXME: this is tricky code; needs its own unit test
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002681 // note that fOtherIndex isn't computed yet, so it can't be used here
caryclark@google.com4eeda372012-12-06 21:47:48 +00002682 void findTooCloseToCall() {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002683 int count = fTs.count();
2684 if (count < 3) { // require t=0, x, 1 at minimum
2685 return;
2686 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002687 int matchIndex = 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002688 int moCount;
2689 Span* match;
2690 Segment* mOther;
2691 do {
2692 match = &fTs[matchIndex];
2693 mOther = match->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002694 // FIXME: allow quads, cubics to be near coincident?
2695 if (mOther->fVerb == SkPath::kLine_Verb) {
2696 moCount = mOther->fTs.count();
2697 if (moCount >= 3) {
2698 break;
2699 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002700 }
2701 if (++matchIndex >= count) {
2702 return;
2703 }
2704 } while (true); // require t=0, x, 1 at minimum
caryclark@google.com15fa1382012-05-07 20:49:36 +00002705 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002706 const SkPoint* matchPt = &xyAtT(match);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002707 // look for a pair of nearby T values that map to the same (x,y) value
2708 // if found, see if the pair of other segments share a common point. If
2709 // so, the span from here to there is coincident.
caryclark@google.com15fa1382012-05-07 20:49:36 +00002710 for (int index = matchIndex + 1; index < count; ++index) {
2711 Span* test = &fTs[index];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002712 if (test->fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002713 continue;
2714 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002715 Segment* tOther = test->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002716 if (tOther->fVerb != SkPath::kLine_Verb) {
2717 continue; // FIXME: allow quads, cubics to be near coincident?
2718 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002719 int toCount = tOther->fTs.count();
2720 if (toCount < 3) { // require t=0, x, 1 at minimum
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002721 continue;
2722 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002723 const SkPoint* testPt = &xyAtT(test);
2724 if (*matchPt != *testPt) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002725 matchIndex = index;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002726 moCount = toCount;
2727 match = test;
2728 mOther = tOther;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002729 matchPt = testPt;
2730 continue;
2731 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002732 int moStart = -1;
2733 int moEnd = -1;
2734 double moStartT, moEndT;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002735 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002736 Span& moSpan = mOther->fTs[moIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002737 if (moSpan.fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002738 continue;
2739 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002740 if (moSpan.fOther == this) {
2741 if (moSpan.fOtherT == match->fT) {
2742 moStart = moIndex;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002743 moStartT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002744 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002745 continue;
2746 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002747 if (moSpan.fOther == tOther) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002748 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002749 moStart = -1;
2750 break;
2751 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002752 SkASSERT(moEnd == -1);
2753 moEnd = moIndex;
2754 moEndT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002755 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002756 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002757 if (moStart < 0 || moEnd < 0) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002758 continue;
2759 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002760 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002761 if (approximately_equal(moStartT, moEndT)) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002762 continue;
2763 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002764 int toStart = -1;
2765 int toEnd = -1;
2766 double toStartT, toEndT;
2767 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2768 Span& toSpan = tOther->fTs[toIndex];
caryclark@google.comc899ad92012-08-23 15:24:42 +00002769 if (toSpan.fDone) {
2770 continue;
2771 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002772 if (toSpan.fOther == this) {
2773 if (toSpan.fOtherT == test->fT) {
2774 toStart = toIndex;
2775 toStartT = toSpan.fT;
2776 }
2777 continue;
2778 }
2779 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002780 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002781 moStart = -1;
2782 break;
2783 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002784 SkASSERT(toEnd == -1);
2785 toEnd = toIndex;
2786 toEndT = toSpan.fT;
2787 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002788 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002789 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2790 if (toStart <= 0 || toEnd <= 0) {
2791 continue;
2792 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002793 if (approximately_equal(toStartT, toEndT)) {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002794 continue;
2795 }
2796 // test to see if the segment between there and here is linear
2797 if (!mOther->isLinear(moStart, moEnd)
2798 || !tOther->isLinear(toStart, toEnd)) {
2799 continue;
2800 }
caryclark@google.comc899ad92012-08-23 15:24:42 +00002801 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002802 if (flipped) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002803 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002804 } else {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002805 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002806 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002807 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002808 }
2809
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002810 // FIXME: either:
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002811 // a) mark spans with either end unsortable as done, or
2812 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2813 // when encountering an unsortable span
2814
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002815 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2816 // and use more concise logic like the old edge walker code?
2817 // FIXME: this needs to deal with coincident edges
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002818 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002819 // iterate through T intersections and return topmost
2820 // topmost tangent from y-min to first pt is closer to horizontal
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002821 SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002822 int firstT = -1;
caryclark@google.comd0a19eb2013-02-19 12:49:33 +00002823 /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002824 SkASSERT(firstT >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002825 // sort the edges to find the leftmost
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002826 int step = 1;
2827 int end = nextSpan(firstT, step);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002828 if (end == -1) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002829 step = -1;
2830 end = nextSpan(firstT, step);
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00002831 SkASSERT(end != -1);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002832 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002833 // if the topmost T is not on end, or is three-way or more, find left
2834 // look for left-ness from tLeft to firstT (matching y of other)
2835 SkTDArray<Angle> angles;
2836 SkASSERT(firstT - end != 0);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002837 addTwoAngles(end, firstT, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002838 buildAngles(firstT, angles, true);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002839 SkTDArray<Angle*> sorted;
caryclark@google.comf839c032012-10-26 21:03:50 +00002840 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002841 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002842 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002843 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002844 if (onlySortable && !sortable) {
2845 unsortable = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002846 return NULL;
2847 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002848 // skip edges that have already been processed
2849 firstT = -1;
2850 Segment* leftSegment;
2851 do {
2852 const Angle* angle = sorted[++firstT];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002853 SkASSERT(!onlySortable || !angle->unsortable());
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002854 leftSegment = angle->segment();
2855 tIndex = angle->end();
2856 endIndex = angle->start();
2857 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002858 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002859 bool bumpsUp = leftSegment->bumpsUp(tIndex, endIndex);
2860 SkPoint xyE = leftSegment->xyAtT(endIndex);
2861 SkPoint xyS = leftSegment->xyAtT(tIndex);
caryclark@google.com47d73da2013-02-17 01:41:25 +00002862 SkPoint dxyE = leftSegment->dxdy(endIndex);
2863 SkPoint dxyS = leftSegment->dxdy(tIndex);
2864 double cross = dxyE.cross(dxyS);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00002865 bool bumpCheck = bumpsUp && xyE.fY < xyS.fY && dxyE.fX < 0;
caryclark@google.com47d73da2013-02-17 01:41:25 +00002866 #if DEBUG_SWAP_TOP
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002867 SkDebugf("%s xyE=(%1.9g,%1.9g) xyS=(%1.9g,%1.9g)\n", __FUNCTION__,
2868 xyE.fX, xyE.fY, xyS.fX, xyS.fY);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00002869 SkDebugf("%s dxyE=(%1.9g,%1.9g) dxyS=(%1.9g,%1.9g) cross=%1.9g bumpsUp=%s\n",
2870 __FUNCTION__,
2871 dxyE.fX, dxyE.fY, dxyS.fX, dxyS.fY, cross, bumpsUp ? "true" : "false");
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002872 if ((cross > 0) ^ bumpCheck) {
2873 leftSegment->bumpsUp(tIndex, endIndex);
2874 SkDebugf("%s cross bump disagree\n", __FUNCTION__);
2875 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00002876 #endif
2877 if (cross > 0 || bumpCheck) {
caryclark@google.com47d73da2013-02-17 01:41:25 +00002878 #if DEBUG_SWAP_TOP
2879 SkDebugf("%s swap\n", __FUNCTION__);
2880 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002881 SkTSwap(tIndex, endIndex);
2882 }
2883 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002884 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002885 return leftSegment;
2886 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002887
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002888 // FIXME: not crazy about this
2889 // when the intersections are performed, the other index is into an
2890 // incomplete array. as the array grows, the indices become incorrect
2891 // while the following fixes the indices up again, it isn't smart about
2892 // skipping segments whose indices are already correct
2893 // assuming we leave the code that wrote the index in the first place
2894 void fixOtherTIndex() {
2895 int iCount = fTs.count();
2896 for (int i = 0; i < iCount; ++i) {
2897 Span& iSpan = fTs[i];
2898 double oT = iSpan.fOtherT;
2899 Segment* other = iSpan.fOther;
2900 int oCount = other->fTs.count();
2901 for (int o = 0; o < oCount; ++o) {
2902 Span& oSpan = other->fTs[o];
2903 if (oT == oSpan.fT && this == oSpan.fOther) {
2904 iSpan.fOtherIndex = o;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002905 break;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002906 }
2907 }
2908 }
2909 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002910
caryclark@google.com4eeda372012-12-06 21:47:48 +00002911 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002912 fDoneSpans = 0;
2913 fOperand = operand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00002914 fXor = evenOdd;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002915 fPts = pts;
2916 fVerb = verb;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002917 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00002918
caryclark@google.com3586ece2012-12-27 18:46:58 +00002919 void initWinding(int start, int end) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002920 int local = spanSign(start, end);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002921 int oppLocal = oppSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002922 (void) markAndChaseWinding(start, end, local, oppLocal);
caryclark@google.com73ca6242013-01-17 21:02:47 +00002923 // OPTIMIZATION: the reverse mark and chase could skip the first marking
2924 (void) markAndChaseWinding(end, start, local, oppLocal);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002925 }
2926
caryclark@google.com3586ece2012-12-27 18:46:58 +00002927 void initWinding(int start, int end, int winding, int oppWinding) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002928 int local = spanSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002929 if (local * winding >= 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002930 winding += local;
2931 }
2932 int oppLocal = oppSign(start, end);
2933 if (oppLocal * oppWinding >= 0) {
2934 oppWinding += oppLocal;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002935 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002936 (void) markAndChaseWinding(start, end, winding, oppWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002937 }
2938
caryclark@google.com3586ece2012-12-27 18:46:58 +00002939/*
2940when we start with a vertical intersect, we try to use the dx to determine if the edge is to
2941the 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 +00002942sign or not. However, this isn't enough.
2943If 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 +00002944If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
2945from 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 +00002946the same winding is shared by both.
caryclark@google.com3586ece2012-12-27 18:46:58 +00002947*/
2948 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
2949 SkScalar hitOppDx) {
2950 SkASSERT(hitDx || !winding);
2951 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
2952 SkASSERT(dx);
2953 int windVal = windValue(SkMin32(start, end));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002954 #if DEBUG_WINDING_AT_T
2955 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
2956 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
2957 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002958 if (!winding) {
2959 winding = dx < 0 ? windVal : -windVal;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002960 } else if (winding * dx < 0) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00002961 int sideWind = winding + (dx < 0 ? windVal : -windVal);
2962 if (abs(winding) < abs(sideWind)) {
2963 winding = sideWind;
2964 }
2965 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002966 #if DEBUG_WINDING_AT_T
2967 SkDebugf(" winding=%d\n", winding);
2968 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002969 int oppLocal = oppSign(start, end);
2970 SkASSERT(hitOppDx || !oppWind || !oppLocal);
2971 int oppWindVal = oppValue(SkMin32(start, end));
2972 if (!oppWind) {
2973 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
2974 } else if (hitOppDx * dx >= 0) {
2975 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
2976 if (abs(oppWind) < abs(oppSideWind)) {
2977 oppWind = oppSideWind;
2978 }
2979 }
2980 (void) markAndChaseWinding(start, end, winding, oppWind);
2981 }
2982
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002983 bool intersected() const {
2984 return fTs.count() > 0;
2985 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002986
caryclark@google.com10227bf2012-12-28 22:10:41 +00002987 bool isCanceled(int tIndex) const {
2988 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
2989 }
2990
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002991 bool isConnected(int startIndex, int endIndex) const {
2992 return fTs[startIndex].fWindSum != SK_MinS32
2993 || fTs[endIndex].fWindSum != SK_MinS32;
2994 }
2995
caryclark@google.com235f56a2012-09-14 14:19:30 +00002996 bool isHorizontal() const {
2997 return fBounds.fTop == fBounds.fBottom;
2998 }
2999
caryclark@google.com15fa1382012-05-07 20:49:36 +00003000 bool isLinear(int start, int end) const {
3001 if (fVerb == SkPath::kLine_Verb) {
3002 return true;
3003 }
3004 if (fVerb == SkPath::kQuad_Verb) {
3005 SkPoint qPart[3];
3006 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
3007 return QuadIsLinear(qPart);
3008 } else {
3009 SkASSERT(fVerb == SkPath::kCubic_Verb);
3010 SkPoint cPart[4];
3011 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
3012 return CubicIsLinear(cPart);
3013 }
3014 }
caryclark@google.comb9738012012-07-03 19:53:30 +00003015
3016 // OPTIMIZE: successive calls could start were the last leaves off
3017 // or calls could specialize to walk forwards or backwards
3018 bool isMissing(double startT) const {
3019 size_t tCount = fTs.count();
3020 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003021 if (approximately_zero(startT - fTs[index].fT)) {
caryclark@google.comb9738012012-07-03 19:53:30 +00003022 return false;
3023 }
3024 }
3025 return true;
3026 }
3027
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003028 bool isSimple(int end) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003029 int count = fTs.count();
3030 if (count == 2) {
3031 return true;
3032 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003033 double t = fTs[end].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003034 if (approximately_less_than_zero(t)) {
3035 return !approximately_less_than_zero(fTs[1].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003036 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003037 if (approximately_greater_than_one(t)) {
3038 return !approximately_greater_than_one(fTs[count - 2].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003039 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003040 return false;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003041 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003042
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003043 bool isVertical() const {
3044 return fBounds.fLeft == fBounds.fRight;
3045 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003046
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003047 bool isVertical(int start, int end) const {
3048 return (*SegmentVertical[fVerb])(fPts, start, end);
3049 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003050
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003051 SkScalar leftMost(int start, int end) const {
3052 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
3053 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003054
caryclark@google.com495f8e42012-05-31 13:13:11 +00003055 // this span is excluded by the winding rule -- chase the ends
3056 // as long as they are unambiguous to mark connections as done
3057 // and give them the same winding value
caryclark@google.com59823f72012-08-09 18:17:47 +00003058 Span* markAndChaseDone(const Angle* angle, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003059 int index = angle->start();
3060 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003061 return markAndChaseDone(index, endIndex, winding);
3062 }
3063
caryclark@google.com31143cf2012-11-09 22:14:19 +00003064 Span* markAndChaseDone(int index, int endIndex, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003065 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003066 int min = SkMin32(index, endIndex);
3067 markDone(min, winding);
3068 Span* last;
3069 Segment* other = this;
3070 while ((other = other->nextChase(index, step, min, last))) {
3071 other->markDone(min, winding);
3072 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003073 return last;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003074 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003075
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003076 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
3077 int index = angle->start();
3078 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003079 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003080 int min = SkMin32(index, endIndex);
3081 markDoneBinary(min, winding, oppWinding);
3082 Span* last;
3083 Segment* other = this;
3084 while ((other = other->nextChase(index, step, min, last))) {
3085 other->markDoneBinary(min, winding, oppWinding);
3086 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003087 return last;
3088 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003089
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003090 Span* markAndChaseDoneBinary(int index, int endIndex) {
3091 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003092 int min = SkMin32(index, endIndex);
3093 markDoneBinary(min);
3094 Span* last;
3095 Segment* other = this;
3096 while ((other = other->nextChase(index, step, min, last))) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003097 if (other->done()) {
3098 return NULL;
3099 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003100 other->markDoneBinary(min);
3101 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003102 return last;
3103 }
3104
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003105 Span* markAndChaseDoneUnary(int index, int endIndex) {
3106 int step = SkSign32(endIndex - index);
3107 int min = SkMin32(index, endIndex);
3108 markDoneUnary(min);
3109 Span* last;
3110 Segment* other = this;
3111 while ((other = other->nextChase(index, step, min, last))) {
3112 if (other->done()) {
3113 return NULL;
3114 }
3115 other->markDoneUnary(min);
3116 }
3117 return last;
3118 }
3119
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003120 Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
3121 int index = angle->start();
3122 int endIndex = angle->end();
3123 return markAndChaseDone(index, endIndex, winding);
3124 }
3125
caryclark@google.com4eeda372012-12-06 21:47:48 +00003126 Span* markAndChaseWinding(const Angle* angle, const int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003127 int index = angle->start();
3128 int endIndex = angle->end();
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003129 int step = SkSign32(endIndex - index);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003130 int min = SkMin32(index, endIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00003131 markWinding(min, winding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003132 Span* last;
3133 Segment* other = this;
3134 while ((other = other->nextChase(index, step, min, last))) {
3135 if (other->fTs[min].fWindSum != SK_MinS32) {
3136 SkASSERT(other->fTs[min].fWindSum == winding);
3137 return NULL;
3138 }
3139 other->markWinding(min, winding);
3140 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003141 return last;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003142 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003143
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003144 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003145 int min = SkMin32(index, endIndex);
3146 int step = SkSign32(endIndex - index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003147 markWinding(min, winding, oppWinding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003148 Span* last;
3149 Segment* other = this;
3150 while ((other = other->nextChase(index, step, min, last))) {
3151 if (other->fTs[min].fWindSum != SK_MinS32) {
3152 SkASSERT(other->fTs[min].fWindSum == winding);
3153 return NULL;
3154 }
3155 other->markWinding(min, winding, oppWinding);
3156 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003157 return last;
3158 }
3159
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003160 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
3161 int start = angle->start();
3162 int end = angle->end();
3163 return markAndChaseWinding(start, end, winding, oppWinding);
3164 }
3165
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003166 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
3167 SkASSERT(angle->segment() == this);
3168 if (useInnerWinding(maxWinding, sumWinding)) {
3169 maxWinding = sumWinding;
3170 }
3171 Span* last;
3172 if (activeAngle) {
3173 last = markAndChaseWinding(angle, maxWinding);
3174 } else {
3175 last = markAndChaseDoneUnary(angle, maxWinding);
3176 }
3177 return last;
3178 }
3179
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003180 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
3181 bool activeAngle, const Angle* angle) {
3182 SkASSERT(angle->segment() == this);
3183 if (useInnerWinding(maxWinding, sumWinding)) {
3184 maxWinding = sumWinding;
3185 }
3186 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
3187 oppMaxWinding = oppSumWinding;
3188 }
3189 Span* last;
3190 if (activeAngle) {
3191 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3192 } else {
3193 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
3194 }
3195 return last;
3196 }
3197
caryclark@google.com495f8e42012-05-31 13:13:11 +00003198 // FIXME: this should also mark spans with equal (x,y)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003199 // This may be called when the segment is already marked done. While this
3200 // wastes time, it shouldn't do any more than spin through the T spans.
rmistry@google.comd6176b02012-08-23 18:14:13 +00003201 // OPTIMIZATION: abort on first done found (assuming that this code is
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003202 // always called to mark segments done).
caryclark@google.com59823f72012-08-09 18:17:47 +00003203 void markDone(int index, int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003204 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003205 SkASSERT(winding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003206 double referenceT = fTs[index].fT;
3207 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003208 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3209 markOneDone(__FUNCTION__, lesser, winding);
3210 }
3211 do {
3212 markOneDone(__FUNCTION__, index, winding);
3213 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003214 }
3215
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003216 void markDoneBinary(int index, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003217 // SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003218 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003219 double referenceT = fTs[index].fT;
3220 int lesser = index;
3221 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003222 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003223 }
3224 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003225 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
3226 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3227 }
3228
3229 void markDoneBinary(int index) {
3230 double referenceT = fTs[index].fT;
3231 int lesser = index;
3232 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3233 markOneDoneBinary(__FUNCTION__, lesser);
3234 }
3235 do {
3236 markOneDoneBinary(__FUNCTION__, index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003237 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003238 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00003239
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003240 void markDoneUnary(int index, int winding) {
3241 // SkASSERT(!done());
3242 SkASSERT(winding);
3243 double referenceT = fTs[index].fT;
3244 int lesser = index;
3245 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3246 markOneDoneUnary(__FUNCTION__, lesser, winding);
3247 }
3248 do {
3249 markOneDoneUnary(__FUNCTION__, index, winding);
3250 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3251 }
3252
3253 void markDoneUnary(int index) {
3254 double referenceT = fTs[index].fT;
3255 int lesser = index;
3256 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3257 markOneDoneUnary(__FUNCTION__, lesser);
3258 }
3259 do {
3260 markOneDoneUnary(__FUNCTION__, index);
3261 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3262 }
3263
caryclark@google.com24bec792012-08-20 12:43:57 +00003264 void markOneDone(const char* funName, int tIndex, int winding) {
3265 Span* span = markOneWinding(funName, tIndex, winding);
3266 if (!span) {
3267 return;
3268 }
3269 span->fDone = true;
3270 fDoneSpans++;
3271 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003272
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003273 void markOneDoneBinary(const char* funName, int tIndex) {
3274 Span* span = verifyOneWinding(funName, tIndex);
3275 if (!span) {
3276 return;
3277 }
3278 span->fDone = true;
3279 fDoneSpans++;
3280 }
3281
3282 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003283 Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
3284 if (!span) {
3285 return;
3286 }
3287 span->fDone = true;
3288 fDoneSpans++;
3289 }
3290
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003291 void markOneDoneUnary(const char* funName, int tIndex) {
3292 Span* span = verifyOneWindingU(funName, tIndex);
3293 if (!span) {
3294 return;
3295 }
3296 span->fDone = true;
3297 fDoneSpans++;
3298 }
3299
3300 void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3301 Span* span = markOneWinding(funName, tIndex, winding);
3302 if (!span) {
3303 return;
3304 }
3305 span->fDone = true;
3306 fDoneSpans++;
3307 }
3308
caryclark@google.com24bec792012-08-20 12:43:57 +00003309 Span* markOneWinding(const char* funName, int tIndex, int winding) {
3310 Span& span = fTs[tIndex];
3311 if (span.fDone) {
3312 return NULL;
3313 }
3314 #if DEBUG_MARK_DONE
3315 debugShowNewWinding(funName, span, winding);
3316 #endif
3317 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com03f97062012-08-21 13:13:52 +00003318 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00003319 SkASSERT(abs(winding) <= gDebugMaxWindSum);
caryclark@google.com03f97062012-08-21 13:13:52 +00003320 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00003321 span.fWindSum = winding;
3322 return &span;
3323 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003324
caryclark@google.com31143cf2012-11-09 22:14:19 +00003325 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
3326 Span& span = fTs[tIndex];
3327 if (span.fDone) {
3328 return NULL;
3329 }
3330 #if DEBUG_MARK_DONE
3331 debugShowNewWinding(funName, span, winding, oppWinding);
3332 #endif
3333 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3334 #ifdef SK_DEBUG
3335 SkASSERT(abs(winding) <= gDebugMaxWindSum);
3336 #endif
3337 span.fWindSum = winding;
3338 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3339 #ifdef SK_DEBUG
3340 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
3341 #endif
3342 span.fOppSum = oppWinding;
3343 return &span;
3344 }
3345
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003346 bool bumpsUp(int tStart, int tEnd) const {
3347 SkPoint edge[4];
caryclark@google.comc83c70e2013-02-22 21:50:07 +00003348 subDivide(tStart, tEnd, edge);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003349 switch (fVerb) {
3350 case SkPath::kLine_Verb:
3351 SkASSERT(0); // shouldn't call in for lines
3352 return true;
3353 case SkPath::kQuad_Verb:
3354 return approximately_greater(edge[0].fY, edge[1].fY)
3355 && approximately_lesser(edge[1].fY, edge[2].fY);
3356 case SkPath::kCubic_Verb:
3357 return (approximately_greater(edge[0].fY, edge[1].fY)
3358 && approximately_lesser(edge[1].fY, edge[3].fY))
3359 || (approximately_greater(edge[0].fY, edge[2].fY)
3360 && approximately_lesser(edge[2].fY, edge[3].fY));
3361 default:
3362 SkASSERT(0);
3363 return false;
3364 }
3365 }
3366
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003367 Span* verifyOneWinding(const char* funName, int tIndex) {
3368 Span& span = fTs[tIndex];
3369 if (span.fDone) {
3370 return NULL;
3371 }
3372 #if DEBUG_MARK_DONE
3373 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3374 #endif
3375 SkASSERT(span.fWindSum != SK_MinS32);
3376 SkASSERT(span.fOppSum != SK_MinS32);
3377 return &span;
3378 }
3379
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003380 Span* verifyOneWindingU(const char* funName, int tIndex) {
3381 Span& span = fTs[tIndex];
3382 if (span.fDone) {
3383 return NULL;
3384 }
3385 #if DEBUG_MARK_DONE
3386 debugShowNewWinding(funName, span, span.fWindSum);
3387 #endif
3388 SkASSERT(span.fWindSum != SK_MinS32);
3389 return &span;
3390 }
3391
caryclark@google.comf839c032012-10-26 21:03:50 +00003392 // note that just because a span has one end that is unsortable, that's
3393 // not enough to mark it done. The other end may be sortable, allowing the
3394 // span to be added.
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003395 // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003396 void markUnsortable(int start, int end) {
3397 Span* span = &fTs[start];
3398 if (start < end) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003399#if DEBUG_UNSORTABLE
3400 SkDebugf("%s start id=%d [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fID, start,
3401 xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003402#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003403 span->fUnsortableStart = true;
3404 } else {
3405 --span;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003406#if DEBUG_UNSORTABLE
3407 SkDebugf("%s end id=%d [%d] (%1.9g,%1.9g) next:(%1.9g,%1.9g)\n", __FUNCTION__, fID,
3408 start - 1, xAtT(start - 1), yAtT(start - 1), xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003409#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003410 span->fUnsortableEnd = true;
3411 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003412 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003413 return;
3414 }
3415 span->fDone = true;
3416 fDoneSpans++;
3417 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003418
caryclark@google.com59823f72012-08-09 18:17:47 +00003419 void markWinding(int index, int winding) {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003420 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003421 SkASSERT(winding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003422 double referenceT = fTs[index].fT;
3423 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003424 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3425 markOneWinding(__FUNCTION__, lesser, winding);
3426 }
3427 do {
3428 markOneWinding(__FUNCTION__, index, winding);
3429 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003430 }
3431
3432 void markWinding(int index, int winding, int oppWinding) {
3433 // SkASSERT(!done());
caryclark@google.com4eeda372012-12-06 21:47:48 +00003434 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003435 double referenceT = fTs[index].fT;
3436 int lesser = index;
3437 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3438 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003439 }
3440 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003441 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3442 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003443 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003444
caryclark@google.com2ddff932012-08-07 21:25:27 +00003445 void matchWindingValue(int tIndex, double t, bool borrowWind) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003446 int nextDoorWind = SK_MaxS32;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003447 int nextOppWind = SK_MaxS32;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003448 if (tIndex > 0) {
3449 const Span& below = fTs[tIndex - 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003450 if (approximately_negative(t - below.fT)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003451 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003452 nextOppWind = below.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003453 }
3454 }
3455 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3456 const Span& above = fTs[tIndex + 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003457 if (approximately_negative(above.fT - t)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003458 nextDoorWind = above.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003459 nextOppWind = above.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003460 }
3461 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003462 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3463 const Span& below = fTs[tIndex - 1];
3464 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003465 nextOppWind = below.fOppValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003466 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003467 if (nextDoorWind != SK_MaxS32) {
3468 Span& newSpan = fTs[tIndex];
3469 newSpan.fWindValue = nextDoorWind;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003470 newSpan.fOppValue = nextOppWind;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003471 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003472 newSpan.fDone = true;
3473 ++fDoneSpans;
3474 }
3475 }
3476 }
3477
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003478 bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3479 // find bounds
3480 Bounds bounds;
3481 bounds.setPoint(xyAtT(index));
3482 bounds.add(xyAtT(endIndex));
3483 SkScalar width = bounds.width();
3484 SkScalar height = bounds.height();
3485 if (width > height) {
3486 if (approximately_negative(width)) {
3487 unsortable = true; // edge is too small to resolve meaningfully
3488 }
3489 return false;
3490 } else {
3491 if (approximately_negative(height)) {
3492 unsortable = true; // edge is too small to resolve meaningfully
3493 }
3494 return true;
3495 }
3496 }
3497
caryclark@google.com9764cc62012-07-12 19:29:45 +00003498 // return span if when chasing, two or more radiating spans are not done
3499 // OPTIMIZATION: ? multiple spans is detected when there is only one valid
3500 // candidate and the remaining spans have windValue == 0 (canceled by
3501 // coincidence). The coincident edges could either be removed altogether,
3502 // or this code could be more complicated in detecting this case. Worth it?
3503 bool multipleSpans(int end) const {
3504 return end > 0 && end < fTs.count() - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00003505 }
3506
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003507 bool nextCandidate(int& start, int& end) const {
caryclark@google.com10227bf2012-12-28 22:10:41 +00003508 while (fTs[end].fDone) {
3509 if (fTs[end].fT == 1) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003510 return false;
3511 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00003512 ++end;
3513 }
3514 start = end;
3515 end = nextExactSpan(start, 1);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003516 return true;
3517 }
3518
caryclark@google.com4eeda372012-12-06 21:47:48 +00003519 Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
3520 int end = nextExactSpan(index, step);
3521 SkASSERT(end >= 0);
3522 if (multipleSpans(end)) {
3523 last = &fTs[end];
3524 return NULL;
3525 }
3526 const Span& endSpan = fTs[end];
3527 Segment* other = endSpan.fOther;
3528 index = endSpan.fOtherIndex;
caryclark@google.comaa358312013-01-29 20:28:49 +00003529 SkASSERT(index >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003530 int otherEnd = other->nextExactSpan(index, step);
caryclark@google.comaa358312013-01-29 20:28:49 +00003531 SkASSERT(otherEnd >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003532 min = SkMin32(index, otherEnd);
3533 return other;
3534 }
3535
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003536 // This has callers for two different situations: one establishes the end
3537 // of the current span, and one establishes the beginning of the next span
3538 // (thus the name). When this is looking for the end of the current span,
3539 // coincidence is found when the beginning Ts contain -step and the end
3540 // contains step. When it is looking for the beginning of the next, the
3541 // first Ts found can be ignored and the last Ts should contain -step.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003542 // OPTIMIZATION: probably should split into two functions
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003543 int nextSpan(int from, int step) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003544 const Span& fromSpan = fTs[from];
caryclark@google.com495f8e42012-05-31 13:13:11 +00003545 int count = fTs.count();
3546 int to = from;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003547 while (step > 0 ? ++to < count : --to >= 0) {
3548 const Span& span = fTs[to];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003549 if (approximately_zero(span.fT - fromSpan.fT)) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003550 continue;
3551 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003552 return to;
3553 }
3554 return -1;
3555 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +00003556
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003557 // FIXME
3558 // this returns at any difference in T, vs. a preset minimum. It may be
3559 // that all callers to nextSpan should use this instead.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003560 // OPTIMIZATION splitting this into separate loops for up/down steps
3561 // would allow using precisely_negative instead of precisely_zero
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003562 int nextExactSpan(int from, int step) const {
3563 const Span& fromSpan = fTs[from];
3564 int count = fTs.count();
3565 int to = from;
3566 while (step > 0 ? ++to < count : --to >= 0) {
3567 const Span& span = fTs[to];
caryclark@google.coma461ff02012-10-11 12:54:23 +00003568 if (precisely_zero(span.fT - fromSpan.fT)) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003569 continue;
3570 }
3571 return to;
3572 }
3573 return -1;
3574 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003575
caryclark@google.com235f56a2012-09-14 14:19:30 +00003576 bool operand() const {
3577 return fOperand;
3578 }
3579
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003580 int oppSign(const Angle* angle) const {
3581 SkASSERT(angle->segment() == this);
3582 return oppSign(angle->start(), angle->end());
3583 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003584
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003585 int oppSign(int startIndex, int endIndex) const {
3586 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3587 : fTs[endIndex].fOppValue;
3588#if DEBUG_WIND_BUMP
3589 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3590#endif
3591 return result;
3592 }
3593
caryclark@google.com31143cf2012-11-09 22:14:19 +00003594 int oppSum(int tIndex) const {
3595 return fTs[tIndex].fOppSum;
3596 }
3597
3598 int oppSum(const Angle* angle) const {
3599 int lesser = SkMin32(angle->start(), angle->end());
3600 return fTs[lesser].fOppSum;
caryclark@google.com235f56a2012-09-14 14:19:30 +00003601 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003602
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003603 int oppValue(int tIndex) const {
3604 return fTs[tIndex].fOppValue;
3605 }
3606
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003607 int oppValue(const Angle* angle) const {
3608 int lesser = SkMin32(angle->start(), angle->end());
3609 return fTs[lesser].fOppValue;
3610 }
3611
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003612 const SkPoint* pts() const {
3613 return fPts;
3614 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003615
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003616 void reset() {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003617 init(NULL, (SkPath::Verb) -1, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003618 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3619 fTs.reset();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003620 }
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +00003621
caryclark@google.com4eeda372012-12-06 21:47:48 +00003622 void setOppXor(bool isOppXor) {
3623 fOppXor = isOppXor;
3624 }
3625
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003626 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3627 int deltaSum = spanSign(index, endIndex);
3628 maxWinding = sumWinding;
3629 sumWinding = sumWinding -= deltaSum;
3630 }
3631
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003632 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3633 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3634 int deltaSum = spanSign(index, endIndex);
3635 int oppDeltaSum = oppSign(index, endIndex);
3636 if (operand()) {
3637 maxWinding = sumSuWinding;
3638 sumWinding = sumSuWinding -= deltaSum;
3639 oppMaxWinding = sumMiWinding;
3640 oppSumWinding = sumMiWinding -= oppDeltaSum;
3641 } else {
3642 maxWinding = sumMiWinding;
3643 sumWinding = sumMiWinding -= deltaSum;
3644 oppMaxWinding = sumSuWinding;
3645 oppSumWinding = sumSuWinding -= oppDeltaSum;
3646 }
3647 }
3648
caryclark@google.comf839c032012-10-26 21:03:50 +00003649 // This marks all spans unsortable so that this info is available for early
3650 // exclusion in find top and others. This could be optimized to only mark
3651 // adjacent spans that unsortable. However, this makes it difficult to later
3652 // determine starting points for edge detection in find top and the like.
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003653 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
caryclark@google.comf839c032012-10-26 21:03:50 +00003654 bool sortable = true;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003655 int angleCount = angles.count();
3656 int angleIndex;
3657 angleList.setReserve(angleCount);
3658 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003659 Angle& angle = angles[angleIndex];
caryclark@google.comf839c032012-10-26 21:03:50 +00003660 *angleList.append() = &angle;
3661 sortable &= !angle.unsortable();
3662 }
3663 if (sortable) {
3664 QSort<Angle>(angleList.begin(), angleList.end() - 1);
3665 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3666 if (angles[angleIndex].unsortable()) {
3667 sortable = false;
3668 break;
3669 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003670 }
3671 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003672 if (!sortable) {
3673 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3674 Angle& angle = angles[angleIndex];
3675 angle.segment()->markUnsortable(angle.start(), angle.end());
3676 }
3677 }
3678 return sortable;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003679 }
3680
caryclark@google.com1577e8f2012-05-22 17:01:14 +00003681 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003682 const Span& span(int tIndex) const {
3683 return fTs[tIndex];
3684 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003685
caryclark@google.com235f56a2012-09-14 14:19:30 +00003686 int spanSign(const Angle* angle) const {
3687 SkASSERT(angle->segment() == this);
3688 return spanSign(angle->start(), angle->end());
3689 }
3690
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003691 int spanSign(int startIndex, int endIndex) const {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003692 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3693 : fTs[endIndex].fWindValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003694#if DEBUG_WIND_BUMP
3695 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3696#endif
3697 return result;
3698 }
skia.committer@gmail.com58433de2013-02-23 07:02:45 +00003699
caryclark@google.comc83c70e2013-02-22 21:50:07 +00003700 void subDivide(int start, int end, SkPoint edge[4]) const {
3701 edge[0] = fTs[start].fPt;
3702 edge[fVerb] = fTs[end].fPt;
3703 if (fVerb == SkPath::kQuad_Verb || fVerb == SkPath::kCubic_Verb) {
3704 _Point sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[fVerb].fX, edge[fVerb].fY }};
3705 if (fVerb == SkPath::kQuad_Verb) {
3706 MAKE_CONST_QUAD(aQuad, fPts);
3707 edge[1] = sub_divide(aQuad, sub[0], sub[1], fTs[start].fT, fTs[end].fT).asSkPoint();
3708 } else {
3709 MAKE_CONST_CUBIC(aCubic, fPts);
3710 sub_divide(aCubic, sub[0], sub[1], fTs[start].fT, fTs[end].fT, sub);
3711 edge[1] = sub[0].asSkPoint();
3712 edge[2] = sub[1].asSkPoint();
3713 }
3714 }
3715 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003716
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003717 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003718 double t(int tIndex) const {
3719 return fTs[tIndex].fT;
3720 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003721
caryclark@google.com10227bf2012-12-28 22:10:41 +00003722 double tAtMid(int start, int end, double mid) const {
3723 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
3724 }
3725
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003726 bool tiny(const Angle* angle) const {
3727 int start = angle->start();
3728 int end = angle->end();
caryclark@google.comf839c032012-10-26 21:03:50 +00003729 const Span& mSpan = fTs[SkMin32(start, end)];
3730 return mSpan.fTiny;
3731 }
3732
caryclark@google.com18063442012-07-25 12:05:18 +00003733 static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3734 double start) {
3735 int outCount = outsideTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003736 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
caryclark@google.com18063442012-07-25 12:05:18 +00003737 *outsideTs.append() = end;
3738 *outsideTs.append() = start;
3739 }
3740 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003741
caryclark@google.com24bec792012-08-20 12:43:57 +00003742 void undoneSpan(int& start, int& end) {
3743 size_t tCount = fTs.count();
3744 size_t index;
3745 for (index = 0; index < tCount; ++index) {
3746 if (!fTs[index].fDone) {
3747 break;
3748 }
3749 }
3750 SkASSERT(index < tCount - 1);
3751 start = index;
3752 double startT = fTs[index].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003753 while (approximately_negative(fTs[++index].fT - startT))
caryclark@google.com24bec792012-08-20 12:43:57 +00003754 SkASSERT(index < tCount);
3755 SkASSERT(index < tCount);
3756 end = index;
3757 }
caryclark@google.com18063442012-07-25 12:05:18 +00003758
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003759 bool unsortable(int index) const {
3760 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3761 }
3762
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003763 void updatePts(const SkPoint pts[]) {
3764 fPts = pts;
3765 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003766
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003767 int updateOppWinding(int index, int endIndex) const {
3768 int lesser = SkMin32(index, endIndex);
3769 int oppWinding = oppSum(lesser);
3770 int oppSpanWinding = oppSign(index, endIndex);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003771 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)
3772 && oppWinding != SK_MaxS32) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003773 oppWinding -= oppSpanWinding;
3774 }
3775 return oppWinding;
3776 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003777
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003778 int updateOppWinding(const Angle* angle) const {
3779 int startIndex = angle->start();
3780 int endIndex = angle->end();
3781 return updateOppWinding(endIndex, startIndex);
3782 }
3783
3784 int updateOppWindingReverse(const Angle* angle) const {
3785 int startIndex = angle->start();
3786 int endIndex = angle->end();
3787 return updateOppWinding(startIndex, endIndex);
3788 }
3789
3790 int updateWinding(int index, int endIndex) const {
3791 int lesser = SkMin32(index, endIndex);
3792 int winding = windSum(lesser);
3793 int spanWinding = spanSign(index, endIndex);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003794 if (winding && useInnerWinding(winding - spanWinding, winding) && winding != SK_MaxS32) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003795 winding -= spanWinding;
3796 }
3797 return winding;
3798 }
3799
3800 int updateWinding(const Angle* angle) const {
3801 int startIndex = angle->start();
3802 int endIndex = angle->end();
3803 return updateWinding(endIndex, startIndex);
3804 }
3805
3806 int updateWindingReverse(const Angle* angle) const {
3807 int startIndex = angle->start();
3808 int endIndex = angle->end();
3809 return updateWinding(startIndex, endIndex);
3810 }
3811
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003812 SkPath::Verb verb() const {
3813 return fVerb;
3814 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003815
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003816 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003817 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3818 return SK_MinS32;
3819 }
3820 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3821 SkASSERT(winding != SK_MinS32);
3822 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003823 #if DEBUG_WINDING_AT_T
3824 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003825 #endif
3826 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark@google.com3586ece2012-12-27 18:46:58 +00003827 dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003828 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3829 dx = fPts[2].fX - fPts[1].fX - dx;
3830 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003831 if (dx == 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003832 #if DEBUG_WINDING_AT_T
3833 SkDebugf(" dx=0 winding=SK_MinS32\n");
3834 #endif
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003835 return SK_MinS32;
3836 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003837 if (winding * dx > 0) { // if same signs, result is negative
3838 winding += dx > 0 ? -windVal : windVal;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003839 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003840 #if DEBUG_WINDING_AT_T
3841 SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding);
3842 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003843 return winding;
3844 }
3845
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003846 int windSum(int tIndex) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003847 return fTs[tIndex].fWindSum;
3848 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003849
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003850 int windSum(const Angle* angle) const {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003851 int start = angle->start();
3852 int end = angle->end();
3853 int index = SkMin32(start, end);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003854 return windSum(index);
caryclark@google.com495f8e42012-05-31 13:13:11 +00003855 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003856
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003857 int windValue(int tIndex) const {
3858 return fTs[tIndex].fWindValue;
3859 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003860
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003861 int windValue(const Angle* angle) const {
3862 int start = angle->start();
3863 int end = angle->end();
3864 int index = SkMin32(start, end);
3865 return windValue(index);
3866 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00003867
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003868 int windValueAt(double t) const {
3869 int count = fTs.count();
3870 for (int index = 0; index < count; ++index) {
3871 if (fTs[index].fT == t) {
3872 return fTs[index].fWindValue;
3873 }
3874 }
3875 SkASSERT(0);
3876 return 0;
3877 }
3878
caryclark@google.com3586ece2012-12-27 18:46:58 +00003879 SkScalar xAtT(int index) const {
3880 return xAtT(&fTs[index]);
3881 }
3882
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003883 SkScalar xAtT(const Span* span) const {
3884 return xyAtT(span).fX;
3885 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003886
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003887 const SkPoint& xyAtT(int index) const {
3888 return xyAtT(&fTs[index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003889 }
3890
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003891 const SkPoint& xyAtT(const Span* span) const {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003892 if (SkScalarIsNaN(span->fPt.fX)) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00003893 SkASSERT(0); // make sure this path is never used
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003894 if (span->fT == 0) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003895 span->fPt = fPts[0];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003896 } else if (span->fT == 1) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003897 span->fPt = fPts[fVerb];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003898 } else {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003899 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003900 }
3901 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00003902 return span->fPt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003903 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003904
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003905 // used only by right angle winding finding
caryclark@google.com10227bf2012-12-28 22:10:41 +00003906 void xyAtT(double mid, SkPoint& pt) const {
3907 (*SegmentXYAtT[fVerb])(fPts, mid, &pt);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003908 }
3909
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003910 SkScalar yAtT(int index) const {
3911 return yAtT(&fTs[index]);
3912 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003913
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003914 SkScalar yAtT(const Span* span) const {
3915 return xyAtT(span).fY;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003916 }
3917
caryclark@google.com4eeda372012-12-06 21:47:48 +00003918 void zeroCoincidentOpp(Span* oTest, int index) {
3919 Span* const test = &fTs[index];
3920 Span* end = test;
3921 do {
3922 end->fOppValue = 0;
3923 end = &fTs[++index];
3924 } while (approximately_negative(end->fT - test->fT));
3925 }
3926
3927 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
3928 Span* const oTest = &fTs[oIndex];
3929 Span* oEnd = oTest;
3930 const double startT = test->fT;
3931 const double oStartT = oTest->fT;
3932 double otherTMatch = (test->fT - startT) * tRatio + oStartT;
3933 while (!approximately_negative(oEndT - oEnd->fT)
3934 && approximately_negative(oEnd->fT - otherTMatch)) {
3935 oEnd->fOppValue = 0;
3936 oEnd = &fTs[++oIndex];
3937 }
3938 }
3939
3940 void zeroSpan(Span* span) {
3941 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
caryclark@google.com6ec15262012-11-16 20:16:50 +00003942 span->fWindValue = 0;
caryclark@google.com729e1c42012-11-21 21:36:34 +00003943 span->fOppValue = 0;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003944 SkASSERT(!span->fDone);
3945 span->fDone = true;
3946 ++fDoneSpans;
caryclark@google.com6ec15262012-11-16 20:16:50 +00003947 }
3948
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003949#if DEBUG_DUMP
3950 void dump() const {
3951 const char className[] = "Segment";
3952 const int tab = 4;
3953 for (int i = 0; i < fTs.count(); ++i) {
3954 SkPoint out;
3955 (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
3956 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003957 " otherT=%1.9g windSum=%d\n",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003958 tab + sizeof(className), className, fID,
3959 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003960 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003961 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00003962 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003963 tab + sizeof(className), className, fID,
caryclark@google.com15fa1382012-05-07 20:49:36 +00003964 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003965 }
3966#endif
3967
caryclark@google.com47580692012-07-23 12:14:49 +00003968#if DEBUG_CONCIDENT
caryclark@google.comaa358312013-01-29 20:28:49 +00003969 // SkASSERT if pair has not already been added
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003970 void debugAddTPair(double t, const Segment& other, double otherT) const {
caryclark@google.comcc905052012-07-25 20:59:42 +00003971 for (int i = 0; i < fTs.count(); ++i) {
3972 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
3973 return;
3974 }
3975 }
3976 SkASSERT(0);
3977 }
3978#endif
3979
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003980#if DEBUG_DUMP
3981 int debugID() const {
3982 return fID;
3983 }
3984#endif
3985
caryclark@google.com24bec792012-08-20 12:43:57 +00003986#if DEBUG_WINDING
3987 void debugShowSums() const {
3988 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
3989 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
3990 for (int i = 0; i < fTs.count(); ++i) {
3991 const Span& span = fTs[i];
3992 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
3993 if (span.fWindSum == SK_MinS32) {
3994 SkDebugf("?");
3995 } else {
3996 SkDebugf("%d", span.fWindSum);
3997 }
3998 SkDebugf("]");
3999 }
4000 SkDebugf("\n");
4001 }
4002#endif
4003
caryclark@google.comcc905052012-07-25 20:59:42 +00004004#if DEBUG_CONCIDENT
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004005 void debugShowTs() const {
caryclark@google.com24bec792012-08-20 12:43:57 +00004006 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com4eeda372012-12-06 21:47:48 +00004007 int lastWind = -1;
4008 int lastOpp = -1;
4009 double lastT = -1;
4010 int i;
4011 for (i = 0; i < fTs.count(); ++i) {
4012 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
4013 || lastOpp != fTs[i].fOppValue;
4014 if (change && lastWind >= 0) {
4015 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
4016 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
4017 }
4018 if (change) {
4019 SkDebugf(" [o=%d", fTs[i].fOther->fID);
4020 lastWind = fTs[i].fWindValue;
4021 lastOpp = fTs[i].fOppValue;
4022 lastT = fTs[i].fT;
4023 } else {
4024 SkDebugf(",%d", fTs[i].fOther->fID);
4025 }
4026 }
4027 if (i <= 0) {
4028 return;
4029 }
4030 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
4031 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
4032 if (fOperand) {
4033 SkDebugf(" operand");
4034 }
4035 if (done()) {
4036 SkDebugf(" done");
caryclark@google.com47580692012-07-23 12:14:49 +00004037 }
4038 SkDebugf("\n");
4039 }
4040#endif
4041
caryclark@google.com027de222012-07-12 12:52:50 +00004042#if DEBUG_ACTIVE_SPANS
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004043 void debugShowActiveSpans() const {
caryclark@google.com027de222012-07-12 12:52:50 +00004044 if (done()) {
4045 return;
4046 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004047#if DEBUG_ACTIVE_SPANS_SHORT_FORM
4048 int lastId = -1;
4049 double lastT = -1;
4050#endif
caryclark@google.com027de222012-07-12 12:52:50 +00004051 for (int i = 0; i < fTs.count(); ++i) {
4052 if (fTs[i].fDone) {
4053 continue;
4054 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004055#if DEBUG_ACTIVE_SPANS_SHORT_FORM
4056 if (lastId == fID && lastT == fTs[i].fT) {
4057 continue;
4058 }
4059 lastId = fID;
4060 lastT = fTs[i].fT;
4061#endif
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004062 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com027de222012-07-12 12:52:50 +00004063 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4064 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4065 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4066 }
4067 const Span* span = &fTs[i];
rmistry@google.comd6176b02012-08-23 18:14:13 +00004068 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
caryclark@google.com0c803d02012-08-06 11:15:47 +00004069 xAtT(span), yAtT(span));
caryclark@google.com47d73da2013-02-17 01:41:25 +00004070 int iEnd = i + 1;
4071 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) {
4072 ++iEnd;
4073 }
4074 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT);
caryclark@google.com027de222012-07-12 12:52:50 +00004075 const Segment* other = fTs[i].fOther;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004076 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
4077 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
4078 if (fTs[i].fWindSum == SK_MinS32) {
4079 SkDebugf("?");
4080 } else {
4081 SkDebugf("%d", fTs[i].fWindSum);
4082 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004083 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
caryclark@google.com027de222012-07-12 12:52:50 +00004084 }
4085 }
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +00004086
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004087 // This isn't useful yet -- but leaving it in for now in case i think of something
4088 // to use it for
4089 void validateActiveSpans() const {
4090 if (done()) {
4091 return;
4092 }
4093 int tCount = fTs.count();
4094 for (int index = 0; index < tCount; ++index) {
4095 if (fTs[index].fDone) {
4096 continue;
4097 }
4098 // count number of connections which are not done
4099 int first = index;
4100 double baseT = fTs[index].fT;
4101 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
4102 --first;
4103 }
4104 int last = index;
4105 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
4106 ++last;
4107 }
4108 int connections = 0;
4109 connections += first > 0 && !fTs[first - 1].fDone;
4110 for (int test = first; test <= last; ++test) {
4111 connections += !fTs[test].fDone;
4112 const Segment* other = fTs[test].fOther;
4113 int oIndex = fTs[test].fOtherIndex;
4114 connections += !other->fTs[oIndex].fDone;
4115 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
4116 }
4117 // SkASSERT(!(connections & 1));
4118 }
4119 }
caryclark@google.com027de222012-07-12 12:52:50 +00004120#endif
4121
caryclark@google.com0c803d02012-08-06 11:15:47 +00004122#if DEBUG_MARK_DONE
4123 void debugShowNewWinding(const char* fun, const Span& span, int winding) {
4124 const SkPoint& pt = xyAtT(&span);
4125 SkDebugf("%s id=%d", fun, fID);
4126 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4127 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4128 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4129 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004130 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4131 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4132 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d windSum=",
4133 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, winding);
caryclark@google.com0c803d02012-08-06 11:15:47 +00004134 if (span.fWindSum == SK_MinS32) {
4135 SkDebugf("?");
4136 } else {
4137 SkDebugf("%d", span.fWindSum);
4138 }
4139 SkDebugf(" windValue=%d\n", span.fWindValue);
4140 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004141
4142 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
4143 const SkPoint& pt = xyAtT(&span);
4144 SkDebugf("%s id=%d", fun, fID);
4145 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4146 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4147 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4148 }
4149 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4150 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4151 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=",
4152 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
4153 winding, oppWinding);
4154 if (span.fOppSum == SK_MinS32) {
4155 SkDebugf("?");
4156 } else {
4157 SkDebugf("%d", span.fOppSum);
4158 }
4159 SkDebugf(" windSum=");
4160 if (span.fWindSum == SK_MinS32) {
4161 SkDebugf("?");
4162 } else {
4163 SkDebugf("%d", span.fWindSum);
4164 }
4165 SkDebugf(" windValue=%d\n", span.fWindValue);
4166 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00004167#endif
4168
caryclark@google.com47580692012-07-23 12:14:49 +00004169#if DEBUG_SORT
caryclark@google.com03f97062012-08-21 13:13:52 +00004170 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
caryclark@google.com31143cf2012-11-09 22:14:19 +00004171 const int contourWinding, const int oppContourWinding) const {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004172 if (--gDebugSortCount < 0) {
4173 return;
4174 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004175 SkASSERT(angles[first]->segment() == this);
caryclark@google.com200c2112012-08-03 15:05:04 +00004176 SkASSERT(angles.count() > 1);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004177 int lastSum = contourWinding;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004178 int oppLastSum = oppContourWinding;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004179 const Angle* firstAngle = angles[first];
4180 int windSum = lastSum - spanSign(firstAngle);
4181 int oppoSign = oppSign(firstAngle);
4182 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004183 #define WIND_AS_STRING(x) char x##Str[12]; if (!valid_wind(x)) strcpy(x##Str, "?"); \
4184 else snprintf(x##Str, sizeof(x##Str), "%d", x)
4185 WIND_AS_STRING(contourWinding);
4186 WIND_AS_STRING(oppContourWinding);
4187 SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FUNCTION__,
4188 contourWindingStr, oppContourWindingStr, spanSign(angles[first]));
caryclark@google.comafe56de2012-07-24 18:11:03 +00004189 int index = first;
4190 bool firstTime = true;
caryclark@google.com47580692012-07-23 12:14:49 +00004191 do {
4192 const Angle& angle = *angles[index];
4193 const Segment& segment = *angle.segment();
4194 int start = angle.start();
4195 int end = angle.end();
4196 const Span& sSpan = segment.fTs[start];
4197 const Span& eSpan = segment.fTs[end];
4198 const Span& mSpan = segment.fTs[SkMin32(start, end)];
caryclark@google.com31143cf2012-11-09 22:14:19 +00004199 bool opp = segment.fOperand ^ fOperand;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004200 if (!firstTime) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004201 oppoSign = segment.oppSign(&angle);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004202 if (opp) {
4203 oppLastSum = oppWindSum;
4204 oppWindSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004205 if (oppoSign) {
4206 lastSum = windSum;
4207 windSum -= oppoSign;
4208 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004209 } else {
4210 lastSum = windSum;
4211 windSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004212 if (oppoSign) {
4213 oppLastSum = oppWindSum;
4214 oppWindSum -= oppoSign;
4215 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004216 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004217 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004218 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 +00004219 " sign=%d windValue=%d windSum=",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004220 __FUNCTION__, index, angle.unsortable() ? "*** UNSORTABLE *** " : "",
caryclark@google.comc91dfe42012-10-16 12:06:27 +00004221 segment.fID, kLVerbStr[segment.fVerb],
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004222 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
4223 segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(),
4224 mSpan.fWindValue);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004225 winding_printf(mSpan.fWindSum);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004226 int last, wind;
4227 if (opp) {
4228 last = oppLastSum;
4229 wind = oppWindSum;
4230 } else {
4231 last = lastSum;
4232 wind = windSum;
4233 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004234 bool useInner = valid_wind(last) && valid_wind(wind) && useInnerWinding(last, wind);
4235 WIND_AS_STRING(last);
4236 WIND_AS_STRING(wind);
4237 WIND_AS_STRING(lastSum);
4238 WIND_AS_STRING(oppLastSum);
4239 WIND_AS_STRING(windSum);
4240 WIND_AS_STRING(oppWindSum);
4241 #undef WIND_AS_STRING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004242 if (!oppoSign) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004243 SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr : lastStr);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004244 } else {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004245 SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : oppLastSumStr,
4246 opp ? windSumStr : oppWindSumStr);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004247 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004248 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004249#if false && DEBUG_ANGLE
caryclark@google.comc899ad92012-08-23 15:24:42 +00004250 angle.debugShow(segment.xyAtT(&sSpan));
4251#endif
caryclark@google.com47580692012-07-23 12:14:49 +00004252 ++index;
4253 if (index == angles.count()) {
4254 index = 0;
4255 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004256 if (firstTime) {
4257 firstTime = false;
4258 }
caryclark@google.com47580692012-07-23 12:14:49 +00004259 } while (index != first);
4260 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00004261
4262 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
4263 const Angle* firstAngle = angles[first];
4264 const Segment* segment = firstAngle->segment();
4265 int winding = segment->updateWinding(firstAngle);
4266 int oppWinding = segment->updateOppWinding(firstAngle);
4267 debugShowSort(fun, angles, first, winding, oppWinding);
4268 }
4269
caryclark@google.com47580692012-07-23 12:14:49 +00004270#endif
4271
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004272#if DEBUG_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004273 static char as_digit(int value) {
4274 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
4275 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004276#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004277
caryclark@google.com729e1c42012-11-21 21:36:34 +00004278#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004279 int debugShowWindingValues(int slotCount, int ofInterest) const {
4280 if (!(1 << fID & ofInterest)) {
4281 return 0;
4282 }
4283 int sum = 0;
4284 SkTDArray<char> slots;
4285 slots.setCount(slotCount * 2);
4286 memset(slots.begin(), ' ', slotCount * 2);
4287 for (int i = 0; i < fTs.count(); ++i) {
4288 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
4289 // continue;
4290 // }
4291 sum += fTs[i].fWindValue;
4292 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
4293 sum += fTs[i].fOppValue;
4294 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
4295 }
4296 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
4297 slots.begin() + slotCount);
4298 return sum;
4299 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004300#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004301
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004302private:
4303 const SkPoint* fPts;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004304 Bounds fBounds;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004305 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
caryclark@google.com4eeda372012-12-06 21:47:48 +00004306 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
caryclark@google.com24bec792012-08-20 12:43:57 +00004307 int fDoneSpans; // quick check that segment is finished
caryclark@google.com4eeda372012-12-06 21:47:48 +00004308 // OPTIMIZATION: force the following to be byte-sized
4309 SkPath::Verb fVerb;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004310 bool fOperand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004311 bool fXor; // set if original contour had even-odd fill
4312 bool fOppXor; // set if opposite operand had even-odd fill
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004313#if DEBUG_DUMP
4314 int fID;
4315#endif
4316};
4317
caryclark@google.comb9738012012-07-03 19:53:30 +00004318class Contour;
4319
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004320struct Coincidence {
caryclark@google.comb9738012012-07-03 19:53:30 +00004321 Contour* fContours[2];
4322 int fSegments[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004323 double fTs[2][2];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004324 SkPoint fPts[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004325};
4326
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004327class Contour {
4328public:
4329 Contour() {
4330 reset();
4331#if DEBUG_DUMP
4332 fID = ++gContourID;
4333#endif
4334 }
4335
4336 bool operator<(const Contour& rh) const {
4337 return fBounds.fTop == rh.fBounds.fTop
4338 ? fBounds.fLeft < rh.fBounds.fLeft
4339 : fBounds.fTop < rh.fBounds.fTop;
4340 }
4341
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004342 void addCoincident(int index, Contour* other, int otherIndex,
4343 const Intersections& ts, bool swap) {
4344 Coincidence& coincidence = *fCoincidences.append();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004345 coincidence.fContours[0] = this; // FIXME: no need to store
caryclark@google.comb9738012012-07-03 19:53:30 +00004346 coincidence.fContours[1] = other;
4347 coincidence.fSegments[0] = index;
4348 coincidence.fSegments[1] = otherIndex;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004349 coincidence.fTs[swap][0] = ts.fT[0][0];
4350 coincidence.fTs[swap][1] = ts.fT[0][1];
4351 coincidence.fTs[!swap][0] = ts.fT[1][0];
4352 coincidence.fTs[!swap][1] = ts.fT[1][1];
4353 coincidence.fPts[0] = ts.fPt[0].asSkPoint();
4354 coincidence.fPts[1] = ts.fPt[1].asSkPoint();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004355 }
4356
4357 void addCross(const Contour* crosser) {
4358#ifdef DEBUG_CROSS
4359 for (int index = 0; index < fCrosses.count(); ++index) {
4360 SkASSERT(fCrosses[index] != crosser);
4361 }
4362#endif
4363 *fCrosses.append() = crosser;
4364 }
4365
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004366 void addCubic(const SkPoint pts[4]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004367 fSegments.push_back().addCubic(pts, fOperand, fXor);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004368 fContainsCurves = fContainsCubics = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004369 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004370
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004371 int addLine(const SkPoint pts[2]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004372 fSegments.push_back().addLine(pts, fOperand, fXor);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004373 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004374 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004375
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004376 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
4377 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
4378 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004379
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004380 int addQuad(const SkPoint pts[3]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004381 fSegments.push_back().addQuad(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004382 fContainsCurves = true;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004383 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004384 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004385
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004386 int addT(int segIndex, double newT, Contour* other, int otherIndex, const SkPoint& pt) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004387 setContainsIntercepts();
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004388 return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex], pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004389 }
4390
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004391 int addUnsortableT(int segIndex, double newT, Contour* other, int otherIndex, bool start,
4392 const SkPoint& pt) {
4393 return fSegments[segIndex].addUnsortableT(newT, &other->fSegments[otherIndex], start, pt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00004394 }
4395
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004396 const Bounds& bounds() const {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004397 return fBounds;
4398 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004399
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004400 void complete() {
4401 setBounds();
4402 fContainsIntercepts = false;
4403 }
skia.committer@gmail.com58433de2013-02-23 07:02:45 +00004404
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004405 bool containsCubics() const {
4406 return fContainsCubics;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004407 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004408
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004409 bool crosses(const Contour* crosser) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004410 for (int index = 0; index < fCrosses.count(); ++index) {
4411 if (fCrosses[index] == crosser) {
4412 return true;
4413 }
4414 }
4415 return false;
4416 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004417
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004418 bool done() const {
4419 return fDone;
4420 }
4421
caryclark@google.comf839c032012-10-26 21:03:50 +00004422 const SkPoint& end() const {
4423 const Segment& segment = fSegments.back();
4424 return segment.pts()[segment.verb()];
4425 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004426
caryclark@google.com4eeda372012-12-06 21:47:48 +00004427 void findTooCloseToCall() {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004428 int segmentCount = fSegments.count();
4429 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004430 fSegments[sIndex].findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004431 }
4432 }
4433
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004434 void fixOtherTIndex() {
4435 int segmentCount = fSegments.count();
4436 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4437 fSegments[sIndex].fixOtherTIndex();
4438 }
4439 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004440
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004441 Segment* nonVerticalSegment(int& start, int& end) {
4442 int segmentCount = fSortedSegments.count();
4443 SkASSERT(segmentCount > 0);
4444 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4445 Segment* testSegment = fSortedSegments[sortedIndex];
4446 if (testSegment->done()) {
4447 continue;
4448 }
4449 start = end = 0;
4450 while (testSegment->nextCandidate(start, end)) {
4451 if (!testSegment->isVertical(start, end)) {
4452 return testSegment;
4453 }
4454 }
4455 }
4456 return NULL;
4457 }
4458
caryclark@google.com31143cf2012-11-09 22:14:19 +00004459 bool operand() const {
4460 return fOperand;
4461 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004462
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004463 void reset() {
4464 fSegments.reset();
4465 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004466 fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004467 }
caryclark@google.comb9738012012-07-03 19:53:30 +00004468
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004469 void resolveCoincidence(SkTDArray<Contour*>& contourList) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004470 int count = fCoincidences.count();
4471 for (int index = 0; index < count; ++index) {
4472 Coincidence& coincidence = fCoincidences[index];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004473 SkASSERT(coincidence.fContours[0] == this);
caryclark@google.comb9738012012-07-03 19:53:30 +00004474 int thisIndex = coincidence.fSegments[0];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004475 Segment& thisOne = fSegments[thisIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004476 Contour* otherContour = coincidence.fContours[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004477 int otherIndex = coincidence.fSegments[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004478 Segment& other = otherContour->fSegments[otherIndex];
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004479 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004480 continue;
4481 }
caryclark@google.com47580692012-07-23 12:14:49 +00004482 #if DEBUG_CONCIDENT
4483 thisOne.debugShowTs();
4484 other.debugShowTs();
4485 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004486 double startT = coincidence.fTs[0][0];
4487 double endT = coincidence.fTs[0][1];
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004488 bool cancelers = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004489 if (startT > endT) {
4490 SkTSwap<double>(startT, endT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004491 cancelers ^= true; // FIXME: just assign true
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004492 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004493 SkASSERT(!approximately_negative(endT - startT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004494 double oStartT = coincidence.fTs[1][0];
4495 double oEndT = coincidence.fTs[1][1];
4496 if (oStartT > oEndT) {
4497 SkTSwap<double>(oStartT, oEndT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004498 cancelers ^= true;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004499 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004500 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00004501 bool opp = fOperand ^ otherContour->fOperand;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004502 if (cancelers && !opp) {
4503 // make sure startT and endT have t entries
caryclark@google.com2ddff932012-08-07 21:25:27 +00004504 if (startT > 0 || oEndT < 1
4505 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004506 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004507 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00004508 if (oStartT > 0 || endT < 1
4509 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004510 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004511 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004512 if (!thisOne.done() && !other.done()) {
4513 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4514 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004515 } else {
caryclark@google.com200c2112012-08-03 15:05:04 +00004516 if (startT > 0 || oStartT > 0
4517 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004518 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004519 }
caryclark@google.com200c2112012-08-03 15:05:04 +00004520 if (endT < 1 || oEndT < 1
4521 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004522 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004523 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004524 if (!thisOne.done() && !other.done()) {
4525 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4526 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004527 }
caryclark@google.com47580692012-07-23 12:14:49 +00004528 #if DEBUG_CONCIDENT
4529 thisOne.debugShowTs();
4530 other.debugShowTs();
4531 #endif
caryclark@google.com729e1c42012-11-21 21:36:34 +00004532 #if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004533 debugShowWindingValues(contourList);
4534 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004535 }
4536 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004537
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004538 // first pass, add missing T values
4539 // second pass, determine winding values of overlaps
4540 void addCoincidentPoints() {
4541 int count = fCoincidences.count();
4542 for (int index = 0; index < count; ++index) {
4543 Coincidence& coincidence = fCoincidences[index];
4544 SkASSERT(coincidence.fContours[0] == this);
4545 int thisIndex = coincidence.fSegments[0];
4546 Segment& thisOne = fSegments[thisIndex];
4547 Contour* otherContour = coincidence.fContours[1];
4548 int otherIndex = coincidence.fSegments[1];
4549 Segment& other = otherContour->fSegments[otherIndex];
4550 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
4551 // OPTIMIZATION: remove from array
4552 continue;
4553 }
4554 #if DEBUG_CONCIDENT
4555 thisOne.debugShowTs();
4556 other.debugShowTs();
4557 #endif
4558 double startT = coincidence.fTs[0][0];
4559 double endT = coincidence.fTs[0][1];
4560 bool cancelers;
4561 if ((cancelers = startT > endT)) {
4562 SkTSwap<double>(startT, endT);
4563 }
4564 SkASSERT(!approximately_negative(endT - startT));
4565 double oStartT = coincidence.fTs[1][0];
4566 double oEndT = coincidence.fTs[1][1];
4567 if (oStartT > oEndT) {
4568 SkTSwap<double>(oStartT, oEndT);
4569 cancelers ^= true;
4570 }
4571 SkASSERT(!approximately_negative(oEndT - oStartT));
4572 bool opp = fOperand ^ otherContour->fOperand;
4573 if (cancelers && !opp) {
4574 // make sure startT and endT have t entries
4575 if (startT > 0 || oEndT < 1
4576 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004577 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004578 }
4579 if (oStartT > 0 || endT < 1
4580 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004581 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004582 }
4583 } else {
4584 if (startT > 0 || oStartT > 0
4585 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004586 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004587 }
4588 if (endT < 1 || oEndT < 1
4589 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004590 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004591 }
4592 }
4593 #if DEBUG_CONCIDENT
4594 thisOne.debugShowTs();
4595 other.debugShowTs();
4596 #endif
4597 }
4598 }
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00004599
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004600 void calcCoincidentWinding() {
4601 int count = fCoincidences.count();
4602 for (int index = 0; index < count; ++index) {
4603 Coincidence& coincidence = fCoincidences[index];
4604 SkASSERT(coincidence.fContours[0] == this);
4605 int thisIndex = coincidence.fSegments[0];
4606 Segment& thisOne = fSegments[thisIndex];
4607 if (thisOne.done()) {
4608 continue;
4609 }
4610 Contour* otherContour = coincidence.fContours[1];
4611 int otherIndex = coincidence.fSegments[1];
4612 Segment& other = otherContour->fSegments[otherIndex];
4613 if (other.done()) {
4614 continue;
4615 }
4616 double startT = coincidence.fTs[0][0];
4617 double endT = coincidence.fTs[0][1];
4618 bool cancelers;
4619 if ((cancelers = startT > endT)) {
4620 SkTSwap<double>(startT, endT);
4621 }
4622 SkASSERT(!approximately_negative(endT - startT));
4623 double oStartT = coincidence.fTs[1][0];
4624 double oEndT = coincidence.fTs[1][1];
4625 if (oStartT > oEndT) {
4626 SkTSwap<double>(oStartT, oEndT);
4627 cancelers ^= true;
4628 }
4629 SkASSERT(!approximately_negative(oEndT - oStartT));
4630 bool opp = fOperand ^ otherContour->fOperand;
4631 if (cancelers && !opp) {
4632 // make sure startT and endT have t entries
4633 if (!thisOne.done() && !other.done()) {
4634 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4635 }
4636 } else {
4637 if (!thisOne.done() && !other.done()) {
4638 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4639 }
4640 }
4641 #if DEBUG_CONCIDENT
4642 thisOne.debugShowTs();
4643 other.debugShowTs();
4644 #endif
4645 }
4646 }
4647
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004648 SkTArray<Segment>& segments() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004649 return fSegments;
4650 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004651
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004652 void setContainsIntercepts() {
4653 fContainsIntercepts = true;
4654 }
4655
caryclark@google.com235f56a2012-09-14 14:19:30 +00004656 void setOperand(bool isOp) {
4657 fOperand = isOp;
4658 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00004659
caryclark@google.com4eeda372012-12-06 21:47:48 +00004660 void setOppXor(bool isOppXor) {
4661 fOppXor = isOppXor;
4662 int segmentCount = fSegments.count();
4663 for (int test = 0; test < segmentCount; ++test) {
4664 fSegments[test].setOppXor(isOppXor);
4665 }
4666 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004667
caryclark@google.com235f56a2012-09-14 14:19:30 +00004668 void setXor(bool isXor) {
4669 fXor = isXor;
4670 }
4671
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004672 void sortSegments() {
4673 int segmentCount = fSegments.count();
4674 fSortedSegments.setReserve(segmentCount);
4675 for (int test = 0; test < segmentCount; ++test) {
4676 *fSortedSegments.append() = &fSegments[test];
4677 }
4678 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4679 fFirstSorted = 0;
4680 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004681
caryclark@google.comf839c032012-10-26 21:03:50 +00004682 const SkPoint& start() const {
4683 return fSegments.front().pts()[0];
4684 }
4685
4686 void toPath(PathWrapper& path) const {
4687 int segmentCount = fSegments.count();
4688 const SkPoint& pt = fSegments.front().pts()[0];
4689 path.deferredMove(pt);
4690 for (int test = 0; test < segmentCount; ++test) {
4691 fSegments[test].addCurveTo(0, 1, path, true);
4692 }
4693 path.close();
4694 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004695
caryclark@google.comf839c032012-10-26 21:03:50 +00004696 void toPartialBackward(PathWrapper& path) const {
4697 int segmentCount = fSegments.count();
4698 for (int test = segmentCount - 1; test >= 0; --test) {
4699 fSegments[test].addCurveTo(1, 0, path, true);
4700 }
4701 }
4702
4703 void toPartialForward(PathWrapper& path) const {
4704 int segmentCount = fSegments.count();
4705 for (int test = 0; test < segmentCount; ++test) {
4706 fSegments[test].addCurveTo(0, 1, path, true);
4707 }
4708 }
4709
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004710 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004711 int segmentCount = fSortedSegments.count();
4712 SkASSERT(segmentCount > 0);
caryclark@google.comf839c032012-10-26 21:03:50 +00004713 int sortedIndex = fFirstSorted;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004714 fDone = true; // may be cleared below
caryclark@google.comf839c032012-10-26 21:03:50 +00004715 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4716 Segment* testSegment = fSortedSegments[sortedIndex];
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004717 if (testSegment->done()) {
caryclark@google.comf839c032012-10-26 21:03:50 +00004718 if (sortedIndex == fFirstSorted) {
4719 ++fFirstSorted;
4720 }
4721 continue;
4722 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004723 fDone = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004724 SkPoint testXY = testSegment->activeLeftTop(true, NULL);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004725 if (topStart) {
4726 if (testXY.fY < topLeft.fY) {
4727 continue;
4728 }
4729 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4730 continue;
4731 }
4732 if (bestXY.fY < testXY.fY) {
4733 continue;
4734 }
4735 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4736 continue;
4737 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004738 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004739 topStart = testSegment;
caryclark@google.comf839c032012-10-26 21:03:50 +00004740 bestXY = testXY;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004741 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004742 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004743
caryclark@google.com24bec792012-08-20 12:43:57 +00004744 Segment* undoneSegment(int& start, int& end) {
4745 int segmentCount = fSegments.count();
4746 for (int test = 0; test < segmentCount; ++test) {
4747 Segment* testSegment = &fSegments[test];
4748 if (testSegment->done()) {
4749 continue;
4750 }
4751 testSegment->undoneSpan(start, end);
4752 return testSegment;
4753 }
4754 return NULL;
4755 }
4756
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004757 int updateSegment(int index, const SkPoint* pts) {
4758 Segment& segment = fSegments[index];
4759 segment.updatePts(pts);
4760 return segment.verb() + 1;
4761 }
4762
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004763#if DEBUG_TEST
4764 SkTArray<Segment>& debugSegments() {
4765 return fSegments;
4766 }
4767#endif
4768
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004769#if DEBUG_DUMP
4770 void dump() {
4771 int i;
4772 const char className[] = "Contour";
4773 const int tab = 4;
4774 SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4775 for (i = 0; i < fSegments.count(); ++i) {
4776 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4777 className, i);
4778 fSegments[i].dump();
4779 }
4780 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4781 tab + sizeof(className), className,
4782 fBounds.fLeft, fBounds.fTop,
4783 fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004784 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4785 className, fContainsIntercepts);
4786 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4787 className, fContainsCurves);
4788 }
4789#endif
4790
caryclark@google.com027de222012-07-12 12:52:50 +00004791#if DEBUG_ACTIVE_SPANS
4792 void debugShowActiveSpans() {
4793 for (int index = 0; index < fSegments.count(); ++index) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004794 fSegments[index].debugShowActiveSpans();
caryclark@google.com027de222012-07-12 12:52:50 +00004795 }
4796 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004797
4798 void validateActiveSpans() {
4799 for (int index = 0; index < fSegments.count(); ++index) {
4800 fSegments[index].validateActiveSpans();
4801 }
4802 }
caryclark@google.com027de222012-07-12 12:52:50 +00004803#endif
4804
caryclark@google.com729e1c42012-11-21 21:36:34 +00004805#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004806 int debugShowWindingValues(int totalSegments, int ofInterest) {
4807 int count = fSegments.count();
4808 int sum = 0;
4809 for (int index = 0; index < count; ++index) {
4810 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4811 }
4812 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4813 return sum;
4814 }
4815
4816 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4817 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4818 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4819 int ofInterest = 1 << 5 | 1 << 8;
4820 int total = 0;
4821 int index;
4822 for (index = 0; index < contourList.count(); ++index) {
4823 total += contourList[index]->segments().count();
4824 }
4825 int sum = 0;
4826 for (index = 0; index < contourList.count(); ++index) {
4827 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4828 }
4829 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4830 }
4831#endif
4832
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004833protected:
4834 void setBounds() {
4835 int count = fSegments.count();
4836 if (count == 0) {
4837 SkDebugf("%s empty contour\n", __FUNCTION__);
4838 SkASSERT(0);
4839 // FIXME: delete empty contour?
4840 return;
4841 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004842 fBounds = fSegments.front().bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004843 for (int index = 1; index < count; ++index) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004844 fBounds.add(fSegments[index].bounds());
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004845 }
4846 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004847
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004848private:
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004849 SkTArray<Segment> fSegments;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004850 SkTDArray<Segment*> fSortedSegments;
4851 int fFirstSorted;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004852 SkTDArray<Coincidence> fCoincidences;
4853 SkTDArray<const Contour*> fCrosses;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004854 Bounds fBounds;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004855 bool fContainsIntercepts; // FIXME: is this used by anybody?
4856 bool fContainsCubics;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004857 bool fContainsCurves;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004858 bool fDone;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004859 bool fOperand; // true for the second argument to a binary operator
4860 bool fXor;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004861 bool fOppXor;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004862#if DEBUG_DUMP
4863 int fID;
4864#endif
4865};
4866
4867class EdgeBuilder {
4868public:
4869
caryclark@google.comf839c032012-10-26 21:03:50 +00004870EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
4871 : fPath(path.nativePath())
4872 , fContours(contours)
4873{
4874 init();
4875}
4876
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004877EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
caryclark@google.com235f56a2012-09-14 14:19:30 +00004878 : fPath(&path)
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004879 , fContours(contours)
4880{
caryclark@google.comf839c032012-10-26 21:03:50 +00004881 init();
4882}
4883
4884void init() {
4885 fCurrentContour = NULL;
4886 fOperand = false;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004887 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004888#if DEBUG_DUMP
4889 gContourID = 0;
4890 gSegmentID = 0;
4891#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00004892 fSecondHalf = preFetch();
4893}
4894
4895void addOperand(const SkPath& path) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00004896 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
4897 fPathVerbs.pop();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004898 fPath = &path;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004899 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004900 preFetch();
4901}
4902
4903void finish() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004904 walk();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004905 complete();
4906 if (fCurrentContour && !fCurrentContour->segments().count()) {
4907 fContours.pop_back();
4908 }
4909 // correct pointers in contours since fReducePts may have moved as it grew
4910 int cIndex = 0;
4911 int extraCount = fExtra.count();
4912 SkASSERT(extraCount == 0 || fExtra[0] == -1);
4913 int eIndex = 0;
4914 int rIndex = 0;
4915 while (++eIndex < extraCount) {
4916 int offset = fExtra[eIndex];
4917 if (offset < 0) {
4918 ++cIndex;
4919 continue;
4920 }
4921 fCurrentContour = &fContours[cIndex];
4922 rIndex += fCurrentContour->updateSegment(offset - 1,
4923 &fReducePts[rIndex]);
4924 }
4925 fExtra.reset(); // we're done with this
4926}
4927
4928ShapeOpMask xorMask() const {
caryclark@google.com729e1c42012-11-21 21:36:34 +00004929 return fXorMask[fOperand];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004930}
4931
4932protected:
4933
4934void complete() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004935 if (fCurrentContour && fCurrentContour->segments().count()) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004936 fCurrentContour->complete();
4937 fCurrentContour = NULL;
4938 }
4939}
4940
caryclark@google.com235f56a2012-09-14 14:19:30 +00004941// FIXME:remove once we can access path pts directly
4942int preFetch() {
4943 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004944 SkPoint pts[4];
4945 SkPath::Verb verb;
4946 do {
4947 verb = iter.next(pts);
4948 *fPathVerbs.append() = verb;
4949 if (verb == SkPath::kMove_Verb) {
4950 *fPathPts.append() = pts[0];
4951 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
4952 fPathPts.append(verb, &pts[1]);
4953 }
4954 } while (verb != SkPath::kDone_Verb);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004955 return fPathVerbs.count() - 1;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004956}
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004957
caryclark@google.com235f56a2012-09-14 14:19:30 +00004958void walk() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004959 SkPath::Verb reducedVerb;
4960 uint8_t* verbPtr = fPathVerbs.begin();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004961 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004962 const SkPoint* pointsPtr = fPathPts.begin();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004963 const SkPoint* finalCurveStart = NULL;
4964 const SkPoint* finalCurveEnd = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004965 SkPath::Verb verb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004966 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
4967 switch (verb) {
4968 case SkPath::kMove_Verb:
4969 complete();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004970 if (!fCurrentContour) {
4971 fCurrentContour = fContours.push_back_n(1);
caryclark@google.com235f56a2012-09-14 14:19:30 +00004972 fCurrentContour->setOperand(fOperand);
caryclark@google.com729e1c42012-11-21 21:36:34 +00004973 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004974 *fExtra.append() = -1; // start new contour
4975 }
caryclark@google.com59823f72012-08-09 18:17:47 +00004976 finalCurveEnd = pointsPtr++;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004977 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004978 case SkPath::kLine_Verb:
4979 // skip degenerate points
4980 if (pointsPtr[-1].fX != pointsPtr[0].fX
4981 || pointsPtr[-1].fY != pointsPtr[0].fY) {
4982 fCurrentContour->addLine(&pointsPtr[-1]);
4983 }
4984 break;
4985 case SkPath::kQuad_Verb:
rmistry@google.comd6176b02012-08-23 18:14:13 +00004986
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004987 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
4988 if (reducedVerb == 0) {
4989 break; // skip degenerate points
4990 }
4991 if (reducedVerb == 1) {
rmistry@google.comd6176b02012-08-23 18:14:13 +00004992 *fExtra.append() =
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004993 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004994 break;
4995 }
4996 fCurrentContour->addQuad(&pointsPtr[-1]);
4997 break;
4998 case SkPath::kCubic_Verb:
4999 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
5000 if (reducedVerb == 0) {
5001 break; // skip degenerate points
5002 }
5003 if (reducedVerb == 1) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005004 *fExtra.append() =
5005 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005006 break;
5007 }
5008 if (reducedVerb == 2) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005009 *fExtra.append() =
5010 fCurrentContour->addQuad(fReducePts.end() - 3);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005011 break;
5012 }
5013 fCurrentContour->addCubic(&pointsPtr[-1]);
5014 break;
5015 case SkPath::kClose_Verb:
5016 SkASSERT(fCurrentContour);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005017 if (finalCurveStart && finalCurveEnd
5018 && *finalCurveStart != *finalCurveEnd) {
5019 *fReducePts.append() = *finalCurveStart;
5020 *fReducePts.append() = *finalCurveEnd;
5021 *fExtra.append() =
5022 fCurrentContour->addLine(fReducePts.end() - 2);
5023 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005024 complete();
caryclark@google.com31143cf2012-11-09 22:14:19 +00005025 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005026 default:
5027 SkDEBUGFAIL("bad verb");
5028 return;
5029 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005030 finalCurveStart = &pointsPtr[verb - 1];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005031 pointsPtr += verb;
5032 SkASSERT(fCurrentContour);
caryclark@google.com31143cf2012-11-09 22:14:19 +00005033 nextVerb:
caryclark@google.com235f56a2012-09-14 14:19:30 +00005034 if (verbPtr == endOfFirstHalf) {
5035 fOperand = true;
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00005036 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005037 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005038}
5039
5040private:
caryclark@google.com235f56a2012-09-14 14:19:30 +00005041 const SkPath* fPath;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005042 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005043 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005044 Contour* fCurrentContour;
5045 SkTArray<Contour>& fContours;
5046 SkTDArray<SkPoint> fReducePts; // segments created on the fly
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005047 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
caryclark@google.com729e1c42012-11-21 21:36:34 +00005048 ShapeOpMask fXorMask[2];
caryclark@google.com235f56a2012-09-14 14:19:30 +00005049 int fSecondHalf;
5050 bool fOperand;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005051};
5052
5053class Work {
5054public:
5055 enum SegmentType {
5056 kHorizontalLine_Segment = -1,
5057 kVerticalLine_Segment = 0,
5058 kLine_Segment = SkPath::kLine_Verb,
5059 kQuad_Segment = SkPath::kQuad_Verb,
5060 kCubic_Segment = SkPath::kCubic_Verb,
5061 };
rmistry@google.comd6176b02012-08-23 18:14:13 +00005062
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005063 void addCoincident(Work& other, const Intersections& ts, bool swap) {
5064 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
5065 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005066
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005067 // FIXME: does it make sense to write otherIndex now if we're going to
5068 // fix it up later?
5069 void addOtherT(int index, double otherT, int otherIndex) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005070 fContour->addOtherT(fIndex, index, otherT, otherIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005071 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005072
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005073 // Avoid collapsing t values that are close to the same since
5074 // we walk ts to describe consecutive intersections. Since a pair of ts can
5075 // be nearly equal, any problems caused by this should be taken care
5076 // of later.
5077 // On the edge or out of range values are negative; add 2 to get end
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005078 int addT(double newT, const Work& other, const SkPoint& pt) {
5079 return fContour->addT(fIndex, newT, other.fContour, other.fIndex, pt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005080 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005081
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005082 int addUnsortableT(double newT, const Work& other, bool start, const SkPoint& pt) {
5083 return fContour->addUnsortableT(fIndex, newT, other.fContour, other.fIndex, start, pt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005084 }
5085
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005086 bool advance() {
5087 return ++fIndex < fLast;
5088 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005089
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005090 SkScalar bottom() const {
5091 return bounds().fBottom;
5092 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005093
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005094 const Bounds& bounds() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005095 return fContour->segments()[fIndex].bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005096 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00005097
caryclark@google.com73ca6242013-01-17 21:02:47 +00005098#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005099 const SkPoint* cubic() const {
5100 return fCubic;
5101 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005102#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005103
5104 void init(Contour* contour) {
5105 fContour = contour;
5106 fIndex = 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005107 fLast = contour->segments().count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005108 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00005109
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00005110 bool isAdjacent(const Work& next) {
5111 return fContour == next.fContour && fIndex + 1 == next.fIndex;
5112 }
5113
5114 bool isFirstLast(const Work& next) {
5115 return fContour == next.fContour && fIndex == 0
5116 && next.fIndex == fLast - 1;
5117 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005118
5119 SkScalar left() const {
5120 return bounds().fLeft;
5121 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005122
caryclark@google.com73ca6242013-01-17 21:02:47 +00005123#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005124 void promoteToCubic() {
5125 fCubic[0] = pts()[0];
5126 fCubic[2] = pts()[1];
5127 fCubic[3] = pts()[2];
5128 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
5129 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
5130 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
5131 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
5132 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005133#endif
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005134
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005135 const SkPoint* pts() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005136 return fContour->segments()[fIndex].pts();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005137 }
5138
5139 SkScalar right() const {
5140 return bounds().fRight;
5141 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005142
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005143 ptrdiff_t segmentIndex() const {
5144 return fIndex;
5145 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005146
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005147 SegmentType segmentType() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005148 const Segment& segment = fContour->segments()[fIndex];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005149 SegmentType type = (SegmentType) segment.verb();
5150 if (type != kLine_Segment) {
5151 return type;
5152 }
5153 if (segment.isHorizontal()) {
5154 return kHorizontalLine_Segment;
5155 }
5156 if (segment.isVertical()) {
5157 return kVerticalLine_Segment;
5158 }
5159 return kLine_Segment;
5160 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005161
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005162 bool startAfter(const Work& after) {
5163 fIndex = after.fIndex;
5164 return advance();
5165 }
5166
5167 SkScalar top() const {
5168 return bounds().fTop;
5169 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005170
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005171 SkPath::Verb verb() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005172 return fContour->segments()[fIndex].verb();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005173 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005174
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005175 SkScalar x() const {
5176 return bounds().fLeft;
5177 }
5178
5179 bool xFlipped() const {
5180 return x() != pts()[0].fX;
5181 }
5182
5183 SkScalar y() const {
5184 return bounds().fTop;
5185 }
5186
5187 bool yFlipped() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005188 return y() != pts()[0].fY;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005189 }
5190
5191protected:
5192 Contour* fContour;
caryclark@google.com73ca6242013-01-17 21:02:47 +00005193#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005194 SkPoint fCubic[4];
caryclark@google.com73ca6242013-01-17 21:02:47 +00005195#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005196 int fIndex;
5197 int fLast;
5198};
5199
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005200#if DEBUG_ADD_INTERSECTING_TS
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005201
5202#define DEBUG_AS_C_CODE 1
5203#if DEBUG_AS_C_CODE
5204#define CUBIC_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}}"
5205#define QUAD_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}}"
5206#define LINE_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}}"
5207#define PT_DEBUG_STR "{{%1.17g,%1.17g}}"
5208#else
5209#define CUBIC_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5210#define QUAD_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5211#define LINE_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g)"
5212#define PT_DEBUG_STR "(%1.9g,%1.9g)"
5213#endif
5214#define T_DEBUG_STR(t, n) #t "[" #n "]=%1.9g"
5215#define TX_DEBUG_STR(t) #t "[%d]=%1.9g"
5216#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
5217#define QUAD_DEBUG_DATA(q) q[0].fX, q[0].fY, q[1].fX, q[1].fY, q[2].fX, q[2].fY
5218#define LINE_DEBUG_DATA(l) l[0].fX, l[0].fY, l[1].fX, l[1].fY
5219#define PT_DEBUG_DATA(i, n) i.fPt[n].x, i.fPt[n].y
5220
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005221static void debugShowLineIntersection(int pts, const Work& wt, const Work& wn,
5222 const Intersections& i) {
5223 SkASSERT(i.used() == pts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005224 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005225 SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n",
5226 __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005227 return;
5228 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005229 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " LINE_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5230 i.fT[0][0], LINE_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005231 if (pts == 2) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005232 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 +00005233 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005234 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005235 if (pts == 2) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005236 SkDebugf(" " T_DEBUG_STR(wnTs, 1), i.fT[1][1]);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005237 }
5238 SkDebugf("\n");
5239}
5240
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005241static void debugShowQuadLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005242 const Work& wn, const Intersections& i) {
5243 SkASSERT(i.used() == pts);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005244 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005245 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " LINE_DEBUG_STR "\n",
5246 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005247 return;
5248 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005249 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5250 i.fT[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5251 for (int n = 1; n < pts; ++n) {
5252 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 +00005253 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005254 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
5255 for (int n = 1; n < pts; ++n) {
5256 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005257 }
5258 SkDebugf("\n");
5259}
5260
caryclark@google.coma461ff02012-10-11 12:54:23 +00005261static void debugShowQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005262 const Work& wn, const Intersections& i) {
5263 SkASSERT(i.used() == pts);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005264 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005265 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " QUAD_DEBUG_STR "\n",
5266 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
caryclark@google.coma461ff02012-10-11 12:54:23 +00005267 return;
5268 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005269 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5270 i.fT[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5271 for (int n = 1; n < pts; ++n) {
5272 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 +00005273 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005274 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i.fT[1][0], QUAD_DEBUG_DATA(wn.pts()));
5275 for (int n = 1; n < pts; ++n) {
5276 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005277 }
caryclark@google.comb9738012012-07-03 19:53:30 +00005278 SkDebugf("\n");
5279}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005280
5281static void debugShowCubicLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005282 const Work& wn, const Intersections& i) {
5283 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005284 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005285 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " LINE_DEBUG_STR "\n",
5286 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005287 return;
5288 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005289 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5290 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5291 for (int n = 1; n < pts; ++n) {
5292 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 +00005293 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005294 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
5295 for (int n = 1; n < pts; ++n) {
5296 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005297 }
5298 SkDebugf("\n");
5299}
5300
caryclark@google.com73ca6242013-01-17 21:02:47 +00005301static void debugShowCubicQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005302 const Work& wn, const Intersections& i) {
5303 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005304 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005305 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " QUAD_DEBUG_STR "\n",
5306 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005307 return;
5308 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005309 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5310 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5311 for (int n = 1; n < pts; ++n) {
5312 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 +00005313 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005314 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i.fT[1][0], QUAD_DEBUG_DATA(wn.pts()));
5315 for (int n = 1; n < pts; ++n) {
5316 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005317 }
5318 SkDebugf("\n");
5319}
5320
caryclark@google.com73ca6242013-01-17 21:02:47 +00005321static void debugShowCubicIntersection(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.com73ca6242013-01-17 21:02:47 +00005324 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005325 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " CUBIC_DEBUG_STR "\n",
5326 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), CUBIC_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005327 return;
5328 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005329 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5330 i.fT[0][0], CUBIC_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.com73ca6242013-01-17 21:02:47 +00005333 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005334 SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i.fT[1][0], CUBIC_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.com73ca6242013-01-17 21:02:47 +00005337 }
5338 SkDebugf("\n");
5339}
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005340
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005341static void debugShowCubicIntersection(int pts, const Work& wt, const Intersections& i) {
5342 SkASSERT(i.used() == pts);
5343 if (!pts) {
5344 SkDebugf("%s no self intersect " CUBIC_DEBUG_STR "\n", __FUNCTION__,
5345 CUBIC_DEBUG_DATA(wt.pts()));
5346 return;
5347 }
5348 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5349 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5350 SkDebugf(" " T_DEBUG_STR(wtTs, 1), i.fT[1][0]);
5351 SkDebugf("\n");
5352}
5353
5354#undef CUBIC_DEBUG_STR
5355#undef QUAD_DEBUG_STR
5356#undef LINE_DEBUG_STR
5357#undef PT_DEBUG_STR
5358#undef T_DEBUG_STR
5359#undef CUBIC_DEBUG_DATA
5360#undef QUAD_DEBUG_DATA
5361#undef LINE_DEBUG_DATA
5362#undef PT_DEBUG_DATA
5363
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005364#else
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005365static void debugShowLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005366}
caryclark@google.coma461ff02012-10-11 12:54:23 +00005367
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005368static void debugShowQuadLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005369}
5370
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005371static void debugShowQuadIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005372}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005373
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005374static void debugShowCubicLineIntersection(int , const Work& , const Work& ,
5375 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005376}
5377
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005378static void debugShowCubicQuadIntersection(int , const Work& , const Work& ,
5379 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005380}
5381
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005382static void debugShowCubicIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005383}
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005384
5385static void debugShowCubicIntersection(int , const Work& , const Intersections& ) {
5386}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005387#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005388
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005389static bool addIntersectTs(Contour* test, Contour* next) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005390
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005391 if (test != next) {
5392 if (test->bounds().fBottom < next->bounds().fTop) {
5393 return false;
5394 }
5395 if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5396 return true;
5397 }
5398 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005399 Work wt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005400 wt.init(test);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005401 bool foundCommonContour = test == next;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005402 do {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005403 Work wn;
5404 wn.init(next);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005405 if (test == next && !wn.startAfter(wt)) {
5406 continue;
5407 }
5408 do {
5409 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5410 continue;
5411 }
5412 int pts;
5413 Intersections ts;
5414 bool swap = false;
5415 switch (wt.segmentType()) {
5416 case Work::kHorizontalLine_Segment:
5417 swap = true;
5418 switch (wn.segmentType()) {
5419 case Work::kHorizontalLine_Segment:
5420 case Work::kVerticalLine_Segment:
5421 case Work::kLine_Segment: {
5422 pts = HLineIntersect(wn.pts(), wt.left(),
5423 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005424 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005425 break;
5426 }
5427 case Work::kQuad_Segment: {
5428 pts = HQuadIntersect(wn.pts(), wt.left(),
5429 wt.right(), wt.y(), wt.xFlipped(), ts);
5430 break;
5431 }
5432 case Work::kCubic_Segment: {
5433 pts = HCubicIntersect(wn.pts(), wt.left(),
5434 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005435 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005436 break;
5437 }
5438 default:
5439 SkASSERT(0);
5440 }
5441 break;
5442 case Work::kVerticalLine_Segment:
5443 swap = true;
5444 switch (wn.segmentType()) {
5445 case Work::kHorizontalLine_Segment:
5446 case Work::kVerticalLine_Segment:
5447 case Work::kLine_Segment: {
5448 pts = VLineIntersect(wn.pts(), wt.top(),
5449 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005450 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005451 break;
5452 }
5453 case Work::kQuad_Segment: {
5454 pts = VQuadIntersect(wn.pts(), wt.top(),
5455 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5456 break;
5457 }
5458 case Work::kCubic_Segment: {
5459 pts = VCubicIntersect(wn.pts(), wt.top(),
5460 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005461 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005462 break;
5463 }
5464 default:
5465 SkASSERT(0);
5466 }
5467 break;
5468 case Work::kLine_Segment:
5469 switch (wn.segmentType()) {
5470 case Work::kHorizontalLine_Segment:
5471 pts = HLineIntersect(wt.pts(), wn.left(),
5472 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005473 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005474 break;
5475 case Work::kVerticalLine_Segment:
5476 pts = VLineIntersect(wt.pts(), wn.top(),
5477 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005478 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005479 break;
5480 case Work::kLine_Segment: {
5481 pts = LineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005482 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005483 break;
5484 }
5485 case Work::kQuad_Segment: {
5486 swap = true;
5487 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005488 debugShowQuadLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005489 break;
5490 }
5491 case Work::kCubic_Segment: {
5492 swap = true;
5493 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005494 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005495 break;
5496 }
5497 default:
5498 SkASSERT(0);
5499 }
5500 break;
5501 case Work::kQuad_Segment:
5502 switch (wn.segmentType()) {
5503 case Work::kHorizontalLine_Segment:
5504 pts = HQuadIntersect(wt.pts(), wn.left(),
5505 wn.right(), wn.y(), wn.xFlipped(), ts);
5506 break;
5507 case Work::kVerticalLine_Segment:
5508 pts = VQuadIntersect(wt.pts(), wn.top(),
5509 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5510 break;
5511 case Work::kLine_Segment: {
5512 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005513 debugShowQuadLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005514 break;
5515 }
5516 case Work::kQuad_Segment: {
5517 pts = QuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005518 debugShowQuadIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005519 break;
5520 }
5521 case Work::kCubic_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005522 #if APPROXIMATE_CUBICS
5523 swap = true;
5524 pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005525 debugShowCubicQuadIntersection(pts, wn, wt, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005526 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005527 wt.promoteToCubic();
5528 pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005529 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005530 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005531 break;
5532 }
5533 default:
5534 SkASSERT(0);
5535 }
5536 break;
5537 case Work::kCubic_Segment:
5538 switch (wn.segmentType()) {
5539 case Work::kHorizontalLine_Segment:
5540 pts = HCubicIntersect(wt.pts(), wn.left(),
5541 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005542 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005543 break;
5544 case Work::kVerticalLine_Segment:
5545 pts = VCubicIntersect(wt.pts(), wn.top(),
5546 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005547 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005548 break;
5549 case Work::kLine_Segment: {
5550 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005551 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005552 break;
5553 }
5554 case Work::kQuad_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005555 #if APPROXIMATE_CUBICS
5556 pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005557 debugShowCubicQuadIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005558 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005559 wn.promoteToCubic();
5560 pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005561 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005562 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005563 break;
5564 }
5565 case Work::kCubic_Segment: {
5566 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005567 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005568 break;
5569 }
5570 default:
5571 SkASSERT(0);
5572 }
5573 break;
5574 default:
5575 SkASSERT(0);
5576 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005577 if (!foundCommonContour && pts > 0) {
5578 test->addCross(next);
5579 next->addCross(test);
5580 foundCommonContour = true;
5581 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005582 // in addition to recording T values, record matching segment
caryclark@google.com73ca6242013-01-17 21:02:47 +00005583 if (ts.unsortable()) {
5584 bool start = true;
5585 for (int pt = 0; pt < ts.used(); ++pt) {
5586 // FIXME: if unsortable, the other points to the original. This logic is
5587 // untested downstream.
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005588 SkPoint point = ts.fPt[pt].asSkPoint();
5589 int testTAt = wt.addUnsortableT(ts.fT[swap][pt], wt, start, point);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005590 wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005591 testTAt = wn.addUnsortableT(ts.fT[!swap][pt], wn, start ^ ts.fFlip, point);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005592 wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt);
5593 start ^= true;
5594 }
5595 continue;
5596 }
caryclark@google.com32546db2012-08-31 20:55:07 +00005597 if (pts == 2) {
5598 if (wn.segmentType() <= Work::kLine_Segment
5599 && wt.segmentType() <= Work::kLine_Segment) {
5600 wt.addCoincident(wn, ts, swap);
5601 continue;
5602 }
caryclark@google.combeda3892013-02-07 13:13:41 +00005603 if (wn.segmentType() >= Work::kQuad_Segment
5604 && wt.segmentType() >= Work::kQuad_Segment
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005605 && ts.fIsCoincident[0]) {
5606 SkASSERT(ts.coincidentUsed() == 2);
caryclark@google.com32546db2012-08-31 20:55:07 +00005607 wt.addCoincident(wn, ts, swap);
5608 continue;
5609 }
5610
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00005611 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00005612 for (int pt = 0; pt < pts; ++pt) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005613 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5614 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005615 SkPoint point = ts.fPt[pt].asSkPoint();
5616 int testTAt = wt.addT(ts.fT[swap][pt], wn, point);
5617 int nextTAt = wn.addT(ts.fT[!swap][pt], wt, point);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005618 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
5619 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005620 }
5621 } while (wn.advance());
5622 } while (wt.advance());
5623 return true;
5624}
5625
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005626static void addSelfIntersectTs(Contour* test) {
5627 Work wt;
5628 wt.init(test);
5629 do {
5630 if (wt.segmentType() != Work::kCubic_Segment) {
5631 continue;
5632 }
5633 Intersections ts;
5634 int pts = CubicIntersect(wt.pts(), ts);
5635 debugShowCubicIntersection(pts, wt, ts);
5636 if (!pts) {
5637 continue;
5638 }
5639 SkASSERT(pts == 1);
5640 SkASSERT(ts.fT[0][0] >= 0 && ts.fT[0][0] <= 1);
5641 SkASSERT(ts.fT[1][0] >= 0 && ts.fT[1][0] <= 1);
5642 SkPoint point = ts.fPt[0].asSkPoint();
5643 int testTAt = wt.addT(ts.fT[0][0], wt, point);
5644 int nextTAt = wt.addT(ts.fT[1][0], wt, point);
5645 wt.addOtherT(testTAt, ts.fT[1][0], nextTAt);
5646 wt.addOtherT(nextTAt, ts.fT[0][0], testTAt);
5647 } while (wt.advance());
5648}
5649
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005650// resolve any coincident pairs found while intersecting, and
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005651// see if coincidence is formed by clipping non-concident segments
caryclark@google.com4eeda372012-12-06 21:47:48 +00005652static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005653 int contourCount = contourList.count();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005654#if ONE_PASS_COINCIDENCE_CHECK
caryclark@google.comf25edfe2012-06-01 18:20:10 +00005655 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005656 Contour* contour = contourList[cIndex];
caryclark@google.com7ba591e2012-11-20 14:21:54 +00005657 contour->resolveCoincidence(contourList);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005658 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005659#else
5660 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5661 Contour* contour = contourList[cIndex];
5662 contour->addCoincidentPoints();
5663 }
5664 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5665 Contour* contour = contourList[cIndex];
5666 contour->calcCoincidentWinding();
5667 }
5668#endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005669 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5670 Contour* contour = contourList[cIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00005671 contour->findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005672 }
5673}
5674
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005675static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005676 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005677 SkPoint basePt;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005678 double tAtMid = current->tAtMid(index, endIndex, mid);
5679 current->xyAtT(tAtMid, basePt);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005680 int contourCount = contourList.count();
5681 SkScalar bestY = SK_ScalarMin;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005682 Segment* bestSeg = NULL;
5683 int bestTIndex;
5684 bool bestOpp;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005685 bool hitSomething = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005686 for (int cTest = 0; cTest < contourCount; ++cTest) {
5687 Contour* contour = contourList[cTest];
5688 bool testOpp = contour->operand() ^ current->operand() ^ opp;
5689 if (basePt.fY < contour->bounds().fTop) {
5690 continue;
5691 }
5692 if (bestY > contour->bounds().fBottom) {
5693 continue;
5694 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005695 int segmentCount = contour->segments().count();
5696 for (int test = 0; test < segmentCount; ++test) {
5697 Segment* testSeg = &contour->segments()[test];
5698 SkScalar testY = bestY;
5699 double testHit;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005700 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
5701 testOpp, testSeg == current);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005702 if (testTIndex < 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005703 if (testTIndex == SK_MinS32) {
5704 hitSomething = true;
5705 bestSeg = NULL;
5706 goto abortContours; // vertical encountered, return and try different point
5707 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005708 continue;
5709 }
5710 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005711 double baseT = current->t(index);
5712 double endT = current->t(endIndex);
5713 double newMid = (testHit - baseT) / (endT - baseT);
5714#if DEBUG_WINDING
5715 SkPoint midXY, newXY;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005716 double midT = current->tAtMid(index, endIndex, mid);
5717 current->xyAtT(midT, midXY);
5718 double newMidT = current->tAtMid(index, endIndex, newMid);
5719 current->xyAtT(newMidT, newXY);
caryclark@google.com3586ece2012-12-27 18:46:58 +00005720 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
5721 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
5722 current->debugID(), mid, newMid,
5723 baseT, current->xAtT(index), current->yAtT(index),
5724 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
5725 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
5726 endT, current->xAtT(endIndex), current->yAtT(endIndex));
5727#endif
5728 mid = newMid * 2; // calling loop with divide by 2 before continuing
5729 return SK_MinS32;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005730 }
5731 bestSeg = testSeg;
5732 bestHit = testHit;
5733 bestOpp = testOpp;
5734 bestTIndex = testTIndex;
5735 bestY = testY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005736 }
5737 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005738abortContours:
caryclark@google.com10227bf2012-12-28 22:10:41 +00005739 int result;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005740 if (!bestSeg) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00005741 result = hitSomething ? SK_MinS32 : 0;
5742 } else {
5743 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
5744 current = bestSeg;
5745 index = bestTIndex;
5746 endIndex = bestSeg->nextSpan(bestTIndex, 1);
5747 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
5748 tryAgain = true;
5749 return 0;
5750 }
5751 result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
5752 SkASSERT(bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005753 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005754 double baseT = current->t(index);
5755 double endT = current->t(endIndex);
5756 bestHit = baseT + mid * (endT - baseT);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005757 return result;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005758}
5759
caryclark@google.com24bec792012-08-20 12:43:57 +00005760static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
5761 int contourCount = contourList.count();
5762 Segment* result;
5763 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5764 Contour* contour = contourList[cIndex];
5765 result = contour->undoneSegment(start, end);
5766 if (result) {
5767 return result;
5768 }
5769 }
5770 return NULL;
5771}
5772
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005773#define OLD_FIND_CHASE 1
caryclark@google.com24bec792012-08-20 12:43:57 +00005774
caryclark@google.com31143cf2012-11-09 22:14:19 +00005775static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005776 while (chase.count()) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005777 Span* span;
5778 chase.pop(&span);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005779 const Span& backPtr = span->fOther->span(span->fOtherIndex);
5780 Segment* segment = backPtr.fOther;
5781 tIndex = backPtr.fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005782 SkTDArray<Angle> angles;
5783 int done = 0;
5784 if (segment->activeAngle(tIndex, done, angles)) {
5785 Angle* last = angles.end() - 1;
5786 tIndex = last->start();
5787 endIndex = last->end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005788 #if TRY_ROTATE
5789 *chase.insert(0) = span;
5790 #else
5791 *chase.append() = span;
5792 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005793 return last->segment();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005794 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005795 if (done == angles.count()) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00005796 continue;
5797 }
5798 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005799 bool sortable = Segment::SortAngles(angles, sorted);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005800 int angleCount = sorted.count();
caryclark@google.com03f97062012-08-21 13:13:52 +00005801#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005802 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00005803#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005804 if (!sortable) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005805 continue;
5806 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005807 // find first angle, initialize winding to computed fWindSum
5808 int firstIndex = -1;
5809 const Angle* angle;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005810#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005811 int winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005812 do {
5813 angle = sorted[++firstIndex];
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005814 segment = angle->segment();
5815 winding = segment->windSum(angle);
5816 } while (winding == SK_MinS32);
5817 int spanWinding = segment->spanSign(angle->start(), angle->end());
5818 #if DEBUG_WINDING
caryclark@google.com31143cf2012-11-09 22:14:19 +00005819 SkDebugf("%s winding=%d spanWinding=%d\n",
5820 __FUNCTION__, winding, spanWinding);
caryclark@google.com47580692012-07-23 12:14:49 +00005821 #endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005822 // turn span winding into contour winding
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005823 if (spanWinding * winding < 0) {
5824 winding += spanWinding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005825 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005826 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005827 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005828 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005829 // we care about first sign and whether wind sum indicates this
5830 // edge is inside or outside. Maybe need to pass span winding
5831 // or first winding or something into this function?
5832 // advance to first undone angle, then return it and winding
5833 // (to set whether edges are active or not)
5834 int nextIndex = firstIndex + 1;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005835 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005836 angle = sorted[firstIndex];
caryclark@google.com2ddff932012-08-07 21:25:27 +00005837 winding -= angle->segment()->spanSign(angle);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005838#else
5839 do {
5840 angle = sorted[++firstIndex];
5841 segment = angle->segment();
5842 } while (segment->windSum(angle) == SK_MinS32);
5843 #if DEBUG_SORT
5844 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5845 #endif
5846 int sumWinding = segment->updateWindingReverse(angle);
5847 int nextIndex = firstIndex + 1;
5848 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5849 Segment* first = NULL;
5850#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005851 do {
5852 SkASSERT(nextIndex != firstIndex);
5853 if (nextIndex == angleCount) {
5854 nextIndex = 0;
5855 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005856 angle = sorted[nextIndex];
caryclark@google.com9764cc62012-07-12 19:29:45 +00005857 segment = angle->segment();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005858#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005859 int maxWinding = winding;
caryclark@google.com2ddff932012-08-07 21:25:27 +00005860 winding -= segment->spanSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005861 #if DEBUG_SORT
caryclark@google.com2ddff932012-08-07 21:25:27 +00005862 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
5863 segment->debugID(), maxWinding, winding, angle->sign());
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005864 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005865 tIndex = angle->start();
5866 endIndex = angle->end();
5867 int lesser = SkMin32(tIndex, endIndex);
5868 const Span& nextSpan = segment->span(lesser);
5869 if (!nextSpan.fDone) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005870#if 1
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005871 // FIXME: this be wrong? assign startWinding if edge is in
caryclark@google.com9764cc62012-07-12 19:29:45 +00005872 // same direction. If the direction is opposite, winding to
5873 // assign is flipped sign or +/- 1?
caryclark@google.com59823f72012-08-09 18:17:47 +00005874 if (useInnerWinding(maxWinding, winding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005875 maxWinding = winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005876 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005877 segment->markAndChaseWinding(angle, maxWinding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005878#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005879 break;
5880 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005881#else
5882 int start = angle->start();
5883 int end = angle->end();
5884 int maxWinding;
5885 segment->setUpWinding(start, end, maxWinding, sumWinding);
5886 if (!segment->done(angle)) {
5887 if (!first) {
5888 first = segment;
5889 tIndex = start;
5890 endIndex = end;
5891 }
5892 (void) segment->markAngle(maxWinding, sumWinding, true, angle);
5893 }
5894#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005895 } while (++nextIndex != lastIndex);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005896 #if TRY_ROTATE
5897 *chase.insert(0) = span;
5898 #else
5899 *chase.append() = span;
5900 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005901 return segment;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005902 }
5903 return NULL;
5904}
5905
caryclark@google.com027de222012-07-12 12:52:50 +00005906#if DEBUG_ACTIVE_SPANS
5907static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005908 int index;
5909 for (index = 0; index < contourList.count(); ++ index) {
caryclark@google.com027de222012-07-12 12:52:50 +00005910 contourList[index]->debugShowActiveSpans();
5911 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005912 for (index = 0; index < contourList.count(); ++ index) {
5913 contourList[index]->validateActiveSpans();
5914 }
caryclark@google.com027de222012-07-12 12:52:50 +00005915}
5916#endif
5917
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005918static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005919 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005920 Segment* result;
5921 do {
caryclark@google.comf839c032012-10-26 21:03:50 +00005922 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005923 int contourCount = contourList.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00005924 Segment* topStart = NULL;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005925 done = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00005926 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5927 Contour* contour = contourList[cIndex];
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005928 if (contour->done()) {
5929 continue;
5930 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005931 const Bounds& bounds = contour->bounds();
5932 if (bounds.fBottom < topLeft.fY) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005933 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005934 continue;
5935 }
5936 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005937 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005938 continue;
5939 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005940 contour->topSortableSegment(topLeft, bestXY, topStart);
5941 if (!contour->done()) {
5942 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005943 }
5944 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005945 if (!topStart) {
5946 return NULL;
5947 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005948 topLeft = bestXY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005949 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005950 } while (!result);
5951 return result;
5952}
caryclark@google.com31143cf2012-11-09 22:14:19 +00005953
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005954static int rightAngleWinding(SkTDArray<Contour*>& contourList,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005955 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005956 bool opp) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005957 double test = 0.9;
5958 int contourWinding;
5959 do {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005960 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
5961 tryAgain, test, opp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005962 if (contourWinding != SK_MinS32 || tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005963 return contourWinding;
5964 }
5965 test /= 2;
5966 } while (!approximately_negative(test));
5967 SkASSERT(0); // should be OK to comment out, but interested when this hits
5968 return contourWinding;
5969}
5970
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005971static void skipVertical(SkTDArray<Contour*>& contourList,
5972 Segment*& current, int& index, int& endIndex) {
5973 if (!current->isVertical(index, endIndex)) {
5974 return;
5975 }
5976 int contourCount = contourList.count();
5977 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5978 Contour* contour = contourList[cIndex];
5979 if (contour->done()) {
5980 continue;
5981 }
5982 current = contour->nonVerticalSegment(index, endIndex);
5983 if (current) {
5984 return;
5985 }
5986 }
5987}
5988
caryclark@google.com3586ece2012-12-27 18:46:58 +00005989static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005990 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
5991 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
5992 true);
5993 if (!current) {
5994 return NULL;
5995 }
5996 if (firstContour) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005997 current->initWinding(index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005998 firstContour = false;
5999 return current;
6000 }
6001 int minIndex = SkMin32(index, endIndex);
6002 int sumWinding = current->windSum(minIndex);
6003 if (sumWinding != SK_MinS32) {
6004 return current;
6005 }
6006 sumWinding = current->computeSum(index, endIndex, binary);
6007 if (sumWinding != SK_MinS32) {
6008 return current;
6009 }
6010 int contourWinding;
6011 int oppContourWinding = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006012 // the simple upward projection of the unresolved points hit unsortable angles
6013 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006014 bool tryAgain;
6015 double tHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006016 SkScalar hitDx = 0;
6017 SkScalar hitOppDx = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006018 do {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006019 // if current is vertical, find another candidate which is not
6020 // if only remaining candidates are vertical, then they can be marked done
caryclark@google.com10227bf2012-12-28 22:10:41 +00006021 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006022 skipVertical(contourList, current, index, endIndex);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006023 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006024 tryAgain = false;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006025 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006026 tryAgain, false);
6027 if (tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006028 continue;
6029 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006030 if (!binary) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006031 break;
6032 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00006033 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006034 tryAgain, true);
6035 } while (tryAgain);
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00006036
caryclark@google.com3586ece2012-12-27 18:46:58 +00006037 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006038 return current;
6039}
6040
6041// rewrite that abandons keeping local track of winding
caryclark@google.com3586ece2012-12-27 18:46:58 +00006042static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006043 bool firstContour = true;
6044 bool unsortable = false;
6045 bool topUnsortable = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006046 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
6047 do {
6048 int index, endIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006049 bool topDone;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006050 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006051 topUnsortable, topDone, false);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006052 if (!current) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006053 if (topUnsortable || !topDone) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006054 topUnsortable = false;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006055 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006056 topLeft.fX = topLeft.fY = SK_ScalarMin;
6057 continue;
6058 }
6059 break;
6060 }
6061 SkTDArray<Span*> chaseArray;
6062 do {
6063 if (current->activeWinding(index, endIndex)) {
6064 do {
6065 #if DEBUG_ACTIVE_SPANS
6066 if (!unsortable && current->done()) {
6067 debugShowActiveSpans(contourList);
6068 }
6069 #endif
6070 SkASSERT(unsortable || !current->done());
6071 int nextStart = index;
6072 int nextEnd = endIndex;
6073 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
6074 unsortable);
6075 if (!next) {
6076 if (!unsortable && simple.hasMove()
6077 && current->verb() != SkPath::kLine_Verb
6078 && !simple.isClosed()) {
6079 current->addCurveTo(index, endIndex, simple, true);
6080 SkASSERT(simple.isClosed());
6081 }
6082 break;
6083 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006084 #if DEBUG_FLOW
6085 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6086 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
6087 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
6088 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006089 current->addCurveTo(index, endIndex, simple, true);
6090 current = next;
6091 index = nextStart;
6092 endIndex = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006093 } while (!simple.isClosed() && (!unsortable
caryclark@google.com10227bf2012-12-28 22:10:41 +00006094 || !current->done(SkMin32(index, endIndex))));
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006095 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
6096 SkASSERT(unsortable);
6097 int min = SkMin32(index, endIndex);
6098 if (!current->done(min)) {
6099 current->addCurveTo(index, endIndex, simple, true);
6100 current->markDoneUnary(min);
6101 }
6102 }
6103 simple.close();
6104 } else {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006105 Span* last = current->markAndChaseDoneUnary(index, endIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006106 if (last) {
6107 *chaseArray.append() = last;
6108 }
6109 }
6110 current = findChase(chaseArray, index, endIndex);
6111 #if DEBUG_ACTIVE_SPANS
6112 debugShowActiveSpans(contourList);
6113 #endif
6114 if (!current) {
6115 break;
6116 }
6117 } while (true);
6118 } while (true);
6119 return simple.someAssemblyRequired();
6120}
6121
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006122// returns true if all edges were processed
caryclark@google.comf839c032012-10-26 21:03:50 +00006123static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006124 Segment* current;
6125 int start, end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006126 bool unsortable = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006127 bool closable = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00006128 while ((current = findUndone(contourList, start, end))) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006129 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006130 #if DEBUG_ACTIVE_SPANS
6131 if (!unsortable && current->done()) {
6132 debugShowActiveSpans(contourList);
6133 }
6134 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006135 SkASSERT(unsortable || !current->done());
caryclark@google.com24bec792012-08-20 12:43:57 +00006136 int nextStart = start;
6137 int nextEnd = end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006138 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
caryclark@google.com24bec792012-08-20 12:43:57 +00006139 if (!next) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006140 if (!unsortable && simple.hasMove()
caryclark@google.comf839c032012-10-26 21:03:50 +00006141 && current->verb() != SkPath::kLine_Verb
6142 && !simple.isClosed()) {
6143 current->addCurveTo(start, end, simple, true);
6144 SkASSERT(simple.isClosed());
caryclark@google.comc899ad92012-08-23 15:24:42 +00006145 }
caryclark@google.com24bec792012-08-20 12:43:57 +00006146 break;
6147 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006148 #if DEBUG_FLOW
6149 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6150 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
6151 current->xyAtT(end).fX, current->xyAtT(end).fY);
6152 #endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006153 current->addCurveTo(start, end, simple, true);
caryclark@google.com24bec792012-08-20 12:43:57 +00006154 current = next;
6155 start = nextStart;
6156 end = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006157 } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006158 if (!simple.isClosed()) {
6159 SkASSERT(unsortable);
6160 int min = SkMin32(start, end);
6161 if (!current->done(min)) {
6162 current->addCurveTo(start, end, simple, true);
6163 current->markDone(min, 1);
6164 }
6165 closable = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00006166 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006167 simple.close();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00006168 #if DEBUG_ACTIVE_SPANS
6169 debugShowActiveSpans(contourList);
6170 #endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00006171 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006172 return closable;
caryclark@google.com24bec792012-08-20 12:43:57 +00006173}
6174
caryclark@google.comb45a1b42012-05-18 20:50:33 +00006175static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
6176 int contourCount = contourList.count();
6177 for (int cTest = 0; cTest < contourCount; ++cTest) {
6178 Contour* contour = contourList[cTest];
6179 contour->fixOtherTIndex();
6180 }
6181}
6182
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006183static void sortSegments(SkTDArray<Contour*>& contourList) {
6184 int contourCount = contourList.count();
6185 for (int cTest = 0; cTest < contourCount; ++cTest) {
6186 Contour* contour = contourList[cTest];
6187 contour->sortSegments();
6188 }
6189}
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006190
caryclark@google.com4eeda372012-12-06 21:47:48 +00006191static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
6192 bool evenOdd, bool oppEvenOdd) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006193 int count = contours.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006194 if (count == 0) {
6195 return;
6196 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006197 for (int index = 0; index < count; ++index) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00006198 Contour& contour = contours[index];
6199 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
6200 *list.append() = &contour;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006201 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006202 QSort<Contour>(list.begin(), list.end() - 1);
6203}
6204
caryclark@google.comf839c032012-10-26 21:03:50 +00006205static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006206 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006207}
6208
caryclark@google.com10227bf2012-12-28 22:10:41 +00006209static bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
6210 return distances[one] < distances[two];
6211}
caryclark@google.comf839c032012-10-26 21:03:50 +00006212 /*
6213 check start and end of each contour
6214 if not the same, record them
6215 match them up
6216 connect closest
6217 reassemble contour pieces into new path
6218 */
6219static void assemble(const PathWrapper& path, PathWrapper& simple) {
6220#if DEBUG_PATH_CONSTRUCTION
6221 SkDebugf("%s\n", __FUNCTION__);
6222#endif
6223 SkTArray<Contour> contours;
6224 EdgeBuilder builder(path, contours);
6225 builder.finish();
6226 int count = contours.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006227 int outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006228 SkTDArray<int> runs; // indices of partial contours
caryclark@google.com0b7da432012-10-31 19:00:20 +00006229 for (outer = 0; outer < count; ++outer) {
6230 const Contour& eContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006231 const SkPoint& eStart = eContour.start();
6232 const SkPoint& eEnd = eContour.end();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006233#if DEBUG_ASSEMBLE
6234 SkDebugf("%s contour", __FUNCTION__);
6235 if (!approximatelyEqual(eStart, eEnd)) {
6236 SkDebugf("[%d]", runs.count());
6237 } else {
6238 SkDebugf(" ");
6239 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006240 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006241 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
6242#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006243 if (approximatelyEqual(eStart, eEnd)) {
6244 eContour.toPath(simple);
6245 continue;
6246 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006247 *runs.append() = outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006248 }
6249 count = runs.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006250 if (count == 0) {
6251 return;
6252 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006253 SkTDArray<int> sLink, eLink;
6254 sLink.setCount(count);
6255 eLink.setCount(count);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006256 int rIndex, iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006257 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006258 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006259 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006260 SkTDArray<double> distances;
6261 const int ends = count * 2; // all starts and ends
6262 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
6263 distances.setCount(entries);
6264 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
6265 outer = runs[rIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006266 const Contour& oContour = contours[outer];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006267 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
6268 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
6269 * ends - rIndex - 1;
6270 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
6271 int inner = runs[iIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006272 const Contour& iContour = contours[inner];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006273 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
6274 double dx = iPt.fX - oPt.fX;
6275 double dy = iPt.fY - oPt.fY;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006276 double dist = dx * dx + dy * dy;
caryclark@google.com10227bf2012-12-28 22:10:41 +00006277 distances[row + iIndex] = dist; // oStart distance from iStart
6278 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006279 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006280 SkTDArray<int> sortedDist;
6281 sortedDist.setCount(entries);
6282 for (rIndex = 0; rIndex < entries; ++rIndex) {
6283 sortedDist[rIndex] = rIndex;
6284 }
6285 QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
6286 int remaining = count; // number of start/end pairs
6287 for (rIndex = 0; rIndex < entries; ++rIndex) {
6288 int pair = sortedDist[rIndex];
6289 int row = pair / ends;
6290 int col = pair - row * ends;
6291 int thingOne = row < col ? row : ends - row - 2;
6292 int ndxOne = thingOne >> 1;
6293 bool endOne = thingOne & 1;
6294 int* linkOne = endOne ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006295 if (linkOne[ndxOne] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006296 continue;
6297 }
6298 int thingTwo = row < col ? col : ends - row + col - 1;
6299 int ndxTwo = thingTwo >> 1;
6300 bool endTwo = thingTwo & 1;
6301 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006302 if (linkTwo[ndxTwo] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006303 continue;
6304 }
6305 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
6306 bool flip = endOne == endTwo;
6307 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
6308 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
6309 if (!--remaining) {
6310 break;
6311 }
6312 }
6313 SkASSERT(!remaining);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006314#if DEBUG_ASSEMBLE
6315 for (rIndex = 0; rIndex < count; ++rIndex) {
6316 int s = sLink[rIndex];
6317 int e = eLink[rIndex];
6318 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
6319 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
caryclark@google.comf839c032012-10-26 21:03:50 +00006320 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006321#endif
6322 rIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00006323 do {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006324 bool forward = true;
6325 bool first = true;
6326 int sIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006327 SkASSERT(sIndex != SK_MaxS32);
6328 sLink[rIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006329 int eIndex;
6330 if (sIndex < 0) {
6331 eIndex = sLink[~sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006332 sLink[~sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006333 } else {
6334 eIndex = eLink[sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006335 eLink[sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006336 }
caryclark@google.comaa358312013-01-29 20:28:49 +00006337 SkASSERT(eIndex != SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006338#if DEBUG_ASSEMBLE
6339 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006340 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
6341 eIndex < 0 ? ~eIndex : eIndex);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006342#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006343 do {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006344 outer = runs[rIndex];
6345 const Contour& contour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006346 if (first) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006347 first = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006348 const SkPoint* startPtr = &contour.start();
caryclark@google.comf839c032012-10-26 21:03:50 +00006349 simple.deferredMove(startPtr[0]);
6350 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006351 if (forward) {
6352 contour.toPartialForward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006353 } else {
6354 contour.toPartialBackward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006355 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006356#if DEBUG_ASSEMBLE
6357 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006358 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006359 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
6360#endif
6361 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006362 simple.close();
caryclark@google.comf839c032012-10-26 21:03:50 +00006363 break;
6364 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006365 if (forward) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006366 eIndex = eLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006367 SkASSERT(eIndex != SK_MaxS32);
6368 eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006369 if (eIndex >= 0) {
6370 SkASSERT(sLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006371 sLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006372 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006373 SkASSERT(eLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006374 eLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006375 }
6376 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006377 eIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006378 SkASSERT(eIndex != SK_MaxS32);
6379 sLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006380 if (eIndex >= 0) {
6381 SkASSERT(eLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006382 eLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006383 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006384 SkASSERT(sLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006385 sLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006386 }
6387 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006388 rIndex = eIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006389 if (rIndex < 0) {
6390 forward ^= 1;
6391 rIndex = ~rIndex;
6392 }
6393 } while (true);
6394 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006395 if (sLink[rIndex] != SK_MaxS32) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006396 break;
6397 }
6398 }
6399 } while (rIndex < count);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006400#if DEBUG_ASSEMBLE
6401 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006402 SkASSERT(sLink[rIndex] == SK_MaxS32);
6403 SkASSERT(eLink[rIndex] == SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006404 }
6405#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006406}
6407
6408void simplifyx(const SkPath& path, SkPath& result) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00006409#if DEBUG_SORT
6410 gDebugSortCount = gDebugSortCountDefault;
6411#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006412 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
caryclark@google.comf839c032012-10-26 21:03:50 +00006413 result.reset();
6414 result.setFillType(SkPath::kEvenOdd_FillType);
6415 PathWrapper simple(result);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006416
6417 // turn path into list of segments
6418 SkTArray<Contour> contours;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006419 EdgeBuilder builder(path, contours);
caryclark@google.com235f56a2012-09-14 14:19:30 +00006420 builder.finish();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006421 SkTDArray<Contour*> contourList;
caryclark@google.com4eeda372012-12-06 21:47:48 +00006422 makeContourList(contours, contourList, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006423 Contour** currentPtr = contourList.begin();
6424 if (!currentPtr) {
6425 return;
6426 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006427 Contour** listEnd = contourList.end();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006428 // find all intersections between segments
6429 do {
6430 Contour** nextPtr = currentPtr;
6431 Contour* current = *currentPtr++;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00006432 if (current->containsCubics()) {
6433 addSelfIntersectTs(current);
6434 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006435 Contour* next;
6436 do {
6437 next = *nextPtr++;
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00006438 } while (addIntersectTs(current, next) && nextPtr != listEnd);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006439 } while (currentPtr != listEnd);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006440 // eat through coincident edges
caryclark@google.com4eeda372012-12-06 21:47:48 +00006441 coincidenceCheck(contourList, 0);
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00006442 fixOtherTIndex(contourList);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006443 sortSegments(contourList);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006444#if DEBUG_ACTIVE_SPANS
6445 debugShowActiveSpans(contourList);
6446#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006447 // construct closed contours
caryclark@google.com3586ece2012-12-27 18:46:58 +00006448 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00006449 : !bridgeXor(contourList, simple))
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006450 { // if some edges could not be resolved, assemble remaining fragments
caryclark@google.comf839c032012-10-26 21:03:50 +00006451 SkPath temp;
6452 temp.setFillType(SkPath::kEvenOdd_FillType);
6453 PathWrapper assembled(temp);
6454 assemble(simple, assembled);
6455 result = *assembled.nativePath();
caryclark@google.com24bec792012-08-20 12:43:57 +00006456 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006457}