blob: ea4c9bf16241cf87be60a26cf1c0d63beeb079d6 [file] [log] [blame]
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
caryclark@google.comb45a1b42012-05-18 20:50:33 +00007#include "Simplify.h"
caryclark@google.comfa0588f2012-04-26 21:01:06 +00008
9#undef SkASSERT
10#define SkASSERT(cond) while (!(cond)) { sk_throw(); }
11
caryclark@google.com15fa1382012-05-07 20:49:36 +000012// Terminology:
13// A Path contains one of more Contours
14// A Contour is made up of Segment array
caryclark@google.comb45a1b42012-05-18 20:50:33 +000015// A Segment is described by a Verb and a Point array with 2, 3, or 4 points
16// A Verb is one of Line, Quad(ratic), or Cubic
caryclark@google.com15fa1382012-05-07 20:49:36 +000017// A Segment contains a Span array
18// A Span is describes a portion of a Segment using starting and ending T
19// T values range from 0 to 1, where 0 is the first Point in the Segment
caryclark@google.com47580692012-07-23 12:14:49 +000020// An Edge is a Segment generated from a Span
caryclark@google.com15fa1382012-05-07 20:49:36 +000021
caryclark@google.comfa0588f2012-04-26 21:01:06 +000022// FIXME: remove once debugging is complete
caryclark@google.com47580692012-07-23 12:14:49 +000023#ifdef SK_DEBUG
24int gDebugMaxWindSum = SK_MaxS32;
25int gDebugMaxWindValue = SK_MaxS32;
26#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +000027
caryclark@google.comf839c032012-10-26 21:03:50 +000028#define PIN_ADD_T 0
caryclark@google.com0b7da432012-10-31 19:00:20 +000029#define TRY_ROTATE 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000030#define ONE_PASS_COINCIDENCE_CHECK 0
caryclark@google.com73ca6242013-01-17 21:02:47 +000031#define APPROXIMATE_CUBICS 1
caryclark@google.coma461ff02012-10-11 12:54:23 +000032
caryclark@google.com47580692012-07-23 12:14:49 +000033#define DEBUG_UNUSED 0 // set to expose unused functions
caryclark@google.com45a8fc62013-02-14 15:29:11 +000034
caryclark@google.comc83c70e2013-02-22 21:50:07 +000035#define FORCE_RELEASE 0 // set force release to 1 for multiple thread -- no debugging
caryclark@google.comfa0588f2012-04-26 21:01:06 +000036
caryclark@google.com31143cf2012-11-09 22:14:19 +000037#if FORCE_RELEASE || defined SK_RELEASE
caryclark@google.com47580692012-07-23 12:14:49 +000038
39const bool gRunTestsInOneThread = false;
40
caryclark@google.combeda3892013-02-07 13:13:41 +000041#define DEBUG_ACTIVE_OP 0
caryclark@google.com47580692012-07-23 12:14:49 +000042#define DEBUG_ACTIVE_SPANS 0
caryclark@google.com4eeda372012-12-06 21:47:48 +000043#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000044#define DEBUG_ADD_INTERSECTING_TS 0
caryclark@google.com47580692012-07-23 12:14:49 +000045#define DEBUG_ADD_T_PAIR 0
caryclark@google.comc899ad92012-08-23 15:24:42 +000046#define DEBUG_ANGLE 0
caryclark@google.com7ff5c842013-02-26 15:56:05 +000047#define DEBUG_AS_C_CODE 1
caryclark@google.come7bd5f42012-12-13 19:47:53 +000048#define DEBUG_ASSEMBLE 0
caryclark@google.com47580692012-07-23 12:14:49 +000049#define DEBUG_CONCIDENT 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000050#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000051#define DEBUG_FLOW 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000052#define DEBUG_MARK_DONE 0
caryclark@google.comf839c032012-10-26 21:03:50 +000053#define DEBUG_PATH_CONSTRUCTION 0
caryclark@google.com729e1c42012-11-21 21:36:34 +000054#define DEBUG_SHOW_WINDING 0
caryclark@google.comc83c70e2013-02-22 21:50:07 +000055#define DEBUG_SORT 0
caryclark@google.com5e0500f2013-02-20 12:51:37 +000056#define DEBUG_SWAP_TOP 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000057#define DEBUG_UNSORTABLE 0
caryclark@google.comafe56de2012-07-24 18:11:03 +000058#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000059#define DEBUG_WINDING 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000060#define DEBUG_WINDING_AT_T 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000061
62#else
63
caryclark@google.com47580692012-07-23 12:14:49 +000064const bool gRunTestsInOneThread = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +000065
caryclark@google.combeda3892013-02-07 13:13:41 +000066#define DEBUG_ACTIVE_OP 1
caryclark@google.comc91dfe42012-10-16 12:06:27 +000067#define DEBUG_ACTIVE_SPANS 1
caryclark@google.com4eeda372012-12-06 21:47:48 +000068#define DEBUG_ACTIVE_SPANS_SHORT_FORM 1
caryclark@google.com6aea33f2012-10-09 14:11:58 +000069#define DEBUG_ADD_INTERSECTING_TS 1
70#define DEBUG_ADD_T_PAIR 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000071#define DEBUG_ANGLE 1
caryclark@google.com7ff5c842013-02-26 15:56:05 +000072#define DEBUG_AS_C_CODE 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000073#define DEBUG_ASSEMBLE 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000074#define DEBUG_CONCIDENT 1
caryclark@google.com534aa5b2012-08-02 20:08:21 +000075#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000076#define DEBUG_FLOW 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000077#define DEBUG_MARK_DONE 1
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000078#define DEBUG_PATH_CONSTRUCTION 1
caryclark@google.com729e1c42012-11-21 21:36:34 +000079#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000080#define DEBUG_SORT 1
caryclark@google.com47d73da2013-02-17 01:41:25 +000081#define DEBUG_SWAP_TOP 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000082#define DEBUG_UNSORTABLE 1
caryclark@google.comafe56de2012-07-24 18:11:03 +000083#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000084#define DEBUG_WINDING 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000085#define DEBUG_WINDING_AT_T 1
caryclark@google.comfa0588f2012-04-26 21:01:06 +000086
87#endif
88
caryclark@google.combeda3892013-02-07 13:13:41 +000089#define DEBUG_DUMP (DEBUG_ACTIVE_OP | DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | \
90 DEBUG_PATH_CONSTRUCTION)
caryclark@google.com027de222012-07-12 12:52:50 +000091
caryclark@google.comfa0588f2012-04-26 21:01:06 +000092#if DEBUG_DUMP
93static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000094// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
caryclark@google.comfa0588f2012-04-26 21:01:06 +000095static int gContourID;
96static int gSegmentID;
97#endif
98
caryclark@google.comc83c70e2013-02-22 21:50:07 +000099#if DEBUG_SORT
100static int gDebugSortCountDefault = 3; // SK_MaxS32;
101static int gDebugSortCount;
102#endif
103
caryclark@google.com5e0500f2013-02-20 12:51:37 +0000104#if DEBUG_ACTIVE_OP
105static const char* kShapeOpStr[] = {"diff", "sect", "union", "xor"};
106#endif
107
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000108#ifndef DEBUG_TEST
109#define DEBUG_TEST 0
110#endif
111
caryclark@google.com32546db2012-08-31 20:55:07 +0000112#define MAKE_CONST_LINE(line, pts) \
113 const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}
114#define MAKE_CONST_QUAD(quad, pts) \
115 const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
116 {pts[2].fX, pts[2].fY}}
117#define MAKE_CONST_CUBIC(cubic, pts) \
118 const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
119 {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}}
120
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000121static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
122 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000123 MAKE_CONST_LINE(aLine, a);
124 MAKE_CONST_LINE(bLine, b);
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000125 return intersect(aLine, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000126}
127
128static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
129 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000130 MAKE_CONST_QUAD(aQuad, a);
131 MAKE_CONST_LINE(bLine, b);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000132 return intersect(aQuad, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000133}
134
caryclark@google.com32546db2012-08-31 20:55:07 +0000135static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000136 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000137 MAKE_CONST_CUBIC(aCubic, a);
138 MAKE_CONST_LINE(bLine, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000139 return intersect(aCubic, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000140}
141
142static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
143 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000144 MAKE_CONST_QUAD(aQuad, a);
145 MAKE_CONST_QUAD(bQuad, b);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000146#define TRY_QUARTIC_SOLUTION 1
147#if TRY_QUARTIC_SOLUTION
148 intersect2(aQuad, bQuad, intersections);
149#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000150 intersect(aQuad, bQuad, intersections);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000151#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000152 return intersections.fUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000153}
154
caryclark@google.com73ca6242013-01-17 21:02:47 +0000155#if APPROXIMATE_CUBICS
156static int CubicQuadIntersect(const SkPoint a[4], const SkPoint b[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000157 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000158 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000159 MAKE_CONST_QUAD(bQuad, b);
160 return intersect(aCubic, bQuad, intersections);
161}
162#endif
163
164static int CubicIntersect(const SkPoint a[4], const SkPoint b[4], Intersections& intersections) {
165 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com32546db2012-08-31 20:55:07 +0000166 MAKE_CONST_CUBIC(bCubic, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000167#if APPROXIMATE_CUBICS
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000168 intersect3(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000169#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000170 intersect(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000171#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000172 return intersections.fUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000173}
174
caryclark@google.comc83c70e2013-02-22 21:50:07 +0000175static int CubicIntersect(const SkPoint a[4], Intersections& intersections) {
176 MAKE_CONST_CUBIC(aCubic, a);
177 return intersect(aCubic, intersections);
178}
179
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000180static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
181 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000182 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000183 return horizontalIntersect(aLine, left, right, y, flipped, intersections);
184}
185
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000186static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
187 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000188 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000189 return horizontalIntersect(aQuad, left, right, y, flipped, intersections);
190}
191
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000192static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
193 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000194 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000195 return horizontalIntersect(aCubic, left, right, y, flipped, intersections);
196}
197
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000198static int (* const HSegmentIntersect[])(const SkPoint [], SkScalar ,
199 SkScalar , SkScalar , bool , Intersections& ) = {
200 NULL,
201 HLineIntersect,
202 HQuadIntersect,
203 HCubicIntersect
204};
205
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000206static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom,
207 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000208 MAKE_CONST_LINE(aLine, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000209 return verticalIntersect(aLine, top, bottom, x, flipped, intersections);
210}
211
212static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom,
213 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000214 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000215 return verticalIntersect(aQuad, top, bottom, x, flipped, intersections);
216}
217
218static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom,
219 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000220 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000221 return verticalIntersect(aCubic, top, bottom, x, flipped, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000222}
223
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000224static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar ,
225 SkScalar , SkScalar , bool , Intersections& ) = {
226 NULL,
227 VLineIntersect,
228 VQuadIntersect,
229 VCubicIntersect
230};
231
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000232static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000233 MAKE_CONST_LINE(line, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000234 double x, y;
235 xy_at_t(line, t, x, y);
236 out->fX = SkDoubleToScalar(x);
237 out->fY = SkDoubleToScalar(y);
238}
239
caryclark@google.comf9502d72013-02-04 14:06:49 +0000240static void LineXYAtT(const SkPoint a[2], double t, _Point* out) {
241 MAKE_CONST_LINE(line, a);
242 xy_at_t(line, t, out->x, out->y);
243}
244
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000245static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000246 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000247 double x, y;
248 xy_at_t(quad, t, x, y);
249 out->fX = SkDoubleToScalar(x);
250 out->fY = SkDoubleToScalar(y);
251}
252
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000253static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
254 MAKE_CONST_QUAD(quad, a);
255 xy_at_t(quad, t, out->x, out->y);
256}
257
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000258static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000259 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000260 double x, y;
261 xy_at_t(cubic, t, x, y);
262 out->fX = SkDoubleToScalar(x);
263 out->fY = SkDoubleToScalar(y);
264}
265
caryclark@google.comf9502d72013-02-04 14:06:49 +0000266static void CubicXYAtT(const SkPoint a[4], double t, _Point* out) {
267 MAKE_CONST_CUBIC(cubic, a);
268 xy_at_t(cubic, t, out->x, out->y);
269}
270
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000271static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
272 NULL,
273 LineXYAtT,
274 QuadXYAtT,
275 CubicXYAtT
276};
277
caryclark@google.comf9502d72013-02-04 14:06:49 +0000278static void (* const SegmentXYAtT2[])(const SkPoint [], double , _Point* ) = {
279 NULL,
280 LineXYAtT,
281 QuadXYAtT,
282 CubicXYAtT
283};
284
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000285static SkScalar LineXAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000286 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000287 double x;
288 xy_at_t(aLine, t, x, *(double*) 0);
289 return SkDoubleToScalar(x);
290}
291
292static SkScalar QuadXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000293 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000294 double x;
295 xy_at_t(quad, t, x, *(double*) 0);
296 return SkDoubleToScalar(x);
297}
298
299static SkScalar CubicXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000300 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000301 double x;
302 xy_at_t(cubic, t, x, *(double*) 0);
303 return SkDoubleToScalar(x);
304}
305
306static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
307 NULL,
308 LineXAtT,
309 QuadXAtT,
310 CubicXAtT
311};
312
313static SkScalar LineYAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000314 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000315 double y;
316 xy_at_t(aLine, t, *(double*) 0, y);
317 return SkDoubleToScalar(y);
318}
319
320static SkScalar QuadYAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000321 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000322 double y;
323 xy_at_t(quad, t, *(double*) 0, y);
324 return SkDoubleToScalar(y);
325}
326
327static SkScalar CubicYAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000328 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000329 double y;
330 xy_at_t(cubic, t, *(double*) 0, y);
331 return SkDoubleToScalar(y);
332}
333
334static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
335 NULL,
336 LineYAtT,
337 QuadYAtT,
338 CubicYAtT
339};
340
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000341static SkScalar LineDXAtT(const SkPoint a[2], double ) {
342 return a[1].fX - a[0].fX;
343}
344
345static SkScalar QuadDXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000346 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000347 double x = dx_at_t(quad, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000348 return SkDoubleToScalar(x);
349}
350
351static SkScalar CubicDXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000352 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000353 double x = dx_at_t(cubic, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000354 return SkDoubleToScalar(x);
355}
356
357static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
358 NULL,
359 LineDXAtT,
360 QuadDXAtT,
361 CubicDXAtT
362};
363
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000364static SkScalar LineDYAtT(const SkPoint a[2], double ) {
365 return a[1].fY - a[0].fY;
366}
367
368static SkScalar QuadDYAtT(const SkPoint a[3], double t) {
369 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000370 double y = dy_at_t(quad, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000371 return SkDoubleToScalar(y);
372}
373
374static SkScalar CubicDYAtT(const SkPoint a[4], double t) {
375 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000376 double y = dy_at_t(cubic, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000377 return SkDoubleToScalar(y);
378}
379
380static SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = {
381 NULL,
382 LineDYAtT,
383 QuadDYAtT,
384 CubicDYAtT
385};
386
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000387static SkVector LineDXDYAtT(const SkPoint a[2], double ) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000388 return a[1] - a[0];
389}
390
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000391static SkVector QuadDXDYAtT(const SkPoint a[3], double t) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000392 MAKE_CONST_QUAD(quad, a);
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000393 _Vector v = dxdy_at_t(quad, t);
394 return v.asSkVector();
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000395}
396
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000397static SkVector CubicDXDYAtT(const SkPoint a[4], double t) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000398 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000399 _Vector v = dxdy_at_t(cubic, t);
400 return v.asSkVector();
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000401}
402
caryclark@google.com7ff5c842013-02-26 15:56:05 +0000403static SkVector (* const SegmentDXDYAtT[])(const SkPoint [], double ) = {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000404 NULL,
405 LineDXDYAtT,
406 QuadDXDYAtT,
407 CubicDXDYAtT
408};
409
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000410static void LineSubDivide(const SkPoint a[2], double startT, double endT,
411 SkPoint sub[2]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000412 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000413 _Line dst;
414 sub_divide(aLine, startT, endT, dst);
415 sub[0].fX = SkDoubleToScalar(dst[0].x);
416 sub[0].fY = SkDoubleToScalar(dst[0].y);
417 sub[1].fX = SkDoubleToScalar(dst[1].x);
418 sub[1].fY = SkDoubleToScalar(dst[1].y);
419}
420
421static void QuadSubDivide(const SkPoint a[3], double startT, double endT,
422 SkPoint sub[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000423 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000424 Quadratic dst;
425 sub_divide(aQuad, startT, endT, dst);
426 sub[0].fX = SkDoubleToScalar(dst[0].x);
427 sub[0].fY = SkDoubleToScalar(dst[0].y);
428 sub[1].fX = SkDoubleToScalar(dst[1].x);
429 sub[1].fY = SkDoubleToScalar(dst[1].y);
430 sub[2].fX = SkDoubleToScalar(dst[2].x);
431 sub[2].fY = SkDoubleToScalar(dst[2].y);
432}
433
434static void CubicSubDivide(const SkPoint a[4], double startT, double endT,
435 SkPoint sub[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000436 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000437 Cubic dst;
438 sub_divide(aCubic, startT, endT, dst);
439 sub[0].fX = SkDoubleToScalar(dst[0].x);
440 sub[0].fY = SkDoubleToScalar(dst[0].y);
441 sub[1].fX = SkDoubleToScalar(dst[1].x);
442 sub[1].fY = SkDoubleToScalar(dst[1].y);
443 sub[2].fX = SkDoubleToScalar(dst[2].x);
444 sub[2].fY = SkDoubleToScalar(dst[2].y);
445 sub[3].fX = SkDoubleToScalar(dst[3].x);
446 sub[3].fY = SkDoubleToScalar(dst[3].y);
447}
448
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000449static void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
450 SkPoint []) = {
451 NULL,
452 LineSubDivide,
453 QuadSubDivide,
454 CubicSubDivide
455};
456
caryclark@google.comaa358312013-01-29 20:28:49 +0000457static void LineSubDivideHD(const SkPoint a[2], double startT, double endT, _Line& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000458 MAKE_CONST_LINE(aLine, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000459 sub_divide(aLine, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000460}
461
caryclark@google.comaa358312013-01-29 20:28:49 +0000462static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT, Quadratic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000463 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000464 sub_divide(aQuad, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000465}
466
caryclark@google.comaa358312013-01-29 20:28:49 +0000467static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT, Cubic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000468 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000469 sub_divide(aCubic, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000470}
471
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000472static SkPoint QuadTop(const SkPoint a[3], double startT, double endT) {
473 MAKE_CONST_QUAD(quad, a);
474 _Point topPt = top(quad, startT, endT);
475 return topPt.asSkPoint();
476}
477
478static SkPoint CubicTop(const SkPoint a[3], double startT, double endT) {
479 MAKE_CONST_CUBIC(cubic, a);
480 _Point topPt = top(cubic, startT, endT);
481 return topPt.asSkPoint();
482}
483
484static SkPoint (* SegmentTop[])(const SkPoint[], double , double ) = {
485 NULL,
486 NULL,
487 QuadTop,
488 CubicTop
489};
490
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000491#if DEBUG_UNUSED
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000492static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
493 SkRect& bounds) {
494 SkPoint dst[3];
495 QuadSubDivide(a, startT, endT, dst);
496 bounds.fLeft = bounds.fRight = dst[0].fX;
497 bounds.fTop = bounds.fBottom = dst[0].fY;
498 for (int index = 1; index < 3; ++index) {
499 bounds.growToInclude(dst[index].fX, dst[index].fY);
500 }
501}
502
503static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
504 SkRect& bounds) {
505 SkPoint dst[4];
506 CubicSubDivide(a, startT, endT, dst);
507 bounds.fLeft = bounds.fRight = dst[0].fX;
508 bounds.fTop = bounds.fBottom = dst[0].fY;
509 for (int index = 1; index < 4; ++index) {
510 bounds.growToInclude(dst[index].fX, dst[index].fY);
511 }
512}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000513#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000514
caryclark@google.com15fa1382012-05-07 20:49:36 +0000515static SkPath::Verb QuadReduceOrder(const SkPoint a[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000516 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000517 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000518 Quadratic dst;
caryclark@google.com47d73da2013-02-17 01:41:25 +0000519 int order = reduceOrder(aQuad, dst, kReduceOrder_TreatAsFill);
caryclark@google.com24bec792012-08-20 12:43:57 +0000520 if (order == 2) { // quad became line
521 for (int index = 0; index < order; ++index) {
522 SkPoint* pt = reducePts.append();
523 pt->fX = SkDoubleToScalar(dst[index].x);
524 pt->fY = SkDoubleToScalar(dst[index].y);
525 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000526 }
527 return (SkPath::Verb) (order - 1);
528}
529
530static SkPath::Verb CubicReduceOrder(const SkPoint a[4],
531 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000532 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000533 Cubic dst;
caryclark@google.com47d73da2013-02-17 01:41:25 +0000534 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed, kReduceOrder_TreatAsFill);
caryclark@google.com24bec792012-08-20 12:43:57 +0000535 if (order == 2 || order == 3) { // cubic became line or quad
536 for (int index = 0; index < order; ++index) {
537 SkPoint* pt = reducePts.append();
538 pt->fX = SkDoubleToScalar(dst[index].x);
539 pt->fY = SkDoubleToScalar(dst[index].y);
540 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000541 }
542 return (SkPath::Verb) (order - 1);
543}
544
caryclark@google.com15fa1382012-05-07 20:49:36 +0000545static bool QuadIsLinear(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000546 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000547 return isLinear(aQuad, 0, 2);
548}
549
550static bool CubicIsLinear(const SkPoint a[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000551 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000552 return isLinear(aCubic, 0, 3);
553}
554
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000555static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000556 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000557 double x[2];
558 xy_at_t(aLine, startT, x[0], *(double*) 0);
caryclark@google.com495f8e42012-05-31 13:13:11 +0000559 xy_at_t(aLine, endT, x[1], *(double*) 0);
560 return SkMinScalar((float) x[0], (float) x[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000561}
562
563static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000564 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000565 return (float) leftMostT(aQuad, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000566}
567
568static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000569 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000570 return (float) leftMostT(aCubic, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000571}
572
573static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
574 NULL,
575 LineLeftMost,
576 QuadLeftMost,
577 CubicLeftMost
578};
579
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000580#if 0 // currently unused
caryclark@google.com235f56a2012-09-14 14:19:30 +0000581static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
582 Intersections& intersections) {
583 MAKE_CONST_QUAD(aQuad, a);
584 MAKE_CONST_LINE(bLine, b);
585 return intersectRay(aQuad, bLine, intersections);
586}
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000587#endif
588
caryclark@google.comf9502d72013-02-04 14:06:49 +0000589static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000590 MAKE_CONST_QUAD(aQuad, a);
591 return intersectRay(aQuad, bLine, intersections);
592}
caryclark@google.com235f56a2012-09-14 14:19:30 +0000593
caryclark@google.comf9502d72013-02-04 14:06:49 +0000594static int CubicRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
595 MAKE_CONST_CUBIC(aCubic, a);
596 return intersectRay(aCubic, bLine, intersections);
597}
598
599static int (* const SegmentRayIntersect[])(const SkPoint [], const _Line& , Intersections&) = {
600 NULL,
601 NULL,
602 QuadRayIntersect,
603 CubicRayIntersect
604};
605
606
607
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000608static bool LineVertical(const SkPoint a[2], double startT, double endT) {
609 MAKE_CONST_LINE(aLine, a);
610 double x[2];
611 xy_at_t(aLine, startT, x[0], *(double*) 0);
612 xy_at_t(aLine, endT, x[1], *(double*) 0);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000613 return AlmostEqualUlps((float) x[0], (float) x[1]);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000614}
615
616static bool QuadVertical(const SkPoint a[3], double startT, double endT) {
617 SkPoint dst[3];
618 QuadSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000619 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000620}
621
622static bool CubicVertical(const SkPoint a[4], double startT, double endT) {
623 SkPoint dst[4];
624 CubicSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000625 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX)
626 && AlmostEqualUlps(dst[2].fX, dst[3].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000627}
628
629static bool (* const SegmentVertical[])(const SkPoint [], double , double) = {
630 NULL,
631 LineVertical,
632 QuadVertical,
633 CubicVertical
634};
635
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000636class Segment;
637
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000638struct Span {
639 Segment* fOther;
640 mutable SkPoint fPt; // lazily computed as needed
641 double fT;
642 double fOtherT; // value at fOther[fOtherIndex].fT
643 int fOtherIndex; // can't be used during intersection
caryclark@google.com31143cf2012-11-09 22:14:19 +0000644 int fWindSum; // accumulated from contours surrounding this one.
645 int fOppSum; // for binary operators: the opposite winding sum
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000646 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
caryclark@google.com57cff8d2012-11-14 21:14:56 +0000647 int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000648 bool fDone; // if set, this span to next higher T has been processed
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000649 bool fUnsortableStart; // set when start is part of an unsortable pair
650 bool fUnsortableEnd; // set when end is part of an unsortable pair
caryclark@google.comf839c032012-10-26 21:03:50 +0000651 bool fTiny; // if set, span may still be considered once for edge following
caryclark@google.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.com7ff5c842013-02-26 15:56:05 +00001649 int addT(Segment* other, const SkPoint& pt, double& newT) {
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;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001695 while (&span[less + 1] - fTs.begin() > 0 && xyAtT(&span[less]) == xyAtT(span)) {
1696#if 1
1697 if (span[less].fDone) {
1698 break;
1699 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001700 double tInterval = newT - span[less].fT;
1701 if (precisely_negative(tInterval)) {
1702 break;
1703 }
1704 if (fVerb == SkPath::kCubic_Verb) {
1705 double tMid = newT - tInterval / 2;
1706 _Point midPt;
1707 CubicXYAtT(fPts, tMid, &midPt);
1708 if (!midPt.approximatelyEqual(xyAtT(span))) {
1709 break;
1710 }
1711 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001712 span[less].fTiny = true;
1713 span[less].fDone = true;
1714 if (approximately_negative(newT - span[less].fT)) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00001715 if (approximately_greater_than_one(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001716 span[less].fUnsortableStart = true;
1717 span[less - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001718 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001719 if (approximately_less_than_zero(span[less].fT)) {
1720 span[less + 1].fUnsortableStart = true;
1721 span[less].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001722 }
1723 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001724 ++fDoneSpans;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001725#else
1726 double tInterval = newT - span[less].fT;
1727 if (precisely_negative(tInterval)) {
1728 break;
1729 }
1730 if (fVerb == SkPath::kCubic_Verb) {
1731 double tMid = newT - tInterval / 2;
1732 _Point midPt;
1733 CubicXYAtT(fPts, tMid, &midPt);
1734 if (!midPt.approximatelyEqual(xyAtT(span))) {
1735 break;
1736 }
1737 }
1738 SkASSERT(span[less].fDone == span->fDone);
1739 if (span[less].fT == 0) {
1740 span->fT = newT = 0;
1741 } else {
1742 setSpanT(less, newT);
1743 }
1744#endif
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001745 --less;
caryclark@google.comf839c032012-10-26 21:03:50 +00001746 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001747 int more = 1;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001748 while (fTs.end() - &span[more - 1] > 1 && xyAtT(&span[more]) == xyAtT(span)) {
1749#if 1
1750 if (span[more - 1].fDone) {
1751 break;
1752 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00001753 double tEndInterval = span[more].fT - newT;
1754 if (precisely_negative(tEndInterval)) {
1755 break;
1756 }
1757 if (fVerb == SkPath::kCubic_Verb) {
1758 double tMid = newT - tEndInterval / 2;
1759 _Point midEndPt;
1760 CubicXYAtT(fPts, tMid, &midEndPt);
1761 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
1762 break;
1763 }
1764 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001765 span[more - 1].fTiny = true;
1766 span[more - 1].fDone = true;
1767 if (approximately_negative(span[more].fT - newT)) {
1768 if (approximately_greater_than_one(span[more].fT)) {
1769 span[more + 1].fUnsortableStart = true;
1770 span[more].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001771 }
1772 if (approximately_less_than_zero(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001773 span[more].fUnsortableStart = true;
1774 span[more - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001775 }
1776 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001777 ++fDoneSpans;
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001778#else
1779 double tEndInterval = span[more].fT - newT;
1780 if (precisely_negative(tEndInterval)) {
1781 break;
1782 }
1783 if (fVerb == SkPath::kCubic_Verb) {
1784 double tMid = newT - tEndInterval / 2;
1785 _Point midEndPt;
1786 CubicXYAtT(fPts, tMid, &midEndPt);
1787 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
1788 break;
1789 }
1790 }
1791 SkASSERT(span[more - 1].fDone == span[more].fDone);
1792 if (newT == 0) {
1793 setSpanT(more, 0);
1794 } else {
1795 span->fT = newT = span[more].fT;
1796 }
1797#endif
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001798 ++more;
caryclark@google.comf839c032012-10-26 21:03:50 +00001799 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001800 return insertedAt;
1801 }
1802
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001803 // set spans from start to end to decrement by one
1804 // note this walks other backwards
1805 // FIMXE: there's probably an edge case that can be constructed where
1806 // two span in one segment are separated by float epsilon on one span but
1807 // not the other, if one segment is very small. For this
1808 // case the counts asserted below may or may not be enough to separate the
caryclark@google.com2ddff932012-08-07 21:25:27 +00001809 // spans. Even if the counts work out, what if the spans aren't correctly
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001810 // sorted? It feels better in such a case to match the span's other span
1811 // pointer since both coincident segments must contain the same spans.
1812 void addTCancel(double startT, double endT, Segment& other,
1813 double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001814 SkASSERT(!approximately_negative(endT - startT));
1815 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00001816 bool binary = fOperand != other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001817 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001818 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001819 ++index;
1820 }
caryclark@google.comb9738012012-07-03 19:53:30 +00001821 int oIndex = other.fTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001822 while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001823 ;
caryclark@google.com59823f72012-08-09 18:17:47 +00001824 double tRatio = (oEndT - oStartT) / (endT - startT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001825 Span* test = &fTs[index];
1826 Span* oTest = &other.fTs[oIndex];
caryclark@google.com18063442012-07-25 12:05:18 +00001827 SkTDArray<double> outsideTs;
1828 SkTDArray<double> oOutsideTs;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001829 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001830 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
caryclark@google.comcc905052012-07-25 20:59:42 +00001831 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.com200c2112012-08-03 15:05:04 +00001832 double testT = test->fT;
1833 double oTestT = oTest->fT;
1834 Span* span = test;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001835 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001836 if (decrement) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001837 decrementSpan(span);
caryclark@google.com200c2112012-08-03 15:05:04 +00001838 } else if (track && span->fT < 1 && oTestT < 1) {
1839 TrackOutside(outsideTs, span->fT, oTestT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001840 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001841 span = &fTs[++index];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001842 } while (approximately_negative(span->fT - testT));
caryclark@google.com200c2112012-08-03 15:05:04 +00001843 Span* oSpan = oTest;
caryclark@google.com59823f72012-08-09 18:17:47 +00001844 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1845 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1846 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001847 while (approximately_negative(otherTMatchStart - oSpan->fT)
1848 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
caryclark@google.com03f97062012-08-21 13:13:52 +00001849 #ifdef SK_DEBUG
caryclark@google.com59823f72012-08-09 18:17:47 +00001850 SkASSERT(originalWindValue == oSpan->fWindValue);
caryclark@google.com03f97062012-08-21 13:13:52 +00001851 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001852 if (decrement) {
caryclark@google.com200c2112012-08-03 15:05:04 +00001853 other.decrementSpan(oSpan);
1854 } else if (track && oSpan->fT < 1 && testT < 1) {
1855 TrackOutside(oOutsideTs, oSpan->fT, testT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001856 }
1857 if (!oIndex) {
1858 break;
1859 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001860 oSpan = &other.fTs[--oIndex];
rmistry@google.comd6176b02012-08-23 18:14:13 +00001861 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001862 test = span;
1863 oTest = oSpan;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001864 } while (!approximately_negative(endT - test->fT));
1865 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
caryclark@google.com18063442012-07-25 12:05:18 +00001866 // FIXME: determine if canceled edges need outside ts added
caryclark@google.comcc905052012-07-25 20:59:42 +00001867 if (!done() && outsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001868 double tStart = outsideTs[0];
1869 double oStart = outsideTs[1];
1870 addCancelOutsides(tStart, oStart, other, oEndT);
1871 int count = outsideTs.count();
1872 if (count > 2) {
1873 double tStart = outsideTs[count - 2];
1874 double oStart = outsideTs[count - 1];
1875 addCancelOutsides(tStart, oStart, other, oEndT);
1876 }
caryclark@google.com18063442012-07-25 12:05:18 +00001877 }
caryclark@google.comcc905052012-07-25 20:59:42 +00001878 if (!other.done() && oOutsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001879 double tStart = oOutsideTs[0];
1880 double oStart = oOutsideTs[1];
1881 other.addCancelOutsides(tStart, oStart, *this, endT);
caryclark@google.com18063442012-07-25 12:05:18 +00001882 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001883 }
skia.committer@gmail.com15dd3002013-01-18 07:07:28 +00001884
caryclark@google.com7ff5c842013-02-26 15:56:05 +00001885 int addUnsortableT(Segment* other, bool start, const SkPoint& pt, double& newT) {
1886 int result = addT(other, pt, newT);
caryclark@google.com73ca6242013-01-17 21:02:47 +00001887 Span* span = &fTs[result];
1888 if (start) {
1889 if (result > 0) {
1890 span[result - 1].fUnsortableEnd = true;
1891 }
1892 span[result].fUnsortableStart = true;
1893 } else {
1894 span[result].fUnsortableEnd = true;
1895 if (result + 1 < fTs.count()) {
1896 span[result + 1].fUnsortableStart = true;
1897 }
1898 }
1899 return result;
1900 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00001901
caryclark@google.com4eeda372012-12-06 21:47:48 +00001902 int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1903 SkTDArray<double>& outsideTs) {
1904 int oWindValue = oTest->fWindValue;
1905 int oOppValue = oTest->fOppValue;
1906 if (opp) {
1907 SkTSwap<int>(oWindValue, oOppValue);
1908 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001909 Span* const test = &fTs[index];
1910 Span* end = test;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001911 const double oStartT = oTest->fT;
1912 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001913 if (bumpSpan(end, oWindValue, oOppValue)) {
1914 TrackOutside(outsideTs, end->fT, oStartT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001915 }
1916 end = &fTs[++index];
1917 } while (approximately_negative(end->fT - test->fT));
1918 return index;
1919 }
1920
1921 // because of the order in which coincidences are resolved, this and other
1922 // may not have the same intermediate points. Compute the corresponding
1923 // intermediate T values (using this as the master, other as the follower)
1924 // and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com4eeda372012-12-06 21:47:48 +00001925 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1926 SkTDArray<double>& oOutsideTs) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001927 Span* const oTest = &fTs[oIndex];
1928 Span* oEnd = oTest;
1929 const double startT = test->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001930 const double oStartT = oTest->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001931 while (!approximately_negative(oEndT - oEnd->fT)
caryclark@google.com4eeda372012-12-06 21:47:48 +00001932 && approximately_negative(oEnd->fT - oStartT)) {
1933 zeroSpan(oEnd);
1934 TrackOutside(oOutsideTs, oEnd->fT, startT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001935 oEnd = &fTs[++oIndex];
1936 }
1937 return oIndex;
1938 }
1939
1940 // FIXME: need to test this case:
1941 // contourA has two segments that are coincident
1942 // contourB has two segments that are coincident in the same place
1943 // each ends up with +2/0 pairs for winding count
1944 // since logic below doesn't transfer count (only increments/decrements) can this be
1945 // resolved to +4/0 ?
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001946
1947 // set spans from start to end to increment the greater by one and decrement
1948 // the lesser
caryclark@google.com4eeda372012-12-06 21:47:48 +00001949 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001950 SkASSERT(!approximately_negative(endT - startT));
1951 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001952 bool opp = fOperand ^ other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001953 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001954 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001955 ++index;
1956 }
1957 int oIndex = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001958 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001959 ++oIndex;
1960 }
1961 Span* test = &fTs[index];
1962 Span* oTest = &other.fTs[oIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001963 SkTDArray<double> outsideTs;
1964 SkTDArray<double> oOutsideTs;
1965 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001966 // if either span has an opposite value and the operands don't match, resolve first
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001967 // SkASSERT(!test->fDone || !oTest->fDone);
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001968 if (test->fDone || oTest->fDone) {
1969 index = advanceCoincidentThis(oTest, opp, index);
1970 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
1971 } else {
1972 index = bumpCoincidentThis(oTest, opp, index, outsideTs);
1973 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
1974 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001975 test = &fTs[index];
1976 oTest = &other.fTs[oIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001977 } while (!approximately_negative(endT - test->fT));
1978 SkASSERT(approximately_negative(oTest->fT - oEndT));
1979 SkASSERT(approximately_negative(oEndT - oTest->fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001980 if (!done() && outsideTs.count()) {
1981 addCoinOutsides(outsideTs, other, oEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001982 }
1983 if (!other.done() && oOutsideTs.count()) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001984 other.addCoinOutsides(oOutsideTs, *this, endT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001985 }
1986 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001987
caryclark@google.comcc905052012-07-25 20:59:42 +00001988 // FIXME: this doesn't prevent the same span from being added twice
caryclark@google.comaa358312013-01-29 20:28:49 +00001989 // fix in caller, SkASSERT here?
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001990 void addTPair(double t, Segment& other, double otherT, bool borrowWind, const SkPoint& pt) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001991 int tCount = fTs.count();
1992 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1993 const Span& span = fTs[tIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001994 if (!approximately_negative(span.fT - t)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001995 break;
1996 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001997 if (approximately_negative(span.fT - t) && span.fOther == &other
1998 && approximately_equal(span.fOtherT, otherT)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001999#if DEBUG_ADD_T_PAIR
2000 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
2001 __FUNCTION__, fID, t, other.fID, otherT);
2002#endif
2003 return;
2004 }
2005 }
caryclark@google.com47580692012-07-23 12:14:49 +00002006#if DEBUG_ADD_T_PAIR
2007 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
2008 __FUNCTION__, fID, t, other.fID, otherT);
2009#endif
caryclark@google.com7ff5c842013-02-26 15:56:05 +00002010 int insertedAt = addT(&other, pt, t);
2011 int otherInsertedAt = other.addT(this, pt, otherT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002012 addOtherT(insertedAt, otherT, otherInsertedAt);
caryclark@google.comb9738012012-07-03 19:53:30 +00002013 other.addOtherT(otherInsertedAt, t, insertedAt);
caryclark@google.com2ddff932012-08-07 21:25:27 +00002014 matchWindingValue(insertedAt, t, borrowWind);
2015 other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002016 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002017
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002018 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002019 // add edge leading into junction
caryclark@google.com4eeda372012-12-06 21:47:48 +00002020 int min = SkMin32(end, start);
2021 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002022 addAngle(angles, end, start);
2023 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002024 // add edge leading away from junction
caryclark@google.com495f8e42012-05-31 13:13:11 +00002025 int step = SkSign32(end - start);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002026 int tIndex = nextExactSpan(end, step);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002027 min = SkMin32(end, tIndex);
2028 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002029 addAngle(angles, end, tIndex);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002030 }
2031 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002032
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002033 int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
2034 Span* const test = &fTs[index];
2035 Span* end = test;
2036 do {
2037 end = &fTs[++index];
2038 } while (approximately_negative(end->fT - test->fT));
2039 return index;
2040 }
2041
2042 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
2043 Span* const oTest = &fTs[oIndex];
2044 Span* oEnd = oTest;
2045 const double oStartT = oTest->fT;
2046 while (!approximately_negative(oEndT - oEnd->fT)
2047 && approximately_negative(oEnd->fT - oStartT)) {
2048 oEnd = &fTs[++oIndex];
2049 }
2050 return oIndex;
2051 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00002052
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002053 bool betweenTs(int lesser, double testT, int greater) {
2054 if (lesser > greater) {
2055 SkTSwap<int>(lesser, greater);
2056 }
2057 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
2058 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002059
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002060 const Bounds& bounds() const {
2061 return fBounds;
2062 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002063
caryclark@google.com31143cf2012-11-09 22:14:19 +00002064 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002065 double referenceT = fTs[index].fT;
2066 int lesser = index;
caryclark@google.com31143cf2012-11-09 22:14:19 +00002067 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
2068 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00002069 buildAnglesInner(lesser, angles);
2070 }
2071 do {
2072 buildAnglesInner(index, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002073 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
2074 && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002075 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002076
2077 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
2078 Span* span = &fTs[index];
2079 Segment* other = span->fOther;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002080 // if there is only one live crossing, and no coincidence, continue
2081 // in the same direction
2082 // if there is coincidence, the only choice may be to reverse direction
2083 // find edge on either side of intersection
2084 int oIndex = span->fOtherIndex;
2085 // if done == -1, prior span has already been processed
2086 int step = 1;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002087 int next = other->nextExactSpan(oIndex, step);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002088 if (next < 0) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002089 step = -step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002090 next = other->nextExactSpan(oIndex, step);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002091 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002092 // add candidate into and away from junction
2093 other->addTwoAngles(next, oIndex, angles);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002094 }
2095
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002096 int computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002097 SkTDArray<Angle> angles;
2098 addTwoAngles(startIndex, endIndex, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002099 buildAngles(endIndex, angles, false);
caryclark@google.comd1688742012-09-18 20:08:37 +00002100 // OPTIMIZATION: check all angles to see if any have computed wind sum
2101 // before sorting (early exit if none)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002102 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002103 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002104#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002105 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002106#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002107 if (!sortable) {
2108 return SK_MinS32;
2109 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002110 int angleCount = angles.count();
2111 const Angle* angle;
2112 const Segment* base;
2113 int winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002114 int oWinding;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002115 int firstIndex = 0;
2116 do {
2117 angle = sorted[firstIndex];
2118 base = angle->segment();
2119 winding = base->windSum(angle);
2120 if (winding != SK_MinS32) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002121 oWinding = base->oppSum(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002122 break;
2123 }
2124 if (++firstIndex == angleCount) {
2125 return SK_MinS32;
2126 }
2127 } while (true);
2128 // turn winding into contourWinding
caryclark@google.com2ddff932012-08-07 21:25:27 +00002129 int spanWinding = base->spanSign(angle);
2130 bool inner = useInnerWinding(winding + spanWinding, winding);
2131 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00002132 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
caryclark@google.com59823f72012-08-09 18:17:47 +00002133 spanWinding, winding, angle->sign(), inner,
caryclark@google.com2ddff932012-08-07 21:25:27 +00002134 inner ? winding + spanWinding : winding);
2135 #endif
2136 if (inner) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002137 winding += spanWinding;
2138 }
2139 #if DEBUG_SORT
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002140 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002141 #endif
2142 int nextIndex = firstIndex + 1;
2143 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com2ddff932012-08-07 21:25:27 +00002144 winding -= base->spanSign(angle);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002145 oWinding -= base->oppSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002146 do {
2147 if (nextIndex == angleCount) {
2148 nextIndex = 0;
2149 }
2150 angle = sorted[nextIndex];
2151 Segment* segment = angle->segment();
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002152 bool opp = base->fOperand ^ segment->fOperand;
2153 int maxWinding, oMaxWinding;
2154 int spanSign = segment->spanSign(angle);
2155 int oppoSign = segment->oppSign(angle);
2156 if (opp) {
2157 oMaxWinding = oWinding;
2158 oWinding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002159 maxWinding = winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002160 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002161 winding -= oppoSign;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002162 }
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002163 } else {
2164 maxWinding = winding;
2165 winding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002166 oMaxWinding = oWinding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002167 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002168 oWinding -= oppoSign;
2169 }
2170 }
2171 if (segment->windSum(angle) == SK_MinS32) {
2172 if (opp) {
2173 if (useInnerWinding(oMaxWinding, oWinding)) {
2174 oMaxWinding = oWinding;
2175 }
2176 if (oppoSign && useInnerWinding(maxWinding, winding)) {
2177 maxWinding = winding;
2178 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002179 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002180 } else {
2181 if (useInnerWinding(maxWinding, winding)) {
2182 maxWinding = winding;
2183 }
2184 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
2185 oMaxWinding = oWinding;
2186 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002187 (void) segment->markAndChaseWinding(angle, maxWinding,
2188 binary ? oMaxWinding : 0);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002189 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002190 }
2191 } while (++nextIndex != lastIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002192 int minIndex = SkMin32(startIndex, endIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002193 return windSum(minIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002194 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002195
caryclark@google.com3586ece2012-12-27 18:46:58 +00002196 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
caryclark@google.com10227bf2012-12-28 22:10:41 +00002197 double mid, bool opp, bool current) const {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002198 SkScalar bottom = fBounds.fBottom;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002199 int bestTIndex = -1;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002200 if (bottom <= bestY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002201 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002202 }
2203 SkScalar top = fBounds.fTop;
2204 if (top >= basePt.fY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002205 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002206 }
2207 if (fBounds.fLeft > basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002208 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002209 }
2210 if (fBounds.fRight < basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002211 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002212 }
2213 if (fBounds.fLeft == fBounds.fRight) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002214 // if vertical, and directly above test point, wait for another one
caryclark@google.com6d0032a2013-01-04 19:41:13 +00002215 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002216 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002217 // intersect ray starting at basePt with edge
2218 Intersections intersections;
2219 // OPTIMIZE: use specialty function that intersects ray with curve,
2220 // returning t values only for curve (we don't care about t on ray)
2221 int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
2222 if (pts == 0 || (current && pts == 1)) {
2223 return bestTIndex;
2224 }
2225 if (current) {
2226 SkASSERT(pts > 1);
2227 int closestIdx = 0;
2228 double closest = fabs(intersections.fT[0][0] - mid);
2229 for (int idx = 1; idx < pts; ++idx) {
2230 double test = fabs(intersections.fT[0][idx] - mid);
2231 if (closest > test) {
2232 closestIdx = idx;
2233 closest = test;
2234 }
2235 }
2236 if (closestIdx < pts - 1) {
2237 intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
2238 }
2239 --pts;
2240 }
2241 double bestT = -1;
2242 for (int index = 0; index < pts; ++index) {
2243 double foundT = intersections.fT[0][index];
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002244 if (approximately_less_than_zero(foundT)
2245 || approximately_greater_than_one(foundT)) {
2246 continue;
2247 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002248 SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
2249 if (approximately_negative(testY - bestY)
2250 || approximately_negative(basePt.fY - testY)) {
caryclark@google.com47580692012-07-23 12:14:49 +00002251 continue;
2252 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002253 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002254 return SK_MinS32; // if the intersection is edge on, wait for another one
caryclark@google.com10227bf2012-12-28 22:10:41 +00002255 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002256 if (fVerb > SkPath::kLine_Verb) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002257 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
2258 if (approximately_zero(dx)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002259 return SK_MinS32; // hit vertical, wait for another one
caryclark@google.com3586ece2012-12-27 18:46:58 +00002260 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00002261 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002262 bestY = testY;
2263 bestT = foundT;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002264 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002265 if (bestT < 0) {
2266 return bestTIndex;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002267 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002268 SkASSERT(bestT >= 0);
2269 SkASSERT(bestT <= 1);
2270 int start;
2271 int end = 0;
2272 do {
2273 start = end;
2274 end = nextSpan(start, 1);
2275 } while (fTs[end].fT < bestT);
2276 // FIXME: see next candidate for a better pattern to find the next start/end pair
2277 while (start + 1 < end && fTs[start].fDone) {
2278 ++start;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002279 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002280 if (!isCanceled(start)) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002281 hitT = bestT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002282 bestTIndex = start;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002283 hitSomething = true;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002284 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002285 return bestTIndex;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002286 }
caryclark@google.com18063442012-07-25 12:05:18 +00002287
caryclark@google.com4eeda372012-12-06 21:47:48 +00002288 void decrementSpan(Span* span) {
caryclark@google.com18063442012-07-25 12:05:18 +00002289 SkASSERT(span->fWindValue > 0);
2290 if (--(span->fWindValue) == 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002291 if (!span->fOppValue && !span->fDone) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002292 span->fDone = true;
2293 ++fDoneSpans;
2294 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002295 }
2296 }
2297
2298 bool bumpSpan(Span* span, int windDelta, int oppDelta) {
2299 SkASSERT(!span->fDone);
2300 span->fWindValue += windDelta;
2301 SkASSERT(span->fWindValue >= 0);
2302 span->fOppValue += oppDelta;
2303 SkASSERT(span->fOppValue >= 0);
2304 if (fXor) {
2305 span->fWindValue &= 1;
2306 }
2307 if (fOppXor) {
2308 span->fOppValue &= 1;
2309 }
2310 if (!span->fWindValue && !span->fOppValue) {
2311 span->fDone = true;
2312 ++fDoneSpans;
caryclark@google.com18063442012-07-25 12:05:18 +00002313 return true;
2314 }
2315 return false;
2316 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002317
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002318 // OPTIMIZE
2319 // when the edges are initially walked, they don't automatically get the prior and next
2320 // 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 +00002321 // and would additionally remove the need for similar checks in condition edges. It would
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002322 // also allow intersection code to assume end of segment intersections (maybe?)
2323 bool complete() const {
2324 int count = fTs.count();
2325 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
2326 }
caryclark@google.com18063442012-07-25 12:05:18 +00002327
caryclark@google.com15fa1382012-05-07 20:49:36 +00002328 bool done() const {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002329 SkASSERT(fDoneSpans <= fTs.count());
2330 return fDoneSpans == fTs.count();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002331 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002332
caryclark@google.comf839c032012-10-26 21:03:50 +00002333 bool done(int min) const {
2334 return fTs[min].fDone;
2335 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002336
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002337 bool done(const Angle* angle) const {
2338 return done(SkMin32(angle->start(), angle->end()));
caryclark@google.com47580692012-07-23 12:14:49 +00002339 }
skia.committer@gmail.com044679e2013-02-15 07:16:57 +00002340
caryclark@google.com7ff5c842013-02-26 15:56:05 +00002341 SkVector dxdy(int index) const {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002342 return (*SegmentDXDYAtT[fVerb])(fPts, fTs[index].fT);
2343 }
2344
2345 SkScalar dy(int index) const {
2346 return (*SegmentDYAtT[fVerb])(fPts, fTs[index].fT);
2347 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00002348
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002349 bool equalPoints(int greaterTIndex, int lesserTIndex) {
2350 SkASSERT(greaterTIndex >= lesserTIndex);
2351 double greaterT = fTs[greaterTIndex].fT;
2352 double lesserT = fTs[lesserTIndex].fT;
2353 if (greaterT == lesserT) {
2354 return true;
2355 }
2356 if (!approximately_negative(greaterT - lesserT)) {
2357 return false;
2358 }
2359 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2360 }
2361
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002362 /*
2363 The M and S variable name parts stand for the operators.
2364 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2365 Su stands for Subtrahend
2366 The Opp variable name part designates that the value is for the Opposite operator.
2367 Opposite values result from combining coincident spans.
2368 */
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002369
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002370 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2371 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002372 const int startIndex = nextStart;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002373 const int endIndex = nextEnd;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002374 SkASSERT(startIndex != endIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002375 const int count = fTs.count();
2376 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2377 const int step = SkSign32(endIndex - startIndex);
2378 const int end = nextExactSpan(startIndex, step);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002379 SkASSERT(end >= 0);
2380 Span* endSpan = &fTs[end];
2381 Segment* other;
2382 if (isSimple(end)) {
2383 // mark the smaller of startIndex, endIndex done, and all adjacent
2384 // spans with the same T value (but not 'other' spans)
2385 #if DEBUG_WINDING
2386 SkDebugf("%s simple\n", __FUNCTION__);
2387 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002388 int min = SkMin32(startIndex, endIndex);
2389 if (fTs[min].fDone) {
2390 return NULL;
2391 }
2392 markDoneBinary(min);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002393 other = endSpan->fOther;
2394 nextStart = endSpan->fOtherIndex;
2395 double startT = other->fTs[nextStart].fT;
2396 nextEnd = nextStart;
2397 do {
2398 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002399 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002400 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002401 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2402 return other;
2403 }
2404 // more than one viable candidate -- measure angles to find best
2405 SkTDArray<Angle> angles;
2406 SkASSERT(startIndex - endIndex != 0);
2407 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2408 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002409 buildAngles(end, angles, true);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002410 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002411 bool sortable = SortAngles(angles, sorted);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002412 int angleCount = angles.count();
2413 int firstIndex = findStartingEdge(sorted, startIndex, end);
2414 SkASSERT(firstIndex >= 0);
2415 #if DEBUG_SORT
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002416 debugShowSort(__FUNCTION__, sorted, firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002417 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002418 if (!sortable) {
2419 unsortable = true;
2420 return NULL;
2421 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002422 SkASSERT(sorted[firstIndex]->segment() == this);
2423 #if DEBUG_WINDING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002424 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2425 sorted[firstIndex]->sign());
caryclark@google.com235f56a2012-09-14 14:19:30 +00002426 #endif
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002427 int sumMiWinding = updateWinding(endIndex, startIndex);
2428 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2429 if (operand()) {
2430 SkTSwap<int>(sumMiWinding, sumSuWinding);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002431 }
2432 int nextIndex = firstIndex + 1;
2433 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2434 const Angle* foundAngle = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002435 bool foundDone = false;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002436 // iterate through the angle, and compute everyone's winding
caryclark@google.com235f56a2012-09-14 14:19:30 +00002437 Segment* nextSegment;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002438 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002439 SkASSERT(nextIndex != firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002440 if (nextIndex == angleCount) {
2441 nextIndex = 0;
2442 }
2443 const Angle* nextAngle = sorted[nextIndex];
2444 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002445 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2446 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2447 nextAngle->end(), op, sumMiWinding, sumSuWinding,
2448 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
2449 if (activeAngle && (!foundAngle || foundDone)) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002450 foundAngle = nextAngle;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002451 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002452 }
2453 if (nextSegment->done()) {
2454 continue;
2455 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002456 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2457 continue;
2458 }
2459 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2460 oppSumWinding, activeAngle, nextAngle);
2461 if (last) {
2462 *chase.append() = last;
2463#if DEBUG_WINDING
2464 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2465 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2466#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002467 }
2468 } while (++nextIndex != lastIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002469 markDoneBinary(SkMin32(startIndex, endIndex));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002470 if (!foundAngle) {
2471 return NULL;
2472 }
2473 nextStart = foundAngle->start();
2474 nextEnd = foundAngle->end();
2475 nextSegment = foundAngle->segment();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002476
caryclark@google.com235f56a2012-09-14 14:19:30 +00002477 #if DEBUG_WINDING
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002478 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2479 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002480 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002481 return nextSegment;
2482 }
caryclark@google.com47580692012-07-23 12:14:49 +00002483
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002484 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2485 bool& unsortable) {
2486 const int startIndex = nextStart;
2487 const int endIndex = nextEnd;
2488 SkASSERT(startIndex != endIndex);
2489 const int count = fTs.count();
2490 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2491 const int step = SkSign32(endIndex - startIndex);
2492 const int end = nextExactSpan(startIndex, step);
2493 SkASSERT(end >= 0);
2494 Span* endSpan = &fTs[end];
2495 Segment* other;
2496 if (isSimple(end)) {
2497 // mark the smaller of startIndex, endIndex done, and all adjacent
2498 // spans with the same T value (but not 'other' spans)
2499 #if DEBUG_WINDING
2500 SkDebugf("%s simple\n", __FUNCTION__);
2501 #endif
2502 int min = SkMin32(startIndex, endIndex);
2503 if (fTs[min].fDone) {
2504 return NULL;
2505 }
2506 markDoneUnary(min);
2507 other = endSpan->fOther;
2508 nextStart = endSpan->fOtherIndex;
2509 double startT = other->fTs[nextStart].fT;
2510 nextEnd = nextStart;
2511 do {
2512 nextEnd += step;
2513 }
2514 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2515 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2516 return other;
2517 }
2518 // more than one viable candidate -- measure angles to find best
2519 SkTDArray<Angle> angles;
2520 SkASSERT(startIndex - endIndex != 0);
2521 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2522 addTwoAngles(startIndex, end, angles);
2523 buildAngles(end, angles, true);
2524 SkTDArray<Angle*> sorted;
2525 bool sortable = SortAngles(angles, sorted);
2526 int angleCount = angles.count();
2527 int firstIndex = findStartingEdge(sorted, startIndex, end);
2528 SkASSERT(firstIndex >= 0);
2529 #if DEBUG_SORT
2530 debugShowSort(__FUNCTION__, sorted, firstIndex);
2531 #endif
2532 if (!sortable) {
2533 unsortable = true;
2534 return NULL;
2535 }
2536 SkASSERT(sorted[firstIndex]->segment() == this);
2537 #if DEBUG_WINDING
2538 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2539 sorted[firstIndex]->sign());
2540 #endif
2541 int sumWinding = updateWinding(endIndex, startIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002542 int nextIndex = firstIndex + 1;
2543 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2544 const Angle* foundAngle = NULL;
2545 bool foundDone = false;
2546 // iterate through the angle, and compute everyone's winding
2547 Segment* nextSegment;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002548 int activeCount = 0;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002549 do {
2550 SkASSERT(nextIndex != firstIndex);
2551 if (nextIndex == angleCount) {
2552 nextIndex = 0;
2553 }
2554 const Angle* nextAngle = sorted[nextIndex];
2555 nextSegment = nextAngle->segment();
2556 int maxWinding;
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00002557 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002558 maxWinding, sumWinding);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002559 if (activeAngle) {
2560 ++activeCount;
2561 if (!foundAngle || (foundDone && activeCount & 1)) {
2562 if (nextSegment->tiny(nextAngle)) {
2563 unsortable = true;
2564 return NULL;
2565 }
2566 foundAngle = nextAngle;
2567 foundDone = nextSegment->done(nextAngle);
2568 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002569 }
2570 if (nextSegment->done()) {
2571 continue;
2572 }
2573 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2574 continue;
2575 }
2576 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2577 if (last) {
2578 *chase.append() = last;
2579#if DEBUG_WINDING
2580 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2581 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2582#endif
2583 }
2584 } while (++nextIndex != lastIndex);
2585 markDoneUnary(SkMin32(startIndex, endIndex));
2586 if (!foundAngle) {
2587 return NULL;
2588 }
2589 nextStart = foundAngle->start();
2590 nextEnd = foundAngle->end();
2591 nextSegment = foundAngle->segment();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002592 #if DEBUG_WINDING
2593 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2594 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2595 #endif
2596 return nextSegment;
2597 }
2598
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002599 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002600 const int startIndex = nextStart;
2601 const int endIndex = nextEnd;
2602 SkASSERT(startIndex != endIndex);
2603 int count = fTs.count();
2604 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2605 : startIndex > 0);
2606 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002607 int end = nextExactSpan(startIndex, step);
caryclark@google.com24bec792012-08-20 12:43:57 +00002608 SkASSERT(end >= 0);
2609 Span* endSpan = &fTs[end];
2610 Segment* other;
caryclark@google.com24bec792012-08-20 12:43:57 +00002611 if (isSimple(end)) {
2612 #if DEBUG_WINDING
2613 SkDebugf("%s simple\n", __FUNCTION__);
2614 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002615 int min = SkMin32(startIndex, endIndex);
2616 if (fTs[min].fDone) {
2617 return NULL;
2618 }
2619 markDone(min, 1);
caryclark@google.com24bec792012-08-20 12:43:57 +00002620 other = endSpan->fOther;
2621 nextStart = endSpan->fOtherIndex;
2622 double startT = other->fTs[nextStart].fT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002623 #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 +00002624 SkDEBUGCODE(bool firstLoop = true;)
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002625 if ((approximately_less_than_zero(startT) && step < 0)
2626 || (approximately_greater_than_one(startT) && step > 0)) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002627 step = -step;
2628 SkDEBUGCODE(firstLoop = false;)
2629 }
2630 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002631 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002632 nextEnd = nextStart;
2633 do {
2634 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002635 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002636 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002637 #if 01
caryclark@google.com24bec792012-08-20 12:43:57 +00002638 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2639 break;
2640 }
caryclark@google.com03f97062012-08-21 13:13:52 +00002641 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00002642 SkASSERT(firstLoop);
caryclark@google.com03f97062012-08-21 13:13:52 +00002643 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002644 SkDEBUGCODE(firstLoop = false;)
2645 step = -step;
2646 } while (true);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002647 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002648 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2649 return other;
2650 }
2651 SkTDArray<Angle> angles;
2652 SkASSERT(startIndex - endIndex != 0);
2653 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2654 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002655 buildAngles(end, angles, false);
caryclark@google.com24bec792012-08-20 12:43:57 +00002656 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002657 bool sortable = SortAngles(angles, sorted);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002658 if (!sortable) {
2659 unsortable = true;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002660 #if DEBUG_SORT
2661 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
2662 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002663 return NULL;
2664 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002665 int angleCount = angles.count();
2666 int firstIndex = findStartingEdge(sorted, startIndex, end);
2667 SkASSERT(firstIndex >= 0);
2668 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002669 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
caryclark@google.com24bec792012-08-20 12:43:57 +00002670 #endif
2671 SkASSERT(sorted[firstIndex]->segment() == this);
2672 int nextIndex = firstIndex + 1;
2673 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002674 const Angle* foundAngle = NULL;
2675 bool foundDone = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002676 Segment* nextSegment;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002677 int activeCount = 0;
caryclark@google.com24bec792012-08-20 12:43:57 +00002678 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002679 SkASSERT(nextIndex != firstIndex);
caryclark@google.com24bec792012-08-20 12:43:57 +00002680 if (nextIndex == angleCount) {
2681 nextIndex = 0;
2682 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002683 const Angle* nextAngle = sorted[nextIndex];
caryclark@google.com24bec792012-08-20 12:43:57 +00002684 nextSegment = nextAngle->segment();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002685 ++activeCount;
2686 if (!foundAngle || (foundDone && activeCount & 1)) {
2687 if (nextSegment->tiny(nextAngle)) {
2688 unsortable = true;
2689 return NULL;
2690 }
2691 foundAngle = nextAngle;
2692 foundDone = nextSegment->done(nextAngle);
2693 }
2694 if (nextSegment->done()) {
2695 continue;
caryclark@google.com24bec792012-08-20 12:43:57 +00002696 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002697 } while (++nextIndex != lastIndex);
2698 markDone(SkMin32(startIndex, endIndex), 1);
2699 if (!foundAngle) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002700 return NULL;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002701 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002702 nextStart = foundAngle->start();
2703 nextEnd = foundAngle->end();
2704 nextSegment = foundAngle->segment();
2705 #if DEBUG_WINDING
2706 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2707 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2708 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002709 return nextSegment;
2710 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002711
2712 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2713 int angleCount = sorted.count();
2714 int firstIndex = -1;
2715 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2716 const Angle* angle = sorted[angleIndex];
2717 if (angle->segment() == this && angle->start() == end &&
2718 angle->end() == start) {
2719 firstIndex = angleIndex;
2720 break;
2721 }
2722 }
2723 return firstIndex;
2724 }
2725
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002726 // FIXME: this is tricky code; needs its own unit test
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002727 // note that fOtherIndex isn't computed yet, so it can't be used here
caryclark@google.com4eeda372012-12-06 21:47:48 +00002728 void findTooCloseToCall() {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002729 int count = fTs.count();
2730 if (count < 3) { // require t=0, x, 1 at minimum
2731 return;
2732 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002733 int matchIndex = 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002734 int moCount;
2735 Span* match;
2736 Segment* mOther;
2737 do {
2738 match = &fTs[matchIndex];
2739 mOther = match->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002740 // FIXME: allow quads, cubics to be near coincident?
2741 if (mOther->fVerb == SkPath::kLine_Verb) {
2742 moCount = mOther->fTs.count();
2743 if (moCount >= 3) {
2744 break;
2745 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002746 }
2747 if (++matchIndex >= count) {
2748 return;
2749 }
2750 } while (true); // require t=0, x, 1 at minimum
caryclark@google.com15fa1382012-05-07 20:49:36 +00002751 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002752 const SkPoint* matchPt = &xyAtT(match);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002753 // look for a pair of nearby T values that map to the same (x,y) value
2754 // if found, see if the pair of other segments share a common point. If
2755 // so, the span from here to there is coincident.
caryclark@google.com15fa1382012-05-07 20:49:36 +00002756 for (int index = matchIndex + 1; index < count; ++index) {
2757 Span* test = &fTs[index];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002758 if (test->fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002759 continue;
2760 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002761 Segment* tOther = test->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002762 if (tOther->fVerb != SkPath::kLine_Verb) {
2763 continue; // FIXME: allow quads, cubics to be near coincident?
2764 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002765 int toCount = tOther->fTs.count();
2766 if (toCount < 3) { // require t=0, x, 1 at minimum
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002767 continue;
2768 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002769 const SkPoint* testPt = &xyAtT(test);
2770 if (*matchPt != *testPt) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002771 matchIndex = index;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002772 moCount = toCount;
2773 match = test;
2774 mOther = tOther;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002775 matchPt = testPt;
2776 continue;
2777 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002778 int moStart = -1;
2779 int moEnd = -1;
2780 double moStartT, moEndT;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002781 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002782 Span& moSpan = mOther->fTs[moIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002783 if (moSpan.fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002784 continue;
2785 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002786 if (moSpan.fOther == this) {
2787 if (moSpan.fOtherT == match->fT) {
2788 moStart = moIndex;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002789 moStartT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002790 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002791 continue;
2792 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002793 if (moSpan.fOther == tOther) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002794 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002795 moStart = -1;
2796 break;
2797 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002798 SkASSERT(moEnd == -1);
2799 moEnd = moIndex;
2800 moEndT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002801 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002802 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002803 if (moStart < 0 || moEnd < 0) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002804 continue;
2805 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002806 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002807 if (approximately_equal(moStartT, moEndT)) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002808 continue;
2809 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002810 int toStart = -1;
2811 int toEnd = -1;
2812 double toStartT, toEndT;
2813 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2814 Span& toSpan = tOther->fTs[toIndex];
caryclark@google.comc899ad92012-08-23 15:24:42 +00002815 if (toSpan.fDone) {
2816 continue;
2817 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002818 if (toSpan.fOther == this) {
2819 if (toSpan.fOtherT == test->fT) {
2820 toStart = toIndex;
2821 toStartT = toSpan.fT;
2822 }
2823 continue;
2824 }
2825 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002826 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002827 moStart = -1;
2828 break;
2829 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002830 SkASSERT(toEnd == -1);
2831 toEnd = toIndex;
2832 toEndT = toSpan.fT;
2833 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002834 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002835 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2836 if (toStart <= 0 || toEnd <= 0) {
2837 continue;
2838 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002839 if (approximately_equal(toStartT, toEndT)) {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002840 continue;
2841 }
2842 // test to see if the segment between there and here is linear
2843 if (!mOther->isLinear(moStart, moEnd)
2844 || !tOther->isLinear(toStart, toEnd)) {
2845 continue;
2846 }
caryclark@google.comc899ad92012-08-23 15:24:42 +00002847 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002848 if (flipped) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002849 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002850 } else {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002851 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002852 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002853 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002854 }
2855
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002856 // FIXME: either:
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002857 // a) mark spans with either end unsortable as done, or
2858 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2859 // when encountering an unsortable span
2860
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002861 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2862 // and use more concise logic like the old edge walker code?
2863 // FIXME: this needs to deal with coincident edges
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002864 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002865 // iterate through T intersections and return topmost
2866 // topmost tangent from y-min to first pt is closer to horizontal
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002867 SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002868 int firstT = -1;
caryclark@google.comd0a19eb2013-02-19 12:49:33 +00002869 /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002870 SkASSERT(firstT >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002871 // sort the edges to find the leftmost
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002872 int step = 1;
2873 int end = nextSpan(firstT, step);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002874 if (end == -1) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002875 step = -1;
2876 end = nextSpan(firstT, step);
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00002877 SkASSERT(end != -1);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002878 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002879 // if the topmost T is not on end, or is three-way or more, find left
2880 // look for left-ness from tLeft to firstT (matching y of other)
2881 SkTDArray<Angle> angles;
2882 SkASSERT(firstT - end != 0);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002883 addTwoAngles(end, firstT, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002884 buildAngles(firstT, angles, true);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002885 SkTDArray<Angle*> sorted;
caryclark@google.comf839c032012-10-26 21:03:50 +00002886 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002887 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002888 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002889 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002890 if (onlySortable && !sortable) {
2891 unsortable = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002892 return NULL;
2893 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002894 // skip edges that have already been processed
2895 firstT = -1;
2896 Segment* leftSegment;
2897 do {
2898 const Angle* angle = sorted[++firstT];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002899 SkASSERT(!onlySortable || !angle->unsortable());
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002900 leftSegment = angle->segment();
2901 tIndex = angle->end();
2902 endIndex = angle->start();
2903 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002904 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002905 bool bumpsUp = leftSegment->bumpsUp(tIndex, endIndex);
2906 SkPoint xyE = leftSegment->xyAtT(endIndex);
2907 SkPoint xyS = leftSegment->xyAtT(tIndex);
caryclark@google.com7ff5c842013-02-26 15:56:05 +00002908 SkVector dxyE = leftSegment->dxdy(endIndex);
2909 SkVector dxyS = leftSegment->dxdy(tIndex);
caryclark@google.com47d73da2013-02-17 01:41:25 +00002910 double cross = dxyE.cross(dxyS);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00002911 bool bumpCheck = bumpsUp && xyE.fY < xyS.fY && dxyE.fX < 0;
caryclark@google.com47d73da2013-02-17 01:41:25 +00002912 #if DEBUG_SWAP_TOP
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002913 SkDebugf("%s xyE=(%1.9g,%1.9g) xyS=(%1.9g,%1.9g)\n", __FUNCTION__,
2914 xyE.fX, xyE.fY, xyS.fX, xyS.fY);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00002915 SkDebugf("%s dxyE=(%1.9g,%1.9g) dxyS=(%1.9g,%1.9g) cross=%1.9g bumpsUp=%s\n",
2916 __FUNCTION__,
2917 dxyE.fX, dxyE.fY, dxyS.fX, dxyS.fY, cross, bumpsUp ? "true" : "false");
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002918 if ((cross > 0) ^ bumpCheck) {
2919 leftSegment->bumpsUp(tIndex, endIndex);
2920 SkDebugf("%s cross bump disagree\n", __FUNCTION__);
2921 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00002922 #endif
2923 if (cross > 0 || bumpCheck) {
caryclark@google.com47d73da2013-02-17 01:41:25 +00002924 #if DEBUG_SWAP_TOP
2925 SkDebugf("%s swap\n", __FUNCTION__);
2926 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002927 SkTSwap(tIndex, endIndex);
2928 }
2929 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002930 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002931 return leftSegment;
2932 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002933
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002934 // FIXME: not crazy about this
2935 // when the intersections are performed, the other index is into an
2936 // incomplete array. as the array grows, the indices become incorrect
2937 // while the following fixes the indices up again, it isn't smart about
2938 // skipping segments whose indices are already correct
2939 // assuming we leave the code that wrote the index in the first place
2940 void fixOtherTIndex() {
2941 int iCount = fTs.count();
2942 for (int i = 0; i < iCount; ++i) {
2943 Span& iSpan = fTs[i];
2944 double oT = iSpan.fOtherT;
2945 Segment* other = iSpan.fOther;
2946 int oCount = other->fTs.count();
2947 for (int o = 0; o < oCount; ++o) {
2948 Span& oSpan = other->fTs[o];
2949 if (oT == oSpan.fT && this == oSpan.fOther) {
2950 iSpan.fOtherIndex = o;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002951 break;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002952 }
2953 }
2954 }
2955 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002956
caryclark@google.com4eeda372012-12-06 21:47:48 +00002957 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002958 fDoneSpans = 0;
2959 fOperand = operand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00002960 fXor = evenOdd;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002961 fPts = pts;
2962 fVerb = verb;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002963 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00002964
caryclark@google.com3586ece2012-12-27 18:46:58 +00002965 void initWinding(int start, int end) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002966 int local = spanSign(start, end);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002967 int oppLocal = oppSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002968 (void) markAndChaseWinding(start, end, local, oppLocal);
caryclark@google.com73ca6242013-01-17 21:02:47 +00002969 // OPTIMIZATION: the reverse mark and chase could skip the first marking
2970 (void) markAndChaseWinding(end, start, local, oppLocal);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002971 }
2972
caryclark@google.com3586ece2012-12-27 18:46:58 +00002973 void initWinding(int start, int end, int winding, int oppWinding) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002974 int local = spanSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002975 if (local * winding >= 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002976 winding += local;
2977 }
2978 int oppLocal = oppSign(start, end);
2979 if (oppLocal * oppWinding >= 0) {
2980 oppWinding += oppLocal;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002981 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002982 (void) markAndChaseWinding(start, end, winding, oppWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002983 }
2984
caryclark@google.com3586ece2012-12-27 18:46:58 +00002985/*
2986when we start with a vertical intersect, we try to use the dx to determine if the edge is to
2987the 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 +00002988sign or not. However, this isn't enough.
2989If 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 +00002990If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
2991from 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 +00002992the same winding is shared by both.
caryclark@google.com3586ece2012-12-27 18:46:58 +00002993*/
2994 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
2995 SkScalar hitOppDx) {
2996 SkASSERT(hitDx || !winding);
2997 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
2998 SkASSERT(dx);
2999 int windVal = windValue(SkMin32(start, end));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003000 #if DEBUG_WINDING_AT_T
3001 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
3002 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
3003 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00003004 if (!winding) {
3005 winding = dx < 0 ? windVal : -windVal;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003006 } else if (winding * dx < 0) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00003007 int sideWind = winding + (dx < 0 ? windVal : -windVal);
3008 if (abs(winding) < abs(sideWind)) {
3009 winding = sideWind;
3010 }
3011 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003012 #if DEBUG_WINDING_AT_T
3013 SkDebugf(" winding=%d\n", winding);
3014 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00003015 int oppLocal = oppSign(start, end);
3016 SkASSERT(hitOppDx || !oppWind || !oppLocal);
3017 int oppWindVal = oppValue(SkMin32(start, end));
3018 if (!oppWind) {
3019 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
3020 } else if (hitOppDx * dx >= 0) {
3021 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
3022 if (abs(oppWind) < abs(oppSideWind)) {
3023 oppWind = oppSideWind;
3024 }
3025 }
3026 (void) markAndChaseWinding(start, end, winding, oppWind);
3027 }
3028
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003029 bool intersected() const {
3030 return fTs.count() > 0;
3031 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00003032
caryclark@google.com10227bf2012-12-28 22:10:41 +00003033 bool isCanceled(int tIndex) const {
3034 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
3035 }
3036
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00003037 bool isConnected(int startIndex, int endIndex) const {
3038 return fTs[startIndex].fWindSum != SK_MinS32
3039 || fTs[endIndex].fWindSum != SK_MinS32;
3040 }
3041
caryclark@google.com235f56a2012-09-14 14:19:30 +00003042 bool isHorizontal() const {
3043 return fBounds.fTop == fBounds.fBottom;
3044 }
3045
caryclark@google.com15fa1382012-05-07 20:49:36 +00003046 bool isLinear(int start, int end) const {
3047 if (fVerb == SkPath::kLine_Verb) {
3048 return true;
3049 }
3050 if (fVerb == SkPath::kQuad_Verb) {
3051 SkPoint qPart[3];
3052 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
3053 return QuadIsLinear(qPart);
3054 } else {
3055 SkASSERT(fVerb == SkPath::kCubic_Verb);
3056 SkPoint cPart[4];
3057 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
3058 return CubicIsLinear(cPart);
3059 }
3060 }
caryclark@google.comb9738012012-07-03 19:53:30 +00003061
3062 // OPTIMIZE: successive calls could start were the last leaves off
3063 // or calls could specialize to walk forwards or backwards
3064 bool isMissing(double startT) const {
3065 size_t tCount = fTs.count();
3066 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003067 if (approximately_zero(startT - fTs[index].fT)) {
caryclark@google.comb9738012012-07-03 19:53:30 +00003068 return false;
3069 }
3070 }
3071 return true;
3072 }
3073
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003074 bool isSimple(int end) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003075 int count = fTs.count();
3076 if (count == 2) {
3077 return true;
3078 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003079 double t = fTs[end].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003080 if (approximately_less_than_zero(t)) {
3081 return !approximately_less_than_zero(fTs[1].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003082 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003083 if (approximately_greater_than_one(t)) {
3084 return !approximately_greater_than_one(fTs[count - 2].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003085 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003086 return false;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003087 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003088
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003089 bool isVertical() const {
3090 return fBounds.fLeft == fBounds.fRight;
3091 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003092
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003093 bool isVertical(int start, int end) const {
3094 return (*SegmentVertical[fVerb])(fPts, start, end);
3095 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003096
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003097 SkScalar leftMost(int start, int end) const {
3098 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
3099 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003100
caryclark@google.com495f8e42012-05-31 13:13:11 +00003101 // this span is excluded by the winding rule -- chase the ends
3102 // as long as they are unambiguous to mark connections as done
3103 // and give them the same winding value
caryclark@google.com59823f72012-08-09 18:17:47 +00003104 Span* markAndChaseDone(const Angle* angle, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003105 int index = angle->start();
3106 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003107 return markAndChaseDone(index, endIndex, winding);
3108 }
3109
caryclark@google.com31143cf2012-11-09 22:14:19 +00003110 Span* markAndChaseDone(int index, int endIndex, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003111 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003112 int min = SkMin32(index, endIndex);
3113 markDone(min, winding);
3114 Span* last;
3115 Segment* other = this;
3116 while ((other = other->nextChase(index, step, min, last))) {
3117 other->markDone(min, winding);
3118 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003119 return last;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003120 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003121
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003122 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
3123 int index = angle->start();
3124 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003125 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003126 int min = SkMin32(index, endIndex);
3127 markDoneBinary(min, winding, oppWinding);
3128 Span* last;
3129 Segment* other = this;
3130 while ((other = other->nextChase(index, step, min, last))) {
3131 other->markDoneBinary(min, winding, oppWinding);
3132 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003133 return last;
3134 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003135
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003136 Span* markAndChaseDoneBinary(int index, int endIndex) {
3137 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003138 int min = SkMin32(index, endIndex);
3139 markDoneBinary(min);
3140 Span* last;
3141 Segment* other = this;
3142 while ((other = other->nextChase(index, step, min, last))) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003143 if (other->done()) {
3144 return NULL;
3145 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003146 other->markDoneBinary(min);
3147 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003148 return last;
3149 }
3150
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003151 Span* markAndChaseDoneUnary(int index, int endIndex) {
3152 int step = SkSign32(endIndex - index);
3153 int min = SkMin32(index, endIndex);
3154 markDoneUnary(min);
3155 Span* last;
3156 Segment* other = this;
3157 while ((other = other->nextChase(index, step, min, last))) {
3158 if (other->done()) {
3159 return NULL;
3160 }
3161 other->markDoneUnary(min);
3162 }
3163 return last;
3164 }
3165
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003166 Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
3167 int index = angle->start();
3168 int endIndex = angle->end();
3169 return markAndChaseDone(index, endIndex, winding);
3170 }
3171
caryclark@google.com4eeda372012-12-06 21:47:48 +00003172 Span* markAndChaseWinding(const Angle* angle, const int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003173 int index = angle->start();
3174 int endIndex = angle->end();
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003175 int step = SkSign32(endIndex - index);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003176 int min = SkMin32(index, endIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00003177 markWinding(min, winding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003178 Span* last;
3179 Segment* other = this;
3180 while ((other = other->nextChase(index, step, min, last))) {
3181 if (other->fTs[min].fWindSum != SK_MinS32) {
3182 SkASSERT(other->fTs[min].fWindSum == winding);
3183 return NULL;
3184 }
3185 other->markWinding(min, winding);
3186 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003187 return last;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003188 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003189
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003190 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003191 int min = SkMin32(index, endIndex);
3192 int step = SkSign32(endIndex - index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003193 markWinding(min, winding, oppWinding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003194 Span* last;
3195 Segment* other = this;
3196 while ((other = other->nextChase(index, step, min, last))) {
3197 if (other->fTs[min].fWindSum != SK_MinS32) {
3198 SkASSERT(other->fTs[min].fWindSum == winding);
3199 return NULL;
3200 }
3201 other->markWinding(min, winding, oppWinding);
3202 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003203 return last;
3204 }
3205
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003206 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
3207 int start = angle->start();
3208 int end = angle->end();
3209 return markAndChaseWinding(start, end, winding, oppWinding);
3210 }
3211
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003212 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
3213 SkASSERT(angle->segment() == this);
3214 if (useInnerWinding(maxWinding, sumWinding)) {
3215 maxWinding = sumWinding;
3216 }
3217 Span* last;
3218 if (activeAngle) {
3219 last = markAndChaseWinding(angle, maxWinding);
3220 } else {
3221 last = markAndChaseDoneUnary(angle, maxWinding);
3222 }
3223 return last;
3224 }
3225
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003226 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
3227 bool activeAngle, const Angle* angle) {
3228 SkASSERT(angle->segment() == this);
3229 if (useInnerWinding(maxWinding, sumWinding)) {
3230 maxWinding = sumWinding;
3231 }
3232 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
3233 oppMaxWinding = oppSumWinding;
3234 }
3235 Span* last;
3236 if (activeAngle) {
3237 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3238 } else {
3239 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
3240 }
3241 return last;
3242 }
3243
caryclark@google.com495f8e42012-05-31 13:13:11 +00003244 // FIXME: this should also mark spans with equal (x,y)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003245 // This may be called when the segment is already marked done. While this
3246 // wastes time, it shouldn't do any more than spin through the T spans.
rmistry@google.comd6176b02012-08-23 18:14:13 +00003247 // OPTIMIZATION: abort on first done found (assuming that this code is
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003248 // always called to mark segments done).
caryclark@google.com59823f72012-08-09 18:17:47 +00003249 void markDone(int index, int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003250 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003251 SkASSERT(winding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003252 double referenceT = fTs[index].fT;
3253 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003254 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3255 markOneDone(__FUNCTION__, lesser, winding);
3256 }
3257 do {
3258 markOneDone(__FUNCTION__, index, winding);
3259 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003260 }
3261
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003262 void markDoneBinary(int index, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003263 // SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003264 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003265 double referenceT = fTs[index].fT;
3266 int lesser = index;
3267 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003268 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003269 }
3270 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003271 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
3272 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3273 }
3274
3275 void markDoneBinary(int index) {
3276 double referenceT = fTs[index].fT;
3277 int lesser = index;
3278 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3279 markOneDoneBinary(__FUNCTION__, lesser);
3280 }
3281 do {
3282 markOneDoneBinary(__FUNCTION__, index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003283 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003284 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00003285
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003286 void markDoneUnary(int index, int winding) {
3287 // SkASSERT(!done());
3288 SkASSERT(winding);
3289 double referenceT = fTs[index].fT;
3290 int lesser = index;
3291 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3292 markOneDoneUnary(__FUNCTION__, lesser, winding);
3293 }
3294 do {
3295 markOneDoneUnary(__FUNCTION__, index, winding);
3296 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3297 }
3298
3299 void markDoneUnary(int index) {
3300 double referenceT = fTs[index].fT;
3301 int lesser = index;
3302 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3303 markOneDoneUnary(__FUNCTION__, lesser);
3304 }
3305 do {
3306 markOneDoneUnary(__FUNCTION__, index);
3307 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3308 }
3309
caryclark@google.com24bec792012-08-20 12:43:57 +00003310 void markOneDone(const char* funName, int tIndex, int winding) {
3311 Span* span = markOneWinding(funName, tIndex, winding);
3312 if (!span) {
3313 return;
3314 }
3315 span->fDone = true;
3316 fDoneSpans++;
3317 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003318
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003319 void markOneDoneBinary(const char* funName, int tIndex) {
3320 Span* span = verifyOneWinding(funName, tIndex);
3321 if (!span) {
3322 return;
3323 }
3324 span->fDone = true;
3325 fDoneSpans++;
3326 }
3327
3328 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003329 Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
3330 if (!span) {
3331 return;
3332 }
3333 span->fDone = true;
3334 fDoneSpans++;
3335 }
3336
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003337 void markOneDoneUnary(const char* funName, int tIndex) {
3338 Span* span = verifyOneWindingU(funName, tIndex);
3339 if (!span) {
3340 return;
3341 }
3342 span->fDone = true;
3343 fDoneSpans++;
3344 }
3345
3346 void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3347 Span* span = markOneWinding(funName, tIndex, winding);
3348 if (!span) {
3349 return;
3350 }
3351 span->fDone = true;
3352 fDoneSpans++;
3353 }
3354
caryclark@google.com24bec792012-08-20 12:43:57 +00003355 Span* markOneWinding(const char* funName, int tIndex, int winding) {
3356 Span& span = fTs[tIndex];
3357 if (span.fDone) {
3358 return NULL;
3359 }
3360 #if DEBUG_MARK_DONE
3361 debugShowNewWinding(funName, span, winding);
3362 #endif
3363 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com03f97062012-08-21 13:13:52 +00003364 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00003365 SkASSERT(abs(winding) <= gDebugMaxWindSum);
caryclark@google.com03f97062012-08-21 13:13:52 +00003366 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00003367 span.fWindSum = winding;
3368 return &span;
3369 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003370
caryclark@google.com31143cf2012-11-09 22:14:19 +00003371 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
3372 Span& span = fTs[tIndex];
3373 if (span.fDone) {
3374 return NULL;
3375 }
3376 #if DEBUG_MARK_DONE
3377 debugShowNewWinding(funName, span, winding, oppWinding);
3378 #endif
3379 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3380 #ifdef SK_DEBUG
3381 SkASSERT(abs(winding) <= gDebugMaxWindSum);
3382 #endif
3383 span.fWindSum = winding;
3384 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3385 #ifdef SK_DEBUG
3386 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
3387 #endif
3388 span.fOppSum = oppWinding;
3389 return &span;
3390 }
3391
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003392 bool bumpsUp(int tStart, int tEnd) const {
3393 SkPoint edge[4];
caryclark@google.comc83c70e2013-02-22 21:50:07 +00003394 subDivide(tStart, tEnd, edge);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003395 switch (fVerb) {
3396 case SkPath::kLine_Verb:
3397 SkASSERT(0); // shouldn't call in for lines
3398 return true;
3399 case SkPath::kQuad_Verb:
3400 return approximately_greater(edge[0].fY, edge[1].fY)
3401 && approximately_lesser(edge[1].fY, edge[2].fY);
3402 case SkPath::kCubic_Verb:
3403 return (approximately_greater(edge[0].fY, edge[1].fY)
3404 && approximately_lesser(edge[1].fY, edge[3].fY))
3405 || (approximately_greater(edge[0].fY, edge[2].fY)
3406 && approximately_lesser(edge[2].fY, edge[3].fY));
3407 default:
3408 SkASSERT(0);
3409 return false;
3410 }
3411 }
3412
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003413 Span* verifyOneWinding(const char* funName, int tIndex) {
3414 Span& span = fTs[tIndex];
3415 if (span.fDone) {
3416 return NULL;
3417 }
3418 #if DEBUG_MARK_DONE
3419 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3420 #endif
3421 SkASSERT(span.fWindSum != SK_MinS32);
3422 SkASSERT(span.fOppSum != SK_MinS32);
3423 return &span;
3424 }
3425
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003426 Span* verifyOneWindingU(const char* funName, int tIndex) {
3427 Span& span = fTs[tIndex];
3428 if (span.fDone) {
3429 return NULL;
3430 }
3431 #if DEBUG_MARK_DONE
3432 debugShowNewWinding(funName, span, span.fWindSum);
3433 #endif
3434 SkASSERT(span.fWindSum != SK_MinS32);
3435 return &span;
3436 }
3437
caryclark@google.comf839c032012-10-26 21:03:50 +00003438 // note that just because a span has one end that is unsortable, that's
3439 // not enough to mark it done. The other end may be sortable, allowing the
3440 // span to be added.
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003441 // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003442 void markUnsortable(int start, int end) {
3443 Span* span = &fTs[start];
3444 if (start < end) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003445#if DEBUG_UNSORTABLE
3446 SkDebugf("%s start id=%d [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fID, start,
3447 xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003448#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003449 span->fUnsortableStart = true;
3450 } else {
3451 --span;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003452#if DEBUG_UNSORTABLE
3453 SkDebugf("%s end id=%d [%d] (%1.9g,%1.9g) next:(%1.9g,%1.9g)\n", __FUNCTION__, fID,
3454 start - 1, xAtT(start - 1), yAtT(start - 1), xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003455#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003456 span->fUnsortableEnd = true;
3457 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003458 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003459 return;
3460 }
3461 span->fDone = true;
3462 fDoneSpans++;
3463 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003464
caryclark@google.com59823f72012-08-09 18:17:47 +00003465 void markWinding(int index, int winding) {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003466 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003467 SkASSERT(winding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003468 double referenceT = fTs[index].fT;
3469 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003470 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3471 markOneWinding(__FUNCTION__, lesser, winding);
3472 }
3473 do {
3474 markOneWinding(__FUNCTION__, index, winding);
3475 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003476 }
3477
3478 void markWinding(int index, int winding, int oppWinding) {
3479 // SkASSERT(!done());
caryclark@google.com4eeda372012-12-06 21:47:48 +00003480 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003481 double referenceT = fTs[index].fT;
3482 int lesser = index;
3483 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3484 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003485 }
3486 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003487 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3488 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003489 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003490
caryclark@google.com2ddff932012-08-07 21:25:27 +00003491 void matchWindingValue(int tIndex, double t, bool borrowWind) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003492 int nextDoorWind = SK_MaxS32;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003493 int nextOppWind = SK_MaxS32;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003494 if (tIndex > 0) {
3495 const Span& below = fTs[tIndex - 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003496 if (approximately_negative(t - below.fT)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003497 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003498 nextOppWind = below.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003499 }
3500 }
3501 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3502 const Span& above = fTs[tIndex + 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003503 if (approximately_negative(above.fT - t)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003504 nextDoorWind = above.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003505 nextOppWind = above.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003506 }
3507 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003508 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3509 const Span& below = fTs[tIndex - 1];
3510 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003511 nextOppWind = below.fOppValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003512 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003513 if (nextDoorWind != SK_MaxS32) {
3514 Span& newSpan = fTs[tIndex];
3515 newSpan.fWindValue = nextDoorWind;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003516 newSpan.fOppValue = nextOppWind;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003517 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003518 newSpan.fDone = true;
3519 ++fDoneSpans;
3520 }
3521 }
3522 }
3523
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003524 bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3525 // find bounds
3526 Bounds bounds;
3527 bounds.setPoint(xyAtT(index));
3528 bounds.add(xyAtT(endIndex));
3529 SkScalar width = bounds.width();
3530 SkScalar height = bounds.height();
3531 if (width > height) {
3532 if (approximately_negative(width)) {
3533 unsortable = true; // edge is too small to resolve meaningfully
3534 }
3535 return false;
3536 } else {
3537 if (approximately_negative(height)) {
3538 unsortable = true; // edge is too small to resolve meaningfully
3539 }
3540 return true;
3541 }
3542 }
3543
caryclark@google.com9764cc62012-07-12 19:29:45 +00003544 // return span if when chasing, two or more radiating spans are not done
3545 // OPTIMIZATION: ? multiple spans is detected when there is only one valid
3546 // candidate and the remaining spans have windValue == 0 (canceled by
3547 // coincidence). The coincident edges could either be removed altogether,
3548 // or this code could be more complicated in detecting this case. Worth it?
3549 bool multipleSpans(int end) const {
3550 return end > 0 && end < fTs.count() - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00003551 }
3552
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003553 bool nextCandidate(int& start, int& end) const {
caryclark@google.com10227bf2012-12-28 22:10:41 +00003554 while (fTs[end].fDone) {
3555 if (fTs[end].fT == 1) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003556 return false;
3557 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00003558 ++end;
3559 }
3560 start = end;
3561 end = nextExactSpan(start, 1);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003562 return true;
3563 }
3564
caryclark@google.com4eeda372012-12-06 21:47:48 +00003565 Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
3566 int end = nextExactSpan(index, step);
3567 SkASSERT(end >= 0);
3568 if (multipleSpans(end)) {
3569 last = &fTs[end];
3570 return NULL;
3571 }
3572 const Span& endSpan = fTs[end];
3573 Segment* other = endSpan.fOther;
3574 index = endSpan.fOtherIndex;
caryclark@google.comaa358312013-01-29 20:28:49 +00003575 SkASSERT(index >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003576 int otherEnd = other->nextExactSpan(index, step);
caryclark@google.comaa358312013-01-29 20:28:49 +00003577 SkASSERT(otherEnd >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003578 min = SkMin32(index, otherEnd);
3579 return other;
3580 }
3581
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003582 // This has callers for two different situations: one establishes the end
3583 // of the current span, and one establishes the beginning of the next span
3584 // (thus the name). When this is looking for the end of the current span,
3585 // coincidence is found when the beginning Ts contain -step and the end
3586 // contains step. When it is looking for the beginning of the next, the
3587 // first Ts found can be ignored and the last Ts should contain -step.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003588 // OPTIMIZATION: probably should split into two functions
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003589 int nextSpan(int from, int step) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003590 const Span& fromSpan = fTs[from];
caryclark@google.com495f8e42012-05-31 13:13:11 +00003591 int count = fTs.count();
3592 int to = from;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003593 while (step > 0 ? ++to < count : --to >= 0) {
3594 const Span& span = fTs[to];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003595 if (approximately_zero(span.fT - fromSpan.fT)) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003596 continue;
3597 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003598 return to;
3599 }
3600 return -1;
3601 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +00003602
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003603 // FIXME
3604 // this returns at any difference in T, vs. a preset minimum. It may be
3605 // that all callers to nextSpan should use this instead.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003606 // OPTIMIZATION splitting this into separate loops for up/down steps
3607 // would allow using precisely_negative instead of precisely_zero
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003608 int nextExactSpan(int from, int step) const {
3609 const Span& fromSpan = fTs[from];
3610 int count = fTs.count();
3611 int to = from;
3612 while (step > 0 ? ++to < count : --to >= 0) {
3613 const Span& span = fTs[to];
caryclark@google.coma461ff02012-10-11 12:54:23 +00003614 if (precisely_zero(span.fT - fromSpan.fT)) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003615 continue;
3616 }
3617 return to;
3618 }
3619 return -1;
3620 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003621
caryclark@google.com235f56a2012-09-14 14:19:30 +00003622 bool operand() const {
3623 return fOperand;
3624 }
3625
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003626 int oppSign(const Angle* angle) const {
3627 SkASSERT(angle->segment() == this);
3628 return oppSign(angle->start(), angle->end());
3629 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003630
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003631 int oppSign(int startIndex, int endIndex) const {
3632 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3633 : fTs[endIndex].fOppValue;
3634#if DEBUG_WIND_BUMP
3635 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3636#endif
3637 return result;
3638 }
3639
caryclark@google.com31143cf2012-11-09 22:14:19 +00003640 int oppSum(int tIndex) const {
3641 return fTs[tIndex].fOppSum;
3642 }
3643
3644 int oppSum(const Angle* angle) const {
3645 int lesser = SkMin32(angle->start(), angle->end());
3646 return fTs[lesser].fOppSum;
caryclark@google.com235f56a2012-09-14 14:19:30 +00003647 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003648
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003649 int oppValue(int tIndex) const {
3650 return fTs[tIndex].fOppValue;
3651 }
3652
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003653 int oppValue(const Angle* angle) const {
3654 int lesser = SkMin32(angle->start(), angle->end());
3655 return fTs[lesser].fOppValue;
3656 }
3657
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003658 const SkPoint* pts() const {
3659 return fPts;
3660 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003661
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003662 void reset() {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003663 init(NULL, (SkPath::Verb) -1, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003664 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3665 fTs.reset();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003666 }
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +00003667
caryclark@google.com4eeda372012-12-06 21:47:48 +00003668 void setOppXor(bool isOppXor) {
3669 fOppXor = isOppXor;
3670 }
caryclark@google.com7ff5c842013-02-26 15:56:05 +00003671
3672 void setSpanT(int index, double t) {
3673 Span& span = fTs[index];
3674 span.fT = t;
3675 span.fOther->fTs[span.fOtherIndex].fOtherT = t;
3676 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003677
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003678 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3679 int deltaSum = spanSign(index, endIndex);
3680 maxWinding = sumWinding;
3681 sumWinding = sumWinding -= deltaSum;
3682 }
3683
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003684 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3685 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3686 int deltaSum = spanSign(index, endIndex);
3687 int oppDeltaSum = oppSign(index, endIndex);
3688 if (operand()) {
3689 maxWinding = sumSuWinding;
3690 sumWinding = sumSuWinding -= deltaSum;
3691 oppMaxWinding = sumMiWinding;
3692 oppSumWinding = sumMiWinding -= oppDeltaSum;
3693 } else {
3694 maxWinding = sumMiWinding;
3695 sumWinding = sumMiWinding -= deltaSum;
3696 oppMaxWinding = sumSuWinding;
3697 oppSumWinding = sumSuWinding -= oppDeltaSum;
3698 }
3699 }
3700
caryclark@google.comf839c032012-10-26 21:03:50 +00003701 // This marks all spans unsortable so that this info is available for early
3702 // exclusion in find top and others. This could be optimized to only mark
3703 // adjacent spans that unsortable. However, this makes it difficult to later
3704 // determine starting points for edge detection in find top and the like.
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003705 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
caryclark@google.comf839c032012-10-26 21:03:50 +00003706 bool sortable = true;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003707 int angleCount = angles.count();
3708 int angleIndex;
3709 angleList.setReserve(angleCount);
3710 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003711 Angle& angle = angles[angleIndex];
caryclark@google.comf839c032012-10-26 21:03:50 +00003712 *angleList.append() = &angle;
3713 sortable &= !angle.unsortable();
3714 }
3715 if (sortable) {
3716 QSort<Angle>(angleList.begin(), angleList.end() - 1);
3717 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3718 if (angles[angleIndex].unsortable()) {
3719 sortable = false;
3720 break;
3721 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003722 }
3723 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003724 if (!sortable) {
3725 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3726 Angle& angle = angles[angleIndex];
3727 angle.segment()->markUnsortable(angle.start(), angle.end());
3728 }
3729 }
3730 return sortable;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003731 }
3732
caryclark@google.com1577e8f2012-05-22 17:01:14 +00003733 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003734 const Span& span(int tIndex) const {
3735 return fTs[tIndex];
3736 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003737
caryclark@google.com235f56a2012-09-14 14:19:30 +00003738 int spanSign(const Angle* angle) const {
3739 SkASSERT(angle->segment() == this);
3740 return spanSign(angle->start(), angle->end());
3741 }
3742
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003743 int spanSign(int startIndex, int endIndex) const {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003744 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3745 : fTs[endIndex].fWindValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003746#if DEBUG_WIND_BUMP
3747 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3748#endif
3749 return result;
3750 }
skia.committer@gmail.com58433de2013-02-23 07:02:45 +00003751
caryclark@google.comc83c70e2013-02-22 21:50:07 +00003752 void subDivide(int start, int end, SkPoint edge[4]) const {
3753 edge[0] = fTs[start].fPt;
3754 edge[fVerb] = fTs[end].fPt;
3755 if (fVerb == SkPath::kQuad_Verb || fVerb == SkPath::kCubic_Verb) {
3756 _Point sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[fVerb].fX, edge[fVerb].fY }};
3757 if (fVerb == SkPath::kQuad_Verb) {
3758 MAKE_CONST_QUAD(aQuad, fPts);
3759 edge[1] = sub_divide(aQuad, sub[0], sub[1], fTs[start].fT, fTs[end].fT).asSkPoint();
3760 } else {
3761 MAKE_CONST_CUBIC(aCubic, fPts);
3762 sub_divide(aCubic, sub[0], sub[1], fTs[start].fT, fTs[end].fT, sub);
3763 edge[1] = sub[0].asSkPoint();
3764 edge[2] = sub[1].asSkPoint();
3765 }
3766 }
3767 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003768
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003769 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003770 double t(int tIndex) const {
3771 return fTs[tIndex].fT;
3772 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003773
caryclark@google.com10227bf2012-12-28 22:10:41 +00003774 double tAtMid(int start, int end, double mid) const {
3775 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
3776 }
3777
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003778 bool tiny(const Angle* angle) const {
3779 int start = angle->start();
3780 int end = angle->end();
caryclark@google.comf839c032012-10-26 21:03:50 +00003781 const Span& mSpan = fTs[SkMin32(start, end)];
3782 return mSpan.fTiny;
3783 }
3784
caryclark@google.com18063442012-07-25 12:05:18 +00003785 static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3786 double start) {
3787 int outCount = outsideTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003788 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
caryclark@google.com18063442012-07-25 12:05:18 +00003789 *outsideTs.append() = end;
3790 *outsideTs.append() = start;
3791 }
3792 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003793
caryclark@google.com24bec792012-08-20 12:43:57 +00003794 void undoneSpan(int& start, int& end) {
3795 size_t tCount = fTs.count();
3796 size_t index;
3797 for (index = 0; index < tCount; ++index) {
3798 if (!fTs[index].fDone) {
3799 break;
3800 }
3801 }
3802 SkASSERT(index < tCount - 1);
3803 start = index;
3804 double startT = fTs[index].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003805 while (approximately_negative(fTs[++index].fT - startT))
caryclark@google.com24bec792012-08-20 12:43:57 +00003806 SkASSERT(index < tCount);
3807 SkASSERT(index < tCount);
3808 end = index;
3809 }
caryclark@google.com18063442012-07-25 12:05:18 +00003810
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003811 bool unsortable(int index) const {
3812 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3813 }
3814
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003815 void updatePts(const SkPoint pts[]) {
3816 fPts = pts;
3817 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003818
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003819 int updateOppWinding(int index, int endIndex) const {
3820 int lesser = SkMin32(index, endIndex);
3821 int oppWinding = oppSum(lesser);
3822 int oppSpanWinding = oppSign(index, endIndex);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003823 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)
3824 && oppWinding != SK_MaxS32) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003825 oppWinding -= oppSpanWinding;
3826 }
3827 return oppWinding;
3828 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003829
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003830 int updateOppWinding(const Angle* angle) const {
3831 int startIndex = angle->start();
3832 int endIndex = angle->end();
3833 return updateOppWinding(endIndex, startIndex);
3834 }
3835
3836 int updateOppWindingReverse(const Angle* angle) const {
3837 int startIndex = angle->start();
3838 int endIndex = angle->end();
3839 return updateOppWinding(startIndex, endIndex);
3840 }
3841
3842 int updateWinding(int index, int endIndex) const {
3843 int lesser = SkMin32(index, endIndex);
3844 int winding = windSum(lesser);
3845 int spanWinding = spanSign(index, endIndex);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003846 if (winding && useInnerWinding(winding - spanWinding, winding) && winding != SK_MaxS32) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003847 winding -= spanWinding;
3848 }
3849 return winding;
3850 }
3851
3852 int updateWinding(const Angle* angle) const {
3853 int startIndex = angle->start();
3854 int endIndex = angle->end();
3855 return updateWinding(endIndex, startIndex);
3856 }
3857
3858 int updateWindingReverse(const Angle* angle) const {
3859 int startIndex = angle->start();
3860 int endIndex = angle->end();
3861 return updateWinding(startIndex, endIndex);
3862 }
3863
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003864 SkPath::Verb verb() const {
3865 return fVerb;
3866 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003867
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003868 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003869 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3870 return SK_MinS32;
3871 }
3872 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3873 SkASSERT(winding != SK_MinS32);
3874 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003875 #if DEBUG_WINDING_AT_T
3876 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003877 #endif
3878 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark@google.com3586ece2012-12-27 18:46:58 +00003879 dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003880 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3881 dx = fPts[2].fX - fPts[1].fX - dx;
3882 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003883 if (dx == 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003884 #if DEBUG_WINDING_AT_T
3885 SkDebugf(" dx=0 winding=SK_MinS32\n");
3886 #endif
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003887 return SK_MinS32;
3888 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003889 if (winding * dx > 0) { // if same signs, result is negative
3890 winding += dx > 0 ? -windVal : windVal;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003891 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003892 #if DEBUG_WINDING_AT_T
3893 SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding);
3894 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003895 return winding;
3896 }
3897
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003898 int windSum(int tIndex) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003899 return fTs[tIndex].fWindSum;
3900 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003901
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003902 int windSum(const Angle* angle) const {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003903 int start = angle->start();
3904 int end = angle->end();
3905 int index = SkMin32(start, end);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003906 return windSum(index);
caryclark@google.com495f8e42012-05-31 13:13:11 +00003907 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003908
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003909 int windValue(int tIndex) const {
3910 return fTs[tIndex].fWindValue;
3911 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003912
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003913 int windValue(const Angle* angle) const {
3914 int start = angle->start();
3915 int end = angle->end();
3916 int index = SkMin32(start, end);
3917 return windValue(index);
3918 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00003919
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003920 int windValueAt(double t) const {
3921 int count = fTs.count();
3922 for (int index = 0; index < count; ++index) {
3923 if (fTs[index].fT == t) {
3924 return fTs[index].fWindValue;
3925 }
3926 }
3927 SkASSERT(0);
3928 return 0;
3929 }
3930
caryclark@google.com3586ece2012-12-27 18:46:58 +00003931 SkScalar xAtT(int index) const {
3932 return xAtT(&fTs[index]);
3933 }
3934
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003935 SkScalar xAtT(const Span* span) const {
3936 return xyAtT(span).fX;
3937 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003938
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003939 const SkPoint& xyAtT(int index) const {
3940 return xyAtT(&fTs[index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003941 }
3942
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003943 const SkPoint& xyAtT(const Span* span) const {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003944 if (SkScalarIsNaN(span->fPt.fX)) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00003945 SkASSERT(0); // make sure this path is never used
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003946 if (span->fT == 0) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003947 span->fPt = fPts[0];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003948 } else if (span->fT == 1) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003949 span->fPt = fPts[fVerb];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003950 } else {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003951 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003952 }
3953 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00003954 return span->fPt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003955 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003956
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003957 // used only by right angle winding finding
caryclark@google.com10227bf2012-12-28 22:10:41 +00003958 void xyAtT(double mid, SkPoint& pt) const {
3959 (*SegmentXYAtT[fVerb])(fPts, mid, &pt);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003960 }
3961
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003962 SkScalar yAtT(int index) const {
3963 return yAtT(&fTs[index]);
3964 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003965
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003966 SkScalar yAtT(const Span* span) const {
3967 return xyAtT(span).fY;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003968 }
3969
caryclark@google.com4eeda372012-12-06 21:47:48 +00003970 void zeroCoincidentOpp(Span* oTest, int index) {
3971 Span* const test = &fTs[index];
3972 Span* end = test;
3973 do {
3974 end->fOppValue = 0;
3975 end = &fTs[++index];
3976 } while (approximately_negative(end->fT - test->fT));
3977 }
3978
3979 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
3980 Span* const oTest = &fTs[oIndex];
3981 Span* oEnd = oTest;
3982 const double startT = test->fT;
3983 const double oStartT = oTest->fT;
3984 double otherTMatch = (test->fT - startT) * tRatio + oStartT;
3985 while (!approximately_negative(oEndT - oEnd->fT)
3986 && approximately_negative(oEnd->fT - otherTMatch)) {
3987 oEnd->fOppValue = 0;
3988 oEnd = &fTs[++oIndex];
3989 }
3990 }
3991
3992 void zeroSpan(Span* span) {
3993 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
caryclark@google.com6ec15262012-11-16 20:16:50 +00003994 span->fWindValue = 0;
caryclark@google.com729e1c42012-11-21 21:36:34 +00003995 span->fOppValue = 0;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003996 SkASSERT(!span->fDone);
3997 span->fDone = true;
3998 ++fDoneSpans;
caryclark@google.com6ec15262012-11-16 20:16:50 +00003999 }
4000
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004001#if DEBUG_DUMP
4002 void dump() const {
4003 const char className[] = "Segment";
4004 const int tab = 4;
4005 for (int i = 0; i < fTs.count(); ++i) {
4006 SkPoint out;
4007 (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
4008 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004009 " otherT=%1.9g windSum=%d\n",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004010 tab + sizeof(className), className, fID,
4011 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004012 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004013 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00004014 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004015 tab + sizeof(className), className, fID,
caryclark@google.com15fa1382012-05-07 20:49:36 +00004016 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004017 }
4018#endif
4019
caryclark@google.com47580692012-07-23 12:14:49 +00004020#if DEBUG_CONCIDENT
caryclark@google.comaa358312013-01-29 20:28:49 +00004021 // SkASSERT if pair has not already been added
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004022 void debugAddTPair(double t, const Segment& other, double otherT) const {
caryclark@google.comcc905052012-07-25 20:59:42 +00004023 for (int i = 0; i < fTs.count(); ++i) {
4024 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
4025 return;
4026 }
4027 }
4028 SkASSERT(0);
4029 }
4030#endif
4031
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004032#if DEBUG_DUMP
4033 int debugID() const {
4034 return fID;
4035 }
4036#endif
4037
caryclark@google.com24bec792012-08-20 12:43:57 +00004038#if DEBUG_WINDING
4039 void debugShowSums() const {
4040 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
4041 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
4042 for (int i = 0; i < fTs.count(); ++i) {
4043 const Span& span = fTs[i];
4044 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
4045 if (span.fWindSum == SK_MinS32) {
4046 SkDebugf("?");
4047 } else {
4048 SkDebugf("%d", span.fWindSum);
4049 }
4050 SkDebugf("]");
4051 }
4052 SkDebugf("\n");
4053 }
4054#endif
4055
caryclark@google.comcc905052012-07-25 20:59:42 +00004056#if DEBUG_CONCIDENT
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004057 void debugShowTs() const {
caryclark@google.com24bec792012-08-20 12:43:57 +00004058 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com4eeda372012-12-06 21:47:48 +00004059 int lastWind = -1;
4060 int lastOpp = -1;
4061 double lastT = -1;
4062 int i;
4063 for (i = 0; i < fTs.count(); ++i) {
4064 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
4065 || lastOpp != fTs[i].fOppValue;
4066 if (change && lastWind >= 0) {
4067 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
4068 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
4069 }
4070 if (change) {
4071 SkDebugf(" [o=%d", fTs[i].fOther->fID);
4072 lastWind = fTs[i].fWindValue;
4073 lastOpp = fTs[i].fOppValue;
4074 lastT = fTs[i].fT;
4075 } else {
4076 SkDebugf(",%d", fTs[i].fOther->fID);
4077 }
4078 }
4079 if (i <= 0) {
4080 return;
4081 }
4082 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
4083 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
4084 if (fOperand) {
4085 SkDebugf(" operand");
4086 }
4087 if (done()) {
4088 SkDebugf(" done");
caryclark@google.com47580692012-07-23 12:14:49 +00004089 }
4090 SkDebugf("\n");
4091 }
4092#endif
4093
caryclark@google.com027de222012-07-12 12:52:50 +00004094#if DEBUG_ACTIVE_SPANS
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004095 void debugShowActiveSpans() const {
caryclark@google.com027de222012-07-12 12:52:50 +00004096 if (done()) {
4097 return;
4098 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004099#if DEBUG_ACTIVE_SPANS_SHORT_FORM
4100 int lastId = -1;
4101 double lastT = -1;
4102#endif
caryclark@google.com027de222012-07-12 12:52:50 +00004103 for (int i = 0; i < fTs.count(); ++i) {
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004104 SkASSERT(&fTs[i] == &fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOther->
4105 fTs[fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOtherIndex]);
caryclark@google.com027de222012-07-12 12:52:50 +00004106 if (fTs[i].fDone) {
4107 continue;
4108 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004109#if DEBUG_ACTIVE_SPANS_SHORT_FORM
4110 if (lastId == fID && lastT == fTs[i].fT) {
4111 continue;
4112 }
4113 lastId = fID;
4114 lastT = fTs[i].fT;
4115#endif
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004116 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com027de222012-07-12 12:52:50 +00004117 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4118 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4119 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4120 }
4121 const Span* span = &fTs[i];
rmistry@google.comd6176b02012-08-23 18:14:13 +00004122 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
caryclark@google.com0c803d02012-08-06 11:15:47 +00004123 xAtT(span), yAtT(span));
caryclark@google.com47d73da2013-02-17 01:41:25 +00004124 int iEnd = i + 1;
4125 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) {
4126 ++iEnd;
4127 }
4128 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT);
caryclark@google.com027de222012-07-12 12:52:50 +00004129 const Segment* other = fTs[i].fOther;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004130 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
4131 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
4132 if (fTs[i].fWindSum == SK_MinS32) {
4133 SkDebugf("?");
4134 } else {
4135 SkDebugf("%d", fTs[i].fWindSum);
4136 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004137 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
caryclark@google.com027de222012-07-12 12:52:50 +00004138 }
4139 }
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +00004140
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004141 // This isn't useful yet -- but leaving it in for now in case i think of something
4142 // to use it for
4143 void validateActiveSpans() const {
4144 if (done()) {
4145 return;
4146 }
4147 int tCount = fTs.count();
4148 for (int index = 0; index < tCount; ++index) {
4149 if (fTs[index].fDone) {
4150 continue;
4151 }
4152 // count number of connections which are not done
4153 int first = index;
4154 double baseT = fTs[index].fT;
4155 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
4156 --first;
4157 }
4158 int last = index;
4159 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
4160 ++last;
4161 }
4162 int connections = 0;
4163 connections += first > 0 && !fTs[first - 1].fDone;
4164 for (int test = first; test <= last; ++test) {
4165 connections += !fTs[test].fDone;
4166 const Segment* other = fTs[test].fOther;
4167 int oIndex = fTs[test].fOtherIndex;
4168 connections += !other->fTs[oIndex].fDone;
4169 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
4170 }
4171 // SkASSERT(!(connections & 1));
4172 }
4173 }
caryclark@google.com027de222012-07-12 12:52:50 +00004174#endif
4175
caryclark@google.com0c803d02012-08-06 11:15:47 +00004176#if DEBUG_MARK_DONE
4177 void debugShowNewWinding(const char* fun, const Span& span, int winding) {
4178 const SkPoint& pt = xyAtT(&span);
4179 SkDebugf("%s id=%d", fun, fID);
4180 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4181 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4182 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4183 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004184 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4185 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4186 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d windSum=",
4187 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, winding);
caryclark@google.com0c803d02012-08-06 11:15:47 +00004188 if (span.fWindSum == SK_MinS32) {
4189 SkDebugf("?");
4190 } else {
4191 SkDebugf("%d", span.fWindSum);
4192 }
4193 SkDebugf(" windValue=%d\n", span.fWindValue);
4194 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004195
4196 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
4197 const SkPoint& pt = xyAtT(&span);
4198 SkDebugf("%s id=%d", fun, fID);
4199 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4200 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4201 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4202 }
4203 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4204 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4205 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=",
4206 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
4207 winding, oppWinding);
4208 if (span.fOppSum == SK_MinS32) {
4209 SkDebugf("?");
4210 } else {
4211 SkDebugf("%d", span.fOppSum);
4212 }
4213 SkDebugf(" windSum=");
4214 if (span.fWindSum == SK_MinS32) {
4215 SkDebugf("?");
4216 } else {
4217 SkDebugf("%d", span.fWindSum);
4218 }
4219 SkDebugf(" windValue=%d\n", span.fWindValue);
4220 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00004221#endif
4222
caryclark@google.com47580692012-07-23 12:14:49 +00004223#if DEBUG_SORT
caryclark@google.com03f97062012-08-21 13:13:52 +00004224 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
caryclark@google.com31143cf2012-11-09 22:14:19 +00004225 const int contourWinding, const int oppContourWinding) const {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004226 if (--gDebugSortCount < 0) {
4227 return;
4228 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004229 SkASSERT(angles[first]->segment() == this);
caryclark@google.com200c2112012-08-03 15:05:04 +00004230 SkASSERT(angles.count() > 1);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004231 int lastSum = contourWinding;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004232 int oppLastSum = oppContourWinding;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004233 const Angle* firstAngle = angles[first];
4234 int windSum = lastSum - spanSign(firstAngle);
4235 int oppoSign = oppSign(firstAngle);
4236 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004237 #define WIND_AS_STRING(x) char x##Str[12]; if (!valid_wind(x)) strcpy(x##Str, "?"); \
4238 else snprintf(x##Str, sizeof(x##Str), "%d", x)
4239 WIND_AS_STRING(contourWinding);
4240 WIND_AS_STRING(oppContourWinding);
4241 SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FUNCTION__,
4242 contourWindingStr, oppContourWindingStr, spanSign(angles[first]));
caryclark@google.comafe56de2012-07-24 18:11:03 +00004243 int index = first;
4244 bool firstTime = true;
caryclark@google.com47580692012-07-23 12:14:49 +00004245 do {
4246 const Angle& angle = *angles[index];
4247 const Segment& segment = *angle.segment();
4248 int start = angle.start();
4249 int end = angle.end();
4250 const Span& sSpan = segment.fTs[start];
4251 const Span& eSpan = segment.fTs[end];
4252 const Span& mSpan = segment.fTs[SkMin32(start, end)];
caryclark@google.com31143cf2012-11-09 22:14:19 +00004253 bool opp = segment.fOperand ^ fOperand;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004254 if (!firstTime) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004255 oppoSign = segment.oppSign(&angle);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004256 if (opp) {
4257 oppLastSum = oppWindSum;
4258 oppWindSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004259 if (oppoSign) {
4260 lastSum = windSum;
4261 windSum -= oppoSign;
4262 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004263 } else {
4264 lastSum = windSum;
4265 windSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004266 if (oppoSign) {
4267 oppLastSum = oppWindSum;
4268 oppWindSum -= oppoSign;
4269 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004270 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004271 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004272 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 +00004273 " sign=%d windValue=%d windSum=",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004274 __FUNCTION__, index, angle.unsortable() ? "*** UNSORTABLE *** " : "",
caryclark@google.comc91dfe42012-10-16 12:06:27 +00004275 segment.fID, kLVerbStr[segment.fVerb],
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004276 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
4277 segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(),
4278 mSpan.fWindValue);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004279 winding_printf(mSpan.fWindSum);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004280 int last, wind;
4281 if (opp) {
4282 last = oppLastSum;
4283 wind = oppWindSum;
4284 } else {
4285 last = lastSum;
4286 wind = windSum;
4287 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004288 bool useInner = valid_wind(last) && valid_wind(wind) && useInnerWinding(last, wind);
4289 WIND_AS_STRING(last);
4290 WIND_AS_STRING(wind);
4291 WIND_AS_STRING(lastSum);
4292 WIND_AS_STRING(oppLastSum);
4293 WIND_AS_STRING(windSum);
4294 WIND_AS_STRING(oppWindSum);
4295 #undef WIND_AS_STRING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004296 if (!oppoSign) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004297 SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr : lastStr);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004298 } else {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004299 SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : oppLastSumStr,
4300 opp ? windSumStr : oppWindSumStr);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004301 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004302 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004303#if false && DEBUG_ANGLE
caryclark@google.comc899ad92012-08-23 15:24:42 +00004304 angle.debugShow(segment.xyAtT(&sSpan));
4305#endif
caryclark@google.com47580692012-07-23 12:14:49 +00004306 ++index;
4307 if (index == angles.count()) {
4308 index = 0;
4309 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004310 if (firstTime) {
4311 firstTime = false;
4312 }
caryclark@google.com47580692012-07-23 12:14:49 +00004313 } while (index != first);
4314 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00004315
4316 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
4317 const Angle* firstAngle = angles[first];
4318 const Segment* segment = firstAngle->segment();
4319 int winding = segment->updateWinding(firstAngle);
4320 int oppWinding = segment->updateOppWinding(firstAngle);
4321 debugShowSort(fun, angles, first, winding, oppWinding);
4322 }
4323
caryclark@google.com47580692012-07-23 12:14:49 +00004324#endif
4325
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004326#if DEBUG_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004327 static char as_digit(int value) {
4328 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
4329 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004330#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004331
caryclark@google.com729e1c42012-11-21 21:36:34 +00004332#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004333 int debugShowWindingValues(int slotCount, int ofInterest) const {
4334 if (!(1 << fID & ofInterest)) {
4335 return 0;
4336 }
4337 int sum = 0;
4338 SkTDArray<char> slots;
4339 slots.setCount(slotCount * 2);
4340 memset(slots.begin(), ' ', slotCount * 2);
4341 for (int i = 0; i < fTs.count(); ++i) {
4342 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
4343 // continue;
4344 // }
4345 sum += fTs[i].fWindValue;
4346 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
4347 sum += fTs[i].fOppValue;
4348 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
4349 }
4350 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
4351 slots.begin() + slotCount);
4352 return sum;
4353 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004354#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004355
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004356private:
4357 const SkPoint* fPts;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004358 Bounds fBounds;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004359 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
caryclark@google.com4eeda372012-12-06 21:47:48 +00004360 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
caryclark@google.com24bec792012-08-20 12:43:57 +00004361 int fDoneSpans; // quick check that segment is finished
caryclark@google.com4eeda372012-12-06 21:47:48 +00004362 // OPTIMIZATION: force the following to be byte-sized
4363 SkPath::Verb fVerb;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004364 bool fOperand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004365 bool fXor; // set if original contour had even-odd fill
4366 bool fOppXor; // set if opposite operand had even-odd fill
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004367#if DEBUG_DUMP
4368 int fID;
4369#endif
4370};
4371
caryclark@google.comb9738012012-07-03 19:53:30 +00004372class Contour;
4373
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004374struct Coincidence {
caryclark@google.comb9738012012-07-03 19:53:30 +00004375 Contour* fContours[2];
4376 int fSegments[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004377 double fTs[2][2];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004378 SkPoint fPts[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004379};
4380
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004381class Contour {
4382public:
4383 Contour() {
4384 reset();
4385#if DEBUG_DUMP
4386 fID = ++gContourID;
4387#endif
4388 }
4389
4390 bool operator<(const Contour& rh) const {
4391 return fBounds.fTop == rh.fBounds.fTop
4392 ? fBounds.fLeft < rh.fBounds.fLeft
4393 : fBounds.fTop < rh.fBounds.fTop;
4394 }
4395
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004396 void addCoincident(int index, Contour* other, int otherIndex,
4397 const Intersections& ts, bool swap) {
4398 Coincidence& coincidence = *fCoincidences.append();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004399 coincidence.fContours[0] = this; // FIXME: no need to store
caryclark@google.comb9738012012-07-03 19:53:30 +00004400 coincidence.fContours[1] = other;
4401 coincidence.fSegments[0] = index;
4402 coincidence.fSegments[1] = otherIndex;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004403 coincidence.fTs[swap][0] = ts.fT[0][0];
4404 coincidence.fTs[swap][1] = ts.fT[0][1];
4405 coincidence.fTs[!swap][0] = ts.fT[1][0];
4406 coincidence.fTs[!swap][1] = ts.fT[1][1];
4407 coincidence.fPts[0] = ts.fPt[0].asSkPoint();
4408 coincidence.fPts[1] = ts.fPt[1].asSkPoint();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004409 }
4410
4411 void addCross(const Contour* crosser) {
4412#ifdef DEBUG_CROSS
4413 for (int index = 0; index < fCrosses.count(); ++index) {
4414 SkASSERT(fCrosses[index] != crosser);
4415 }
4416#endif
4417 *fCrosses.append() = crosser;
4418 }
4419
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004420 void addCubic(const SkPoint pts[4]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004421 fSegments.push_back().addCubic(pts, fOperand, fXor);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004422 fContainsCurves = fContainsCubics = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004423 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004424
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004425 int addLine(const SkPoint pts[2]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004426 fSegments.push_back().addLine(pts, fOperand, fXor);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004427 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004428 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004429
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004430 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
4431 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
4432 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004433
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004434 int addQuad(const SkPoint pts[3]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004435 fSegments.push_back().addQuad(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004436 fContainsCurves = true;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004437 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004438 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004439
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004440 int addT(int segIndex, Contour* other, int otherIndex, const SkPoint& pt, double& newT) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004441 setContainsIntercepts();
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004442 return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004443 }
4444
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004445 int addUnsortableT(int segIndex, Contour* other, int otherIndex, bool start,
4446 const SkPoint& pt, double& newT) {
4447 return fSegments[segIndex].addUnsortableT(&other->fSegments[otherIndex], start, pt, newT);
caryclark@google.com73ca6242013-01-17 21:02:47 +00004448 }
4449
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004450 const Bounds& bounds() const {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004451 return fBounds;
4452 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004453
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004454 void complete() {
4455 setBounds();
4456 fContainsIntercepts = false;
4457 }
skia.committer@gmail.com58433de2013-02-23 07:02:45 +00004458
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004459 bool containsCubics() const {
4460 return fContainsCubics;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004461 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004462
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004463 bool crosses(const Contour* crosser) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004464 for (int index = 0; index < fCrosses.count(); ++index) {
4465 if (fCrosses[index] == crosser) {
4466 return true;
4467 }
4468 }
4469 return false;
4470 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004471
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004472 bool done() const {
4473 return fDone;
4474 }
4475
caryclark@google.comf839c032012-10-26 21:03:50 +00004476 const SkPoint& end() const {
4477 const Segment& segment = fSegments.back();
4478 return segment.pts()[segment.verb()];
4479 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004480
caryclark@google.com4eeda372012-12-06 21:47:48 +00004481 void findTooCloseToCall() {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004482 int segmentCount = fSegments.count();
4483 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004484 fSegments[sIndex].findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004485 }
4486 }
4487
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004488 void fixOtherTIndex() {
4489 int segmentCount = fSegments.count();
4490 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4491 fSegments[sIndex].fixOtherTIndex();
4492 }
4493 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004494
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004495 Segment* nonVerticalSegment(int& start, int& end) {
4496 int segmentCount = fSortedSegments.count();
4497 SkASSERT(segmentCount > 0);
4498 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4499 Segment* testSegment = fSortedSegments[sortedIndex];
4500 if (testSegment->done()) {
4501 continue;
4502 }
4503 start = end = 0;
4504 while (testSegment->nextCandidate(start, end)) {
4505 if (!testSegment->isVertical(start, end)) {
4506 return testSegment;
4507 }
4508 }
4509 }
4510 return NULL;
4511 }
4512
caryclark@google.com31143cf2012-11-09 22:14:19 +00004513 bool operand() const {
4514 return fOperand;
4515 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004516
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004517 void reset() {
4518 fSegments.reset();
4519 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004520 fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004521 }
caryclark@google.comb9738012012-07-03 19:53:30 +00004522
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004523 void resolveCoincidence(SkTDArray<Contour*>& contourList) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004524 int count = fCoincidences.count();
4525 for (int index = 0; index < count; ++index) {
4526 Coincidence& coincidence = fCoincidences[index];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004527 SkASSERT(coincidence.fContours[0] == this);
caryclark@google.comb9738012012-07-03 19:53:30 +00004528 int thisIndex = coincidence.fSegments[0];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004529 Segment& thisOne = fSegments[thisIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004530 Contour* otherContour = coincidence.fContours[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004531 int otherIndex = coincidence.fSegments[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004532 Segment& other = otherContour->fSegments[otherIndex];
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004533 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004534 continue;
4535 }
caryclark@google.com47580692012-07-23 12:14:49 +00004536 #if DEBUG_CONCIDENT
4537 thisOne.debugShowTs();
4538 other.debugShowTs();
4539 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004540 double startT = coincidence.fTs[0][0];
4541 double endT = coincidence.fTs[0][1];
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004542 bool cancelers = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004543 if (startT > endT) {
4544 SkTSwap<double>(startT, endT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004545 cancelers ^= true; // FIXME: just assign true
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004546 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004547 SkASSERT(!approximately_negative(endT - startT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004548 double oStartT = coincidence.fTs[1][0];
4549 double oEndT = coincidence.fTs[1][1];
4550 if (oStartT > oEndT) {
4551 SkTSwap<double>(oStartT, oEndT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004552 cancelers ^= true;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004553 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004554 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00004555 bool opp = fOperand ^ otherContour->fOperand;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004556 if (cancelers && !opp) {
4557 // make sure startT and endT have t entries
caryclark@google.com2ddff932012-08-07 21:25:27 +00004558 if (startT > 0 || oEndT < 1
4559 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004560 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004561 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00004562 if (oStartT > 0 || endT < 1
4563 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004564 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004565 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004566 if (!thisOne.done() && !other.done()) {
4567 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4568 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004569 } else {
caryclark@google.com200c2112012-08-03 15:05:04 +00004570 if (startT > 0 || oStartT > 0
4571 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004572 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004573 }
caryclark@google.com200c2112012-08-03 15:05:04 +00004574 if (endT < 1 || oEndT < 1
4575 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004576 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004577 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004578 if (!thisOne.done() && !other.done()) {
4579 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4580 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004581 }
caryclark@google.com47580692012-07-23 12:14:49 +00004582 #if DEBUG_CONCIDENT
4583 thisOne.debugShowTs();
4584 other.debugShowTs();
4585 #endif
caryclark@google.com729e1c42012-11-21 21:36:34 +00004586 #if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004587 debugShowWindingValues(contourList);
4588 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004589 }
4590 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004591
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004592 // first pass, add missing T values
4593 // second pass, determine winding values of overlaps
4594 void addCoincidentPoints() {
4595 int count = fCoincidences.count();
4596 for (int index = 0; index < count; ++index) {
4597 Coincidence& coincidence = fCoincidences[index];
4598 SkASSERT(coincidence.fContours[0] == this);
4599 int thisIndex = coincidence.fSegments[0];
4600 Segment& thisOne = fSegments[thisIndex];
4601 Contour* otherContour = coincidence.fContours[1];
4602 int otherIndex = coincidence.fSegments[1];
4603 Segment& other = otherContour->fSegments[otherIndex];
4604 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
4605 // OPTIMIZATION: remove from array
4606 continue;
4607 }
4608 #if DEBUG_CONCIDENT
4609 thisOne.debugShowTs();
4610 other.debugShowTs();
4611 #endif
4612 double startT = coincidence.fTs[0][0];
4613 double endT = coincidence.fTs[0][1];
4614 bool cancelers;
4615 if ((cancelers = startT > endT)) {
caryclark@google.com7ff5c842013-02-26 15:56:05 +00004616 SkTSwap(startT, endT);
4617 SkTSwap(coincidence.fPts[0], coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004618 }
4619 SkASSERT(!approximately_negative(endT - startT));
4620 double oStartT = coincidence.fTs[1][0];
4621 double oEndT = coincidence.fTs[1][1];
4622 if (oStartT > oEndT) {
4623 SkTSwap<double>(oStartT, oEndT);
4624 cancelers ^= true;
4625 }
4626 SkASSERT(!approximately_negative(oEndT - oStartT));
4627 bool opp = fOperand ^ otherContour->fOperand;
4628 if (cancelers && !opp) {
4629 // make sure startT and endT have t entries
4630 if (startT > 0 || oEndT < 1
4631 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004632 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004633 }
4634 if (oStartT > 0 || endT < 1
4635 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004636 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004637 }
4638 } else {
4639 if (startT > 0 || oStartT > 0
4640 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004641 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004642 }
4643 if (endT < 1 || oEndT < 1
4644 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004645 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004646 }
4647 }
4648 #if DEBUG_CONCIDENT
4649 thisOne.debugShowTs();
4650 other.debugShowTs();
4651 #endif
4652 }
4653 }
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00004654
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004655 void calcCoincidentWinding() {
4656 int count = fCoincidences.count();
4657 for (int index = 0; index < count; ++index) {
4658 Coincidence& coincidence = fCoincidences[index];
4659 SkASSERT(coincidence.fContours[0] == this);
4660 int thisIndex = coincidence.fSegments[0];
4661 Segment& thisOne = fSegments[thisIndex];
4662 if (thisOne.done()) {
4663 continue;
4664 }
4665 Contour* otherContour = coincidence.fContours[1];
4666 int otherIndex = coincidence.fSegments[1];
4667 Segment& other = otherContour->fSegments[otherIndex];
4668 if (other.done()) {
4669 continue;
4670 }
4671 double startT = coincidence.fTs[0][0];
4672 double endT = coincidence.fTs[0][1];
4673 bool cancelers;
4674 if ((cancelers = startT > endT)) {
4675 SkTSwap<double>(startT, endT);
4676 }
4677 SkASSERT(!approximately_negative(endT - startT));
4678 double oStartT = coincidence.fTs[1][0];
4679 double oEndT = coincidence.fTs[1][1];
4680 if (oStartT > oEndT) {
4681 SkTSwap<double>(oStartT, oEndT);
4682 cancelers ^= true;
4683 }
4684 SkASSERT(!approximately_negative(oEndT - oStartT));
4685 bool opp = fOperand ^ otherContour->fOperand;
4686 if (cancelers && !opp) {
4687 // make sure startT and endT have t entries
4688 if (!thisOne.done() && !other.done()) {
4689 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4690 }
4691 } else {
4692 if (!thisOne.done() && !other.done()) {
4693 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4694 }
4695 }
4696 #if DEBUG_CONCIDENT
4697 thisOne.debugShowTs();
4698 other.debugShowTs();
4699 #endif
4700 }
4701 }
4702
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004703 SkTArray<Segment>& segments() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004704 return fSegments;
4705 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004706
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004707 void setContainsIntercepts() {
4708 fContainsIntercepts = true;
4709 }
4710
caryclark@google.com235f56a2012-09-14 14:19:30 +00004711 void setOperand(bool isOp) {
4712 fOperand = isOp;
4713 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00004714
caryclark@google.com4eeda372012-12-06 21:47:48 +00004715 void setOppXor(bool isOppXor) {
4716 fOppXor = isOppXor;
4717 int segmentCount = fSegments.count();
4718 for (int test = 0; test < segmentCount; ++test) {
4719 fSegments[test].setOppXor(isOppXor);
4720 }
4721 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004722
caryclark@google.com235f56a2012-09-14 14:19:30 +00004723 void setXor(bool isXor) {
4724 fXor = isXor;
4725 }
4726
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004727 void sortSegments() {
4728 int segmentCount = fSegments.count();
4729 fSortedSegments.setReserve(segmentCount);
4730 for (int test = 0; test < segmentCount; ++test) {
4731 *fSortedSegments.append() = &fSegments[test];
4732 }
4733 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4734 fFirstSorted = 0;
4735 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004736
caryclark@google.comf839c032012-10-26 21:03:50 +00004737 const SkPoint& start() const {
4738 return fSegments.front().pts()[0];
4739 }
4740
4741 void toPath(PathWrapper& path) const {
4742 int segmentCount = fSegments.count();
4743 const SkPoint& pt = fSegments.front().pts()[0];
4744 path.deferredMove(pt);
4745 for (int test = 0; test < segmentCount; ++test) {
4746 fSegments[test].addCurveTo(0, 1, path, true);
4747 }
4748 path.close();
4749 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004750
caryclark@google.comf839c032012-10-26 21:03:50 +00004751 void toPartialBackward(PathWrapper& path) const {
4752 int segmentCount = fSegments.count();
4753 for (int test = segmentCount - 1; test >= 0; --test) {
4754 fSegments[test].addCurveTo(1, 0, path, true);
4755 }
4756 }
4757
4758 void toPartialForward(PathWrapper& path) const {
4759 int segmentCount = fSegments.count();
4760 for (int test = 0; test < segmentCount; ++test) {
4761 fSegments[test].addCurveTo(0, 1, path, true);
4762 }
4763 }
4764
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004765 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004766 int segmentCount = fSortedSegments.count();
4767 SkASSERT(segmentCount > 0);
caryclark@google.comf839c032012-10-26 21:03:50 +00004768 int sortedIndex = fFirstSorted;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004769 fDone = true; // may be cleared below
caryclark@google.comf839c032012-10-26 21:03:50 +00004770 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4771 Segment* testSegment = fSortedSegments[sortedIndex];
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004772 if (testSegment->done()) {
caryclark@google.comf839c032012-10-26 21:03:50 +00004773 if (sortedIndex == fFirstSorted) {
4774 ++fFirstSorted;
4775 }
4776 continue;
4777 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004778 fDone = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004779 SkPoint testXY = testSegment->activeLeftTop(true, NULL);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004780 if (topStart) {
4781 if (testXY.fY < topLeft.fY) {
4782 continue;
4783 }
4784 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4785 continue;
4786 }
4787 if (bestXY.fY < testXY.fY) {
4788 continue;
4789 }
4790 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4791 continue;
4792 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004793 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004794 topStart = testSegment;
caryclark@google.comf839c032012-10-26 21:03:50 +00004795 bestXY = testXY;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004796 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004797 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004798
caryclark@google.com24bec792012-08-20 12:43:57 +00004799 Segment* undoneSegment(int& start, int& end) {
4800 int segmentCount = fSegments.count();
4801 for (int test = 0; test < segmentCount; ++test) {
4802 Segment* testSegment = &fSegments[test];
4803 if (testSegment->done()) {
4804 continue;
4805 }
4806 testSegment->undoneSpan(start, end);
4807 return testSegment;
4808 }
4809 return NULL;
4810 }
4811
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004812 int updateSegment(int index, const SkPoint* pts) {
4813 Segment& segment = fSegments[index];
4814 segment.updatePts(pts);
4815 return segment.verb() + 1;
4816 }
4817
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004818#if DEBUG_TEST
4819 SkTArray<Segment>& debugSegments() {
4820 return fSegments;
4821 }
4822#endif
4823
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004824#if DEBUG_DUMP
4825 void dump() {
4826 int i;
4827 const char className[] = "Contour";
4828 const int tab = 4;
4829 SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4830 for (i = 0; i < fSegments.count(); ++i) {
4831 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4832 className, i);
4833 fSegments[i].dump();
4834 }
4835 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4836 tab + sizeof(className), className,
4837 fBounds.fLeft, fBounds.fTop,
4838 fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004839 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4840 className, fContainsIntercepts);
4841 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4842 className, fContainsCurves);
4843 }
4844#endif
4845
caryclark@google.com027de222012-07-12 12:52:50 +00004846#if DEBUG_ACTIVE_SPANS
4847 void debugShowActiveSpans() {
4848 for (int index = 0; index < fSegments.count(); ++index) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004849 fSegments[index].debugShowActiveSpans();
caryclark@google.com027de222012-07-12 12:52:50 +00004850 }
4851 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004852
4853 void validateActiveSpans() {
4854 for (int index = 0; index < fSegments.count(); ++index) {
4855 fSegments[index].validateActiveSpans();
4856 }
4857 }
caryclark@google.com027de222012-07-12 12:52:50 +00004858#endif
4859
caryclark@google.com729e1c42012-11-21 21:36:34 +00004860#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004861 int debugShowWindingValues(int totalSegments, int ofInterest) {
4862 int count = fSegments.count();
4863 int sum = 0;
4864 for (int index = 0; index < count; ++index) {
4865 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4866 }
4867 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4868 return sum;
4869 }
4870
4871 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4872 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4873 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4874 int ofInterest = 1 << 5 | 1 << 8;
4875 int total = 0;
4876 int index;
4877 for (index = 0; index < contourList.count(); ++index) {
4878 total += contourList[index]->segments().count();
4879 }
4880 int sum = 0;
4881 for (index = 0; index < contourList.count(); ++index) {
4882 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4883 }
4884 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4885 }
4886#endif
4887
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004888protected:
4889 void setBounds() {
4890 int count = fSegments.count();
4891 if (count == 0) {
4892 SkDebugf("%s empty contour\n", __FUNCTION__);
4893 SkASSERT(0);
4894 // FIXME: delete empty contour?
4895 return;
4896 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004897 fBounds = fSegments.front().bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004898 for (int index = 1; index < count; ++index) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004899 fBounds.add(fSegments[index].bounds());
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004900 }
4901 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004902
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004903private:
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004904 SkTArray<Segment> fSegments;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004905 SkTDArray<Segment*> fSortedSegments;
4906 int fFirstSorted;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004907 SkTDArray<Coincidence> fCoincidences;
4908 SkTDArray<const Contour*> fCrosses;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004909 Bounds fBounds;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00004910 bool fContainsIntercepts; // FIXME: is this used by anybody?
4911 bool fContainsCubics;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004912 bool fContainsCurves;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004913 bool fDone;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004914 bool fOperand; // true for the second argument to a binary operator
4915 bool fXor;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004916 bool fOppXor;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004917#if DEBUG_DUMP
4918 int fID;
4919#endif
4920};
4921
4922class EdgeBuilder {
4923public:
4924
caryclark@google.comf839c032012-10-26 21:03:50 +00004925EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
4926 : fPath(path.nativePath())
4927 , fContours(contours)
4928{
4929 init();
4930}
4931
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004932EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
caryclark@google.com235f56a2012-09-14 14:19:30 +00004933 : fPath(&path)
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004934 , fContours(contours)
4935{
caryclark@google.comf839c032012-10-26 21:03:50 +00004936 init();
4937}
4938
4939void init() {
4940 fCurrentContour = NULL;
4941 fOperand = false;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004942 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004943#if DEBUG_DUMP
4944 gContourID = 0;
4945 gSegmentID = 0;
4946#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00004947 fSecondHalf = preFetch();
4948}
4949
4950void addOperand(const SkPath& path) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00004951 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
4952 fPathVerbs.pop();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004953 fPath = &path;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004954 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004955 preFetch();
4956}
4957
4958void finish() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004959 walk();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004960 complete();
4961 if (fCurrentContour && !fCurrentContour->segments().count()) {
4962 fContours.pop_back();
4963 }
4964 // correct pointers in contours since fReducePts may have moved as it grew
4965 int cIndex = 0;
4966 int extraCount = fExtra.count();
4967 SkASSERT(extraCount == 0 || fExtra[0] == -1);
4968 int eIndex = 0;
4969 int rIndex = 0;
4970 while (++eIndex < extraCount) {
4971 int offset = fExtra[eIndex];
4972 if (offset < 0) {
4973 ++cIndex;
4974 continue;
4975 }
4976 fCurrentContour = &fContours[cIndex];
4977 rIndex += fCurrentContour->updateSegment(offset - 1,
4978 &fReducePts[rIndex]);
4979 }
4980 fExtra.reset(); // we're done with this
4981}
4982
4983ShapeOpMask xorMask() const {
caryclark@google.com729e1c42012-11-21 21:36:34 +00004984 return fXorMask[fOperand];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004985}
4986
4987protected:
4988
4989void complete() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004990 if (fCurrentContour && fCurrentContour->segments().count()) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004991 fCurrentContour->complete();
4992 fCurrentContour = NULL;
4993 }
4994}
4995
caryclark@google.com235f56a2012-09-14 14:19:30 +00004996// FIXME:remove once we can access path pts directly
4997int preFetch() {
4998 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004999 SkPoint pts[4];
5000 SkPath::Verb verb;
5001 do {
5002 verb = iter.next(pts);
5003 *fPathVerbs.append() = verb;
5004 if (verb == SkPath::kMove_Verb) {
5005 *fPathPts.append() = pts[0];
5006 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
5007 fPathPts.append(verb, &pts[1]);
5008 }
5009 } while (verb != SkPath::kDone_Verb);
caryclark@google.com31143cf2012-11-09 22:14:19 +00005010 return fPathVerbs.count() - 1;
caryclark@google.com235f56a2012-09-14 14:19:30 +00005011}
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005012
caryclark@google.com235f56a2012-09-14 14:19:30 +00005013void walk() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005014 SkPath::Verb reducedVerb;
5015 uint8_t* verbPtr = fPathVerbs.begin();
caryclark@google.com235f56a2012-09-14 14:19:30 +00005016 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005017 const SkPoint* pointsPtr = fPathPts.begin();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005018 const SkPoint* finalCurveStart = NULL;
5019 const SkPoint* finalCurveEnd = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00005020 SkPath::Verb verb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005021 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
5022 switch (verb) {
5023 case SkPath::kMove_Verb:
5024 complete();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005025 if (!fCurrentContour) {
5026 fCurrentContour = fContours.push_back_n(1);
caryclark@google.com235f56a2012-09-14 14:19:30 +00005027 fCurrentContour->setOperand(fOperand);
caryclark@google.com729e1c42012-11-21 21:36:34 +00005028 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005029 *fExtra.append() = -1; // start new contour
5030 }
caryclark@google.com59823f72012-08-09 18:17:47 +00005031 finalCurveEnd = pointsPtr++;
caryclark@google.com31143cf2012-11-09 22:14:19 +00005032 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005033 case SkPath::kLine_Verb:
5034 // skip degenerate points
5035 if (pointsPtr[-1].fX != pointsPtr[0].fX
5036 || pointsPtr[-1].fY != pointsPtr[0].fY) {
5037 fCurrentContour->addLine(&pointsPtr[-1]);
5038 }
5039 break;
5040 case SkPath::kQuad_Verb:
rmistry@google.comd6176b02012-08-23 18:14:13 +00005041
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005042 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
5043 if (reducedVerb == 0) {
5044 break; // skip degenerate points
5045 }
5046 if (reducedVerb == 1) {
rmistry@google.comd6176b02012-08-23 18:14:13 +00005047 *fExtra.append() =
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005048 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005049 break;
5050 }
5051 fCurrentContour->addQuad(&pointsPtr[-1]);
5052 break;
5053 case SkPath::kCubic_Verb:
5054 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
5055 if (reducedVerb == 0) {
5056 break; // skip degenerate points
5057 }
5058 if (reducedVerb == 1) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005059 *fExtra.append() =
5060 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005061 break;
5062 }
5063 if (reducedVerb == 2) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005064 *fExtra.append() =
5065 fCurrentContour->addQuad(fReducePts.end() - 3);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005066 break;
5067 }
5068 fCurrentContour->addCubic(&pointsPtr[-1]);
5069 break;
5070 case SkPath::kClose_Verb:
5071 SkASSERT(fCurrentContour);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005072 if (finalCurveStart && finalCurveEnd
5073 && *finalCurveStart != *finalCurveEnd) {
5074 *fReducePts.append() = *finalCurveStart;
5075 *fReducePts.append() = *finalCurveEnd;
5076 *fExtra.append() =
5077 fCurrentContour->addLine(fReducePts.end() - 2);
5078 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005079 complete();
caryclark@google.com31143cf2012-11-09 22:14:19 +00005080 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005081 default:
5082 SkDEBUGFAIL("bad verb");
5083 return;
5084 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005085 finalCurveStart = &pointsPtr[verb - 1];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005086 pointsPtr += verb;
5087 SkASSERT(fCurrentContour);
caryclark@google.com31143cf2012-11-09 22:14:19 +00005088 nextVerb:
caryclark@google.com235f56a2012-09-14 14:19:30 +00005089 if (verbPtr == endOfFirstHalf) {
5090 fOperand = true;
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00005091 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005092 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005093}
5094
5095private:
caryclark@google.com235f56a2012-09-14 14:19:30 +00005096 const SkPath* fPath;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005097 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005098 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005099 Contour* fCurrentContour;
5100 SkTArray<Contour>& fContours;
5101 SkTDArray<SkPoint> fReducePts; // segments created on the fly
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005102 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
caryclark@google.com729e1c42012-11-21 21:36:34 +00005103 ShapeOpMask fXorMask[2];
caryclark@google.com235f56a2012-09-14 14:19:30 +00005104 int fSecondHalf;
5105 bool fOperand;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005106};
5107
5108class Work {
5109public:
5110 enum SegmentType {
5111 kHorizontalLine_Segment = -1,
5112 kVerticalLine_Segment = 0,
5113 kLine_Segment = SkPath::kLine_Verb,
5114 kQuad_Segment = SkPath::kQuad_Verb,
5115 kCubic_Segment = SkPath::kCubic_Verb,
5116 };
rmistry@google.comd6176b02012-08-23 18:14:13 +00005117
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005118 void addCoincident(Work& other, const Intersections& ts, bool swap) {
5119 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
5120 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005121
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005122 // FIXME: does it make sense to write otherIndex now if we're going to
5123 // fix it up later?
5124 void addOtherT(int index, double otherT, int otherIndex) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005125 fContour->addOtherT(fIndex, index, otherT, otherIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005126 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005127
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005128 // Avoid collapsing t values that are close to the same since
5129 // we walk ts to describe consecutive intersections. Since a pair of ts can
5130 // be nearly equal, any problems caused by this should be taken care
5131 // of later.
5132 // On the edge or out of range values are negative; add 2 to get end
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005133 int addT(const Work& other, const SkPoint& pt, double& newT) {
5134 return fContour->addT(fIndex, other.fContour, other.fIndex, pt, newT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005135 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005136
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005137 int addUnsortableT(const Work& other, bool start, const SkPoint& pt, double& newT) {
5138 return fContour->addUnsortableT(fIndex, other.fContour, other.fIndex, start, pt, newT);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005139 }
5140
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005141 bool advance() {
5142 return ++fIndex < fLast;
5143 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005144
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005145 SkScalar bottom() const {
5146 return bounds().fBottom;
5147 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005148
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005149 const Bounds& bounds() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005150 return fContour->segments()[fIndex].bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005151 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00005152
caryclark@google.com73ca6242013-01-17 21:02:47 +00005153#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005154 const SkPoint* cubic() const {
5155 return fCubic;
5156 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005157#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005158
5159 void init(Contour* contour) {
5160 fContour = contour;
5161 fIndex = 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005162 fLast = contour->segments().count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005163 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00005164
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00005165 bool isAdjacent(const Work& next) {
5166 return fContour == next.fContour && fIndex + 1 == next.fIndex;
5167 }
5168
5169 bool isFirstLast(const Work& next) {
5170 return fContour == next.fContour && fIndex == 0
5171 && next.fIndex == fLast - 1;
5172 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005173
5174 SkScalar left() const {
5175 return bounds().fLeft;
5176 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005177
caryclark@google.com73ca6242013-01-17 21:02:47 +00005178#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005179 void promoteToCubic() {
5180 fCubic[0] = pts()[0];
5181 fCubic[2] = pts()[1];
5182 fCubic[3] = pts()[2];
5183 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
5184 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
5185 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
5186 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
5187 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005188#endif
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005189
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005190 const SkPoint* pts() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005191 return fContour->segments()[fIndex].pts();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005192 }
5193
5194 SkScalar right() const {
5195 return bounds().fRight;
5196 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005197
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005198 ptrdiff_t segmentIndex() const {
5199 return fIndex;
5200 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005201
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005202 SegmentType segmentType() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005203 const Segment& segment = fContour->segments()[fIndex];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005204 SegmentType type = (SegmentType) segment.verb();
5205 if (type != kLine_Segment) {
5206 return type;
5207 }
5208 if (segment.isHorizontal()) {
5209 return kHorizontalLine_Segment;
5210 }
5211 if (segment.isVertical()) {
5212 return kVerticalLine_Segment;
5213 }
5214 return kLine_Segment;
5215 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005216
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005217 bool startAfter(const Work& after) {
5218 fIndex = after.fIndex;
5219 return advance();
5220 }
5221
5222 SkScalar top() const {
5223 return bounds().fTop;
5224 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005225
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005226 SkPath::Verb verb() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005227 return fContour->segments()[fIndex].verb();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005228 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005229
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005230 SkScalar x() const {
5231 return bounds().fLeft;
5232 }
5233
5234 bool xFlipped() const {
5235 return x() != pts()[0].fX;
5236 }
5237
5238 SkScalar y() const {
5239 return bounds().fTop;
5240 }
5241
5242 bool yFlipped() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005243 return y() != pts()[0].fY;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005244 }
5245
5246protected:
5247 Contour* fContour;
caryclark@google.com73ca6242013-01-17 21:02:47 +00005248#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005249 SkPoint fCubic[4];
caryclark@google.com73ca6242013-01-17 21:02:47 +00005250#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005251 int fIndex;
5252 int fLast;
5253};
5254
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005255#if DEBUG_ADD_INTERSECTING_TS
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005256
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005257#if DEBUG_AS_C_CODE
5258#define CUBIC_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}}"
5259#define QUAD_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}}"
5260#define LINE_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}}"
5261#define PT_DEBUG_STR "{{%1.17g,%1.17g}}"
5262#else
5263#define CUBIC_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5264#define QUAD_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5265#define LINE_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g)"
5266#define PT_DEBUG_STR "(%1.9g,%1.9g)"
5267#endif
5268#define T_DEBUG_STR(t, n) #t "[" #n "]=%1.9g"
5269#define TX_DEBUG_STR(t) #t "[%d]=%1.9g"
5270#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
5271#define QUAD_DEBUG_DATA(q) q[0].fX, q[0].fY, q[1].fX, q[1].fY, q[2].fX, q[2].fY
5272#define LINE_DEBUG_DATA(l) l[0].fX, l[0].fY, l[1].fX, l[1].fY
5273#define PT_DEBUG_DATA(i, n) i.fPt[n].x, i.fPt[n].y
5274
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005275static void debugShowLineIntersection(int pts, const Work& wt, const Work& wn,
5276 const Intersections& i) {
5277 SkASSERT(i.used() == pts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005278 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005279 SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n",
5280 __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005281 return;
5282 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005283 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " LINE_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5284 i.fT[0][0], LINE_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005285 if (pts == 2) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005286 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 +00005287 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005288 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005289 if (pts == 2) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005290 SkDebugf(" " T_DEBUG_STR(wnTs, 1), i.fT[1][1]);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005291 }
5292 SkDebugf("\n");
5293}
5294
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005295static void debugShowQuadLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005296 const Work& wn, const Intersections& i) {
5297 SkASSERT(i.used() == pts);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005298 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005299 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " LINE_DEBUG_STR "\n",
5300 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005301 return;
5302 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005303 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5304 i.fT[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5305 for (int n = 1; n < pts; ++n) {
5306 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 +00005307 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005308 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
5309 for (int n = 1; n < pts; ++n) {
5310 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005311 }
5312 SkDebugf("\n");
5313}
5314
caryclark@google.coma461ff02012-10-11 12:54:23 +00005315static void debugShowQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005316 const Work& wn, const Intersections& i) {
5317 SkASSERT(i.used() == pts);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005318 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005319 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " QUAD_DEBUG_STR "\n",
5320 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
caryclark@google.coma461ff02012-10-11 12:54:23 +00005321 return;
5322 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005323 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5324 i.fT[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5325 for (int n = 1; n < pts; ++n) {
5326 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 +00005327 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005328 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i.fT[1][0], QUAD_DEBUG_DATA(wn.pts()));
5329 for (int n = 1; n < pts; ++n) {
5330 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005331 }
caryclark@google.comb9738012012-07-03 19:53:30 +00005332 SkDebugf("\n");
5333}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005334
5335static void debugShowCubicLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005336 const Work& wn, const Intersections& i) {
5337 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005338 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005339 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " LINE_DEBUG_STR "\n",
5340 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005341 return;
5342 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005343 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5344 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5345 for (int n = 1; n < pts; ++n) {
5346 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 +00005347 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005348 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts()));
5349 for (int n = 1; n < pts; ++n) {
5350 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005351 }
5352 SkDebugf("\n");
5353}
5354
caryclark@google.com73ca6242013-01-17 21:02:47 +00005355static void debugShowCubicQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005356 const Work& wn, const Intersections& i) {
5357 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005358 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005359 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " QUAD_DEBUG_STR "\n",
5360 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005361 return;
5362 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005363 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5364 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5365 for (int n = 1; n < pts; ++n) {
5366 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 +00005367 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005368 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i.fT[1][0], QUAD_DEBUG_DATA(wn.pts()));
5369 for (int n = 1; n < pts; ++n) {
5370 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005371 }
5372 SkDebugf("\n");
5373}
5374
caryclark@google.com73ca6242013-01-17 21:02:47 +00005375static void debugShowCubicIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005376 const Work& wn, const Intersections& i) {
5377 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005378 if (!pts) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005379 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " CUBIC_DEBUG_STR "\n",
5380 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), CUBIC_DEBUG_DATA(wn.pts()));
caryclark@google.com73ca6242013-01-17 21:02:47 +00005381 return;
5382 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005383 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5384 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5385 for (int n = 1; n < pts; ++n) {
5386 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 +00005387 }
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005388 SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i.fT[1][0], CUBIC_DEBUG_DATA(wn.pts()));
5389 for (int n = 1; n < pts; ++n) {
5390 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005391 }
5392 SkDebugf("\n");
5393}
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005394
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005395static void debugShowCubicIntersection(int pts, const Work& wt, const Intersections& i) {
5396 SkASSERT(i.used() == pts);
5397 if (!pts) {
5398 SkDebugf("%s no self intersect " CUBIC_DEBUG_STR "\n", __FUNCTION__,
5399 CUBIC_DEBUG_DATA(wt.pts()));
5400 return;
5401 }
5402 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
5403 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
5404 SkDebugf(" " T_DEBUG_STR(wtTs, 1), i.fT[1][0]);
5405 SkDebugf("\n");
5406}
5407
5408#undef CUBIC_DEBUG_STR
5409#undef QUAD_DEBUG_STR
5410#undef LINE_DEBUG_STR
5411#undef PT_DEBUG_STR
5412#undef T_DEBUG_STR
5413#undef CUBIC_DEBUG_DATA
5414#undef QUAD_DEBUG_DATA
5415#undef LINE_DEBUG_DATA
5416#undef PT_DEBUG_DATA
5417
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005418#else
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005419static void debugShowLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005420}
caryclark@google.coma461ff02012-10-11 12:54:23 +00005421
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005422static void debugShowQuadLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005423}
5424
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005425static void debugShowQuadIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005426}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005427
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005428static void debugShowCubicLineIntersection(int , const Work& , const Work& ,
5429 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005430}
5431
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005432static void debugShowCubicQuadIntersection(int , const Work& , const Work& ,
5433 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005434}
5435
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005436static void debugShowCubicIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005437}
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005438
5439static void debugShowCubicIntersection(int , const Work& , const Intersections& ) {
5440}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005441#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005442
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005443static bool addIntersectTs(Contour* test, Contour* next) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005444
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005445 if (test != next) {
5446 if (test->bounds().fBottom < next->bounds().fTop) {
5447 return false;
5448 }
5449 if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5450 return true;
5451 }
5452 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005453 Work wt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005454 wt.init(test);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005455 bool foundCommonContour = test == next;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005456 do {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005457 Work wn;
5458 wn.init(next);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005459 if (test == next && !wn.startAfter(wt)) {
5460 continue;
5461 }
5462 do {
5463 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5464 continue;
5465 }
5466 int pts;
5467 Intersections ts;
5468 bool swap = false;
5469 switch (wt.segmentType()) {
5470 case Work::kHorizontalLine_Segment:
5471 swap = true;
5472 switch (wn.segmentType()) {
5473 case Work::kHorizontalLine_Segment:
5474 case Work::kVerticalLine_Segment:
5475 case Work::kLine_Segment: {
5476 pts = HLineIntersect(wn.pts(), wt.left(),
5477 wt.right(), wt.y(), wt.xFlipped(), 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 }
5481 case Work::kQuad_Segment: {
5482 pts = HQuadIntersect(wn.pts(), wt.left(),
5483 wt.right(), wt.y(), wt.xFlipped(), ts);
5484 break;
5485 }
5486 case Work::kCubic_Segment: {
5487 pts = HCubicIntersect(wn.pts(), wt.left(),
5488 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005489 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005490 break;
5491 }
5492 default:
5493 SkASSERT(0);
5494 }
5495 break;
5496 case Work::kVerticalLine_Segment:
5497 swap = true;
5498 switch (wn.segmentType()) {
5499 case Work::kHorizontalLine_Segment:
5500 case Work::kVerticalLine_Segment:
5501 case Work::kLine_Segment: {
5502 pts = VLineIntersect(wn.pts(), wt.top(),
5503 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005504 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005505 break;
5506 }
5507 case Work::kQuad_Segment: {
5508 pts = VQuadIntersect(wn.pts(), wt.top(),
5509 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5510 break;
5511 }
5512 case Work::kCubic_Segment: {
5513 pts = VCubicIntersect(wn.pts(), wt.top(),
5514 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005515 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005516 break;
5517 }
5518 default:
5519 SkASSERT(0);
5520 }
5521 break;
5522 case Work::kLine_Segment:
5523 switch (wn.segmentType()) {
5524 case Work::kHorizontalLine_Segment:
5525 pts = HLineIntersect(wt.pts(), wn.left(),
5526 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005527 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005528 break;
5529 case Work::kVerticalLine_Segment:
5530 pts = VLineIntersect(wt.pts(), wn.top(),
5531 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005532 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005533 break;
5534 case Work::kLine_Segment: {
5535 pts = LineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005536 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005537 break;
5538 }
5539 case Work::kQuad_Segment: {
5540 swap = true;
5541 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005542 debugShowQuadLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005543 break;
5544 }
5545 case Work::kCubic_Segment: {
5546 swap = true;
5547 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005548 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005549 break;
5550 }
5551 default:
5552 SkASSERT(0);
5553 }
5554 break;
5555 case Work::kQuad_Segment:
5556 switch (wn.segmentType()) {
5557 case Work::kHorizontalLine_Segment:
5558 pts = HQuadIntersect(wt.pts(), wn.left(),
5559 wn.right(), wn.y(), wn.xFlipped(), ts);
5560 break;
5561 case Work::kVerticalLine_Segment:
5562 pts = VQuadIntersect(wt.pts(), wn.top(),
5563 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5564 break;
5565 case Work::kLine_Segment: {
5566 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005567 debugShowQuadLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005568 break;
5569 }
5570 case Work::kQuad_Segment: {
5571 pts = QuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005572 debugShowQuadIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005573 break;
5574 }
5575 case Work::kCubic_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005576 #if APPROXIMATE_CUBICS
5577 swap = true;
5578 pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005579 debugShowCubicQuadIntersection(pts, wn, wt, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005580 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005581 wt.promoteToCubic();
5582 pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005583 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005584 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005585 break;
5586 }
5587 default:
5588 SkASSERT(0);
5589 }
5590 break;
5591 case Work::kCubic_Segment:
5592 switch (wn.segmentType()) {
5593 case Work::kHorizontalLine_Segment:
5594 pts = HCubicIntersect(wt.pts(), wn.left(),
5595 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005596 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005597 break;
5598 case Work::kVerticalLine_Segment:
5599 pts = VCubicIntersect(wt.pts(), wn.top(),
5600 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005601 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005602 break;
5603 case Work::kLine_Segment: {
5604 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005605 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005606 break;
5607 }
5608 case Work::kQuad_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005609 #if APPROXIMATE_CUBICS
5610 pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005611 debugShowCubicQuadIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005612 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005613 wn.promoteToCubic();
5614 pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005615 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005616 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005617 break;
5618 }
5619 case Work::kCubic_Segment: {
5620 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005621 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005622 break;
5623 }
5624 default:
5625 SkASSERT(0);
5626 }
5627 break;
5628 default:
5629 SkASSERT(0);
5630 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005631 if (!foundCommonContour && pts > 0) {
5632 test->addCross(next);
5633 next->addCross(test);
5634 foundCommonContour = true;
5635 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005636 // in addition to recording T values, record matching segment
caryclark@google.com73ca6242013-01-17 21:02:47 +00005637 if (ts.unsortable()) {
5638 bool start = true;
5639 for (int pt = 0; pt < ts.used(); ++pt) {
5640 // FIXME: if unsortable, the other points to the original. This logic is
5641 // untested downstream.
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005642 SkPoint point = ts.fPt[pt].asSkPoint();
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005643 int testTAt = wt.addUnsortableT(wt, start, point, ts.fT[swap][pt]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005644 wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt);
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005645 testTAt = wn.addUnsortableT(wn, start ^ ts.fFlip, point, ts.fT[!swap][pt]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005646 wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt);
5647 start ^= true;
5648 }
5649 continue;
5650 }
caryclark@google.com32546db2012-08-31 20:55:07 +00005651 if (pts == 2) {
5652 if (wn.segmentType() <= Work::kLine_Segment
5653 && wt.segmentType() <= Work::kLine_Segment) {
5654 wt.addCoincident(wn, ts, swap);
5655 continue;
5656 }
caryclark@google.combeda3892013-02-07 13:13:41 +00005657 if (wn.segmentType() >= Work::kQuad_Segment
5658 && wt.segmentType() >= Work::kQuad_Segment
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005659 && ts.fIsCoincident[0]) {
5660 SkASSERT(ts.coincidentUsed() == 2);
caryclark@google.com32546db2012-08-31 20:55:07 +00005661 wt.addCoincident(wn, ts, swap);
5662 continue;
5663 }
5664
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00005665 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00005666 for (int pt = 0; pt < pts; ++pt) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005667 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5668 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005669 SkPoint point = ts.fPt[pt].asSkPoint();
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005670 int testTAt = wt.addT(wn, point, ts.fT[swap][pt]);
5671 int nextTAt = wn.addT(wt, point, ts.fT[!swap][pt]);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005672 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
5673 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005674 }
5675 } while (wn.advance());
5676 } while (wt.advance());
5677 return true;
5678}
5679
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005680static void addSelfIntersectTs(Contour* test) {
5681 Work wt;
5682 wt.init(test);
5683 do {
5684 if (wt.segmentType() != Work::kCubic_Segment) {
5685 continue;
5686 }
5687 Intersections ts;
5688 int pts = CubicIntersect(wt.pts(), ts);
5689 debugShowCubicIntersection(pts, wt, ts);
5690 if (!pts) {
5691 continue;
5692 }
5693 SkASSERT(pts == 1);
5694 SkASSERT(ts.fT[0][0] >= 0 && ts.fT[0][0] <= 1);
5695 SkASSERT(ts.fT[1][0] >= 0 && ts.fT[1][0] <= 1);
5696 SkPoint point = ts.fPt[0].asSkPoint();
caryclark@google.com7ff5c842013-02-26 15:56:05 +00005697 int testTAt = wt.addT(wt, point, ts.fT[0][0]);
5698 int nextTAt = wt.addT(wt, point, ts.fT[1][0]);
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005699 wt.addOtherT(testTAt, ts.fT[1][0], nextTAt);
5700 wt.addOtherT(nextTAt, ts.fT[0][0], testTAt);
5701 } while (wt.advance());
5702}
5703
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005704// resolve any coincident pairs found while intersecting, and
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005705// see if coincidence is formed by clipping non-concident segments
caryclark@google.com4eeda372012-12-06 21:47:48 +00005706static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005707 int contourCount = contourList.count();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005708#if ONE_PASS_COINCIDENCE_CHECK
caryclark@google.comf25edfe2012-06-01 18:20:10 +00005709 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005710 Contour* contour = contourList[cIndex];
caryclark@google.com7ba591e2012-11-20 14:21:54 +00005711 contour->resolveCoincidence(contourList);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005712 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005713#else
5714 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5715 Contour* contour = contourList[cIndex];
5716 contour->addCoincidentPoints();
5717 }
5718 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5719 Contour* contour = contourList[cIndex];
5720 contour->calcCoincidentWinding();
5721 }
5722#endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005723 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5724 Contour* contour = contourList[cIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00005725 contour->findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005726 }
5727}
5728
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005729static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005730 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005731 SkPoint basePt;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005732 double tAtMid = current->tAtMid(index, endIndex, mid);
5733 current->xyAtT(tAtMid, basePt);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005734 int contourCount = contourList.count();
5735 SkScalar bestY = SK_ScalarMin;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005736 Segment* bestSeg = NULL;
5737 int bestTIndex;
5738 bool bestOpp;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005739 bool hitSomething = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005740 for (int cTest = 0; cTest < contourCount; ++cTest) {
5741 Contour* contour = contourList[cTest];
5742 bool testOpp = contour->operand() ^ current->operand() ^ opp;
5743 if (basePt.fY < contour->bounds().fTop) {
5744 continue;
5745 }
5746 if (bestY > contour->bounds().fBottom) {
5747 continue;
5748 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005749 int segmentCount = contour->segments().count();
5750 for (int test = 0; test < segmentCount; ++test) {
5751 Segment* testSeg = &contour->segments()[test];
5752 SkScalar testY = bestY;
5753 double testHit;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005754 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
5755 testOpp, testSeg == current);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005756 if (testTIndex < 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005757 if (testTIndex == SK_MinS32) {
5758 hitSomething = true;
5759 bestSeg = NULL;
5760 goto abortContours; // vertical encountered, return and try different point
5761 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005762 continue;
5763 }
5764 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005765 double baseT = current->t(index);
5766 double endT = current->t(endIndex);
5767 double newMid = (testHit - baseT) / (endT - baseT);
5768#if DEBUG_WINDING
5769 SkPoint midXY, newXY;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005770 double midT = current->tAtMid(index, endIndex, mid);
5771 current->xyAtT(midT, midXY);
5772 double newMidT = current->tAtMid(index, endIndex, newMid);
5773 current->xyAtT(newMidT, newXY);
caryclark@google.com3586ece2012-12-27 18:46:58 +00005774 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
5775 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
5776 current->debugID(), mid, newMid,
5777 baseT, current->xAtT(index), current->yAtT(index),
5778 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
5779 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
5780 endT, current->xAtT(endIndex), current->yAtT(endIndex));
5781#endif
5782 mid = newMid * 2; // calling loop with divide by 2 before continuing
5783 return SK_MinS32;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005784 }
5785 bestSeg = testSeg;
5786 bestHit = testHit;
5787 bestOpp = testOpp;
5788 bestTIndex = testTIndex;
5789 bestY = testY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005790 }
5791 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005792abortContours:
caryclark@google.com10227bf2012-12-28 22:10:41 +00005793 int result;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005794 if (!bestSeg) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00005795 result = hitSomething ? SK_MinS32 : 0;
5796 } else {
5797 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
5798 current = bestSeg;
5799 index = bestTIndex;
5800 endIndex = bestSeg->nextSpan(bestTIndex, 1);
5801 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
5802 tryAgain = true;
5803 return 0;
5804 }
5805 result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
5806 SkASSERT(bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005807 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005808 double baseT = current->t(index);
5809 double endT = current->t(endIndex);
5810 bestHit = baseT + mid * (endT - baseT);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005811 return result;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005812}
5813
caryclark@google.com24bec792012-08-20 12:43:57 +00005814static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
5815 int contourCount = contourList.count();
5816 Segment* result;
5817 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5818 Contour* contour = contourList[cIndex];
5819 result = contour->undoneSegment(start, end);
5820 if (result) {
5821 return result;
5822 }
5823 }
5824 return NULL;
5825}
5826
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005827#define OLD_FIND_CHASE 1
caryclark@google.com24bec792012-08-20 12:43:57 +00005828
caryclark@google.com31143cf2012-11-09 22:14:19 +00005829static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005830 while (chase.count()) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005831 Span* span;
5832 chase.pop(&span);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005833 const Span& backPtr = span->fOther->span(span->fOtherIndex);
5834 Segment* segment = backPtr.fOther;
5835 tIndex = backPtr.fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005836 SkTDArray<Angle> angles;
5837 int done = 0;
5838 if (segment->activeAngle(tIndex, done, angles)) {
5839 Angle* last = angles.end() - 1;
5840 tIndex = last->start();
5841 endIndex = last->end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005842 #if TRY_ROTATE
5843 *chase.insert(0) = span;
5844 #else
5845 *chase.append() = span;
5846 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005847 return last->segment();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005848 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005849 if (done == angles.count()) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00005850 continue;
5851 }
5852 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005853 bool sortable = Segment::SortAngles(angles, sorted);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005854 int angleCount = sorted.count();
caryclark@google.com03f97062012-08-21 13:13:52 +00005855#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005856 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00005857#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005858 if (!sortable) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005859 continue;
5860 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005861 // find first angle, initialize winding to computed fWindSum
5862 int firstIndex = -1;
5863 const Angle* angle;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005864#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005865 int winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005866 do {
5867 angle = sorted[++firstIndex];
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005868 segment = angle->segment();
5869 winding = segment->windSum(angle);
5870 } while (winding == SK_MinS32);
5871 int spanWinding = segment->spanSign(angle->start(), angle->end());
5872 #if DEBUG_WINDING
caryclark@google.com31143cf2012-11-09 22:14:19 +00005873 SkDebugf("%s winding=%d spanWinding=%d\n",
5874 __FUNCTION__, winding, spanWinding);
caryclark@google.com47580692012-07-23 12:14:49 +00005875 #endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005876 // turn span winding into contour winding
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005877 if (spanWinding * winding < 0) {
5878 winding += spanWinding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005879 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005880 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005881 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005882 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005883 // we care about first sign and whether wind sum indicates this
5884 // edge is inside or outside. Maybe need to pass span winding
5885 // or first winding or something into this function?
5886 // advance to first undone angle, then return it and winding
5887 // (to set whether edges are active or not)
5888 int nextIndex = firstIndex + 1;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005889 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005890 angle = sorted[firstIndex];
caryclark@google.com2ddff932012-08-07 21:25:27 +00005891 winding -= angle->segment()->spanSign(angle);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005892#else
5893 do {
5894 angle = sorted[++firstIndex];
5895 segment = angle->segment();
5896 } while (segment->windSum(angle) == SK_MinS32);
5897 #if DEBUG_SORT
5898 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5899 #endif
5900 int sumWinding = segment->updateWindingReverse(angle);
5901 int nextIndex = firstIndex + 1;
5902 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5903 Segment* first = NULL;
5904#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005905 do {
5906 SkASSERT(nextIndex != firstIndex);
5907 if (nextIndex == angleCount) {
5908 nextIndex = 0;
5909 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005910 angle = sorted[nextIndex];
caryclark@google.com9764cc62012-07-12 19:29:45 +00005911 segment = angle->segment();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005912#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005913 int maxWinding = winding;
caryclark@google.com2ddff932012-08-07 21:25:27 +00005914 winding -= segment->spanSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005915 #if DEBUG_SORT
caryclark@google.com2ddff932012-08-07 21:25:27 +00005916 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
5917 segment->debugID(), maxWinding, winding, angle->sign());
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005918 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005919 tIndex = angle->start();
5920 endIndex = angle->end();
5921 int lesser = SkMin32(tIndex, endIndex);
5922 const Span& nextSpan = segment->span(lesser);
5923 if (!nextSpan.fDone) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005924#if 1
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005925 // FIXME: this be wrong? assign startWinding if edge is in
caryclark@google.com9764cc62012-07-12 19:29:45 +00005926 // same direction. If the direction is opposite, winding to
5927 // assign is flipped sign or +/- 1?
caryclark@google.com59823f72012-08-09 18:17:47 +00005928 if (useInnerWinding(maxWinding, winding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005929 maxWinding = winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005930 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005931 segment->markAndChaseWinding(angle, maxWinding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005932#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005933 break;
5934 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005935#else
5936 int start = angle->start();
5937 int end = angle->end();
5938 int maxWinding;
5939 segment->setUpWinding(start, end, maxWinding, sumWinding);
5940 if (!segment->done(angle)) {
5941 if (!first) {
5942 first = segment;
5943 tIndex = start;
5944 endIndex = end;
5945 }
5946 (void) segment->markAngle(maxWinding, sumWinding, true, angle);
5947 }
5948#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005949 } while (++nextIndex != lastIndex);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005950 #if TRY_ROTATE
5951 *chase.insert(0) = span;
5952 #else
5953 *chase.append() = span;
5954 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005955 return segment;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005956 }
5957 return NULL;
5958}
5959
caryclark@google.com027de222012-07-12 12:52:50 +00005960#if DEBUG_ACTIVE_SPANS
5961static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005962 int index;
5963 for (index = 0; index < contourList.count(); ++ index) {
caryclark@google.com027de222012-07-12 12:52:50 +00005964 contourList[index]->debugShowActiveSpans();
5965 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005966 for (index = 0; index < contourList.count(); ++ index) {
5967 contourList[index]->validateActiveSpans();
5968 }
caryclark@google.com027de222012-07-12 12:52:50 +00005969}
5970#endif
5971
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005972static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005973 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005974 Segment* result;
5975 do {
caryclark@google.comf839c032012-10-26 21:03:50 +00005976 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005977 int contourCount = contourList.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00005978 Segment* topStart = NULL;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005979 done = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00005980 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5981 Contour* contour = contourList[cIndex];
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005982 if (contour->done()) {
5983 continue;
5984 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005985 const Bounds& bounds = contour->bounds();
5986 if (bounds.fBottom < topLeft.fY) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005987 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005988 continue;
5989 }
5990 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005991 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005992 continue;
5993 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005994 contour->topSortableSegment(topLeft, bestXY, topStart);
5995 if (!contour->done()) {
5996 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005997 }
5998 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005999 if (!topStart) {
6000 return NULL;
6001 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006002 topLeft = bestXY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006003 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006004 } while (!result);
6005 return result;
6006}
caryclark@google.com31143cf2012-11-09 22:14:19 +00006007
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006008static int rightAngleWinding(SkTDArray<Contour*>& contourList,
caryclark@google.com3586ece2012-12-27 18:46:58 +00006009 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006010 bool opp) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006011 double test = 0.9;
6012 int contourWinding;
6013 do {
caryclark@google.com3586ece2012-12-27 18:46:58 +00006014 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
6015 tryAgain, test, opp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006016 if (contourWinding != SK_MinS32 || tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006017 return contourWinding;
6018 }
6019 test /= 2;
6020 } while (!approximately_negative(test));
6021 SkASSERT(0); // should be OK to comment out, but interested when this hits
6022 return contourWinding;
6023}
6024
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006025static void skipVertical(SkTDArray<Contour*>& contourList,
6026 Segment*& current, int& index, int& endIndex) {
6027 if (!current->isVertical(index, endIndex)) {
6028 return;
6029 }
6030 int contourCount = contourList.count();
6031 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
6032 Contour* contour = contourList[cIndex];
6033 if (contour->done()) {
6034 continue;
6035 }
6036 current = contour->nonVerticalSegment(index, endIndex);
6037 if (current) {
6038 return;
6039 }
6040 }
6041}
6042
caryclark@google.com3586ece2012-12-27 18:46:58 +00006043static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006044 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
6045 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
6046 true);
6047 if (!current) {
6048 return NULL;
6049 }
6050 if (firstContour) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00006051 current->initWinding(index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006052 firstContour = false;
6053 return current;
6054 }
6055 int minIndex = SkMin32(index, endIndex);
6056 int sumWinding = current->windSum(minIndex);
6057 if (sumWinding != SK_MinS32) {
6058 return current;
6059 }
6060 sumWinding = current->computeSum(index, endIndex, binary);
6061 if (sumWinding != SK_MinS32) {
6062 return current;
6063 }
6064 int contourWinding;
6065 int oppContourWinding = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006066 // the simple upward projection of the unresolved points hit unsortable angles
6067 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006068 bool tryAgain;
6069 double tHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006070 SkScalar hitDx = 0;
6071 SkScalar hitOppDx = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006072 do {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006073 // if current is vertical, find another candidate which is not
6074 // if only remaining candidates are vertical, then they can be marked done
caryclark@google.com10227bf2012-12-28 22:10:41 +00006075 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006076 skipVertical(contourList, current, index, endIndex);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006077 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006078 tryAgain = false;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006079 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006080 tryAgain, false);
6081 if (tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006082 continue;
6083 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006084 if (!binary) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006085 break;
6086 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00006087 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006088 tryAgain, true);
6089 } while (tryAgain);
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00006090
caryclark@google.com3586ece2012-12-27 18:46:58 +00006091 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006092 return current;
6093}
6094
6095// rewrite that abandons keeping local track of winding
caryclark@google.com3586ece2012-12-27 18:46:58 +00006096static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006097 bool firstContour = true;
6098 bool unsortable = false;
6099 bool topUnsortable = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006100 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
6101 do {
6102 int index, endIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006103 bool topDone;
caryclark@google.com3586ece2012-12-27 18:46:58 +00006104 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006105 topUnsortable, topDone, false);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006106 if (!current) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006107 if (topUnsortable || !topDone) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006108 topUnsortable = false;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006109 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006110 topLeft.fX = topLeft.fY = SK_ScalarMin;
6111 continue;
6112 }
6113 break;
6114 }
6115 SkTDArray<Span*> chaseArray;
6116 do {
6117 if (current->activeWinding(index, endIndex)) {
6118 do {
6119 #if DEBUG_ACTIVE_SPANS
6120 if (!unsortable && current->done()) {
6121 debugShowActiveSpans(contourList);
6122 }
6123 #endif
6124 SkASSERT(unsortable || !current->done());
6125 int nextStart = index;
6126 int nextEnd = endIndex;
6127 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
6128 unsortable);
6129 if (!next) {
6130 if (!unsortable && simple.hasMove()
6131 && current->verb() != SkPath::kLine_Verb
6132 && !simple.isClosed()) {
6133 current->addCurveTo(index, endIndex, simple, true);
6134 SkASSERT(simple.isClosed());
6135 }
6136 break;
6137 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006138 #if DEBUG_FLOW
6139 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6140 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
6141 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
6142 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006143 current->addCurveTo(index, endIndex, simple, true);
6144 current = next;
6145 index = nextStart;
6146 endIndex = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006147 } while (!simple.isClosed() && (!unsortable
caryclark@google.com10227bf2012-12-28 22:10:41 +00006148 || !current->done(SkMin32(index, endIndex))));
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006149 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
6150 SkASSERT(unsortable);
6151 int min = SkMin32(index, endIndex);
6152 if (!current->done(min)) {
6153 current->addCurveTo(index, endIndex, simple, true);
6154 current->markDoneUnary(min);
6155 }
6156 }
6157 simple.close();
6158 } else {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006159 Span* last = current->markAndChaseDoneUnary(index, endIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006160 if (last) {
6161 *chaseArray.append() = last;
6162 }
6163 }
6164 current = findChase(chaseArray, index, endIndex);
6165 #if DEBUG_ACTIVE_SPANS
6166 debugShowActiveSpans(contourList);
6167 #endif
6168 if (!current) {
6169 break;
6170 }
6171 } while (true);
6172 } while (true);
6173 return simple.someAssemblyRequired();
6174}
6175
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006176// returns true if all edges were processed
caryclark@google.comf839c032012-10-26 21:03:50 +00006177static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006178 Segment* current;
6179 int start, end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006180 bool unsortable = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006181 bool closable = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00006182 while ((current = findUndone(contourList, start, end))) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006183 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006184 #if DEBUG_ACTIVE_SPANS
6185 if (!unsortable && current->done()) {
6186 debugShowActiveSpans(contourList);
6187 }
6188 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006189 SkASSERT(unsortable || !current->done());
caryclark@google.com24bec792012-08-20 12:43:57 +00006190 int nextStart = start;
6191 int nextEnd = end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006192 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
caryclark@google.com24bec792012-08-20 12:43:57 +00006193 if (!next) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006194 if (!unsortable && simple.hasMove()
caryclark@google.comf839c032012-10-26 21:03:50 +00006195 && current->verb() != SkPath::kLine_Verb
6196 && !simple.isClosed()) {
6197 current->addCurveTo(start, end, simple, true);
6198 SkASSERT(simple.isClosed());
caryclark@google.comc899ad92012-08-23 15:24:42 +00006199 }
caryclark@google.com24bec792012-08-20 12:43:57 +00006200 break;
6201 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006202 #if DEBUG_FLOW
6203 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6204 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
6205 current->xyAtT(end).fX, current->xyAtT(end).fY);
6206 #endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006207 current->addCurveTo(start, end, simple, true);
caryclark@google.com24bec792012-08-20 12:43:57 +00006208 current = next;
6209 start = nextStart;
6210 end = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006211 } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006212 if (!simple.isClosed()) {
6213 SkASSERT(unsortable);
6214 int min = SkMin32(start, end);
6215 if (!current->done(min)) {
6216 current->addCurveTo(start, end, simple, true);
6217 current->markDone(min, 1);
6218 }
6219 closable = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00006220 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006221 simple.close();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00006222 #if DEBUG_ACTIVE_SPANS
6223 debugShowActiveSpans(contourList);
6224 #endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00006225 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006226 return closable;
caryclark@google.com24bec792012-08-20 12:43:57 +00006227}
6228
caryclark@google.comb45a1b42012-05-18 20:50:33 +00006229static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
6230 int contourCount = contourList.count();
6231 for (int cTest = 0; cTest < contourCount; ++cTest) {
6232 Contour* contour = contourList[cTest];
6233 contour->fixOtherTIndex();
6234 }
6235}
6236
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006237static void sortSegments(SkTDArray<Contour*>& contourList) {
6238 int contourCount = contourList.count();
6239 for (int cTest = 0; cTest < contourCount; ++cTest) {
6240 Contour* contour = contourList[cTest];
6241 contour->sortSegments();
6242 }
6243}
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006244
caryclark@google.com4eeda372012-12-06 21:47:48 +00006245static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
6246 bool evenOdd, bool oppEvenOdd) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006247 int count = contours.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006248 if (count == 0) {
6249 return;
6250 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006251 for (int index = 0; index < count; ++index) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00006252 Contour& contour = contours[index];
6253 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
6254 *list.append() = &contour;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006255 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006256 QSort<Contour>(list.begin(), list.end() - 1);
6257}
6258
caryclark@google.comf839c032012-10-26 21:03:50 +00006259static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006260 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006261}
6262
caryclark@google.com10227bf2012-12-28 22:10:41 +00006263static bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
6264 return distances[one] < distances[two];
6265}
caryclark@google.comf839c032012-10-26 21:03:50 +00006266 /*
6267 check start and end of each contour
6268 if not the same, record them
6269 match them up
6270 connect closest
6271 reassemble contour pieces into new path
6272 */
6273static void assemble(const PathWrapper& path, PathWrapper& simple) {
6274#if DEBUG_PATH_CONSTRUCTION
6275 SkDebugf("%s\n", __FUNCTION__);
6276#endif
6277 SkTArray<Contour> contours;
6278 EdgeBuilder builder(path, contours);
6279 builder.finish();
6280 int count = contours.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006281 int outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006282 SkTDArray<int> runs; // indices of partial contours
caryclark@google.com0b7da432012-10-31 19:00:20 +00006283 for (outer = 0; outer < count; ++outer) {
6284 const Contour& eContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006285 const SkPoint& eStart = eContour.start();
6286 const SkPoint& eEnd = eContour.end();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006287#if DEBUG_ASSEMBLE
6288 SkDebugf("%s contour", __FUNCTION__);
6289 if (!approximatelyEqual(eStart, eEnd)) {
6290 SkDebugf("[%d]", runs.count());
6291 } else {
6292 SkDebugf(" ");
6293 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006294 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006295 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
6296#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006297 if (approximatelyEqual(eStart, eEnd)) {
6298 eContour.toPath(simple);
6299 continue;
6300 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006301 *runs.append() = outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006302 }
6303 count = runs.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006304 if (count == 0) {
6305 return;
6306 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006307 SkTDArray<int> sLink, eLink;
6308 sLink.setCount(count);
6309 eLink.setCount(count);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006310 int rIndex, iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006311 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006312 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006313 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006314 SkTDArray<double> distances;
6315 const int ends = count * 2; // all starts and ends
6316 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
6317 distances.setCount(entries);
6318 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
6319 outer = runs[rIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006320 const Contour& oContour = contours[outer];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006321 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
6322 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
6323 * ends - rIndex - 1;
6324 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
6325 int inner = runs[iIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006326 const Contour& iContour = contours[inner];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006327 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
6328 double dx = iPt.fX - oPt.fX;
6329 double dy = iPt.fY - oPt.fY;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006330 double dist = dx * dx + dy * dy;
caryclark@google.com10227bf2012-12-28 22:10:41 +00006331 distances[row + iIndex] = dist; // oStart distance from iStart
6332 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006333 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006334 SkTDArray<int> sortedDist;
6335 sortedDist.setCount(entries);
6336 for (rIndex = 0; rIndex < entries; ++rIndex) {
6337 sortedDist[rIndex] = rIndex;
6338 }
6339 QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
6340 int remaining = count; // number of start/end pairs
6341 for (rIndex = 0; rIndex < entries; ++rIndex) {
6342 int pair = sortedDist[rIndex];
6343 int row = pair / ends;
6344 int col = pair - row * ends;
6345 int thingOne = row < col ? row : ends - row - 2;
6346 int ndxOne = thingOne >> 1;
6347 bool endOne = thingOne & 1;
6348 int* linkOne = endOne ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006349 if (linkOne[ndxOne] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006350 continue;
6351 }
6352 int thingTwo = row < col ? col : ends - row + col - 1;
6353 int ndxTwo = thingTwo >> 1;
6354 bool endTwo = thingTwo & 1;
6355 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006356 if (linkTwo[ndxTwo] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006357 continue;
6358 }
6359 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
6360 bool flip = endOne == endTwo;
6361 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
6362 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
6363 if (!--remaining) {
6364 break;
6365 }
6366 }
6367 SkASSERT(!remaining);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006368#if DEBUG_ASSEMBLE
6369 for (rIndex = 0; rIndex < count; ++rIndex) {
6370 int s = sLink[rIndex];
6371 int e = eLink[rIndex];
6372 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
6373 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
caryclark@google.comf839c032012-10-26 21:03:50 +00006374 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006375#endif
6376 rIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00006377 do {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006378 bool forward = true;
6379 bool first = true;
6380 int sIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006381 SkASSERT(sIndex != SK_MaxS32);
6382 sLink[rIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006383 int eIndex;
6384 if (sIndex < 0) {
6385 eIndex = sLink[~sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006386 sLink[~sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006387 } else {
6388 eIndex = eLink[sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006389 eLink[sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006390 }
caryclark@google.comaa358312013-01-29 20:28:49 +00006391 SkASSERT(eIndex != SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006392#if DEBUG_ASSEMBLE
6393 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006394 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
6395 eIndex < 0 ? ~eIndex : eIndex);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006396#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006397 do {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006398 outer = runs[rIndex];
6399 const Contour& contour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006400 if (first) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006401 first = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006402 const SkPoint* startPtr = &contour.start();
caryclark@google.comf839c032012-10-26 21:03:50 +00006403 simple.deferredMove(startPtr[0]);
6404 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006405 if (forward) {
6406 contour.toPartialForward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006407 } else {
6408 contour.toPartialBackward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006409 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006410#if DEBUG_ASSEMBLE
6411 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006412 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006413 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
6414#endif
6415 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006416 simple.close();
caryclark@google.comf839c032012-10-26 21:03:50 +00006417 break;
6418 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006419 if (forward) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006420 eIndex = eLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006421 SkASSERT(eIndex != SK_MaxS32);
6422 eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006423 if (eIndex >= 0) {
6424 SkASSERT(sLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006425 sLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006426 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006427 SkASSERT(eLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006428 eLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006429 }
6430 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006431 eIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006432 SkASSERT(eIndex != SK_MaxS32);
6433 sLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006434 if (eIndex >= 0) {
6435 SkASSERT(eLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006436 eLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006437 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006438 SkASSERT(sLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006439 sLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006440 }
6441 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006442 rIndex = eIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006443 if (rIndex < 0) {
6444 forward ^= 1;
6445 rIndex = ~rIndex;
6446 }
6447 } while (true);
6448 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006449 if (sLink[rIndex] != SK_MaxS32) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006450 break;
6451 }
6452 }
6453 } while (rIndex < count);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006454#if DEBUG_ASSEMBLE
6455 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006456 SkASSERT(sLink[rIndex] == SK_MaxS32);
6457 SkASSERT(eLink[rIndex] == SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006458 }
6459#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006460}
6461
6462void simplifyx(const SkPath& path, SkPath& result) {
caryclark@google.comc83c70e2013-02-22 21:50:07 +00006463#if DEBUG_SORT
6464 gDebugSortCount = gDebugSortCountDefault;
6465#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006466 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
caryclark@google.comf839c032012-10-26 21:03:50 +00006467 result.reset();
6468 result.setFillType(SkPath::kEvenOdd_FillType);
6469 PathWrapper simple(result);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006470
6471 // turn path into list of segments
6472 SkTArray<Contour> contours;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006473 EdgeBuilder builder(path, contours);
caryclark@google.com235f56a2012-09-14 14:19:30 +00006474 builder.finish();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006475 SkTDArray<Contour*> contourList;
caryclark@google.com4eeda372012-12-06 21:47:48 +00006476 makeContourList(contours, contourList, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006477 Contour** currentPtr = contourList.begin();
6478 if (!currentPtr) {
6479 return;
6480 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006481 Contour** listEnd = contourList.end();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006482 // find all intersections between segments
6483 do {
6484 Contour** nextPtr = currentPtr;
6485 Contour* current = *currentPtr++;
caryclark@google.comc83c70e2013-02-22 21:50:07 +00006486 if (current->containsCubics()) {
6487 addSelfIntersectTs(current);
6488 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006489 Contour* next;
6490 do {
6491 next = *nextPtr++;
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00006492 } while (addIntersectTs(current, next) && nextPtr != listEnd);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006493 } while (currentPtr != listEnd);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006494 // eat through coincident edges
caryclark@google.com4eeda372012-12-06 21:47:48 +00006495 coincidenceCheck(contourList, 0);
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00006496 fixOtherTIndex(contourList);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006497 sortSegments(contourList);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006498#if DEBUG_ACTIVE_SPANS
6499 debugShowActiveSpans(contourList);
6500#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006501 // construct closed contours
caryclark@google.com3586ece2012-12-27 18:46:58 +00006502 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00006503 : !bridgeXor(contourList, simple))
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006504 { // if some edges could not be resolved, assemble remaining fragments
caryclark@google.comf839c032012-10-26 21:03:50 +00006505 SkPath temp;
6506 temp.setFillType(SkPath::kEvenOdd_FillType);
6507 PathWrapper assembled(temp);
6508 assemble(simple, assembled);
6509 result = *assembled.nativePath();
caryclark@google.com24bec792012-08-20 12:43:57 +00006510 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006511}