blob: f629a1605745584dd1bfb4a32027a7ccbe0afa06 [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.comf9502d72013-02-04 14:06:49 +000034#define FORCE_RELEASE 0 // set force release to 1 for multiple thread -- no debugging
caryclark@google.comfa0588f2012-04-26 21:01:06 +000035
caryclark@google.com31143cf2012-11-09 22:14:19 +000036#if FORCE_RELEASE || defined SK_RELEASE
caryclark@google.com47580692012-07-23 12:14:49 +000037
38const bool gRunTestsInOneThread = false;
39
40#define DEBUG_ACTIVE_SPANS 0
caryclark@google.com4eeda372012-12-06 21:47:48 +000041#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000042#define DEBUG_ADD_INTERSECTING_TS 0
caryclark@google.com47580692012-07-23 12:14:49 +000043#define DEBUG_ADD_T_PAIR 0
caryclark@google.comc899ad92012-08-23 15:24:42 +000044#define DEBUG_ANGLE 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000045#define DEBUG_ASSEMBLE 0
caryclark@google.com47580692012-07-23 12:14:49 +000046#define DEBUG_CONCIDENT 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000047#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000048#define DEBUG_FLOW 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000049#define DEBUG_MARK_DONE 0
caryclark@google.comf839c032012-10-26 21:03:50 +000050#define DEBUG_PATH_CONSTRUCTION 0
caryclark@google.com729e1c42012-11-21 21:36:34 +000051#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000052#define DEBUG_SORT 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000053#define DEBUG_UNSORTABLE 0
caryclark@google.comafe56de2012-07-24 18:11:03 +000054#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000055#define DEBUG_WINDING 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000056#define DEBUG_WINDING_AT_T 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000057
58#else
59
caryclark@google.com47580692012-07-23 12:14:49 +000060const bool gRunTestsInOneThread = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +000061
caryclark@google.comc91dfe42012-10-16 12:06:27 +000062#define DEBUG_ACTIVE_SPANS 1
caryclark@google.com4eeda372012-12-06 21:47:48 +000063#define DEBUG_ACTIVE_SPANS_SHORT_FORM 1
caryclark@google.com6aea33f2012-10-09 14:11:58 +000064#define DEBUG_ADD_INTERSECTING_TS 1
65#define DEBUG_ADD_T_PAIR 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000066#define DEBUG_ANGLE 1
caryclark@google.come7bd5f42012-12-13 19:47:53 +000067#define DEBUG_ASSEMBLE 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000068#define DEBUG_CONCIDENT 1
caryclark@google.com534aa5b2012-08-02 20:08:21 +000069#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000070#define DEBUG_FLOW 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000071#define DEBUG_MARK_DONE 1
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000072#define DEBUG_PATH_CONSTRUCTION 1
caryclark@google.com729e1c42012-11-21 21:36:34 +000073#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000074#define DEBUG_SORT 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000075#define DEBUG_UNSORTABLE 1
caryclark@google.comafe56de2012-07-24 18:11:03 +000076#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000077#define DEBUG_WINDING 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000078#define DEBUG_WINDING_AT_T 1
caryclark@google.comfa0588f2012-04-26 21:01:06 +000079
80#endif
81
caryclark@google.com6aea33f2012-10-09 14:11:58 +000082#define DEBUG_DUMP (DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | DEBUG_PATH_CONSTRUCTION)
caryclark@google.com027de222012-07-12 12:52:50 +000083
caryclark@google.comfa0588f2012-04-26 21:01:06 +000084#if DEBUG_DUMP
85static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000086// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
caryclark@google.comfa0588f2012-04-26 21:01:06 +000087static int gContourID;
88static int gSegmentID;
89#endif
90
caryclark@google.com8dcf1142012-07-02 20:27:02 +000091#ifndef DEBUG_TEST
92#define DEBUG_TEST 0
93#endif
94
caryclark@google.com32546db2012-08-31 20:55:07 +000095#define MAKE_CONST_LINE(line, pts) \
96 const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}
97#define MAKE_CONST_QUAD(quad, pts) \
98 const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
99 {pts[2].fX, pts[2].fY}}
100#define MAKE_CONST_CUBIC(cubic, pts) \
101 const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
102 {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}}
103
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000104static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
105 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000106 MAKE_CONST_LINE(aLine, a);
107 MAKE_CONST_LINE(bLine, b);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000108 return intersect(aLine, bLine, intersections.fT[0], intersections.fT[1]);
109}
110
111static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
112 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000113 MAKE_CONST_QUAD(aQuad, a);
114 MAKE_CONST_LINE(bLine, b);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000115 return intersect(aQuad, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000116}
117
caryclark@google.com32546db2012-08-31 20:55:07 +0000118static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000119 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000120 MAKE_CONST_CUBIC(aCubic, a);
121 MAKE_CONST_LINE(bLine, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000122 return intersect(aCubic, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000123}
124
125static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
126 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000127 MAKE_CONST_QUAD(aQuad, a);
128 MAKE_CONST_QUAD(bQuad, b);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000129#define TRY_QUARTIC_SOLUTION 1
130#if TRY_QUARTIC_SOLUTION
131 intersect2(aQuad, bQuad, intersections);
132#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000133 intersect(aQuad, bQuad, intersections);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000134#endif
caryclark@google.com32546db2012-08-31 20:55:07 +0000135 return intersections.fUsed ? intersections.fUsed : intersections.fCoincidentUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000136}
137
caryclark@google.com73ca6242013-01-17 21:02:47 +0000138#if APPROXIMATE_CUBICS
139static int CubicQuadIntersect(const SkPoint a[4], const SkPoint b[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000140 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000141 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000142 MAKE_CONST_QUAD(bQuad, b);
143 return intersect(aCubic, bQuad, intersections);
144}
145#endif
146
147static int CubicIntersect(const SkPoint a[4], const SkPoint b[4], Intersections& intersections) {
148 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com32546db2012-08-31 20:55:07 +0000149 MAKE_CONST_CUBIC(bCubic, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000150#if APPROXIMATE_CUBICS
151 intersect2(aCubic, bCubic, intersections);
152#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000153 intersect(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000154#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000155 return intersections.fUsed;
156}
157
158static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
159 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000160 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000161 return horizontalIntersect(aLine, left, right, y, flipped, intersections);
162}
163
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000164static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
165 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000166 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000167 return horizontalIntersect(aQuad, left, right, y, flipped, intersections);
168}
169
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000170static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
171 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000172 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000173 return horizontalIntersect(aCubic, left, right, y, flipped, intersections);
174}
175
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000176static int (* const HSegmentIntersect[])(const SkPoint [], SkScalar ,
177 SkScalar , SkScalar , bool , Intersections& ) = {
178 NULL,
179 HLineIntersect,
180 HQuadIntersect,
181 HCubicIntersect
182};
183
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000184static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom,
185 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000186 MAKE_CONST_LINE(aLine, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000187 return verticalIntersect(aLine, top, bottom, x, flipped, intersections);
188}
189
190static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom,
191 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000192 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000193 return verticalIntersect(aQuad, top, bottom, x, flipped, intersections);
194}
195
196static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom,
197 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000198 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000199 return verticalIntersect(aCubic, top, bottom, x, flipped, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000200}
201
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000202static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar ,
203 SkScalar , SkScalar , bool , Intersections& ) = {
204 NULL,
205 VLineIntersect,
206 VQuadIntersect,
207 VCubicIntersect
208};
209
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000210static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000211 MAKE_CONST_LINE(line, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000212 double x, y;
213 xy_at_t(line, t, x, y);
214 out->fX = SkDoubleToScalar(x);
215 out->fY = SkDoubleToScalar(y);
216}
217
caryclark@google.comf9502d72013-02-04 14:06:49 +0000218static void LineXYAtT(const SkPoint a[2], double t, _Point* out) {
219 MAKE_CONST_LINE(line, a);
220 xy_at_t(line, t, out->x, out->y);
221}
222
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000223static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000224 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000225 double x, y;
226 xy_at_t(quad, t, x, y);
227 out->fX = SkDoubleToScalar(x);
228 out->fY = SkDoubleToScalar(y);
229}
230
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000231static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
232 MAKE_CONST_QUAD(quad, a);
233 xy_at_t(quad, t, out->x, out->y);
234}
235
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000236static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000237 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000238 double x, y;
239 xy_at_t(cubic, t, x, y);
240 out->fX = SkDoubleToScalar(x);
241 out->fY = SkDoubleToScalar(y);
242}
243
caryclark@google.comf9502d72013-02-04 14:06:49 +0000244static void CubicXYAtT(const SkPoint a[4], double t, _Point* out) {
245 MAKE_CONST_CUBIC(cubic, a);
246 xy_at_t(cubic, t, out->x, out->y);
247}
248
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000249static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
250 NULL,
251 LineXYAtT,
252 QuadXYAtT,
253 CubicXYAtT
254};
255
caryclark@google.comf9502d72013-02-04 14:06:49 +0000256static void (* const SegmentXYAtT2[])(const SkPoint [], double , _Point* ) = {
257 NULL,
258 LineXYAtT,
259 QuadXYAtT,
260 CubicXYAtT
261};
262
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000263static SkScalar LineXAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000264 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000265 double x;
266 xy_at_t(aLine, t, x, *(double*) 0);
267 return SkDoubleToScalar(x);
268}
269
270static SkScalar QuadXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000271 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000272 double x;
273 xy_at_t(quad, t, x, *(double*) 0);
274 return SkDoubleToScalar(x);
275}
276
277static SkScalar CubicXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000278 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000279 double x;
280 xy_at_t(cubic, t, x, *(double*) 0);
281 return SkDoubleToScalar(x);
282}
283
284static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
285 NULL,
286 LineXAtT,
287 QuadXAtT,
288 CubicXAtT
289};
290
291static SkScalar LineYAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000292 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000293 double y;
294 xy_at_t(aLine, t, *(double*) 0, y);
295 return SkDoubleToScalar(y);
296}
297
298static SkScalar QuadYAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000299 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000300 double y;
301 xy_at_t(quad, t, *(double*) 0, y);
302 return SkDoubleToScalar(y);
303}
304
305static SkScalar CubicYAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000306 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000307 double y;
308 xy_at_t(cubic, t, *(double*) 0, y);
309 return SkDoubleToScalar(y);
310}
311
312static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
313 NULL,
314 LineYAtT,
315 QuadYAtT,
316 CubicYAtT
317};
318
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000319static SkScalar LineDXAtT(const SkPoint a[2], double ) {
320 return a[1].fX - a[0].fX;
321}
322
323static SkScalar QuadDXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000324 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000325 double x = dx_at_t(quad, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000326 return SkDoubleToScalar(x);
327}
328
329static SkScalar CubicDXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000330 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000331 double x = dx_at_t(cubic, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000332 return SkDoubleToScalar(x);
333}
334
335static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
336 NULL,
337 LineDXAtT,
338 QuadDXAtT,
339 CubicDXAtT
340};
341
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000342static SkScalar LineDYAtT(const SkPoint a[2], double ) {
343 return a[1].fY - a[0].fY;
344}
345
346static SkScalar QuadDYAtT(const SkPoint a[3], double t) {
347 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000348 double y = dy_at_t(quad, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000349 return SkDoubleToScalar(y);
350}
351
352static SkScalar CubicDYAtT(const SkPoint a[4], double t) {
353 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000354 double y = dy_at_t(cubic, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000355 return SkDoubleToScalar(y);
356}
357
358static SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = {
359 NULL,
360 LineDYAtT,
361 QuadDYAtT,
362 CubicDYAtT
363};
364
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000365static void LineSubDivide(const SkPoint a[2], double startT, double endT,
366 SkPoint sub[2]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000367 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000368 _Line dst;
369 sub_divide(aLine, startT, endT, dst);
370 sub[0].fX = SkDoubleToScalar(dst[0].x);
371 sub[0].fY = SkDoubleToScalar(dst[0].y);
372 sub[1].fX = SkDoubleToScalar(dst[1].x);
373 sub[1].fY = SkDoubleToScalar(dst[1].y);
374}
375
376static void QuadSubDivide(const SkPoint a[3], double startT, double endT,
377 SkPoint sub[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000378 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000379 Quadratic dst;
380 sub_divide(aQuad, startT, endT, dst);
381 sub[0].fX = SkDoubleToScalar(dst[0].x);
382 sub[0].fY = SkDoubleToScalar(dst[0].y);
383 sub[1].fX = SkDoubleToScalar(dst[1].x);
384 sub[1].fY = SkDoubleToScalar(dst[1].y);
385 sub[2].fX = SkDoubleToScalar(dst[2].x);
386 sub[2].fY = SkDoubleToScalar(dst[2].y);
387}
388
389static void CubicSubDivide(const SkPoint a[4], double startT, double endT,
390 SkPoint sub[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000391 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000392 Cubic dst;
393 sub_divide(aCubic, startT, endT, dst);
394 sub[0].fX = SkDoubleToScalar(dst[0].x);
395 sub[0].fY = SkDoubleToScalar(dst[0].y);
396 sub[1].fX = SkDoubleToScalar(dst[1].x);
397 sub[1].fY = SkDoubleToScalar(dst[1].y);
398 sub[2].fX = SkDoubleToScalar(dst[2].x);
399 sub[2].fY = SkDoubleToScalar(dst[2].y);
400 sub[3].fX = SkDoubleToScalar(dst[3].x);
401 sub[3].fY = SkDoubleToScalar(dst[3].y);
402}
403
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000404static void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
405 SkPoint []) = {
406 NULL,
407 LineSubDivide,
408 QuadSubDivide,
409 CubicSubDivide
410};
411
caryclark@google.comaa358312013-01-29 20:28:49 +0000412static void LineSubDivideHD(const SkPoint a[2], double startT, double endT, _Line& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000413 MAKE_CONST_LINE(aLine, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000414 sub_divide(aLine, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000415}
416
caryclark@google.comaa358312013-01-29 20:28:49 +0000417static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT, Quadratic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000418 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000419 sub_divide(aQuad, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000420}
421
caryclark@google.comaa358312013-01-29 20:28:49 +0000422static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT, Cubic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000423 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000424 sub_divide(aCubic, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000425}
426
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000427#if DEBUG_UNUSED
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000428static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
429 SkRect& bounds) {
430 SkPoint dst[3];
431 QuadSubDivide(a, startT, endT, dst);
432 bounds.fLeft = bounds.fRight = dst[0].fX;
433 bounds.fTop = bounds.fBottom = dst[0].fY;
434 for (int index = 1; index < 3; ++index) {
435 bounds.growToInclude(dst[index].fX, dst[index].fY);
436 }
437}
438
439static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
440 SkRect& bounds) {
441 SkPoint dst[4];
442 CubicSubDivide(a, startT, endT, dst);
443 bounds.fLeft = bounds.fRight = dst[0].fX;
444 bounds.fTop = bounds.fBottom = dst[0].fY;
445 for (int index = 1; index < 4; ++index) {
446 bounds.growToInclude(dst[index].fX, dst[index].fY);
447 }
448}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000449#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000450
caryclark@google.com15fa1382012-05-07 20:49:36 +0000451static SkPath::Verb QuadReduceOrder(const SkPoint a[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000452 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000453 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000454 Quadratic dst;
455 int order = reduceOrder(aQuad, dst);
caryclark@google.com24bec792012-08-20 12:43:57 +0000456 if (order == 2) { // quad became line
457 for (int index = 0; index < order; ++index) {
458 SkPoint* pt = reducePts.append();
459 pt->fX = SkDoubleToScalar(dst[index].x);
460 pt->fY = SkDoubleToScalar(dst[index].y);
461 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000462 }
463 return (SkPath::Verb) (order - 1);
464}
465
466static SkPath::Verb CubicReduceOrder(const SkPoint a[4],
467 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000468 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000469 Cubic dst;
470 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed);
caryclark@google.com24bec792012-08-20 12:43:57 +0000471 if (order == 2 || order == 3) { // cubic became line or quad
472 for (int index = 0; index < order; ++index) {
473 SkPoint* pt = reducePts.append();
474 pt->fX = SkDoubleToScalar(dst[index].x);
475 pt->fY = SkDoubleToScalar(dst[index].y);
476 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000477 }
478 return (SkPath::Verb) (order - 1);
479}
480
caryclark@google.com15fa1382012-05-07 20:49:36 +0000481static bool QuadIsLinear(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000482 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000483 return isLinear(aQuad, 0, 2);
484}
485
486static bool CubicIsLinear(const SkPoint a[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000487 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000488 return isLinear(aCubic, 0, 3);
489}
490
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000491static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000492 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000493 double x[2];
494 xy_at_t(aLine, startT, x[0], *(double*) 0);
caryclark@google.com495f8e42012-05-31 13:13:11 +0000495 xy_at_t(aLine, endT, x[1], *(double*) 0);
496 return SkMinScalar((float) x[0], (float) x[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000497}
498
499static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000500 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000501 return (float) leftMostT(aQuad, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000502}
503
504static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000505 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000506 return (float) leftMostT(aCubic, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000507}
508
509static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
510 NULL,
511 LineLeftMost,
512 QuadLeftMost,
513 CubicLeftMost
514};
515
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000516#if 0 // currently unused
caryclark@google.com235f56a2012-09-14 14:19:30 +0000517static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
518 Intersections& intersections) {
519 MAKE_CONST_QUAD(aQuad, a);
520 MAKE_CONST_LINE(bLine, b);
521 return intersectRay(aQuad, bLine, intersections);
522}
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000523#endif
524
caryclark@google.comf9502d72013-02-04 14:06:49 +0000525static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000526 MAKE_CONST_QUAD(aQuad, a);
527 return intersectRay(aQuad, bLine, intersections);
528}
caryclark@google.com235f56a2012-09-14 14:19:30 +0000529
caryclark@google.comf9502d72013-02-04 14:06:49 +0000530static int CubicRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
531 MAKE_CONST_CUBIC(aCubic, a);
532 return intersectRay(aCubic, bLine, intersections);
533}
534
535static int (* const SegmentRayIntersect[])(const SkPoint [], const _Line& , Intersections&) = {
536 NULL,
537 NULL,
538 QuadRayIntersect,
539 CubicRayIntersect
540};
541
542
543
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000544static bool LineVertical(const SkPoint a[2], double startT, double endT) {
545 MAKE_CONST_LINE(aLine, a);
546 double x[2];
547 xy_at_t(aLine, startT, x[0], *(double*) 0);
548 xy_at_t(aLine, endT, x[1], *(double*) 0);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000549 return AlmostEqualUlps((float) x[0], (float) x[1]);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000550}
551
552static bool QuadVertical(const SkPoint a[3], double startT, double endT) {
553 SkPoint dst[3];
554 QuadSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000555 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000556}
557
558static bool CubicVertical(const SkPoint a[4], double startT, double endT) {
559 SkPoint dst[4];
560 CubicSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000561 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX)
562 && AlmostEqualUlps(dst[2].fX, dst[3].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000563}
564
565static bool (* const SegmentVertical[])(const SkPoint [], double , double) = {
566 NULL,
567 LineVertical,
568 QuadVertical,
569 CubicVertical
570};
571
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000572class Segment;
573
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000574struct Span {
575 Segment* fOther;
576 mutable SkPoint fPt; // lazily computed as needed
577 double fT;
578 double fOtherT; // value at fOther[fOtherIndex].fT
579 int fOtherIndex; // can't be used during intersection
caryclark@google.com31143cf2012-11-09 22:14:19 +0000580 int fWindSum; // accumulated from contours surrounding this one.
581 int fOppSum; // for binary operators: the opposite winding sum
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000582 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
caryclark@google.com57cff8d2012-11-14 21:14:56 +0000583 int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000584 bool fDone; // if set, this span to next higher T has been processed
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000585 bool fUnsortableStart; // set when start is part of an unsortable pair
586 bool fUnsortableEnd; // set when end is part of an unsortable pair
caryclark@google.comf839c032012-10-26 21:03:50 +0000587 bool fTiny; // if set, span may still be considered once for edge following
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000588};
589
caryclark@google.com15fa1382012-05-07 20:49:36 +0000590// sorting angles
591// given angles of {dx dy ddx ddy dddx dddy} sort them
592class Angle {
593public:
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000594 // FIXME: this is bogus for quads and cubics
595 // if the quads and cubics' line from end pt to ctrl pt are coincident,
596 // there's no obvious way to determine the curve ordering from the
597 // derivatives alone. In particular, if one quadratic's coincident tangent
598 // is longer than the other curve, the final control point can place the
599 // longer curve on either side of the shorter one.
600 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
601 // may provide some help, but nothing has been figured out yet.
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000602
caryclark@google.com32546db2012-08-31 20:55:07 +0000603 /*(
604 for quads and cubics, set up a parameterized line (e.g. LineParameters )
605 for points [0] to [1]. See if point [2] is on that line, or on one side
606 or the other. If it both quads' end points are on the same side, choose
607 the shorter tangent. If the tangents are equal, choose the better second
608 tangent angle
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000609
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000610 maybe I could set up LineParameters lazily
caryclark@google.com32546db2012-08-31 20:55:07 +0000611 */
caryclark@google.com15fa1382012-05-07 20:49:36 +0000612 bool operator<(const Angle& rh) const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000613 double y = dy();
614 double ry = rh.dy();
615 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
616 return y < 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000617 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000618 double x = dx();
619 double rx = rh.dx();
620 if (y == 0 && ry == 0 && x * rx < 0) {
621 return x < rx;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000622 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000623 double x_ry = x * ry;
624 double rx_y = rx * y;
625 double cmp = x_ry - rx_y;
caryclark@google.comc899ad92012-08-23 15:24:42 +0000626 if (!approximately_zero(cmp)) {
caryclark@google.com15fa1382012-05-07 20:49:36 +0000627 return cmp < 0;
628 }
caryclark@google.comd1688742012-09-18 20:08:37 +0000629 if (approximately_zero(x_ry) && approximately_zero(rx_y)
630 && !approximately_zero_squared(cmp)) {
631 return cmp < 0;
632 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000633 // at this point, the initial tangent line is coincident
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000634 // see if edges curl away from each other
caryclark@google.com31143cf2012-11-09 22:14:19 +0000635 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
636 || !approximately_zero(rh.fSide))) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000637 // FIXME: running demo will trigger this assertion
638 // (don't know if commenting out will trigger further assertion or not)
639 // commenting it out allows demo to run in release, though
640 // SkASSERT(fSide != rh.fSide);
641 return fSide < rh.fSide;
642 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000643 // see if either curve can be lengthened and try the tangent compare again
644 if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
645 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
646 Angle longer = *this;
647 Angle rhLonger = rh;
648 if (longer.lengthen() | rhLonger.lengthen()) {
649 return longer < rhLonger;
650 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000651 #if 0
caryclark@google.coma461ff02012-10-11 12:54:23 +0000652 // what if we extend in the other direction?
653 longer = *this;
654 rhLonger = rh;
655 if (longer.reverseLengthen() | rhLonger.reverseLengthen()) {
656 return longer < rhLonger;
657 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000658 #endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000659 }
caryclark@google.com185c7c42012-10-19 18:26:24 +0000660 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
caryclark@google.com31143cf2012-11-09 22:14:19 +0000661 || (rh.fVerb == SkPath::kLine_Verb
662 && approximately_zero(rx) && approximately_zero(ry))) {
caryclark@google.com185c7c42012-10-19 18:26:24 +0000663 // See general unsortable comment below. This case can happen when
664 // one line has a non-zero change in t but no change in x and y.
665 fUnsortable = true;
666 rh.fUnsortable = true;
667 return this < &rh; // even with no solution, return a stable sort
668 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000669 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
670 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
671 fUnsortable = true;
672 rh.fUnsortable = true;
673 return this < &rh; // even with no solution, return a stable sort
674 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000675 SkASSERT(fVerb >= SkPath::kQuad_Verb);
676 SkASSERT(rh.fVerb >= SkPath::kQuad_Verb);
skia.committer@gmail.comc1ad0222012-09-19 02:01:47 +0000677 // FIXME: until I can think of something better, project a ray from the
caryclark@google.comd1688742012-09-18 20:08:37 +0000678 // end of the shorter tangent to midway between the end points
679 // through both curves and use the resulting angle to sort
caryclark@google.com235f56a2012-09-14 14:19:30 +0000680 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
681 double len = fTangent1.normalSquared();
682 double rlen = rh.fTangent1.normalSquared();
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000683 _Line ray;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000684 Intersections i, ri;
caryclark@google.comd1688742012-09-18 20:08:37 +0000685 int roots, rroots;
686 bool flip = false;
687 do {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000688 bool useThis = (len < rlen) ^ flip;
689 const Cubic& part = useThis ? fCurvePart : rh.fCurvePart;
690 SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb;
691 ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ?
692 part[2] : part[1];
693 ray[1].x = (part[0].x + part[partVerb].x) / 2;
694 ray[1].y = (part[0].y + part[partVerb].y) / 2;
caryclark@google.comd1688742012-09-18 20:08:37 +0000695 SkASSERT(ray[0] != ray[1]);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000696 roots = (*SegmentRayIntersect[fVerb])(fPts, ray, i);
697 rroots = (*SegmentRayIntersect[rh.fVerb])(rh.fPts, ray, ri);
caryclark@google.comd1688742012-09-18 20:08:37 +0000698 } while ((roots == 0 || rroots == 0) && (flip ^= true));
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000699 if (roots == 0 || rroots == 0) {
700 // FIXME: we don't have a solution in this case. The interim solution
701 // is to mark the edges as unsortable, exclude them from this and
702 // future computations, and allow the returned path to be fragmented
703 fUnsortable = true;
704 rh.fUnsortable = true;
705 return this < &rh; // even with no solution, return a stable sort
706 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000707 _Point loc;
708 double best = SK_ScalarInfinity;
709 double dx, dy, dist;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000710 int index;
711 for (index = 0; index < roots; ++index) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000712 (*SegmentXYAtT2[fVerb])(fPts, i.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000713 dx = loc.x - ray[0].x;
714 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000715 dist = dx * dx + dy * dy;
716 if (best > dist) {
717 best = dist;
718 }
719 }
720 for (index = 0; index < rroots; ++index) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000721 (*SegmentXYAtT2[rh.fVerb])(rh.fPts, ri.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000722 dx = loc.x - ray[0].x;
723 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000724 dist = dx * dx + dy * dy;
725 if (best > dist) {
726 return fSide < 0;
727 }
728 }
729 return fSide > 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000730 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000731
caryclark@google.com47580692012-07-23 12:14:49 +0000732 double dx() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000733 return fTangent1.dx();
caryclark@google.com47580692012-07-23 12:14:49 +0000734 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000735
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000736 double dy() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000737 return fTangent1.dy();
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000738 }
739
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000740 int end() const {
741 return fEnd;
742 }
743
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000744 bool isHorizontal() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000745 return dy() == 0 && fVerb == SkPath::kLine_Verb;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000746 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000747
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000748 bool lengthen() {
749 int newEnd = fEnd;
750 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
751 fEnd = newEnd;
752 setSpans();
753 return true;
754 }
755 return false;
756 }
757
caryclark@google.coma461ff02012-10-11 12:54:23 +0000758 bool reverseLengthen() {
759 if (fReversed) {
760 return false;
761 }
762 int newEnd = fStart;
763 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
764 fEnd = newEnd;
765 fReversed = true;
766 setSpans();
767 return true;
768 }
769 return false;
770 }
771
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000772 void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000773 int start, int end, const SkTDArray<Span>& spans) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000774 fSegment = segment;
775 fStart = start;
776 fEnd = end;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000777 fPts = orig;
778 fVerb = verb;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000779 fSpans = &spans;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000780 fReversed = false;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000781 fUnsortable = false;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000782 setSpans();
783 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000784
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000785
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000786 void setSpans() {
787 double startT = (*fSpans)[fStart].fT;
788 double endT = (*fSpans)[fEnd].fT;
789 switch (fVerb) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000790 case SkPath::kLine_Verb:
791 _Line l;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000792 LineSubDivideHD(fPts, startT, endT, l);
caryclark@google.com32546db2012-08-31 20:55:07 +0000793 // OPTIMIZATION: for pure line compares, we never need fTangent1.c
794 fTangent1.lineEndPoints(l);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000795 fSide = 0;
caryclark@google.com32546db2012-08-31 20:55:07 +0000796 break;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000797 case SkPath::kQuad_Verb: {
798 Quadratic& quad = (Quadratic&)fCurvePart;
799 QuadSubDivideHD(fPts, startT, endT, quad);
800 fTangent1.quadEndPoints(quad, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000801 #if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
802 if (dx() == 0 && dy() == 0) {
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000803 SkDebugf("*** %s quad is line\n", __FUNCTION__);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000804 fTangent1.quadEndPoints(quad);
caryclark@google.comaa358312013-01-29 20:28:49 +0000805 }
806 #endif
caryclark@google.comf9502d72013-02-04 14:06:49 +0000807 fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- compare sign only
808 } break;
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000809 case SkPath::kCubic_Verb: {
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000810 int nextC = 2;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000811 CubicSubDivideHD(fPts, startT, endT, fCurvePart);
812 fTangent1.cubicEndPoints(fCurvePart, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000813 if (dx() == 0 && dy() == 0) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000814 fTangent1.cubicEndPoints(fCurvePart, 0, 2);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000815 nextC = 3;
caryclark@google.comaa358312013-01-29 20:28:49 +0000816 #if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
817 if (dx() == 0 && dy() == 0) {
818 SkDebugf("*** %s cubic is line\n");
caryclark@google.comf9502d72013-02-04 14:06:49 +0000819 fTangent1.cubicEndPoints(fCurvePart, 0, 3);
caryclark@google.comaa358312013-01-29 20:28:49 +0000820 }
821 #endif
822 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000823 fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign only
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000824 if (nextC == 2 && approximately_zero(fSide)) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000825 fSide = -fTangent1.pointDistance(fCurvePart[3]);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000826 }
827 } break;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000828 default:
829 SkASSERT(0);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000830 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000831 fUnsortable = dx() == 0 && dy() == 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000832 if (fUnsortable) {
833 return;
834 }
835 SkASSERT(fStart != fEnd);
836 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
837 for (int index = fStart; index != fEnd; index += step) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000838#if 1
839 const Span& thisSpan = (*fSpans)[index];
840 const Span& nextSpan = (*fSpans)[index + step];
841 if (thisSpan.fTiny || thisSpan.fT == nextSpan.fT) {
842 continue;
caryclark@google.comf839c032012-10-26 21:03:50 +0000843 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000844 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
845#if DEBUG_UNSORTABLE
846 if (fUnsortable) {
847 SkPoint iPt, ePt;
848 (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt);
849 (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt);
850 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
851 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
852 }
853#endif
854 return;
855#else
856 if ((*fSpans)[index].fUnsortableStart) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000857 fUnsortable = true;
858 return;
859 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000860#endif
caryclark@google.comf839c032012-10-26 21:03:50 +0000861 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000862#if 1
863#if DEBUG_UNSORTABLE
864 SkPoint iPt, ePt;
865 (*SegmentXYAtT[fVerb])(fPts, startT, &iPt);
866 (*SegmentXYAtT[fVerb])(fPts, endT, &ePt);
867 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
868 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
869#endif
870 fUnsortable = true;
871#endif
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000872 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000873
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000874 Segment* segment() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000875 return const_cast<Segment*>(fSegment);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000876 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000877
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000878 int sign() const {
caryclark@google.com495f8e42012-05-31 13:13:11 +0000879 return SkSign32(fStart - fEnd);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000880 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000881
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000882 const SkTDArray<Span>* spans() const {
883 return fSpans;
884 }
885
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000886 int start() const {
887 return fStart;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000888 }
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +0000889
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000890 bool unsortable() const {
891 return fUnsortable;
892 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000893
caryclark@google.comc899ad92012-08-23 15:24:42 +0000894#if DEBUG_ANGLE
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000895 const SkPoint* pts() const {
896 return fPts;
897 }
898
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000899 SkPath::Verb verb() const {
900 return fVerb;
901 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000902
caryclark@google.comc899ad92012-08-23 15:24:42 +0000903 void debugShow(const SkPoint& a) const {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000904 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
caryclark@google.comc899ad92012-08-23 15:24:42 +0000905 }
906#endif
907
caryclark@google.com15fa1382012-05-07 20:49:36 +0000908private:
caryclark@google.com235f56a2012-09-14 14:19:30 +0000909 const SkPoint* fPts;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000910 Cubic fCurvePart;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000911 SkPath::Verb fVerb;
912 double fSide;
913 LineParameters fTangent1;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000914 const SkTDArray<Span>* fSpans;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000915 const Segment* fSegment;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000916 int fStart;
917 int fEnd;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000918 bool fReversed;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000919 mutable bool fUnsortable; // this alone is editable by the less than operator
caryclark@google.com15fa1382012-05-07 20:49:36 +0000920};
921
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000922// Bounds, unlike Rect, does not consider a line to be empty.
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000923struct Bounds : public SkRect {
924 static bool Intersects(const Bounds& a, const Bounds& b) {
925 return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
926 a.fTop <= b.fBottom && b.fTop <= a.fBottom;
927 }
928
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000929 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
930 if (left < fLeft) {
931 fLeft = left;
932 }
933 if (top < fTop) {
934 fTop = top;
935 }
936 if (right > fRight) {
937 fRight = right;
938 }
939 if (bottom > fBottom) {
940 fBottom = bottom;
941 }
942 }
943
944 void add(const Bounds& toAdd) {
945 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
946 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000947
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000948 void add(const SkPoint& pt) {
949 if (pt.fX < fLeft) fLeft = pt.fX;
950 if (pt.fY < fTop) fTop = pt.fY;
951 if (pt.fX > fRight) fRight = pt.fX;
952 if (pt.fY > fBottom) fBottom = pt.fY;
953 }
954
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000955 bool isEmpty() {
956 return fLeft > fRight || fTop > fBottom
caryclark@google.com235f56a2012-09-14 14:19:30 +0000957 || (fLeft == fRight && fTop == fBottom)
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000958 || isnan(fLeft) || isnan(fRight)
959 || isnan(fTop) || isnan(fBottom);
960 }
961
962 void setCubicBounds(const SkPoint a[4]) {
963 _Rect dRect;
caryclark@google.com32546db2012-08-31 20:55:07 +0000964 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000965 dRect.setBounds(cubic);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000966 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
967 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000968 }
969
970 void setQuadBounds(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000971 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000972 _Rect dRect;
973 dRect.setBounds(quad);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000974 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
975 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000976 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000977
978 void setPoint(const SkPoint& pt) {
979 fLeft = fRight = pt.fX;
980 fTop = fBottom = pt.fY;
981 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000982};
983
caryclark@google.com7ba591e2012-11-20 14:21:54 +0000984// OPTIMIZATION: does the following also work, and is it any faster?
985// return outerWinding * innerWinding > 0
986// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
caryclark@google.com2ddff932012-08-07 21:25:27 +0000987static bool useInnerWinding(int outerWinding, int innerWinding) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000988 // SkASSERT(outerWinding != innerWinding);
caryclark@google.com2ddff932012-08-07 21:25:27 +0000989 int absOut = abs(outerWinding);
990 int absIn = abs(innerWinding);
991 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
992 if (outerWinding * innerWinding < 0) {
993#if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +0000994 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
caryclark@google.com2ddff932012-08-07 21:25:27 +0000995 outerWinding, innerWinding, result ? "true" : "false");
996#endif
997 }
998 return result;
999}
1000
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001001#define F (false) // discard the edge
1002#define T (true) // keep the edge
1003
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001004static const bool gUnaryActiveEdge[2][2] = {
1005// from=0 from=1
1006// to=0,1 to=0,1
1007 {F, T}, {T, F},
1008};
1009
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001010static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
1011// miFrom=0 miFrom=1
1012// miTo=0 miTo=1 miTo=0 miTo=1
1013// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
1014// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
1015 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
1016 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
1017 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
1018 {{{{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 +00001019};
1020
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001021#undef F
1022#undef T
caryclark@google.com235f56a2012-09-14 14:19:30 +00001023
caryclark@google.comf839c032012-10-26 21:03:50 +00001024// wrap path to keep track of whether the contour is initialized and non-empty
1025class PathWrapper {
1026public:
1027 PathWrapper(SkPath& path)
1028 : fPathPtr(&path)
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001029 , fCloses(0)
1030 , fMoves(0)
caryclark@google.comf839c032012-10-26 21:03:50 +00001031 {
1032 init();
1033 }
1034
1035 void close() {
1036 if (!fHasMove) {
1037 return;
1038 }
1039 bool callClose = isClosed();
1040 lineTo();
1041 if (fEmpty) {
1042 return;
1043 }
1044 if (callClose) {
1045 #if DEBUG_PATH_CONSTRUCTION
1046 SkDebugf("path.close();\n");
1047 #endif
1048 fPathPtr->close();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001049 fCloses++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001050 }
1051 init();
1052 }
1053
1054 void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
1055 lineTo();
1056 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001057 fDefer[1] = pt3;
1058 nudge();
1059 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001060#if DEBUG_PATH_CONSTRUCTION
1061 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001062 pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001063#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001064 fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001065 fEmpty = false;
1066 }
1067
1068 void deferredLine(const SkPoint& pt) {
1069 if (pt == fDefer[1]) {
1070 return;
1071 }
1072 if (changedSlopes(pt)) {
1073 lineTo();
1074 fDefer[0] = fDefer[1];
1075 }
1076 fDefer[1] = pt;
1077 }
1078
1079 void deferredMove(const SkPoint& pt) {
1080 fMoved = true;
1081 fHasMove = true;
1082 fEmpty = true;
1083 fDefer[0] = fDefer[1] = pt;
1084 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001085
caryclark@google.comf839c032012-10-26 21:03:50 +00001086 void deferredMoveLine(const SkPoint& pt) {
1087 if (!fHasMove) {
1088 deferredMove(pt);
1089 }
1090 deferredLine(pt);
1091 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001092
caryclark@google.comf839c032012-10-26 21:03:50 +00001093 bool hasMove() const {
1094 return fHasMove;
1095 }
1096
1097 void init() {
1098 fEmpty = true;
1099 fHasMove = false;
1100 fMoved = false;
1101 }
1102
1103 bool isClosed() const {
1104 return !fEmpty && fFirstPt == fDefer[1];
1105 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001106
caryclark@google.comf839c032012-10-26 21:03:50 +00001107 void lineTo() {
1108 if (fDefer[0] == fDefer[1]) {
1109 return;
1110 }
1111 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001112 nudge();
caryclark@google.comf839c032012-10-26 21:03:50 +00001113 fEmpty = false;
1114#if DEBUG_PATH_CONSTRUCTION
1115 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
1116#endif
1117 fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
1118 fDefer[0] = fDefer[1];
1119 }
1120
1121 const SkPath* nativePath() const {
1122 return fPathPtr;
1123 }
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +00001124
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001125 void nudge() {
1126 if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX)
1127 || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) {
1128 return;
1129 }
1130 fDefer[1] = fFirstPt;
1131 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001132
1133 void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
1134 lineTo();
1135 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001136 fDefer[1] = pt2;
1137 nudge();
1138 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001139#if DEBUG_PATH_CONSTRUCTION
1140 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001141 pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001142#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001143 fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001144 fEmpty = false;
1145 }
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00001146
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001147 bool someAssemblyRequired() const {
1148 return fCloses < fMoves;
1149 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001150
1151protected:
1152 bool changedSlopes(const SkPoint& pt) const {
1153 if (fDefer[0] == fDefer[1]) {
1154 return false;
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001155 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001156 SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
1157 SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
1158 SkScalar lineDx = pt.fX - fDefer[1].fX;
1159 SkScalar lineDy = pt.fY - fDefer[1].fY;
1160 return deferDx * lineDy != deferDy * lineDx;
1161 }
1162
1163 void moveTo() {
1164 if (!fMoved) {
1165 return;
1166 }
1167 fFirstPt = fDefer[0];
1168#if DEBUG_PATH_CONSTRUCTION
1169 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
1170#endif
1171 fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
1172 fMoved = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001173 fMoves++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001174 }
1175
1176private:
1177 SkPath* fPathPtr;
1178 SkPoint fDefer[2];
1179 SkPoint fFirstPt;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001180 int fCloses;
1181 int fMoves;
caryclark@google.comf839c032012-10-26 21:03:50 +00001182 bool fEmpty;
1183 bool fHasMove;
1184 bool fMoved;
1185};
1186
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001187class Segment {
1188public:
1189 Segment() {
1190#if DEBUG_DUMP
1191 fID = ++gSegmentID;
1192#endif
1193 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00001194
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001195 bool operator<(const Segment& rh) const {
1196 return fBounds.fTop < rh.fBounds.fTop;
1197 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001198
caryclark@google.com4eeda372012-12-06 21:47:48 +00001199 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001200 if (activeAngleInner(index, done, angles)) {
1201 return true;
1202 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001203 int lesser = index;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001204 while (--lesser >= 0 && equalPoints(index, lesser)) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001205 if (activeAngleOther(lesser, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001206 return true;
1207 }
1208 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001209 lesser = index;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001210 do {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001211 if (activeAngleOther(index, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001212 return true;
1213 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001214 } while (++index < fTs.count() && equalPoints(index, lesser));
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001215 return false;
1216 }
1217
caryclark@google.com4eeda372012-12-06 21:47:48 +00001218 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001219 Span* span = &fTs[index];
1220 Segment* other = span->fOther;
1221 int oIndex = span->fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001222 return other->activeAngleInner(oIndex, done, angles);
1223 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001224
caryclark@google.com4eeda372012-12-06 21:47:48 +00001225 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001226 int next = nextExactSpan(index, 1);
caryclark@google.com9764cc62012-07-12 19:29:45 +00001227 if (next > 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001228 Span& upSpan = fTs[index];
1229 if (upSpan.fWindValue || upSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001230 addAngle(angles, index, next);
caryclark@google.comf839c032012-10-26 21:03:50 +00001231 if (upSpan.fDone || upSpan.fUnsortableEnd) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001232 done++;
1233 } else if (upSpan.fWindSum != SK_MinS32) {
1234 return true;
1235 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001236 } else if (!upSpan.fDone) {
1237 upSpan.fDone = true;
1238 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001239 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001240 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001241 int prev = nextExactSpan(index, -1);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001242 // edge leading into junction
caryclark@google.com9764cc62012-07-12 19:29:45 +00001243 if (prev >= 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001244 Span& downSpan = fTs[prev];
1245 if (downSpan.fWindValue || downSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001246 addAngle(angles, index, prev);
1247 if (downSpan.fDone) {
1248 done++;
1249 } else if (downSpan.fWindSum != SK_MinS32) {
1250 return true;
1251 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001252 } else if (!downSpan.fDone) {
1253 downSpan.fDone = true;
1254 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001255 }
1256 }
1257 return false;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001258 }
1259
caryclark@google.comf839c032012-10-26 21:03:50 +00001260 void activeLeftTop(SkPoint& result) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001261 SkASSERT(!done());
1262 int count = fTs.count();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001263 result.fX = result.fY = SK_ScalarMax;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001264 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00001265 bool lastUnsortable = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001266 for (int index = 0; index < count; ++index) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001267 const Span& span = fTs[index];
1268 if (span.fUnsortableStart | lastUnsortable) {
1269 goto next;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001270 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001271 if (!span.fDone | !lastDone) {
1272 const SkPoint& xy = xyAtT(index);
1273 if (result.fY < xy.fY) {
1274 goto next;
1275 }
1276 if (result.fY == xy.fY && result.fX < xy.fX) {
1277 goto next;
1278 }
1279 result = xy;
1280 }
1281 next:
1282 lastDone = span.fDone;
1283 lastUnsortable = span.fUnsortableEnd;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001284 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001285 }
1286
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001287 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
1288 int sumMiWinding = updateWinding(endIndex, index);
1289 int sumSuWinding = updateOppWinding(endIndex, index);
1290 if (fOperand) {
1291 SkTSwap<int>(sumMiWinding, sumSuWinding);
1292 }
1293 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1294 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001295 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001296 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001297
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001298 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00001299 int& sumMiWinding, int& sumSuWinding,
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001300 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
1301 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1302 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001303 bool miFrom;
1304 bool miTo;
1305 bool suFrom;
1306 bool suTo;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001307 if (operand()) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001308 miFrom = (oppMaxWinding & xorMiMask) != 0;
1309 miTo = (oppSumWinding & xorMiMask) != 0;
1310 suFrom = (maxWinding & xorSuMask) != 0;
1311 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001312 } else {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001313 miFrom = (maxWinding & xorMiMask) != 0;
1314 miTo = (sumWinding & xorMiMask) != 0;
1315 suFrom = (oppMaxWinding & xorSuMask) != 0;
1316 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001317 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001318 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
1319 SkASSERT(result != -1);
1320 return result;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001321 }
1322
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001323 bool activeWinding(int index, int endIndex) {
1324 int sumWinding = updateWinding(endIndex, index);
1325 int maxWinding;
1326 return activeWinding(index, endIndex, maxWinding, sumWinding);
1327 }
1328
1329 bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
1330 setUpWinding(index, endIndex, maxWinding, sumWinding);
1331 bool from = maxWinding != 0;
1332 bool to = sumWinding != 0;
1333 bool result = gUnaryActiveEdge[from][to];
1334 SkASSERT(result != -1);
1335 return result;
1336 }
1337
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001338 void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001339 SkASSERT(start != end);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001340 Angle* angle = angles.append();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001341#if DEBUG_ANGLE
caryclark@google.com31143cf2012-11-09 22:14:19 +00001342 if (angles.count() > 1 && !fTs[start].fTiny) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001343 SkPoint angle0Pt, newPt;
1344 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
1345 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
1346 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
caryclark@google.com6d0032a2013-01-04 19:41:13 +00001347 SkASSERT(AlmostEqualUlps(angle0Pt.fX, newPt.fX));
1348 SkASSERT(AlmostEqualUlps(angle0Pt.fY, newPt.fY));
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001349 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001350#endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001351 angle->set(fPts, fVerb, this, start, end, fTs);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001352 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001353
caryclark@google.com2ddff932012-08-07 21:25:27 +00001354 void addCancelOutsides(double tStart, double oStart, Segment& other,
caryclark@google.comcc905052012-07-25 20:59:42 +00001355 double oEnd) {
1356 int tIndex = -1;
1357 int tCount = fTs.count();
1358 int oIndex = -1;
1359 int oCount = other.fTs.count();
caryclark@google.comcc905052012-07-25 20:59:42 +00001360 do {
1361 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001362 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001363 int tIndexStart = tIndex;
1364 do {
1365 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001366 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001367 int oIndexStart = oIndex;
1368 double nextT;
1369 do {
1370 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001371 } while (nextT < 1 && approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001372 double oNextT;
1373 do {
1374 oNextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001375 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001376 // at this point, spans before and after are at:
1377 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1378 // if tIndexStart == 0, no prior span
1379 // if nextT == 1, no following span
rmistry@google.comd6176b02012-08-23 18:14:13 +00001380
caryclark@google.comcc905052012-07-25 20:59:42 +00001381 // advance the span with zero winding
1382 // if the following span exists (not past the end, non-zero winding)
1383 // connect the two edges
1384 if (!fTs[tIndexStart].fWindValue) {
1385 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1386 #if DEBUG_CONCIDENT
1387 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1388 __FUNCTION__, fID, other.fID, tIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001389 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
1390 xyAtT(tIndexStart).fY);
caryclark@google.comcc905052012-07-25 20:59:42 +00001391 #endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001392 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001393 }
1394 if (nextT < 1 && fTs[tIndex].fWindValue) {
1395 #if DEBUG_CONCIDENT
1396 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1397 __FUNCTION__, fID, other.fID, tIndex,
1398 fTs[tIndex].fT, xyAtT(tIndex).fX,
1399 xyAtT(tIndex).fY);
1400 #endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001401 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001402 }
1403 } else {
1404 SkASSERT(!other.fTs[oIndexStart].fWindValue);
1405 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1406 #if DEBUG_CONCIDENT
1407 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1408 __FUNCTION__, fID, other.fID, oIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001409 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
1410 other.xyAtT(oIndexStart).fY);
1411 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
caryclark@google.comcc905052012-07-25 20:59:42 +00001412 #endif
caryclark@google.comcc905052012-07-25 20:59:42 +00001413 }
1414 if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1415 #if DEBUG_CONCIDENT
1416 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1417 __FUNCTION__, fID, other.fID, oIndex,
1418 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1419 other.xyAtT(oIndex).fY);
1420 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1421 #endif
1422 }
1423 }
1424 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001425
caryclark@google.comcc905052012-07-25 20:59:42 +00001426 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1427 double oEnd) {
1428 // walk this to outsideTs[0]
1429 // walk other to outsideTs[1]
1430 // if either is > 0, add a pointer to the other, copying adjacent winding
1431 int tIndex = -1;
1432 int oIndex = -1;
1433 double tStart = outsideTs[0];
1434 double oStart = outsideTs[1];
1435 do {
1436 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001437 } while (!approximately_negative(tStart - fTs[tIndex].fT));
caryclark@google.comcc905052012-07-25 20:59:42 +00001438 do {
1439 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001440 } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001441 if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001442 addTPair(tStart, other, oStart, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001443 }
1444 tStart = fTs[tIndex].fT;
1445 oStart = other.fTs[oIndex].fT;
1446 do {
1447 double nextT;
1448 do {
1449 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001450 } while (approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001451 tStart = nextT;
1452 do {
1453 nextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001454 } while (approximately_negative(nextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001455 oStart = nextT;
caryclark@google.com4eeda372012-12-06 21:47:48 +00001456 if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001457 break;
1458 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00001459 addTPair(tStart, other, oStart, false);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001460 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001461 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001462
caryclark@google.com4eeda372012-12-06 21:47:48 +00001463 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
1464 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001465 fBounds.setCubicBounds(pts);
1466 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001467
caryclark@google.comf839c032012-10-26 21:03:50 +00001468 /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001469 SkPoint edge[4];
caryclark@google.comf839c032012-10-26 21:03:50 +00001470 const SkPoint* ePtr;
1471 int lastT = fTs.count() - 1;
1472 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1473 ePtr = fPts;
1474 } else {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001475 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
caryclark@google.comf839c032012-10-26 21:03:50 +00001476 (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
1477 ePtr = edge;
1478 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001479 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001480 bool reverse = ePtr == fPts && start != 0;
1481 if (reverse) {
1482 path.deferredMoveLine(ePtr[fVerb]);
1483 switch (fVerb) {
1484 case SkPath::kLine_Verb:
1485 path.deferredLine(ePtr[0]);
1486 break;
1487 case SkPath::kQuad_Verb:
1488 path.quadTo(ePtr[1], ePtr[0]);
1489 break;
1490 case SkPath::kCubic_Verb:
1491 path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1492 break;
1493 default:
1494 SkASSERT(0);
1495 }
1496 // return ePtr[0];
1497 } else {
1498 path.deferredMoveLine(ePtr[0]);
1499 switch (fVerb) {
1500 case SkPath::kLine_Verb:
1501 path.deferredLine(ePtr[1]);
1502 break;
1503 case SkPath::kQuad_Verb:
1504 path.quadTo(ePtr[1], ePtr[2]);
1505 break;
1506 case SkPath::kCubic_Verb:
1507 path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1508 break;
1509 default:
1510 SkASSERT(0);
1511 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001512 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001513 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001514 // return ePtr[fVerb];
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001515 }
1516
caryclark@google.com4eeda372012-12-06 21:47:48 +00001517 void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
1518 init(pts, SkPath::kLine_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001519 fBounds.set(pts, 2);
1520 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001521
caryclark@google.comf839c032012-10-26 21:03:50 +00001522#if 0
1523 const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001524 const SkPoint& pt = xyAtT(tIndex);
1525 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001526 path.deferredMove(pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001527 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00001528 return pt;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001529 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001530#endif
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001531
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001532 // add 2 to edge or out of range values to get T extremes
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001533 void addOtherT(int index, double otherT, int otherIndex) {
1534 Span& span = fTs[index];
caryclark@google.comf839c032012-10-26 21:03:50 +00001535 #if PIN_ADD_T
caryclark@google.com185c7c42012-10-19 18:26:24 +00001536 if (precisely_less_than_zero(otherT)) {
1537 otherT = 0;
1538 } else if (precisely_greater_than_one(otherT)) {
1539 otherT = 1;
1540 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001541 #endif
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001542 span.fOtherT = otherT;
1543 span.fOtherIndex = otherIndex;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001544 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001545
caryclark@google.com4eeda372012-12-06 21:47:48 +00001546 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
1547 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001548 fBounds.setQuadBounds(pts);
1549 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001550
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001551 // Defer all coincident edge processing until
1552 // after normal intersections have been computed
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001553
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001554// no need to be tricky; insert in normal T order
1555// resolve overlapping ts when considering coincidence later
1556
1557 // add non-coincident intersection. Resulting edges are sorted in T.
1558 int addT(double newT, Segment* other) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001559 // FIXME: in the pathological case where there is a ton of intercepts,
1560 // binary search?
1561 int insertedAt = -1;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001562 size_t tCount = fTs.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00001563 #if PIN_ADD_T
caryclark@google.comc899ad92012-08-23 15:24:42 +00001564 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
caryclark@google.com185c7c42012-10-19 18:26:24 +00001565 if (precisely_less_than_zero(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001566 newT = 0;
caryclark@google.com185c7c42012-10-19 18:26:24 +00001567 } else if (precisely_greater_than_one(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001568 newT = 1;
1569 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001570 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001571 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001572 // OPTIMIZATION: if there are three or more identical Ts, then
1573 // the fourth and following could be further insertion-sorted so
1574 // that all the edges are clockwise or counterclockwise.
1575 // This could later limit segment tests to the two adjacent
1576 // neighbors, although it doesn't help with determining which
1577 // circular direction to go in.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001578 if (newT < fTs[index].fT) {
1579 insertedAt = index;
1580 break;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001581 }
1582 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001583 Span* span;
1584 if (insertedAt >= 0) {
1585 span = fTs.insert(insertedAt);
1586 } else {
1587 insertedAt = tCount;
1588 span = fTs.append();
1589 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001590 span->fT = newT;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001591 span->fOther = other;
caryclark@google.com27c449a2012-07-27 18:26:38 +00001592 span->fPt.fX = SK_ScalarNaN;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001593 span->fWindSum = SK_MinS32;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001594 span->fOppSum = SK_MinS32;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001595 span->fWindValue = 1;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001596 span->fOppValue = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00001597 span->fTiny = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001598 if ((span->fDone = newT == 1)) {
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00001599 ++fDoneSpans;
rmistry@google.comd6176b02012-08-23 18:14:13 +00001600 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001601 span->fUnsortableStart = false;
1602 span->fUnsortableEnd = false;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001603 int less = -1;
1604 while (&span[less + 1] - fTs.begin() > 0 && !span[less].fDone
1605 && !precisely_negative(newT - span[less].fT)
1606 // && approximately_negative(newT - span[less].fT)
1607 && xyAtT(&span[less]) == xyAtT(span)) {
1608 span[less].fTiny = true;
1609 span[less].fDone = true;
1610 if (approximately_negative(newT - span[less].fT)) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00001611 if (approximately_greater_than_one(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001612 span[less].fUnsortableStart = true;
1613 span[less - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001614 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001615 if (approximately_less_than_zero(span[less].fT)) {
1616 span[less + 1].fUnsortableStart = true;
1617 span[less].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001618 }
1619 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001620 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001621 --less;
caryclark@google.comf839c032012-10-26 21:03:50 +00001622 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001623 int more = 1;
1624 while (fTs.end() - &span[more - 1] > 1 && !span[more - 1].fDone
1625 && !precisely_negative(span[more].fT - newT)
1626 // && approximately_negative(span[more].fT - newT)
1627 && xyAtT(&span[more]) == xyAtT(span)) {
1628 span[more - 1].fTiny = true;
1629 span[more - 1].fDone = true;
1630 if (approximately_negative(span[more].fT - newT)) {
1631 if (approximately_greater_than_one(span[more].fT)) {
1632 span[more + 1].fUnsortableStart = true;
1633 span[more].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001634 }
1635 if (approximately_less_than_zero(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001636 span[more].fUnsortableStart = true;
1637 span[more - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001638 }
1639 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001640 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001641 ++more;
caryclark@google.comf839c032012-10-26 21:03:50 +00001642 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001643 return insertedAt;
1644 }
1645
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001646 // set spans from start to end to decrement by one
1647 // note this walks other backwards
1648 // FIMXE: there's probably an edge case that can be constructed where
1649 // two span in one segment are separated by float epsilon on one span but
1650 // not the other, if one segment is very small. For this
1651 // case the counts asserted below may or may not be enough to separate the
caryclark@google.com2ddff932012-08-07 21:25:27 +00001652 // spans. Even if the counts work out, what if the spans aren't correctly
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001653 // sorted? It feels better in such a case to match the span's other span
1654 // pointer since both coincident segments must contain the same spans.
1655 void addTCancel(double startT, double endT, Segment& other,
1656 double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001657 SkASSERT(!approximately_negative(endT - startT));
1658 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00001659 bool binary = fOperand != other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001660 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001661 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001662 ++index;
1663 }
caryclark@google.comb9738012012-07-03 19:53:30 +00001664 int oIndex = other.fTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001665 while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001666 ;
caryclark@google.com59823f72012-08-09 18:17:47 +00001667 double tRatio = (oEndT - oStartT) / (endT - startT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001668 Span* test = &fTs[index];
1669 Span* oTest = &other.fTs[oIndex];
caryclark@google.com18063442012-07-25 12:05:18 +00001670 SkTDArray<double> outsideTs;
1671 SkTDArray<double> oOutsideTs;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001672 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001673 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
caryclark@google.comcc905052012-07-25 20:59:42 +00001674 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.com200c2112012-08-03 15:05:04 +00001675 double testT = test->fT;
1676 double oTestT = oTest->fT;
1677 Span* span = test;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001678 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001679 if (decrement) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001680 decrementSpan(span);
caryclark@google.com200c2112012-08-03 15:05:04 +00001681 } else if (track && span->fT < 1 && oTestT < 1) {
1682 TrackOutside(outsideTs, span->fT, oTestT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001683 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001684 span = &fTs[++index];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001685 } while (approximately_negative(span->fT - testT));
caryclark@google.com200c2112012-08-03 15:05:04 +00001686 Span* oSpan = oTest;
caryclark@google.com59823f72012-08-09 18:17:47 +00001687 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1688 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1689 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001690 while (approximately_negative(otherTMatchStart - oSpan->fT)
1691 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
caryclark@google.com03f97062012-08-21 13:13:52 +00001692 #ifdef SK_DEBUG
caryclark@google.com59823f72012-08-09 18:17:47 +00001693 SkASSERT(originalWindValue == oSpan->fWindValue);
caryclark@google.com03f97062012-08-21 13:13:52 +00001694 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001695 if (decrement) {
caryclark@google.com200c2112012-08-03 15:05:04 +00001696 other.decrementSpan(oSpan);
1697 } else if (track && oSpan->fT < 1 && testT < 1) {
1698 TrackOutside(oOutsideTs, oSpan->fT, testT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001699 }
1700 if (!oIndex) {
1701 break;
1702 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001703 oSpan = &other.fTs[--oIndex];
rmistry@google.comd6176b02012-08-23 18:14:13 +00001704 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001705 test = span;
1706 oTest = oSpan;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001707 } while (!approximately_negative(endT - test->fT));
1708 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
caryclark@google.com18063442012-07-25 12:05:18 +00001709 // FIXME: determine if canceled edges need outside ts added
caryclark@google.comcc905052012-07-25 20:59:42 +00001710 if (!done() && outsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001711 double tStart = outsideTs[0];
1712 double oStart = outsideTs[1];
1713 addCancelOutsides(tStart, oStart, other, oEndT);
1714 int count = outsideTs.count();
1715 if (count > 2) {
1716 double tStart = outsideTs[count - 2];
1717 double oStart = outsideTs[count - 1];
1718 addCancelOutsides(tStart, oStart, other, oEndT);
1719 }
caryclark@google.com18063442012-07-25 12:05:18 +00001720 }
caryclark@google.comcc905052012-07-25 20:59:42 +00001721 if (!other.done() && oOutsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001722 double tStart = oOutsideTs[0];
1723 double oStart = oOutsideTs[1];
1724 other.addCancelOutsides(tStart, oStart, *this, endT);
caryclark@google.com18063442012-07-25 12:05:18 +00001725 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001726 }
skia.committer@gmail.com15dd3002013-01-18 07:07:28 +00001727
caryclark@google.com73ca6242013-01-17 21:02:47 +00001728 int addUnsortableT(double newT, Segment* other, bool start) {
1729 int result = addT(newT, other);
1730 Span* span = &fTs[result];
1731 if (start) {
1732 if (result > 0) {
1733 span[result - 1].fUnsortableEnd = true;
1734 }
1735 span[result].fUnsortableStart = true;
1736 } else {
1737 span[result].fUnsortableEnd = true;
1738 if (result + 1 < fTs.count()) {
1739 span[result + 1].fUnsortableStart = true;
1740 }
1741 }
1742 return result;
1743 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00001744
caryclark@google.com4eeda372012-12-06 21:47:48 +00001745 int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1746 SkTDArray<double>& outsideTs) {
1747 int oWindValue = oTest->fWindValue;
1748 int oOppValue = oTest->fOppValue;
1749 if (opp) {
1750 SkTSwap<int>(oWindValue, oOppValue);
1751 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001752 Span* const test = &fTs[index];
1753 Span* end = test;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001754 const double oStartT = oTest->fT;
1755 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001756 if (bumpSpan(end, oWindValue, oOppValue)) {
1757 TrackOutside(outsideTs, end->fT, oStartT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001758 }
1759 end = &fTs[++index];
1760 } while (approximately_negative(end->fT - test->fT));
1761 return index;
1762 }
1763
1764 // because of the order in which coincidences are resolved, this and other
1765 // may not have the same intermediate points. Compute the corresponding
1766 // intermediate T values (using this as the master, other as the follower)
1767 // and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com4eeda372012-12-06 21:47:48 +00001768 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1769 SkTDArray<double>& oOutsideTs) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001770 Span* const oTest = &fTs[oIndex];
1771 Span* oEnd = oTest;
1772 const double startT = test->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001773 const double oStartT = oTest->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001774 while (!approximately_negative(oEndT - oEnd->fT)
caryclark@google.com4eeda372012-12-06 21:47:48 +00001775 && approximately_negative(oEnd->fT - oStartT)) {
1776 zeroSpan(oEnd);
1777 TrackOutside(oOutsideTs, oEnd->fT, startT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001778 oEnd = &fTs[++oIndex];
1779 }
1780 return oIndex;
1781 }
1782
1783 // FIXME: need to test this case:
1784 // contourA has two segments that are coincident
1785 // contourB has two segments that are coincident in the same place
1786 // each ends up with +2/0 pairs for winding count
1787 // since logic below doesn't transfer count (only increments/decrements) can this be
1788 // resolved to +4/0 ?
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001789
1790 // set spans from start to end to increment the greater by one and decrement
1791 // the lesser
caryclark@google.com4eeda372012-12-06 21:47:48 +00001792 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001793 SkASSERT(!approximately_negative(endT - startT));
1794 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001795 bool opp = fOperand ^ other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001796 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001797 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001798 ++index;
1799 }
1800 int oIndex = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001801 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001802 ++oIndex;
1803 }
1804 Span* test = &fTs[index];
1805 Span* oTest = &other.fTs[oIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001806 SkTDArray<double> outsideTs;
1807 SkTDArray<double> oOutsideTs;
1808 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001809 // if either span has an opposite value and the operands don't match, resolve first
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001810 // SkASSERT(!test->fDone || !oTest->fDone);
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001811 if (test->fDone || oTest->fDone) {
1812 index = advanceCoincidentThis(oTest, opp, index);
1813 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
1814 } else {
1815 index = bumpCoincidentThis(oTest, opp, index, outsideTs);
1816 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
1817 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001818 test = &fTs[index];
1819 oTest = &other.fTs[oIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001820 } while (!approximately_negative(endT - test->fT));
1821 SkASSERT(approximately_negative(oTest->fT - oEndT));
1822 SkASSERT(approximately_negative(oEndT - oTest->fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001823 if (!done() && outsideTs.count()) {
1824 addCoinOutsides(outsideTs, other, oEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001825 }
1826 if (!other.done() && oOutsideTs.count()) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001827 other.addCoinOutsides(oOutsideTs, *this, endT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001828 }
1829 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001830
caryclark@google.comcc905052012-07-25 20:59:42 +00001831 // FIXME: this doesn't prevent the same span from being added twice
caryclark@google.comaa358312013-01-29 20:28:49 +00001832 // fix in caller, SkASSERT here?
caryclark@google.com2ddff932012-08-07 21:25:27 +00001833 void addTPair(double t, Segment& other, double otherT, bool borrowWind) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001834 int tCount = fTs.count();
1835 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1836 const Span& span = fTs[tIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001837 if (!approximately_negative(span.fT - t)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001838 break;
1839 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001840 if (approximately_negative(span.fT - t) && span.fOther == &other
1841 && approximately_equal(span.fOtherT, otherT)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001842#if DEBUG_ADD_T_PAIR
1843 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1844 __FUNCTION__, fID, t, other.fID, otherT);
1845#endif
1846 return;
1847 }
1848 }
caryclark@google.com47580692012-07-23 12:14:49 +00001849#if DEBUG_ADD_T_PAIR
1850 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1851 __FUNCTION__, fID, t, other.fID, otherT);
1852#endif
caryclark@google.comb9738012012-07-03 19:53:30 +00001853 int insertedAt = addT(t, &other);
1854 int otherInsertedAt = other.addT(otherT, this);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001855 addOtherT(insertedAt, otherT, otherInsertedAt);
caryclark@google.comb9738012012-07-03 19:53:30 +00001856 other.addOtherT(otherInsertedAt, t, insertedAt);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001857 matchWindingValue(insertedAt, t, borrowWind);
1858 other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001859 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001860
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001861 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001862 // add edge leading into junction
caryclark@google.com4eeda372012-12-06 21:47:48 +00001863 int min = SkMin32(end, start);
1864 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001865 addAngle(angles, end, start);
1866 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001867 // add edge leading away from junction
caryclark@google.com495f8e42012-05-31 13:13:11 +00001868 int step = SkSign32(end - start);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001869 int tIndex = nextExactSpan(end, step);
caryclark@google.com4eeda372012-12-06 21:47:48 +00001870 min = SkMin32(end, tIndex);
1871 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001872 addAngle(angles, end, tIndex);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001873 }
1874 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001875
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001876 int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
1877 Span* const test = &fTs[index];
1878 Span* end = test;
1879 do {
1880 end = &fTs[++index];
1881 } while (approximately_negative(end->fT - test->fT));
1882 return index;
1883 }
1884
1885 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
1886 Span* const oTest = &fTs[oIndex];
1887 Span* oEnd = oTest;
1888 const double oStartT = oTest->fT;
1889 while (!approximately_negative(oEndT - oEnd->fT)
1890 && approximately_negative(oEnd->fT - oStartT)) {
1891 oEnd = &fTs[++oIndex];
1892 }
1893 return oIndex;
1894 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00001895
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001896 bool betweenTs(int lesser, double testT, int greater) {
1897 if (lesser > greater) {
1898 SkTSwap<int>(lesser, greater);
1899 }
1900 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
1901 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001902
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001903 const Bounds& bounds() const {
1904 return fBounds;
1905 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001906
caryclark@google.com31143cf2012-11-09 22:14:19 +00001907 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001908 double referenceT = fTs[index].fT;
1909 int lesser = index;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001910 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
1911 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00001912 buildAnglesInner(lesser, angles);
1913 }
1914 do {
1915 buildAnglesInner(index, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001916 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
1917 && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001918 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001919
1920 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
1921 Span* span = &fTs[index];
1922 Segment* other = span->fOther;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001923 // if there is only one live crossing, and no coincidence, continue
1924 // in the same direction
1925 // if there is coincidence, the only choice may be to reverse direction
1926 // find edge on either side of intersection
1927 int oIndex = span->fOtherIndex;
1928 // if done == -1, prior span has already been processed
1929 int step = 1;
caryclark@google.coma461ff02012-10-11 12:54:23 +00001930 int next = other->nextExactSpan(oIndex, step);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001931 if (next < 0) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001932 step = -step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00001933 next = other->nextExactSpan(oIndex, step);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001934 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001935 // add candidate into and away from junction
1936 other->addTwoAngles(next, oIndex, angles);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001937 }
1938
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001939 int computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001940 SkTDArray<Angle> angles;
1941 addTwoAngles(startIndex, endIndex, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001942 buildAngles(endIndex, angles, false);
caryclark@google.comd1688742012-09-18 20:08:37 +00001943 // OPTIMIZATION: check all angles to see if any have computed wind sum
1944 // before sorting (early exit if none)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001945 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001946 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00001947#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00001948 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00001949#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001950 if (!sortable) {
1951 return SK_MinS32;
1952 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001953 int angleCount = angles.count();
1954 const Angle* angle;
1955 const Segment* base;
1956 int winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001957 int oWinding;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001958 int firstIndex = 0;
1959 do {
1960 angle = sorted[firstIndex];
1961 base = angle->segment();
1962 winding = base->windSum(angle);
1963 if (winding != SK_MinS32) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001964 oWinding = base->oppSum(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001965 break;
1966 }
1967 if (++firstIndex == angleCount) {
1968 return SK_MinS32;
1969 }
1970 } while (true);
1971 // turn winding into contourWinding
caryclark@google.com2ddff932012-08-07 21:25:27 +00001972 int spanWinding = base->spanSign(angle);
1973 bool inner = useInnerWinding(winding + spanWinding, winding);
1974 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00001975 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
caryclark@google.com59823f72012-08-09 18:17:47 +00001976 spanWinding, winding, angle->sign(), inner,
caryclark@google.com2ddff932012-08-07 21:25:27 +00001977 inner ? winding + spanWinding : winding);
1978 #endif
1979 if (inner) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001980 winding += spanWinding;
1981 }
1982 #if DEBUG_SORT
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001983 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001984 #endif
1985 int nextIndex = firstIndex + 1;
1986 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com2ddff932012-08-07 21:25:27 +00001987 winding -= base->spanSign(angle);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001988 oWinding -= base->oppSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001989 do {
1990 if (nextIndex == angleCount) {
1991 nextIndex = 0;
1992 }
1993 angle = sorted[nextIndex];
1994 Segment* segment = angle->segment();
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001995 bool opp = base->fOperand ^ segment->fOperand;
1996 int maxWinding, oMaxWinding;
1997 int spanSign = segment->spanSign(angle);
1998 int oppoSign = segment->oppSign(angle);
1999 if (opp) {
2000 oMaxWinding = oWinding;
2001 oWinding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002002 maxWinding = winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002003 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002004 winding -= oppoSign;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002005 }
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002006 } else {
2007 maxWinding = winding;
2008 winding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002009 oMaxWinding = oWinding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002010 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002011 oWinding -= oppoSign;
2012 }
2013 }
2014 if (segment->windSum(angle) == SK_MinS32) {
2015 if (opp) {
2016 if (useInnerWinding(oMaxWinding, oWinding)) {
2017 oMaxWinding = oWinding;
2018 }
2019 if (oppoSign && useInnerWinding(maxWinding, winding)) {
2020 maxWinding = winding;
2021 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002022 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002023 } else {
2024 if (useInnerWinding(maxWinding, winding)) {
2025 maxWinding = winding;
2026 }
2027 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
2028 oMaxWinding = oWinding;
2029 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002030 (void) segment->markAndChaseWinding(angle, maxWinding,
2031 binary ? oMaxWinding : 0);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002032 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002033 }
2034 } while (++nextIndex != lastIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002035 int minIndex = SkMin32(startIndex, endIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002036 return windSum(minIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002037 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002038
caryclark@google.com3586ece2012-12-27 18:46:58 +00002039 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
caryclark@google.com10227bf2012-12-28 22:10:41 +00002040 double mid, bool opp, bool current) const {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002041 SkScalar bottom = fBounds.fBottom;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002042 int bestTIndex = -1;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002043 if (bottom <= bestY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002044 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002045 }
2046 SkScalar top = fBounds.fTop;
2047 if (top >= basePt.fY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002048 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002049 }
2050 if (fBounds.fLeft > basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002051 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002052 }
2053 if (fBounds.fRight < basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002054 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002055 }
2056 if (fBounds.fLeft == fBounds.fRight) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002057 // if vertical, and directly above test point, wait for another one
caryclark@google.com6d0032a2013-01-04 19:41:13 +00002058 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002059 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002060 // intersect ray starting at basePt with edge
2061 Intersections intersections;
2062 // OPTIMIZE: use specialty function that intersects ray with curve,
2063 // returning t values only for curve (we don't care about t on ray)
2064 int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
2065 if (pts == 0 || (current && pts == 1)) {
2066 return bestTIndex;
2067 }
2068 if (current) {
2069 SkASSERT(pts > 1);
2070 int closestIdx = 0;
2071 double closest = fabs(intersections.fT[0][0] - mid);
2072 for (int idx = 1; idx < pts; ++idx) {
2073 double test = fabs(intersections.fT[0][idx] - mid);
2074 if (closest > test) {
2075 closestIdx = idx;
2076 closest = test;
2077 }
2078 }
2079 if (closestIdx < pts - 1) {
2080 intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
2081 }
2082 --pts;
2083 }
2084 double bestT = -1;
2085 for (int index = 0; index < pts; ++index) {
2086 double foundT = intersections.fT[0][index];
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002087 if (approximately_less_than_zero(foundT)
2088 || approximately_greater_than_one(foundT)) {
2089 continue;
2090 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002091 SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
2092 if (approximately_negative(testY - bestY)
2093 || approximately_negative(basePt.fY - testY)) {
caryclark@google.com47580692012-07-23 12:14:49 +00002094 continue;
2095 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002096 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002097 return SK_MinS32; // if the intersection is edge on, wait for another one
caryclark@google.com10227bf2012-12-28 22:10:41 +00002098 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002099 if (fVerb > SkPath::kLine_Verb) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002100 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
2101 if (approximately_zero(dx)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002102 return SK_MinS32; // hit vertical, wait for another one
caryclark@google.com3586ece2012-12-27 18:46:58 +00002103 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00002104 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002105 bestY = testY;
2106 bestT = foundT;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002107 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002108 if (bestT < 0) {
2109 return bestTIndex;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002110 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002111 SkASSERT(bestT >= 0);
2112 SkASSERT(bestT <= 1);
2113 int start;
2114 int end = 0;
2115 do {
2116 start = end;
2117 end = nextSpan(start, 1);
2118 } while (fTs[end].fT < bestT);
2119 // FIXME: see next candidate for a better pattern to find the next start/end pair
2120 while (start + 1 < end && fTs[start].fDone) {
2121 ++start;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002122 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002123 if (!isCanceled(start)) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002124 hitT = bestT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002125 bestTIndex = start;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002126 hitSomething = true;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002127 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002128 return bestTIndex;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002129 }
caryclark@google.com18063442012-07-25 12:05:18 +00002130
caryclark@google.com4eeda372012-12-06 21:47:48 +00002131 void decrementSpan(Span* span) {
caryclark@google.com18063442012-07-25 12:05:18 +00002132 SkASSERT(span->fWindValue > 0);
2133 if (--(span->fWindValue) == 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002134 if (!span->fOppValue && !span->fDone) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002135 span->fDone = true;
2136 ++fDoneSpans;
2137 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002138 }
2139 }
2140
2141 bool bumpSpan(Span* span, int windDelta, int oppDelta) {
2142 SkASSERT(!span->fDone);
2143 span->fWindValue += windDelta;
2144 SkASSERT(span->fWindValue >= 0);
2145 span->fOppValue += oppDelta;
2146 SkASSERT(span->fOppValue >= 0);
2147 if (fXor) {
2148 span->fWindValue &= 1;
2149 }
2150 if (fOppXor) {
2151 span->fOppValue &= 1;
2152 }
2153 if (!span->fWindValue && !span->fOppValue) {
2154 span->fDone = true;
2155 ++fDoneSpans;
caryclark@google.com18063442012-07-25 12:05:18 +00002156 return true;
2157 }
2158 return false;
2159 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002160
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002161 // OPTIMIZE
2162 // when the edges are initially walked, they don't automatically get the prior and next
2163 // 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 +00002164 // and would additionally remove the need for similar checks in condition edges. It would
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002165 // also allow intersection code to assume end of segment intersections (maybe?)
2166 bool complete() const {
2167 int count = fTs.count();
2168 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
2169 }
caryclark@google.com18063442012-07-25 12:05:18 +00002170
caryclark@google.com15fa1382012-05-07 20:49:36 +00002171 bool done() const {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002172 SkASSERT(fDoneSpans <= fTs.count());
2173 return fDoneSpans == fTs.count();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002174 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002175
caryclark@google.comf839c032012-10-26 21:03:50 +00002176 bool done(int min) const {
2177 return fTs[min].fDone;
2178 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002179
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002180 bool done(const Angle* angle) const {
2181 return done(SkMin32(angle->start(), angle->end()));
caryclark@google.com47580692012-07-23 12:14:49 +00002182 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00002183
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002184 bool equalPoints(int greaterTIndex, int lesserTIndex) {
2185 SkASSERT(greaterTIndex >= lesserTIndex);
2186 double greaterT = fTs[greaterTIndex].fT;
2187 double lesserT = fTs[lesserTIndex].fT;
2188 if (greaterT == lesserT) {
2189 return true;
2190 }
2191 if (!approximately_negative(greaterT - lesserT)) {
2192 return false;
2193 }
2194 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2195 }
2196
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002197 /*
2198 The M and S variable name parts stand for the operators.
2199 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2200 Su stands for Subtrahend
2201 The Opp variable name part designates that the value is for the Opposite operator.
2202 Opposite values result from combining coincident spans.
2203 */
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002204
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002205 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2206 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002207 const int startIndex = nextStart;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002208 const int endIndex = nextEnd;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002209 SkASSERT(startIndex != endIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002210 const int count = fTs.count();
2211 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2212 const int step = SkSign32(endIndex - startIndex);
2213 const int end = nextExactSpan(startIndex, step);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002214 SkASSERT(end >= 0);
2215 Span* endSpan = &fTs[end];
2216 Segment* other;
2217 if (isSimple(end)) {
2218 // mark the smaller of startIndex, endIndex done, and all adjacent
2219 // spans with the same T value (but not 'other' spans)
2220 #if DEBUG_WINDING
2221 SkDebugf("%s simple\n", __FUNCTION__);
2222 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002223 int min = SkMin32(startIndex, endIndex);
2224 if (fTs[min].fDone) {
2225 return NULL;
2226 }
2227 markDoneBinary(min);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002228 other = endSpan->fOther;
2229 nextStart = endSpan->fOtherIndex;
2230 double startT = other->fTs[nextStart].fT;
2231 nextEnd = nextStart;
2232 do {
2233 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002234 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002235 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002236 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2237 return other;
2238 }
2239 // more than one viable candidate -- measure angles to find best
2240 SkTDArray<Angle> angles;
2241 SkASSERT(startIndex - endIndex != 0);
2242 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2243 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002244 buildAngles(end, angles, true);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002245 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002246 bool sortable = SortAngles(angles, sorted);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002247 int angleCount = angles.count();
2248 int firstIndex = findStartingEdge(sorted, startIndex, end);
2249 SkASSERT(firstIndex >= 0);
2250 #if DEBUG_SORT
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002251 debugShowSort(__FUNCTION__, sorted, firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002252 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002253 if (!sortable) {
2254 unsortable = true;
2255 return NULL;
2256 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002257 SkASSERT(sorted[firstIndex]->segment() == this);
2258 #if DEBUG_WINDING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002259 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2260 sorted[firstIndex]->sign());
caryclark@google.com235f56a2012-09-14 14:19:30 +00002261 #endif
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002262 int sumMiWinding = updateWinding(endIndex, startIndex);
2263 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2264 if (operand()) {
2265 SkTSwap<int>(sumMiWinding, sumSuWinding);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002266 }
2267 int nextIndex = firstIndex + 1;
2268 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2269 const Angle* foundAngle = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002270 bool foundDone = false;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002271 // iterate through the angle, and compute everyone's winding
caryclark@google.com235f56a2012-09-14 14:19:30 +00002272 Segment* nextSegment;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002273 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002274 SkASSERT(nextIndex != firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002275 if (nextIndex == angleCount) {
2276 nextIndex = 0;
2277 }
2278 const Angle* nextAngle = sorted[nextIndex];
2279 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002280 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2281 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2282 nextAngle->end(), op, sumMiWinding, sumSuWinding,
2283 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
2284 if (activeAngle && (!foundAngle || foundDone)) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002285 foundAngle = nextAngle;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002286 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002287 }
2288 if (nextSegment->done()) {
2289 continue;
2290 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002291 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2292 continue;
2293 }
2294 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2295 oppSumWinding, activeAngle, nextAngle);
2296 if (last) {
2297 *chase.append() = last;
2298#if DEBUG_WINDING
2299 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2300 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2301#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002302 }
2303 } while (++nextIndex != lastIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002304 markDoneBinary(SkMin32(startIndex, endIndex));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002305 if (!foundAngle) {
2306 return NULL;
2307 }
2308 nextStart = foundAngle->start();
2309 nextEnd = foundAngle->end();
2310 nextSegment = foundAngle->segment();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002311
caryclark@google.com235f56a2012-09-14 14:19:30 +00002312 #if DEBUG_WINDING
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002313 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2314 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002315 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002316 return nextSegment;
2317 }
caryclark@google.com47580692012-07-23 12:14:49 +00002318
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002319 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2320 bool& unsortable) {
2321 const int startIndex = nextStart;
2322 const int endIndex = nextEnd;
2323 SkASSERT(startIndex != endIndex);
2324 const int count = fTs.count();
2325 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2326 const int step = SkSign32(endIndex - startIndex);
2327 const int end = nextExactSpan(startIndex, step);
2328 SkASSERT(end >= 0);
2329 Span* endSpan = &fTs[end];
2330 Segment* other;
2331 if (isSimple(end)) {
2332 // mark the smaller of startIndex, endIndex done, and all adjacent
2333 // spans with the same T value (but not 'other' spans)
2334 #if DEBUG_WINDING
2335 SkDebugf("%s simple\n", __FUNCTION__);
2336 #endif
2337 int min = SkMin32(startIndex, endIndex);
2338 if (fTs[min].fDone) {
2339 return NULL;
2340 }
2341 markDoneUnary(min);
2342 other = endSpan->fOther;
2343 nextStart = endSpan->fOtherIndex;
2344 double startT = other->fTs[nextStart].fT;
2345 nextEnd = nextStart;
2346 do {
2347 nextEnd += step;
2348 }
2349 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2350 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2351 return other;
2352 }
2353 // more than one viable candidate -- measure angles to find best
2354 SkTDArray<Angle> angles;
2355 SkASSERT(startIndex - endIndex != 0);
2356 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2357 addTwoAngles(startIndex, end, angles);
2358 buildAngles(end, angles, true);
2359 SkTDArray<Angle*> sorted;
2360 bool sortable = SortAngles(angles, sorted);
2361 int angleCount = angles.count();
2362 int firstIndex = findStartingEdge(sorted, startIndex, end);
2363 SkASSERT(firstIndex >= 0);
2364 #if DEBUG_SORT
2365 debugShowSort(__FUNCTION__, sorted, firstIndex);
2366 #endif
2367 if (!sortable) {
2368 unsortable = true;
2369 return NULL;
2370 }
2371 SkASSERT(sorted[firstIndex]->segment() == this);
2372 #if DEBUG_WINDING
2373 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2374 sorted[firstIndex]->sign());
2375 #endif
2376 int sumWinding = updateWinding(endIndex, startIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002377 int nextIndex = firstIndex + 1;
2378 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2379 const Angle* foundAngle = NULL;
2380 bool foundDone = false;
2381 // iterate through the angle, and compute everyone's winding
2382 Segment* nextSegment;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002383 int activeCount = 0;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002384 do {
2385 SkASSERT(nextIndex != firstIndex);
2386 if (nextIndex == angleCount) {
2387 nextIndex = 0;
2388 }
2389 const Angle* nextAngle = sorted[nextIndex];
2390 nextSegment = nextAngle->segment();
2391 int maxWinding;
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00002392 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002393 maxWinding, sumWinding);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002394 if (activeAngle) {
2395 ++activeCount;
2396 if (!foundAngle || (foundDone && activeCount & 1)) {
2397 if (nextSegment->tiny(nextAngle)) {
2398 unsortable = true;
2399 return NULL;
2400 }
2401 foundAngle = nextAngle;
2402 foundDone = nextSegment->done(nextAngle);
2403 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002404 }
2405 if (nextSegment->done()) {
2406 continue;
2407 }
2408 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2409 continue;
2410 }
2411 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2412 if (last) {
2413 *chase.append() = last;
2414#if DEBUG_WINDING
2415 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2416 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2417#endif
2418 }
2419 } while (++nextIndex != lastIndex);
2420 markDoneUnary(SkMin32(startIndex, endIndex));
2421 if (!foundAngle) {
2422 return NULL;
2423 }
2424 nextStart = foundAngle->start();
2425 nextEnd = foundAngle->end();
2426 nextSegment = foundAngle->segment();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002427 #if DEBUG_WINDING
2428 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2429 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2430 #endif
2431 return nextSegment;
2432 }
2433
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002434 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002435 const int startIndex = nextStart;
2436 const int endIndex = nextEnd;
2437 SkASSERT(startIndex != endIndex);
2438 int count = fTs.count();
2439 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2440 : startIndex > 0);
2441 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002442 int end = nextExactSpan(startIndex, step);
caryclark@google.com24bec792012-08-20 12:43:57 +00002443 SkASSERT(end >= 0);
2444 Span* endSpan = &fTs[end];
2445 Segment* other;
caryclark@google.com24bec792012-08-20 12:43:57 +00002446 if (isSimple(end)) {
2447 #if DEBUG_WINDING
2448 SkDebugf("%s simple\n", __FUNCTION__);
2449 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002450 int min = SkMin32(startIndex, endIndex);
2451 if (fTs[min].fDone) {
2452 return NULL;
2453 }
2454 markDone(min, 1);
caryclark@google.com24bec792012-08-20 12:43:57 +00002455 other = endSpan->fOther;
2456 nextStart = endSpan->fOtherIndex;
2457 double startT = other->fTs[nextStart].fT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002458 #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 +00002459 SkDEBUGCODE(bool firstLoop = true;)
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002460 if ((approximately_less_than_zero(startT) && step < 0)
2461 || (approximately_greater_than_one(startT) && step > 0)) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002462 step = -step;
2463 SkDEBUGCODE(firstLoop = false;)
2464 }
2465 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002466 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002467 nextEnd = nextStart;
2468 do {
2469 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002470 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002471 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002472 #if 01
caryclark@google.com24bec792012-08-20 12:43:57 +00002473 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2474 break;
2475 }
caryclark@google.com03f97062012-08-21 13:13:52 +00002476 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00002477 SkASSERT(firstLoop);
caryclark@google.com03f97062012-08-21 13:13:52 +00002478 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002479 SkDEBUGCODE(firstLoop = false;)
2480 step = -step;
2481 } while (true);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002482 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002483 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2484 return other;
2485 }
2486 SkTDArray<Angle> angles;
2487 SkASSERT(startIndex - endIndex != 0);
2488 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2489 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002490 buildAngles(end, angles, false);
caryclark@google.com24bec792012-08-20 12:43:57 +00002491 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002492 bool sortable = SortAngles(angles, sorted);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002493 if (!sortable) {
2494 unsortable = true;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002495 #if DEBUG_SORT
2496 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
2497 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002498 return NULL;
2499 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002500 int angleCount = angles.count();
2501 int firstIndex = findStartingEdge(sorted, startIndex, end);
2502 SkASSERT(firstIndex >= 0);
2503 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002504 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
caryclark@google.com24bec792012-08-20 12:43:57 +00002505 #endif
2506 SkASSERT(sorted[firstIndex]->segment() == this);
2507 int nextIndex = firstIndex + 1;
2508 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002509 const Angle* foundAngle = NULL;
2510 bool foundDone = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002511 Segment* nextSegment;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002512 int activeCount = 0;
caryclark@google.com24bec792012-08-20 12:43:57 +00002513 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002514 SkASSERT(nextIndex != firstIndex);
caryclark@google.com24bec792012-08-20 12:43:57 +00002515 if (nextIndex == angleCount) {
2516 nextIndex = 0;
2517 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002518 const Angle* nextAngle = sorted[nextIndex];
caryclark@google.com24bec792012-08-20 12:43:57 +00002519 nextSegment = nextAngle->segment();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002520 ++activeCount;
2521 if (!foundAngle || (foundDone && activeCount & 1)) {
2522 if (nextSegment->tiny(nextAngle)) {
2523 unsortable = true;
2524 return NULL;
2525 }
2526 foundAngle = nextAngle;
2527 foundDone = nextSegment->done(nextAngle);
2528 }
2529 if (nextSegment->done()) {
2530 continue;
caryclark@google.com24bec792012-08-20 12:43:57 +00002531 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002532 } while (++nextIndex != lastIndex);
2533 markDone(SkMin32(startIndex, endIndex), 1);
2534 if (!foundAngle) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002535 return NULL;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002536 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002537 nextStart = foundAngle->start();
2538 nextEnd = foundAngle->end();
2539 nextSegment = foundAngle->segment();
2540 #if DEBUG_WINDING
2541 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2542 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2543 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002544 return nextSegment;
2545 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002546
2547 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2548 int angleCount = sorted.count();
2549 int firstIndex = -1;
2550 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2551 const Angle* angle = sorted[angleIndex];
2552 if (angle->segment() == this && angle->start() == end &&
2553 angle->end() == start) {
2554 firstIndex = angleIndex;
2555 break;
2556 }
2557 }
2558 return firstIndex;
2559 }
2560
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002561 // FIXME: this is tricky code; needs its own unit test
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002562 // note that fOtherIndex isn't computed yet, so it can't be used here
caryclark@google.com4eeda372012-12-06 21:47:48 +00002563 void findTooCloseToCall() {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002564 int count = fTs.count();
2565 if (count < 3) { // require t=0, x, 1 at minimum
2566 return;
2567 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002568 int matchIndex = 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002569 int moCount;
2570 Span* match;
2571 Segment* mOther;
2572 do {
2573 match = &fTs[matchIndex];
2574 mOther = match->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002575 // FIXME: allow quads, cubics to be near coincident?
2576 if (mOther->fVerb == SkPath::kLine_Verb) {
2577 moCount = mOther->fTs.count();
2578 if (moCount >= 3) {
2579 break;
2580 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002581 }
2582 if (++matchIndex >= count) {
2583 return;
2584 }
2585 } while (true); // require t=0, x, 1 at minimum
caryclark@google.com15fa1382012-05-07 20:49:36 +00002586 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002587 const SkPoint* matchPt = &xyAtT(match);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002588 // look for a pair of nearby T values that map to the same (x,y) value
2589 // if found, see if the pair of other segments share a common point. If
2590 // so, the span from here to there is coincident.
caryclark@google.com15fa1382012-05-07 20:49:36 +00002591 for (int index = matchIndex + 1; index < count; ++index) {
2592 Span* test = &fTs[index];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002593 if (test->fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002594 continue;
2595 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002596 Segment* tOther = test->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002597 if (tOther->fVerb != SkPath::kLine_Verb) {
2598 continue; // FIXME: allow quads, cubics to be near coincident?
2599 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002600 int toCount = tOther->fTs.count();
2601 if (toCount < 3) { // require t=0, x, 1 at minimum
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002602 continue;
2603 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002604 const SkPoint* testPt = &xyAtT(test);
2605 if (*matchPt != *testPt) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002606 matchIndex = index;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002607 moCount = toCount;
2608 match = test;
2609 mOther = tOther;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002610 matchPt = testPt;
2611 continue;
2612 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002613 int moStart = -1;
2614 int moEnd = -1;
2615 double moStartT, moEndT;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002616 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002617 Span& moSpan = mOther->fTs[moIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002618 if (moSpan.fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002619 continue;
2620 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002621 if (moSpan.fOther == this) {
2622 if (moSpan.fOtherT == match->fT) {
2623 moStart = moIndex;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002624 moStartT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002625 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002626 continue;
2627 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002628 if (moSpan.fOther == tOther) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002629 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002630 moStart = -1;
2631 break;
2632 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002633 SkASSERT(moEnd == -1);
2634 moEnd = moIndex;
2635 moEndT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002636 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002637 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002638 if (moStart < 0 || moEnd < 0) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002639 continue;
2640 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002641 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002642 if (approximately_equal(moStartT, moEndT)) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002643 continue;
2644 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002645 int toStart = -1;
2646 int toEnd = -1;
2647 double toStartT, toEndT;
2648 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2649 Span& toSpan = tOther->fTs[toIndex];
caryclark@google.comc899ad92012-08-23 15:24:42 +00002650 if (toSpan.fDone) {
2651 continue;
2652 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002653 if (toSpan.fOther == this) {
2654 if (toSpan.fOtherT == test->fT) {
2655 toStart = toIndex;
2656 toStartT = toSpan.fT;
2657 }
2658 continue;
2659 }
2660 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002661 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002662 moStart = -1;
2663 break;
2664 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002665 SkASSERT(toEnd == -1);
2666 toEnd = toIndex;
2667 toEndT = toSpan.fT;
2668 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002669 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002670 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2671 if (toStart <= 0 || toEnd <= 0) {
2672 continue;
2673 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002674 if (approximately_equal(toStartT, toEndT)) {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002675 continue;
2676 }
2677 // test to see if the segment between there and here is linear
2678 if (!mOther->isLinear(moStart, moEnd)
2679 || !tOther->isLinear(toStart, toEnd)) {
2680 continue;
2681 }
caryclark@google.comc899ad92012-08-23 15:24:42 +00002682 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002683 if (flipped) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002684 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002685 } else {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002686 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002687 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002688 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002689 }
2690
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002691 // start here;
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00002692 // either:
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002693 // a) mark spans with either end unsortable as done, or
2694 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2695 // when encountering an unsortable span
2696
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002697 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2698 // and use more concise logic like the old edge walker code?
2699 // FIXME: this needs to deal with coincident edges
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002700 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002701 // iterate through T intersections and return topmost
2702 // topmost tangent from y-min to first pt is closer to horizontal
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002703 SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002704 int firstT = -1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002705 SkPoint topPt;
2706 topPt.fY = SK_ScalarMax;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002707 int count = fTs.count();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002708 // see if either end is not done since we want smaller Y of the pair
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002709 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002710 bool lastUnsortable = false;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002711 for (int index = 0; index < count; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002712 const Span& span = fTs[index];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002713 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002714 goto next;
2715 }
2716 if (!span.fDone | !lastDone) {
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002717 const SkPoint& intercept = xyAtT(&span);
2718 if (topPt.fY > intercept.fY || (topPt.fY == intercept.fY
2719 && topPt.fX > intercept.fX)) {
2720 topPt = intercept;
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002721 firstT = index;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002722 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002723 }
caryclark@google.comf839c032012-10-26 21:03:50 +00002724 next:
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002725 lastDone = span.fDone;
caryclark@google.comf839c032012-10-26 21:03:50 +00002726 lastUnsortable = span.fUnsortableEnd;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002727 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002728 SkASSERT(firstT >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002729 // sort the edges to find the leftmost
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002730 int step = 1;
2731 int end = nextSpan(firstT, step);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002732 if (end == -1) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002733 step = -1;
2734 end = nextSpan(firstT, step);
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00002735 SkASSERT(end != -1);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002736 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002737 // if the topmost T is not on end, or is three-way or more, find left
2738 // look for left-ness from tLeft to firstT (matching y of other)
2739 SkTDArray<Angle> angles;
2740 SkASSERT(firstT - end != 0);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002741 addTwoAngles(end, firstT, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002742 buildAngles(firstT, angles, true);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002743 SkTDArray<Angle*> sorted;
caryclark@google.comf839c032012-10-26 21:03:50 +00002744 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002745 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002746 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002747 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002748 if (onlySortable && !sortable) {
2749 unsortable = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002750 return NULL;
2751 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002752 // skip edges that have already been processed
2753 firstT = -1;
2754 Segment* leftSegment;
2755 do {
2756 const Angle* angle = sorted[++firstT];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002757 SkASSERT(!onlySortable || !angle->unsortable());
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002758 leftSegment = angle->segment();
2759 tIndex = angle->end();
2760 endIndex = angle->start();
2761 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002762 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002763 return leftSegment;
2764 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002765
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002766 // FIXME: not crazy about this
2767 // when the intersections are performed, the other index is into an
2768 // incomplete array. as the array grows, the indices become incorrect
2769 // while the following fixes the indices up again, it isn't smart about
2770 // skipping segments whose indices are already correct
2771 // assuming we leave the code that wrote the index in the first place
2772 void fixOtherTIndex() {
2773 int iCount = fTs.count();
2774 for (int i = 0; i < iCount; ++i) {
2775 Span& iSpan = fTs[i];
2776 double oT = iSpan.fOtherT;
2777 Segment* other = iSpan.fOther;
2778 int oCount = other->fTs.count();
2779 for (int o = 0; o < oCount; ++o) {
2780 Span& oSpan = other->fTs[o];
2781 if (oT == oSpan.fT && this == oSpan.fOther) {
2782 iSpan.fOtherIndex = o;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002783 break;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002784 }
2785 }
2786 }
2787 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002788
caryclark@google.com4eeda372012-12-06 21:47:48 +00002789 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002790 fDoneSpans = 0;
2791 fOperand = operand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00002792 fXor = evenOdd;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002793 fPts = pts;
2794 fVerb = verb;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002795 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00002796
caryclark@google.com3586ece2012-12-27 18:46:58 +00002797 void initWinding(int start, int end) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002798 int local = spanSign(start, end);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002799 int oppLocal = oppSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002800 (void) markAndChaseWinding(start, end, local, oppLocal);
caryclark@google.com73ca6242013-01-17 21:02:47 +00002801 // OPTIMIZATION: the reverse mark and chase could skip the first marking
2802 (void) markAndChaseWinding(end, start, local, oppLocal);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002803 }
2804
caryclark@google.com3586ece2012-12-27 18:46:58 +00002805 void initWinding(int start, int end, int winding, int oppWinding) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002806 int local = spanSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002807 if (local * winding >= 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002808 winding += local;
2809 }
2810 int oppLocal = oppSign(start, end);
2811 if (oppLocal * oppWinding >= 0) {
2812 oppWinding += oppLocal;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002813 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002814 (void) markAndChaseWinding(start, end, winding, oppWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002815 }
2816
caryclark@google.com3586ece2012-12-27 18:46:58 +00002817/*
2818when we start with a vertical intersect, we try to use the dx to determine if the edge is to
2819the 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 +00002820sign or not. However, this isn't enough.
2821If 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 +00002822If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
2823from 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 +00002824the same winding is shared by both.
caryclark@google.com3586ece2012-12-27 18:46:58 +00002825*/
2826 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
2827 SkScalar hitOppDx) {
2828 SkASSERT(hitDx || !winding);
2829 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
2830 SkASSERT(dx);
2831 int windVal = windValue(SkMin32(start, end));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002832 #if DEBUG_WINDING_AT_T
2833 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
2834 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
2835 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002836 if (!winding) {
2837 winding = dx < 0 ? windVal : -windVal;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002838 } else if (winding * dx < 0) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00002839 int sideWind = winding + (dx < 0 ? windVal : -windVal);
2840 if (abs(winding) < abs(sideWind)) {
2841 winding = sideWind;
2842 }
2843 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002844 #if DEBUG_WINDING_AT_T
2845 SkDebugf(" winding=%d\n", winding);
2846 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002847 int oppLocal = oppSign(start, end);
2848 SkASSERT(hitOppDx || !oppWind || !oppLocal);
2849 int oppWindVal = oppValue(SkMin32(start, end));
2850 if (!oppWind) {
2851 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
2852 } else if (hitOppDx * dx >= 0) {
2853 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
2854 if (abs(oppWind) < abs(oppSideWind)) {
2855 oppWind = oppSideWind;
2856 }
2857 }
2858 (void) markAndChaseWinding(start, end, winding, oppWind);
2859 }
2860
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002861 bool intersected() const {
2862 return fTs.count() > 0;
2863 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002864
caryclark@google.com10227bf2012-12-28 22:10:41 +00002865 bool isCanceled(int tIndex) const {
2866 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
2867 }
2868
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002869 bool isConnected(int startIndex, int endIndex) const {
2870 return fTs[startIndex].fWindSum != SK_MinS32
2871 || fTs[endIndex].fWindSum != SK_MinS32;
2872 }
2873
caryclark@google.com235f56a2012-09-14 14:19:30 +00002874 bool isHorizontal() const {
2875 return fBounds.fTop == fBounds.fBottom;
2876 }
2877
caryclark@google.com15fa1382012-05-07 20:49:36 +00002878 bool isLinear(int start, int end) const {
2879 if (fVerb == SkPath::kLine_Verb) {
2880 return true;
2881 }
2882 if (fVerb == SkPath::kQuad_Verb) {
2883 SkPoint qPart[3];
2884 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
2885 return QuadIsLinear(qPart);
2886 } else {
2887 SkASSERT(fVerb == SkPath::kCubic_Verb);
2888 SkPoint cPart[4];
2889 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
2890 return CubicIsLinear(cPart);
2891 }
2892 }
caryclark@google.comb9738012012-07-03 19:53:30 +00002893
2894 // OPTIMIZE: successive calls could start were the last leaves off
2895 // or calls could specialize to walk forwards or backwards
2896 bool isMissing(double startT) const {
2897 size_t tCount = fTs.count();
2898 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002899 if (approximately_zero(startT - fTs[index].fT)) {
caryclark@google.comb9738012012-07-03 19:53:30 +00002900 return false;
2901 }
2902 }
2903 return true;
2904 }
2905
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002906 bool isSimple(int end) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002907 int count = fTs.count();
2908 if (count == 2) {
2909 return true;
2910 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002911 double t = fTs[end].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002912 if (approximately_less_than_zero(t)) {
2913 return !approximately_less_than_zero(fTs[1].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002914 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002915 if (approximately_greater_than_one(t)) {
2916 return !approximately_greater_than_one(fTs[count - 2].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002917 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002918 return false;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002919 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002920
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002921 bool isVertical() const {
2922 return fBounds.fLeft == fBounds.fRight;
2923 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00002924
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002925 bool isVertical(int start, int end) const {
2926 return (*SegmentVertical[fVerb])(fPts, start, end);
2927 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002928
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002929 SkScalar leftMost(int start, int end) const {
2930 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
2931 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002932
caryclark@google.com495f8e42012-05-31 13:13:11 +00002933 // this span is excluded by the winding rule -- chase the ends
2934 // as long as they are unambiguous to mark connections as done
2935 // and give them the same winding value
caryclark@google.com59823f72012-08-09 18:17:47 +00002936 Span* markAndChaseDone(const Angle* angle, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002937 int index = angle->start();
2938 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00002939 return markAndChaseDone(index, endIndex, winding);
2940 }
2941
caryclark@google.com31143cf2012-11-09 22:14:19 +00002942 Span* markAndChaseDone(int index, int endIndex, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002943 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002944 int min = SkMin32(index, endIndex);
2945 markDone(min, winding);
2946 Span* last;
2947 Segment* other = this;
2948 while ((other = other->nextChase(index, step, min, last))) {
2949 other->markDone(min, winding);
2950 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002951 return last;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002952 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002953
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002954 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
2955 int index = angle->start();
2956 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00002957 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002958 int min = SkMin32(index, endIndex);
2959 markDoneBinary(min, winding, oppWinding);
2960 Span* last;
2961 Segment* other = this;
2962 while ((other = other->nextChase(index, step, min, last))) {
2963 other->markDoneBinary(min, winding, oppWinding);
2964 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002965 return last;
2966 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002967
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002968 Span* markAndChaseDoneBinary(int index, int endIndex) {
2969 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002970 int min = SkMin32(index, endIndex);
2971 markDoneBinary(min);
2972 Span* last;
2973 Segment* other = this;
2974 while ((other = other->nextChase(index, step, min, last))) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002975 if (other->done()) {
2976 return NULL;
2977 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002978 other->markDoneBinary(min);
2979 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00002980 return last;
2981 }
2982
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002983 Span* markAndChaseDoneUnary(int index, int endIndex) {
2984 int step = SkSign32(endIndex - index);
2985 int min = SkMin32(index, endIndex);
2986 markDoneUnary(min);
2987 Span* last;
2988 Segment* other = this;
2989 while ((other = other->nextChase(index, step, min, last))) {
2990 if (other->done()) {
2991 return NULL;
2992 }
2993 other->markDoneUnary(min);
2994 }
2995 return last;
2996 }
2997
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002998 Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
2999 int index = angle->start();
3000 int endIndex = angle->end();
3001 return markAndChaseDone(index, endIndex, winding);
3002 }
3003
caryclark@google.com4eeda372012-12-06 21:47:48 +00003004 Span* markAndChaseWinding(const Angle* angle, const int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003005 int index = angle->start();
3006 int endIndex = angle->end();
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003007 int step = SkSign32(endIndex - index);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003008 int min = SkMin32(index, endIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00003009 markWinding(min, winding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003010 Span* last;
3011 Segment* other = this;
3012 while ((other = other->nextChase(index, step, min, last))) {
3013 if (other->fTs[min].fWindSum != SK_MinS32) {
3014 SkASSERT(other->fTs[min].fWindSum == winding);
3015 return NULL;
3016 }
3017 other->markWinding(min, winding);
3018 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003019 return last;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003020 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003021
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003022 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003023 int min = SkMin32(index, endIndex);
3024 int step = SkSign32(endIndex - index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003025 markWinding(min, winding, oppWinding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003026 Span* last;
3027 Segment* other = this;
3028 while ((other = other->nextChase(index, step, min, last))) {
3029 if (other->fTs[min].fWindSum != SK_MinS32) {
3030 SkASSERT(other->fTs[min].fWindSum == winding);
3031 return NULL;
3032 }
3033 other->markWinding(min, winding, oppWinding);
3034 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003035 return last;
3036 }
3037
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003038 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
3039 int start = angle->start();
3040 int end = angle->end();
3041 return markAndChaseWinding(start, end, winding, oppWinding);
3042 }
3043
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003044 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
3045 SkASSERT(angle->segment() == this);
3046 if (useInnerWinding(maxWinding, sumWinding)) {
3047 maxWinding = sumWinding;
3048 }
3049 Span* last;
3050 if (activeAngle) {
3051 last = markAndChaseWinding(angle, maxWinding);
3052 } else {
3053 last = markAndChaseDoneUnary(angle, maxWinding);
3054 }
3055 return last;
3056 }
3057
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003058 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
3059 bool activeAngle, const Angle* angle) {
3060 SkASSERT(angle->segment() == this);
3061 if (useInnerWinding(maxWinding, sumWinding)) {
3062 maxWinding = sumWinding;
3063 }
3064 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
3065 oppMaxWinding = oppSumWinding;
3066 }
3067 Span* last;
3068 if (activeAngle) {
3069 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3070 } else {
3071 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
3072 }
3073 return last;
3074 }
3075
caryclark@google.com495f8e42012-05-31 13:13:11 +00003076 // FIXME: this should also mark spans with equal (x,y)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003077 // This may be called when the segment is already marked done. While this
3078 // wastes time, it shouldn't do any more than spin through the T spans.
rmistry@google.comd6176b02012-08-23 18:14:13 +00003079 // OPTIMIZATION: abort on first done found (assuming that this code is
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003080 // always called to mark segments done).
caryclark@google.com59823f72012-08-09 18:17:47 +00003081 void markDone(int index, int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003082 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003083 SkASSERT(winding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003084 double referenceT = fTs[index].fT;
3085 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003086 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3087 markOneDone(__FUNCTION__, lesser, winding);
3088 }
3089 do {
3090 markOneDone(__FUNCTION__, index, winding);
3091 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003092 }
3093
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003094 void markDoneBinary(int index, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003095 // SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003096 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003097 double referenceT = fTs[index].fT;
3098 int lesser = index;
3099 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003100 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003101 }
3102 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003103 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
3104 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3105 }
3106
3107 void markDoneBinary(int index) {
3108 double referenceT = fTs[index].fT;
3109 int lesser = index;
3110 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3111 markOneDoneBinary(__FUNCTION__, lesser);
3112 }
3113 do {
3114 markOneDoneBinary(__FUNCTION__, index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003115 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003116 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00003117
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003118 void markDoneUnary(int index, int winding) {
3119 // SkASSERT(!done());
3120 SkASSERT(winding);
3121 double referenceT = fTs[index].fT;
3122 int lesser = index;
3123 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3124 markOneDoneUnary(__FUNCTION__, lesser, winding);
3125 }
3126 do {
3127 markOneDoneUnary(__FUNCTION__, index, winding);
3128 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3129 }
3130
3131 void markDoneUnary(int index) {
3132 double referenceT = fTs[index].fT;
3133 int lesser = index;
3134 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3135 markOneDoneUnary(__FUNCTION__, lesser);
3136 }
3137 do {
3138 markOneDoneUnary(__FUNCTION__, index);
3139 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3140 }
3141
caryclark@google.com24bec792012-08-20 12:43:57 +00003142 void markOneDone(const char* funName, int tIndex, int winding) {
3143 Span* span = markOneWinding(funName, tIndex, winding);
3144 if (!span) {
3145 return;
3146 }
3147 span->fDone = true;
3148 fDoneSpans++;
3149 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003150
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003151 void markOneDoneBinary(const char* funName, int tIndex) {
3152 Span* span = verifyOneWinding(funName, tIndex);
3153 if (!span) {
3154 return;
3155 }
3156 span->fDone = true;
3157 fDoneSpans++;
3158 }
3159
3160 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003161 Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
3162 if (!span) {
3163 return;
3164 }
3165 span->fDone = true;
3166 fDoneSpans++;
3167 }
3168
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003169 void markOneDoneUnary(const char* funName, int tIndex) {
3170 Span* span = verifyOneWindingU(funName, tIndex);
3171 if (!span) {
3172 return;
3173 }
3174 span->fDone = true;
3175 fDoneSpans++;
3176 }
3177
3178 void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3179 Span* span = markOneWinding(funName, tIndex, winding);
3180 if (!span) {
3181 return;
3182 }
3183 span->fDone = true;
3184 fDoneSpans++;
3185 }
3186
caryclark@google.com24bec792012-08-20 12:43:57 +00003187 Span* markOneWinding(const char* funName, int tIndex, int winding) {
3188 Span& span = fTs[tIndex];
3189 if (span.fDone) {
3190 return NULL;
3191 }
3192 #if DEBUG_MARK_DONE
3193 debugShowNewWinding(funName, span, winding);
3194 #endif
3195 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com03f97062012-08-21 13:13:52 +00003196 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00003197 SkASSERT(abs(winding) <= gDebugMaxWindSum);
caryclark@google.com03f97062012-08-21 13:13:52 +00003198 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00003199 span.fWindSum = winding;
3200 return &span;
3201 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003202
caryclark@google.com31143cf2012-11-09 22:14:19 +00003203 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
3204 Span& span = fTs[tIndex];
3205 if (span.fDone) {
3206 return NULL;
3207 }
3208 #if DEBUG_MARK_DONE
3209 debugShowNewWinding(funName, span, winding, oppWinding);
3210 #endif
3211 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3212 #ifdef SK_DEBUG
3213 SkASSERT(abs(winding) <= gDebugMaxWindSum);
3214 #endif
3215 span.fWindSum = winding;
3216 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3217 #ifdef SK_DEBUG
3218 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
3219 #endif
3220 span.fOppSum = oppWinding;
3221 return &span;
3222 }
3223
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003224 Span* verifyOneWinding(const char* funName, int tIndex) {
3225 Span& span = fTs[tIndex];
3226 if (span.fDone) {
3227 return NULL;
3228 }
3229 #if DEBUG_MARK_DONE
3230 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3231 #endif
3232 SkASSERT(span.fWindSum != SK_MinS32);
3233 SkASSERT(span.fOppSum != SK_MinS32);
3234 return &span;
3235 }
3236
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003237 Span* verifyOneWindingU(const char* funName, int tIndex) {
3238 Span& span = fTs[tIndex];
3239 if (span.fDone) {
3240 return NULL;
3241 }
3242 #if DEBUG_MARK_DONE
3243 debugShowNewWinding(funName, span, span.fWindSum);
3244 #endif
3245 SkASSERT(span.fWindSum != SK_MinS32);
3246 return &span;
3247 }
3248
caryclark@google.comf839c032012-10-26 21:03:50 +00003249 // note that just because a span has one end that is unsortable, that's
3250 // not enough to mark it done. The other end may be sortable, allowing the
3251 // span to be added.
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003252 // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003253 void markUnsortable(int start, int end) {
3254 Span* span = &fTs[start];
3255 if (start < end) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003256#if DEBUG_UNSORTABLE
3257 SkDebugf("%s start id=%d [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fID, start,
3258 xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003259#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003260 span->fUnsortableStart = true;
3261 } else {
3262 --span;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003263#if DEBUG_UNSORTABLE
3264 SkDebugf("%s end id=%d [%d] (%1.9g,%1.9g) next:(%1.9g,%1.9g)\n", __FUNCTION__, fID,
3265 start - 1, xAtT(start - 1), yAtT(start - 1), xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003266#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003267 span->fUnsortableEnd = true;
3268 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003269 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003270 return;
3271 }
3272 span->fDone = true;
3273 fDoneSpans++;
3274 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003275
caryclark@google.com59823f72012-08-09 18:17:47 +00003276 void markWinding(int index, int winding) {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003277 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003278 SkASSERT(winding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003279 double referenceT = fTs[index].fT;
3280 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003281 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3282 markOneWinding(__FUNCTION__, lesser, winding);
3283 }
3284 do {
3285 markOneWinding(__FUNCTION__, index, winding);
3286 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003287 }
3288
3289 void markWinding(int index, int winding, int oppWinding) {
3290 // SkASSERT(!done());
caryclark@google.com4eeda372012-12-06 21:47:48 +00003291 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003292 double referenceT = fTs[index].fT;
3293 int lesser = index;
3294 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3295 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003296 }
3297 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003298 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3299 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003300 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003301
caryclark@google.com2ddff932012-08-07 21:25:27 +00003302 void matchWindingValue(int tIndex, double t, bool borrowWind) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003303 int nextDoorWind = SK_MaxS32;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003304 int nextOppWind = SK_MaxS32;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003305 if (tIndex > 0) {
3306 const Span& below = fTs[tIndex - 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003307 if (approximately_negative(t - below.fT)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003308 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003309 nextOppWind = below.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003310 }
3311 }
3312 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3313 const Span& above = fTs[tIndex + 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003314 if (approximately_negative(above.fT - t)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003315 nextDoorWind = above.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003316 nextOppWind = above.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003317 }
3318 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003319 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3320 const Span& below = fTs[tIndex - 1];
3321 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003322 nextOppWind = below.fOppValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003323 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003324 if (nextDoorWind != SK_MaxS32) {
3325 Span& newSpan = fTs[tIndex];
3326 newSpan.fWindValue = nextDoorWind;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003327 newSpan.fOppValue = nextOppWind;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003328 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003329 newSpan.fDone = true;
3330 ++fDoneSpans;
3331 }
3332 }
3333 }
3334
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003335 bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3336 // find bounds
3337 Bounds bounds;
3338 bounds.setPoint(xyAtT(index));
3339 bounds.add(xyAtT(endIndex));
3340 SkScalar width = bounds.width();
3341 SkScalar height = bounds.height();
3342 if (width > height) {
3343 if (approximately_negative(width)) {
3344 unsortable = true; // edge is too small to resolve meaningfully
3345 }
3346 return false;
3347 } else {
3348 if (approximately_negative(height)) {
3349 unsortable = true; // edge is too small to resolve meaningfully
3350 }
3351 return true;
3352 }
3353 }
3354
caryclark@google.com9764cc62012-07-12 19:29:45 +00003355 // return span if when chasing, two or more radiating spans are not done
3356 // OPTIMIZATION: ? multiple spans is detected when there is only one valid
3357 // candidate and the remaining spans have windValue == 0 (canceled by
3358 // coincidence). The coincident edges could either be removed altogether,
3359 // or this code could be more complicated in detecting this case. Worth it?
3360 bool multipleSpans(int end) const {
3361 return end > 0 && end < fTs.count() - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00003362 }
3363
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003364 bool nextCandidate(int& start, int& end) const {
caryclark@google.com10227bf2012-12-28 22:10:41 +00003365 while (fTs[end].fDone) {
3366 if (fTs[end].fT == 1) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003367 return false;
3368 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00003369 ++end;
3370 }
3371 start = end;
3372 end = nextExactSpan(start, 1);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003373 return true;
3374 }
3375
caryclark@google.com4eeda372012-12-06 21:47:48 +00003376 Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
3377 int end = nextExactSpan(index, step);
3378 SkASSERT(end >= 0);
3379 if (multipleSpans(end)) {
3380 last = &fTs[end];
3381 return NULL;
3382 }
3383 const Span& endSpan = fTs[end];
3384 Segment* other = endSpan.fOther;
3385 index = endSpan.fOtherIndex;
caryclark@google.comaa358312013-01-29 20:28:49 +00003386 SkASSERT(index >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003387 int otherEnd = other->nextExactSpan(index, step);
caryclark@google.comaa358312013-01-29 20:28:49 +00003388 SkASSERT(otherEnd >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003389 min = SkMin32(index, otherEnd);
3390 return other;
3391 }
3392
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003393 // This has callers for two different situations: one establishes the end
3394 // of the current span, and one establishes the beginning of the next span
3395 // (thus the name). When this is looking for the end of the current span,
3396 // coincidence is found when the beginning Ts contain -step and the end
3397 // contains step. When it is looking for the beginning of the next, the
3398 // first Ts found can be ignored and the last Ts should contain -step.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003399 // OPTIMIZATION: probably should split into two functions
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003400 int nextSpan(int from, int step) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003401 const Span& fromSpan = fTs[from];
caryclark@google.com495f8e42012-05-31 13:13:11 +00003402 int count = fTs.count();
3403 int to = from;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003404 while (step > 0 ? ++to < count : --to >= 0) {
3405 const Span& span = fTs[to];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003406 if (approximately_zero(span.fT - fromSpan.fT)) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003407 continue;
3408 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003409 return to;
3410 }
3411 return -1;
3412 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +00003413
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003414 // FIXME
3415 // this returns at any difference in T, vs. a preset minimum. It may be
3416 // that all callers to nextSpan should use this instead.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003417 // OPTIMIZATION splitting this into separate loops for up/down steps
3418 // would allow using precisely_negative instead of precisely_zero
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003419 int nextExactSpan(int from, int step) const {
3420 const Span& fromSpan = fTs[from];
3421 int count = fTs.count();
3422 int to = from;
3423 while (step > 0 ? ++to < count : --to >= 0) {
3424 const Span& span = fTs[to];
caryclark@google.coma461ff02012-10-11 12:54:23 +00003425 if (precisely_zero(span.fT - fromSpan.fT)) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003426 continue;
3427 }
3428 return to;
3429 }
3430 return -1;
3431 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003432
caryclark@google.com235f56a2012-09-14 14:19:30 +00003433 bool operand() const {
3434 return fOperand;
3435 }
3436
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003437 int oppSign(const Angle* angle) const {
3438 SkASSERT(angle->segment() == this);
3439 return oppSign(angle->start(), angle->end());
3440 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003441
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003442 int oppSign(int startIndex, int endIndex) const {
3443 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3444 : fTs[endIndex].fOppValue;
3445#if DEBUG_WIND_BUMP
3446 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3447#endif
3448 return result;
3449 }
3450
caryclark@google.com31143cf2012-11-09 22:14:19 +00003451 int oppSum(int tIndex) const {
3452 return fTs[tIndex].fOppSum;
3453 }
3454
3455 int oppSum(const Angle* angle) const {
3456 int lesser = SkMin32(angle->start(), angle->end());
3457 return fTs[lesser].fOppSum;
caryclark@google.com235f56a2012-09-14 14:19:30 +00003458 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003459
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003460 int oppValue(int tIndex) const {
3461 return fTs[tIndex].fOppValue;
3462 }
3463
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003464 int oppValue(const Angle* angle) const {
3465 int lesser = SkMin32(angle->start(), angle->end());
3466 return fTs[lesser].fOppValue;
3467 }
3468
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003469 const SkPoint* pts() const {
3470 return fPts;
3471 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003472
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003473 void reset() {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003474 init(NULL, (SkPath::Verb) -1, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003475 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3476 fTs.reset();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003477 }
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +00003478
caryclark@google.com4eeda372012-12-06 21:47:48 +00003479 void setOppXor(bool isOppXor) {
3480 fOppXor = isOppXor;
3481 }
3482
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003483 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3484 int deltaSum = spanSign(index, endIndex);
3485 maxWinding = sumWinding;
3486 sumWinding = sumWinding -= deltaSum;
3487 }
3488
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003489 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3490 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3491 int deltaSum = spanSign(index, endIndex);
3492 int oppDeltaSum = oppSign(index, endIndex);
3493 if (operand()) {
3494 maxWinding = sumSuWinding;
3495 sumWinding = sumSuWinding -= deltaSum;
3496 oppMaxWinding = sumMiWinding;
3497 oppSumWinding = sumMiWinding -= oppDeltaSum;
3498 } else {
3499 maxWinding = sumMiWinding;
3500 sumWinding = sumMiWinding -= deltaSum;
3501 oppMaxWinding = sumSuWinding;
3502 oppSumWinding = sumSuWinding -= oppDeltaSum;
3503 }
3504 }
3505
caryclark@google.comf839c032012-10-26 21:03:50 +00003506 // This marks all spans unsortable so that this info is available for early
3507 // exclusion in find top and others. This could be optimized to only mark
3508 // adjacent spans that unsortable. However, this makes it difficult to later
3509 // determine starting points for edge detection in find top and the like.
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003510 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
caryclark@google.comf839c032012-10-26 21:03:50 +00003511 bool sortable = true;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003512 int angleCount = angles.count();
3513 int angleIndex;
3514 angleList.setReserve(angleCount);
3515 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003516 Angle& angle = angles[angleIndex];
caryclark@google.comf839c032012-10-26 21:03:50 +00003517 *angleList.append() = &angle;
3518 sortable &= !angle.unsortable();
3519 }
3520 if (sortable) {
3521 QSort<Angle>(angleList.begin(), angleList.end() - 1);
3522 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3523 if (angles[angleIndex].unsortable()) {
3524 sortable = false;
3525 break;
3526 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003527 }
3528 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003529 if (!sortable) {
3530 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3531 Angle& angle = angles[angleIndex];
3532 angle.segment()->markUnsortable(angle.start(), angle.end());
3533 }
3534 }
3535 return sortable;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003536 }
3537
caryclark@google.com1577e8f2012-05-22 17:01:14 +00003538 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003539 const Span& span(int tIndex) const {
3540 return fTs[tIndex];
3541 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003542
caryclark@google.com235f56a2012-09-14 14:19:30 +00003543 int spanSign(const Angle* angle) const {
3544 SkASSERT(angle->segment() == this);
3545 return spanSign(angle->start(), angle->end());
3546 }
3547
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003548 int spanSign(int startIndex, int endIndex) const {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003549 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3550 : fTs[endIndex].fWindValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003551#if DEBUG_WIND_BUMP
3552 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3553#endif
3554 return result;
3555 }
3556
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003557 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003558 double t(int tIndex) const {
3559 return fTs[tIndex].fT;
3560 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003561
caryclark@google.com10227bf2012-12-28 22:10:41 +00003562 double tAtMid(int start, int end, double mid) const {
3563 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
3564 }
3565
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003566 bool tiny(const Angle* angle) const {
3567 int start = angle->start();
3568 int end = angle->end();
caryclark@google.comf839c032012-10-26 21:03:50 +00003569 const Span& mSpan = fTs[SkMin32(start, end)];
3570 return mSpan.fTiny;
3571 }
3572
caryclark@google.com18063442012-07-25 12:05:18 +00003573 static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3574 double start) {
3575 int outCount = outsideTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003576 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
caryclark@google.com18063442012-07-25 12:05:18 +00003577 *outsideTs.append() = end;
3578 *outsideTs.append() = start;
3579 }
3580 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003581
caryclark@google.com24bec792012-08-20 12:43:57 +00003582 void undoneSpan(int& start, int& end) {
3583 size_t tCount = fTs.count();
3584 size_t index;
3585 for (index = 0; index < tCount; ++index) {
3586 if (!fTs[index].fDone) {
3587 break;
3588 }
3589 }
3590 SkASSERT(index < tCount - 1);
3591 start = index;
3592 double startT = fTs[index].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003593 while (approximately_negative(fTs[++index].fT - startT))
caryclark@google.com24bec792012-08-20 12:43:57 +00003594 SkASSERT(index < tCount);
3595 SkASSERT(index < tCount);
3596 end = index;
3597 }
caryclark@google.com18063442012-07-25 12:05:18 +00003598
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003599 bool unsortable(int index) const {
3600 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3601 }
3602
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003603 void updatePts(const SkPoint pts[]) {
3604 fPts = pts;
3605 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003606
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003607 int updateOppWinding(int index, int endIndex) const {
3608 int lesser = SkMin32(index, endIndex);
3609 int oppWinding = oppSum(lesser);
3610 int oppSpanWinding = oppSign(index, endIndex);
3611 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)) {
3612 oppWinding -= oppSpanWinding;
3613 }
3614 return oppWinding;
3615 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003616
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003617 int updateOppWinding(const Angle* angle) const {
3618 int startIndex = angle->start();
3619 int endIndex = angle->end();
3620 return updateOppWinding(endIndex, startIndex);
3621 }
3622
3623 int updateOppWindingReverse(const Angle* angle) const {
3624 int startIndex = angle->start();
3625 int endIndex = angle->end();
3626 return updateOppWinding(startIndex, endIndex);
3627 }
3628
3629 int updateWinding(int index, int endIndex) const {
3630 int lesser = SkMin32(index, endIndex);
3631 int winding = windSum(lesser);
3632 int spanWinding = spanSign(index, endIndex);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003633 if (winding && useInnerWinding(winding - spanWinding, winding)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003634 winding -= spanWinding;
3635 }
3636 return winding;
3637 }
3638
3639 int updateWinding(const Angle* angle) const {
3640 int startIndex = angle->start();
3641 int endIndex = angle->end();
3642 return updateWinding(endIndex, startIndex);
3643 }
3644
3645 int updateWindingReverse(const Angle* angle) const {
3646 int startIndex = angle->start();
3647 int endIndex = angle->end();
3648 return updateWinding(startIndex, endIndex);
3649 }
3650
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003651 SkPath::Verb verb() const {
3652 return fVerb;
3653 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003654
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003655 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003656 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3657 return SK_MinS32;
3658 }
3659 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3660 SkASSERT(winding != SK_MinS32);
3661 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003662 #if DEBUG_WINDING_AT_T
3663 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003664 #endif
3665 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark@google.com3586ece2012-12-27 18:46:58 +00003666 dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003667 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3668 dx = fPts[2].fX - fPts[1].fX - dx;
3669 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003670 if (dx == 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003671 #if DEBUG_WINDING_AT_T
3672 SkDebugf(" dx=0 winding=SK_MinS32\n");
3673 #endif
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003674 return SK_MinS32;
3675 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003676 if (winding * dx > 0) { // if same signs, result is negative
3677 winding += dx > 0 ? -windVal : windVal;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003678 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003679 #if DEBUG_WINDING_AT_T
3680 SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding);
3681 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003682 return winding;
3683 }
3684
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003685 int windSum(int tIndex) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003686 return fTs[tIndex].fWindSum;
3687 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003688
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003689 int windSum(const Angle* angle) const {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003690 int start = angle->start();
3691 int end = angle->end();
3692 int index = SkMin32(start, end);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003693 return windSum(index);
caryclark@google.com495f8e42012-05-31 13:13:11 +00003694 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003695
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003696 int windValue(int tIndex) const {
3697 return fTs[tIndex].fWindValue;
3698 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003699
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003700 int windValue(const Angle* angle) const {
3701 int start = angle->start();
3702 int end = angle->end();
3703 int index = SkMin32(start, end);
3704 return windValue(index);
3705 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00003706
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003707 int windValueAt(double t) const {
3708 int count = fTs.count();
3709 for (int index = 0; index < count; ++index) {
3710 if (fTs[index].fT == t) {
3711 return fTs[index].fWindValue;
3712 }
3713 }
3714 SkASSERT(0);
3715 return 0;
3716 }
3717
caryclark@google.com3586ece2012-12-27 18:46:58 +00003718 SkScalar xAtT(int index) const {
3719 return xAtT(&fTs[index]);
3720 }
3721
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003722 SkScalar xAtT(const Span* span) const {
3723 return xyAtT(span).fX;
3724 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003725
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003726 const SkPoint& xyAtT(int index) const {
3727 return xyAtT(&fTs[index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003728 }
3729
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003730 const SkPoint& xyAtT(const Span* span) const {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003731 if (SkScalarIsNaN(span->fPt.fX)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003732 if (span->fT == 0) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003733 span->fPt = fPts[0];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003734 } else if (span->fT == 1) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003735 span->fPt = fPts[fVerb];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003736 } else {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003737 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003738 }
3739 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00003740 return span->fPt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003741 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003742
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003743 // used only by right angle winding finding
caryclark@google.com10227bf2012-12-28 22:10:41 +00003744 void xyAtT(double mid, SkPoint& pt) const {
3745 (*SegmentXYAtT[fVerb])(fPts, mid, &pt);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003746 }
3747
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003748 SkScalar yAtT(int index) const {
3749 return yAtT(&fTs[index]);
3750 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003751
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003752 SkScalar yAtT(const Span* span) const {
3753 return xyAtT(span).fY;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003754 }
3755
caryclark@google.com4eeda372012-12-06 21:47:48 +00003756 void zeroCoincidentOpp(Span* oTest, int index) {
3757 Span* const test = &fTs[index];
3758 Span* end = test;
3759 do {
3760 end->fOppValue = 0;
3761 end = &fTs[++index];
3762 } while (approximately_negative(end->fT - test->fT));
3763 }
3764
3765 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
3766 Span* const oTest = &fTs[oIndex];
3767 Span* oEnd = oTest;
3768 const double startT = test->fT;
3769 const double oStartT = oTest->fT;
3770 double otherTMatch = (test->fT - startT) * tRatio + oStartT;
3771 while (!approximately_negative(oEndT - oEnd->fT)
3772 && approximately_negative(oEnd->fT - otherTMatch)) {
3773 oEnd->fOppValue = 0;
3774 oEnd = &fTs[++oIndex];
3775 }
3776 }
3777
3778 void zeroSpan(Span* span) {
3779 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
caryclark@google.com6ec15262012-11-16 20:16:50 +00003780 span->fWindValue = 0;
caryclark@google.com729e1c42012-11-21 21:36:34 +00003781 span->fOppValue = 0;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003782 SkASSERT(!span->fDone);
3783 span->fDone = true;
3784 ++fDoneSpans;
caryclark@google.com6ec15262012-11-16 20:16:50 +00003785 }
3786
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003787#if DEBUG_DUMP
3788 void dump() const {
3789 const char className[] = "Segment";
3790 const int tab = 4;
3791 for (int i = 0; i < fTs.count(); ++i) {
3792 SkPoint out;
3793 (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
3794 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003795 " otherT=%1.9g windSum=%d\n",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003796 tab + sizeof(className), className, fID,
3797 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003798 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003799 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00003800 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003801 tab + sizeof(className), className, fID,
caryclark@google.com15fa1382012-05-07 20:49:36 +00003802 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003803 }
3804#endif
3805
caryclark@google.com47580692012-07-23 12:14:49 +00003806#if DEBUG_CONCIDENT
caryclark@google.comaa358312013-01-29 20:28:49 +00003807 // SkASSERT if pair has not already been added
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003808 void debugAddTPair(double t, const Segment& other, double otherT) const {
caryclark@google.comcc905052012-07-25 20:59:42 +00003809 for (int i = 0; i < fTs.count(); ++i) {
3810 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
3811 return;
3812 }
3813 }
3814 SkASSERT(0);
3815 }
3816#endif
3817
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003818#if DEBUG_DUMP
3819 int debugID() const {
3820 return fID;
3821 }
3822#endif
3823
caryclark@google.com24bec792012-08-20 12:43:57 +00003824#if DEBUG_WINDING
3825 void debugShowSums() const {
3826 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
3827 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
3828 for (int i = 0; i < fTs.count(); ++i) {
3829 const Span& span = fTs[i];
3830 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
3831 if (span.fWindSum == SK_MinS32) {
3832 SkDebugf("?");
3833 } else {
3834 SkDebugf("%d", span.fWindSum);
3835 }
3836 SkDebugf("]");
3837 }
3838 SkDebugf("\n");
3839 }
3840#endif
3841
caryclark@google.comcc905052012-07-25 20:59:42 +00003842#if DEBUG_CONCIDENT
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003843 void debugShowTs() const {
caryclark@google.com24bec792012-08-20 12:43:57 +00003844 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003845 int lastWind = -1;
3846 int lastOpp = -1;
3847 double lastT = -1;
3848 int i;
3849 for (i = 0; i < fTs.count(); ++i) {
3850 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
3851 || lastOpp != fTs[i].fOppValue;
3852 if (change && lastWind >= 0) {
3853 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3854 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3855 }
3856 if (change) {
3857 SkDebugf(" [o=%d", fTs[i].fOther->fID);
3858 lastWind = fTs[i].fWindValue;
3859 lastOpp = fTs[i].fOppValue;
3860 lastT = fTs[i].fT;
3861 } else {
3862 SkDebugf(",%d", fTs[i].fOther->fID);
3863 }
3864 }
3865 if (i <= 0) {
3866 return;
3867 }
3868 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3869 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3870 if (fOperand) {
3871 SkDebugf(" operand");
3872 }
3873 if (done()) {
3874 SkDebugf(" done");
caryclark@google.com47580692012-07-23 12:14:49 +00003875 }
3876 SkDebugf("\n");
3877 }
3878#endif
3879
caryclark@google.com027de222012-07-12 12:52:50 +00003880#if DEBUG_ACTIVE_SPANS
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003881 void debugShowActiveSpans() const {
caryclark@google.com027de222012-07-12 12:52:50 +00003882 if (done()) {
3883 return;
3884 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003885#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3886 int lastId = -1;
3887 double lastT = -1;
3888#endif
caryclark@google.com027de222012-07-12 12:52:50 +00003889 for (int i = 0; i < fTs.count(); ++i) {
3890 if (fTs[i].fDone) {
3891 continue;
3892 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003893#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3894 if (lastId == fID && lastT == fTs[i].fT) {
3895 continue;
3896 }
3897 lastId = fID;
3898 lastT = fTs[i].fT;
3899#endif
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003900 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com027de222012-07-12 12:52:50 +00003901 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3902 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3903 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3904 }
3905 const Span* span = &fTs[i];
rmistry@google.comd6176b02012-08-23 18:14:13 +00003906 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
caryclark@google.com0c803d02012-08-06 11:15:47 +00003907 xAtT(span), yAtT(span));
caryclark@google.com027de222012-07-12 12:52:50 +00003908 const Segment* other = fTs[i].fOther;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003909 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
3910 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
3911 if (fTs[i].fWindSum == SK_MinS32) {
3912 SkDebugf("?");
3913 } else {
3914 SkDebugf("%d", fTs[i].fWindSum);
3915 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003916 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
caryclark@google.com027de222012-07-12 12:52:50 +00003917 }
3918 }
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +00003919
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003920 // This isn't useful yet -- but leaving it in for now in case i think of something
3921 // to use it for
3922 void validateActiveSpans() const {
3923 if (done()) {
3924 return;
3925 }
3926 int tCount = fTs.count();
3927 for (int index = 0; index < tCount; ++index) {
3928 if (fTs[index].fDone) {
3929 continue;
3930 }
3931 // count number of connections which are not done
3932 int first = index;
3933 double baseT = fTs[index].fT;
3934 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
3935 --first;
3936 }
3937 int last = index;
3938 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
3939 ++last;
3940 }
3941 int connections = 0;
3942 connections += first > 0 && !fTs[first - 1].fDone;
3943 for (int test = first; test <= last; ++test) {
3944 connections += !fTs[test].fDone;
3945 const Segment* other = fTs[test].fOther;
3946 int oIndex = fTs[test].fOtherIndex;
3947 connections += !other->fTs[oIndex].fDone;
3948 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
3949 }
3950 // SkASSERT(!(connections & 1));
3951 }
3952 }
caryclark@google.com027de222012-07-12 12:52:50 +00003953#endif
3954
caryclark@google.com0c803d02012-08-06 11:15:47 +00003955#if DEBUG_MARK_DONE
3956 void debugShowNewWinding(const char* fun, const Span& span, int winding) {
3957 const SkPoint& pt = xyAtT(&span);
3958 SkDebugf("%s id=%d", fun, fID);
3959 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3960 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3961 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3962 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003963 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3964 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3965 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d windSum=",
3966 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, winding);
caryclark@google.com0c803d02012-08-06 11:15:47 +00003967 if (span.fWindSum == SK_MinS32) {
3968 SkDebugf("?");
3969 } else {
3970 SkDebugf("%d", span.fWindSum);
3971 }
3972 SkDebugf(" windValue=%d\n", span.fWindValue);
3973 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003974
3975 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
3976 const SkPoint& pt = xyAtT(&span);
3977 SkDebugf("%s id=%d", fun, fID);
3978 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3979 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3980 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3981 }
3982 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3983 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3984 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=",
3985 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
3986 winding, oppWinding);
3987 if (span.fOppSum == SK_MinS32) {
3988 SkDebugf("?");
3989 } else {
3990 SkDebugf("%d", span.fOppSum);
3991 }
3992 SkDebugf(" windSum=");
3993 if (span.fWindSum == SK_MinS32) {
3994 SkDebugf("?");
3995 } else {
3996 SkDebugf("%d", span.fWindSum);
3997 }
3998 SkDebugf(" windValue=%d\n", span.fWindValue);
3999 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00004000#endif
4001
caryclark@google.com47580692012-07-23 12:14:49 +00004002#if DEBUG_SORT
caryclark@google.com03f97062012-08-21 13:13:52 +00004003 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
caryclark@google.com31143cf2012-11-09 22:14:19 +00004004 const int contourWinding, const int oppContourWinding) const {
caryclark@google.comafe56de2012-07-24 18:11:03 +00004005 SkASSERT(angles[first]->segment() == this);
caryclark@google.com200c2112012-08-03 15:05:04 +00004006 SkASSERT(angles.count() > 1);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004007 int lastSum = contourWinding;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004008 int oppLastSum = oppContourWinding;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004009 const Angle* firstAngle = angles[first];
4010 int windSum = lastSum - spanSign(firstAngle);
4011 int oppoSign = oppSign(firstAngle);
4012 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004013 SkDebugf("%s %s contourWinding=%d oppContourWinding=%d sign=%d\n", fun, __FUNCTION__,
4014 contourWinding, oppContourWinding, spanSign(angles[first]));
caryclark@google.comafe56de2012-07-24 18:11:03 +00004015 int index = first;
4016 bool firstTime = true;
caryclark@google.com47580692012-07-23 12:14:49 +00004017 do {
4018 const Angle& angle = *angles[index];
4019 const Segment& segment = *angle.segment();
4020 int start = angle.start();
4021 int end = angle.end();
4022 const Span& sSpan = segment.fTs[start];
4023 const Span& eSpan = segment.fTs[end];
4024 const Span& mSpan = segment.fTs[SkMin32(start, end)];
caryclark@google.com31143cf2012-11-09 22:14:19 +00004025 bool opp = segment.fOperand ^ fOperand;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004026 if (!firstTime) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004027 oppoSign = segment.oppSign(&angle);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004028 if (opp) {
4029 oppLastSum = oppWindSum;
4030 oppWindSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004031 if (oppoSign) {
4032 lastSum = windSum;
4033 windSum -= oppoSign;
4034 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004035 } else {
4036 lastSum = windSum;
4037 windSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004038 if (oppoSign) {
4039 oppLastSum = oppWindSum;
4040 oppWindSum -= oppoSign;
4041 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004042 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004043 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004044 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 +00004045 " sign=%d windValue=%d windSum=",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004046 __FUNCTION__, index, angle.unsortable() ? "*** UNSORTABLE *** " : "",
caryclark@google.comc91dfe42012-10-16 12:06:27 +00004047 segment.fID, kLVerbStr[segment.fVerb],
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004048 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
4049 segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(),
4050 mSpan.fWindValue);
4051 if (mSpan.fWindSum == SK_MinS32) {
4052 SkDebugf("?");
4053 } else {
4054 SkDebugf("%d", mSpan.fWindSum);
4055 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004056 int last, wind;
4057 if (opp) {
4058 last = oppLastSum;
4059 wind = oppWindSum;
4060 } else {
4061 last = lastSum;
4062 wind = windSum;
4063 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004064 if (!oppoSign) {
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00004065 SkDebugf(" %d->%d (max=%d)", last, wind,
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004066 useInnerWinding(last, wind) ? wind : last);
4067 } else {
4068 SkDebugf(" %d->%d (%d->%d)", last, wind, opp ? lastSum : oppLastSum,
4069 opp ? windSum : oppWindSum);
4070 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004071 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004072#if false && DEBUG_ANGLE
caryclark@google.comc899ad92012-08-23 15:24:42 +00004073 angle.debugShow(segment.xyAtT(&sSpan));
4074#endif
caryclark@google.com47580692012-07-23 12:14:49 +00004075 ++index;
4076 if (index == angles.count()) {
4077 index = 0;
4078 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004079 if (firstTime) {
4080 firstTime = false;
4081 }
caryclark@google.com47580692012-07-23 12:14:49 +00004082 } while (index != first);
4083 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00004084
4085 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
4086 const Angle* firstAngle = angles[first];
4087 const Segment* segment = firstAngle->segment();
4088 int winding = segment->updateWinding(firstAngle);
4089 int oppWinding = segment->updateOppWinding(firstAngle);
4090 debugShowSort(fun, angles, first, winding, oppWinding);
4091 }
4092
caryclark@google.com47580692012-07-23 12:14:49 +00004093#endif
4094
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004095#if DEBUG_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004096 static char as_digit(int value) {
4097 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
4098 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004099#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004100
caryclark@google.com729e1c42012-11-21 21:36:34 +00004101#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004102 int debugShowWindingValues(int slotCount, int ofInterest) const {
4103 if (!(1 << fID & ofInterest)) {
4104 return 0;
4105 }
4106 int sum = 0;
4107 SkTDArray<char> slots;
4108 slots.setCount(slotCount * 2);
4109 memset(slots.begin(), ' ', slotCount * 2);
4110 for (int i = 0; i < fTs.count(); ++i) {
4111 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
4112 // continue;
4113 // }
4114 sum += fTs[i].fWindValue;
4115 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
4116 sum += fTs[i].fOppValue;
4117 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
4118 }
4119 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
4120 slots.begin() + slotCount);
4121 return sum;
4122 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004123#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004124
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004125private:
4126 const SkPoint* fPts;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004127 Bounds fBounds;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004128 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
caryclark@google.com4eeda372012-12-06 21:47:48 +00004129 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
caryclark@google.com24bec792012-08-20 12:43:57 +00004130 int fDoneSpans; // quick check that segment is finished
caryclark@google.com4eeda372012-12-06 21:47:48 +00004131 // OPTIMIZATION: force the following to be byte-sized
4132 SkPath::Verb fVerb;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004133 bool fOperand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004134 bool fXor; // set if original contour had even-odd fill
4135 bool fOppXor; // set if opposite operand had even-odd fill
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004136#if DEBUG_DUMP
4137 int fID;
4138#endif
4139};
4140
caryclark@google.comb9738012012-07-03 19:53:30 +00004141class Contour;
4142
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004143struct Coincidence {
caryclark@google.comb9738012012-07-03 19:53:30 +00004144 Contour* fContours[2];
4145 int fSegments[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004146 double fTs[2][2];
4147};
4148
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004149class Contour {
4150public:
4151 Contour() {
4152 reset();
4153#if DEBUG_DUMP
4154 fID = ++gContourID;
4155#endif
4156 }
4157
4158 bool operator<(const Contour& rh) const {
4159 return fBounds.fTop == rh.fBounds.fTop
4160 ? fBounds.fLeft < rh.fBounds.fLeft
4161 : fBounds.fTop < rh.fBounds.fTop;
4162 }
4163
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004164 void addCoincident(int index, Contour* other, int otherIndex,
4165 const Intersections& ts, bool swap) {
4166 Coincidence& coincidence = *fCoincidences.append();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004167 coincidence.fContours[0] = this; // FIXME: no need to store
caryclark@google.comb9738012012-07-03 19:53:30 +00004168 coincidence.fContours[1] = other;
4169 coincidence.fSegments[0] = index;
4170 coincidence.fSegments[1] = otherIndex;
caryclark@google.com32546db2012-08-31 20:55:07 +00004171 if (fSegments[index].verb() == SkPath::kLine_Verb &&
4172 other->fSegments[otherIndex].verb() == SkPath::kLine_Verb) {
4173 // FIXME: coincident lines use legacy Ts instead of coincident Ts
4174 coincidence.fTs[swap][0] = ts.fT[0][0];
4175 coincidence.fTs[swap][1] = ts.fT[0][1];
4176 coincidence.fTs[!swap][0] = ts.fT[1][0];
4177 coincidence.fTs[!swap][1] = ts.fT[1][1];
4178 } else if (fSegments[index].verb() == SkPath::kQuad_Verb &&
4179 other->fSegments[otherIndex].verb() == SkPath::kQuad_Verb) {
4180 coincidence.fTs[swap][0] = ts.fCoincidentT[0][0];
4181 coincidence.fTs[swap][1] = ts.fCoincidentT[0][1];
4182 coincidence.fTs[!swap][0] = ts.fCoincidentT[1][0];
4183 coincidence.fTs[!swap][1] = ts.fCoincidentT[1][1];
4184 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004185 }
4186
4187 void addCross(const Contour* crosser) {
4188#ifdef DEBUG_CROSS
4189 for (int index = 0; index < fCrosses.count(); ++index) {
4190 SkASSERT(fCrosses[index] != crosser);
4191 }
4192#endif
4193 *fCrosses.append() = crosser;
4194 }
4195
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004196 void addCubic(const SkPoint pts[4]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004197 fSegments.push_back().addCubic(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004198 fContainsCurves = true;
4199 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004200
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004201 int addLine(const SkPoint pts[2]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004202 fSegments.push_back().addLine(pts, fOperand, fXor);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004203 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004204 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004205
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004206 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
4207 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
4208 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004209
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004210 int addQuad(const SkPoint pts[3]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004211 fSegments.push_back().addQuad(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004212 fContainsCurves = true;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004213 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004214 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004215
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004216 int addT(int segIndex, double newT, Contour* other, int otherIndex) {
4217 containsIntercepts();
4218 return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex]);
4219 }
4220
caryclark@google.com73ca6242013-01-17 21:02:47 +00004221 int addUnsortableT(int segIndex, double newT, Contour* other, int otherIndex, bool start) {
4222 return fSegments[segIndex].addUnsortableT(newT, &other->fSegments[otherIndex], start);
4223 }
4224
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004225 const Bounds& bounds() const {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004226 return fBounds;
4227 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004228
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004229 void complete() {
4230 setBounds();
4231 fContainsIntercepts = false;
4232 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004233
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004234 void containsIntercepts() {
4235 fContainsIntercepts = true;
4236 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004237
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004238 bool crosses(const Contour* crosser) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004239 for (int index = 0; index < fCrosses.count(); ++index) {
4240 if (fCrosses[index] == crosser) {
4241 return true;
4242 }
4243 }
4244 return false;
4245 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004246
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004247 bool done() const {
4248 return fDone;
4249 }
4250
caryclark@google.comf839c032012-10-26 21:03:50 +00004251 const SkPoint& end() const {
4252 const Segment& segment = fSegments.back();
4253 return segment.pts()[segment.verb()];
4254 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004255
caryclark@google.com4eeda372012-12-06 21:47:48 +00004256 void findTooCloseToCall() {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004257 int segmentCount = fSegments.count();
4258 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004259 fSegments[sIndex].findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004260 }
4261 }
4262
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004263 void fixOtherTIndex() {
4264 int segmentCount = fSegments.count();
4265 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4266 fSegments[sIndex].fixOtherTIndex();
4267 }
4268 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004269
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004270 Segment* nonVerticalSegment(int& start, int& end) {
4271 int segmentCount = fSortedSegments.count();
4272 SkASSERT(segmentCount > 0);
4273 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4274 Segment* testSegment = fSortedSegments[sortedIndex];
4275 if (testSegment->done()) {
4276 continue;
4277 }
4278 start = end = 0;
4279 while (testSegment->nextCandidate(start, end)) {
4280 if (!testSegment->isVertical(start, end)) {
4281 return testSegment;
4282 }
4283 }
4284 }
4285 return NULL;
4286 }
4287
caryclark@google.com31143cf2012-11-09 22:14:19 +00004288 bool operand() const {
4289 return fOperand;
4290 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004291
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004292 void reset() {
4293 fSegments.reset();
4294 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004295 fContainsCurves = fContainsIntercepts = fDone = false;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004296 }
caryclark@google.comb9738012012-07-03 19:53:30 +00004297
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004298 void resolveCoincidence(SkTDArray<Contour*>& contourList) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004299 int count = fCoincidences.count();
4300 for (int index = 0; index < count; ++index) {
4301 Coincidence& coincidence = fCoincidences[index];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004302 SkASSERT(coincidence.fContours[0] == this);
caryclark@google.comb9738012012-07-03 19:53:30 +00004303 int thisIndex = coincidence.fSegments[0];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004304 Segment& thisOne = fSegments[thisIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004305 Contour* otherContour = coincidence.fContours[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004306 int otherIndex = coincidence.fSegments[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004307 Segment& other = otherContour->fSegments[otherIndex];
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004308 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004309 continue;
4310 }
caryclark@google.com47580692012-07-23 12:14:49 +00004311 #if DEBUG_CONCIDENT
4312 thisOne.debugShowTs();
4313 other.debugShowTs();
4314 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004315 double startT = coincidence.fTs[0][0];
4316 double endT = coincidence.fTs[0][1];
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004317 bool cancelers = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004318 if (startT > endT) {
4319 SkTSwap<double>(startT, endT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004320 cancelers ^= true; // FIXME: just assign true
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004321 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004322 SkASSERT(!approximately_negative(endT - startT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004323 double oStartT = coincidence.fTs[1][0];
4324 double oEndT = coincidence.fTs[1][1];
4325 if (oStartT > oEndT) {
4326 SkTSwap<double>(oStartT, oEndT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004327 cancelers ^= true;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004328 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004329 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00004330 bool opp = fOperand ^ otherContour->fOperand;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004331 if (cancelers && !opp) {
4332 // make sure startT and endT have t entries
caryclark@google.com2ddff932012-08-07 21:25:27 +00004333 if (startT > 0 || oEndT < 1
4334 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
4335 thisOne.addTPair(startT, other, oEndT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004336 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00004337 if (oStartT > 0 || endT < 1
4338 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
4339 other.addTPair(oStartT, thisOne, endT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004340 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004341 if (!thisOne.done() && !other.done()) {
4342 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4343 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004344 } else {
caryclark@google.com200c2112012-08-03 15:05:04 +00004345 if (startT > 0 || oStartT > 0
4346 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00004347 thisOne.addTPair(startT, other, oStartT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004348 }
caryclark@google.com200c2112012-08-03 15:05:04 +00004349 if (endT < 1 || oEndT < 1
4350 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00004351 other.addTPair(oEndT, thisOne, endT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004352 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004353 if (!thisOne.done() && !other.done()) {
4354 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4355 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004356 }
caryclark@google.com47580692012-07-23 12:14:49 +00004357 #if DEBUG_CONCIDENT
4358 thisOne.debugShowTs();
4359 other.debugShowTs();
4360 #endif
caryclark@google.com729e1c42012-11-21 21:36:34 +00004361 #if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004362 debugShowWindingValues(contourList);
4363 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004364 }
4365 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004366
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004367 // first pass, add missing T values
4368 // second pass, determine winding values of overlaps
4369 void addCoincidentPoints() {
4370 int count = fCoincidences.count();
4371 for (int index = 0; index < count; ++index) {
4372 Coincidence& coincidence = fCoincidences[index];
4373 SkASSERT(coincidence.fContours[0] == this);
4374 int thisIndex = coincidence.fSegments[0];
4375 Segment& thisOne = fSegments[thisIndex];
4376 Contour* otherContour = coincidence.fContours[1];
4377 int otherIndex = coincidence.fSegments[1];
4378 Segment& other = otherContour->fSegments[otherIndex];
4379 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
4380 // OPTIMIZATION: remove from array
4381 continue;
4382 }
4383 #if DEBUG_CONCIDENT
4384 thisOne.debugShowTs();
4385 other.debugShowTs();
4386 #endif
4387 double startT = coincidence.fTs[0][0];
4388 double endT = coincidence.fTs[0][1];
4389 bool cancelers;
4390 if ((cancelers = startT > endT)) {
4391 SkTSwap<double>(startT, endT);
4392 }
4393 SkASSERT(!approximately_negative(endT - startT));
4394 double oStartT = coincidence.fTs[1][0];
4395 double oEndT = coincidence.fTs[1][1];
4396 if (oStartT > oEndT) {
4397 SkTSwap<double>(oStartT, oEndT);
4398 cancelers ^= true;
4399 }
4400 SkASSERT(!approximately_negative(oEndT - oStartT));
4401 bool opp = fOperand ^ otherContour->fOperand;
4402 if (cancelers && !opp) {
4403 // make sure startT and endT have t entries
4404 if (startT > 0 || oEndT < 1
4405 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
4406 thisOne.addTPair(startT, other, oEndT, true);
4407 }
4408 if (oStartT > 0 || endT < 1
4409 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
4410 other.addTPair(oStartT, thisOne, endT, true);
4411 }
4412 } else {
4413 if (startT > 0 || oStartT > 0
4414 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
4415 thisOne.addTPair(startT, other, oStartT, true);
4416 }
4417 if (endT < 1 || oEndT < 1
4418 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
4419 other.addTPair(oEndT, thisOne, endT, true);
4420 }
4421 }
4422 #if DEBUG_CONCIDENT
4423 thisOne.debugShowTs();
4424 other.debugShowTs();
4425 #endif
4426 }
4427 }
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00004428
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004429 void calcCoincidentWinding() {
4430 int count = fCoincidences.count();
4431 for (int index = 0; index < count; ++index) {
4432 Coincidence& coincidence = fCoincidences[index];
4433 SkASSERT(coincidence.fContours[0] == this);
4434 int thisIndex = coincidence.fSegments[0];
4435 Segment& thisOne = fSegments[thisIndex];
4436 if (thisOne.done()) {
4437 continue;
4438 }
4439 Contour* otherContour = coincidence.fContours[1];
4440 int otherIndex = coincidence.fSegments[1];
4441 Segment& other = otherContour->fSegments[otherIndex];
4442 if (other.done()) {
4443 continue;
4444 }
4445 double startT = coincidence.fTs[0][0];
4446 double endT = coincidence.fTs[0][1];
4447 bool cancelers;
4448 if ((cancelers = startT > endT)) {
4449 SkTSwap<double>(startT, endT);
4450 }
4451 SkASSERT(!approximately_negative(endT - startT));
4452 double oStartT = coincidence.fTs[1][0];
4453 double oEndT = coincidence.fTs[1][1];
4454 if (oStartT > oEndT) {
4455 SkTSwap<double>(oStartT, oEndT);
4456 cancelers ^= true;
4457 }
4458 SkASSERT(!approximately_negative(oEndT - oStartT));
4459 bool opp = fOperand ^ otherContour->fOperand;
4460 if (cancelers && !opp) {
4461 // make sure startT and endT have t entries
4462 if (!thisOne.done() && !other.done()) {
4463 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4464 }
4465 } else {
4466 if (!thisOne.done() && !other.done()) {
4467 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4468 }
4469 }
4470 #if DEBUG_CONCIDENT
4471 thisOne.debugShowTs();
4472 other.debugShowTs();
4473 #endif
4474 }
4475 }
4476
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004477 SkTArray<Segment>& segments() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004478 return fSegments;
4479 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004480
caryclark@google.com235f56a2012-09-14 14:19:30 +00004481 void setOperand(bool isOp) {
4482 fOperand = isOp;
4483 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00004484
caryclark@google.com4eeda372012-12-06 21:47:48 +00004485 void setOppXor(bool isOppXor) {
4486 fOppXor = isOppXor;
4487 int segmentCount = fSegments.count();
4488 for (int test = 0; test < segmentCount; ++test) {
4489 fSegments[test].setOppXor(isOppXor);
4490 }
4491 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004492
caryclark@google.com235f56a2012-09-14 14:19:30 +00004493 void setXor(bool isXor) {
4494 fXor = isXor;
4495 }
4496
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004497 void sortSegments() {
4498 int segmentCount = fSegments.count();
4499 fSortedSegments.setReserve(segmentCount);
4500 for (int test = 0; test < segmentCount; ++test) {
4501 *fSortedSegments.append() = &fSegments[test];
4502 }
4503 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4504 fFirstSorted = 0;
4505 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004506
caryclark@google.comf839c032012-10-26 21:03:50 +00004507 const SkPoint& start() const {
4508 return fSegments.front().pts()[0];
4509 }
4510
4511 void toPath(PathWrapper& path) const {
4512 int segmentCount = fSegments.count();
4513 const SkPoint& pt = fSegments.front().pts()[0];
4514 path.deferredMove(pt);
4515 for (int test = 0; test < segmentCount; ++test) {
4516 fSegments[test].addCurveTo(0, 1, path, true);
4517 }
4518 path.close();
4519 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004520
caryclark@google.comf839c032012-10-26 21:03:50 +00004521 void toPartialBackward(PathWrapper& path) const {
4522 int segmentCount = fSegments.count();
4523 for (int test = segmentCount - 1; test >= 0; --test) {
4524 fSegments[test].addCurveTo(1, 0, path, true);
4525 }
4526 }
4527
4528 void toPartialForward(PathWrapper& path) const {
4529 int segmentCount = fSegments.count();
4530 for (int test = 0; test < segmentCount; ++test) {
4531 fSegments[test].addCurveTo(0, 1, path, true);
4532 }
4533 }
4534
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004535 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004536 int segmentCount = fSortedSegments.count();
4537 SkASSERT(segmentCount > 0);
caryclark@google.comf839c032012-10-26 21:03:50 +00004538 int sortedIndex = fFirstSorted;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004539 fDone = true; // may be cleared below
caryclark@google.comf839c032012-10-26 21:03:50 +00004540 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4541 Segment* testSegment = fSortedSegments[sortedIndex];
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004542 if (testSegment->done()) {
caryclark@google.comf839c032012-10-26 21:03:50 +00004543 if (sortedIndex == fFirstSorted) {
4544 ++fFirstSorted;
4545 }
4546 continue;
4547 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004548 fDone = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00004549 SkPoint testXY;
4550 testSegment->activeLeftTop(testXY);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004551 if (topStart) {
4552 if (testXY.fY < topLeft.fY) {
4553 continue;
4554 }
4555 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4556 continue;
4557 }
4558 if (bestXY.fY < testXY.fY) {
4559 continue;
4560 }
4561 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4562 continue;
4563 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004564 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004565 topStart = testSegment;
caryclark@google.comf839c032012-10-26 21:03:50 +00004566 bestXY = testXY;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004567 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004568 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004569
caryclark@google.com24bec792012-08-20 12:43:57 +00004570 Segment* undoneSegment(int& start, int& end) {
4571 int segmentCount = fSegments.count();
4572 for (int test = 0; test < segmentCount; ++test) {
4573 Segment* testSegment = &fSegments[test];
4574 if (testSegment->done()) {
4575 continue;
4576 }
4577 testSegment->undoneSpan(start, end);
4578 return testSegment;
4579 }
4580 return NULL;
4581 }
4582
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004583 int updateSegment(int index, const SkPoint* pts) {
4584 Segment& segment = fSegments[index];
4585 segment.updatePts(pts);
4586 return segment.verb() + 1;
4587 }
4588
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004589#if DEBUG_TEST
4590 SkTArray<Segment>& debugSegments() {
4591 return fSegments;
4592 }
4593#endif
4594
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004595#if DEBUG_DUMP
4596 void dump() {
4597 int i;
4598 const char className[] = "Contour";
4599 const int tab = 4;
4600 SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4601 for (i = 0; i < fSegments.count(); ++i) {
4602 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4603 className, i);
4604 fSegments[i].dump();
4605 }
4606 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4607 tab + sizeof(className), className,
4608 fBounds.fLeft, fBounds.fTop,
4609 fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004610 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4611 className, fContainsIntercepts);
4612 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4613 className, fContainsCurves);
4614 }
4615#endif
4616
caryclark@google.com027de222012-07-12 12:52:50 +00004617#if DEBUG_ACTIVE_SPANS
4618 void debugShowActiveSpans() {
4619 for (int index = 0; index < fSegments.count(); ++index) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004620 fSegments[index].debugShowActiveSpans();
caryclark@google.com027de222012-07-12 12:52:50 +00004621 }
4622 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004623
4624 void validateActiveSpans() {
4625 for (int index = 0; index < fSegments.count(); ++index) {
4626 fSegments[index].validateActiveSpans();
4627 }
4628 }
caryclark@google.com027de222012-07-12 12:52:50 +00004629#endif
4630
caryclark@google.com729e1c42012-11-21 21:36:34 +00004631#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004632 int debugShowWindingValues(int totalSegments, int ofInterest) {
4633 int count = fSegments.count();
4634 int sum = 0;
4635 for (int index = 0; index < count; ++index) {
4636 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4637 }
4638 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4639 return sum;
4640 }
4641
4642 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4643 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4644 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4645 int ofInterest = 1 << 5 | 1 << 8;
4646 int total = 0;
4647 int index;
4648 for (index = 0; index < contourList.count(); ++index) {
4649 total += contourList[index]->segments().count();
4650 }
4651 int sum = 0;
4652 for (index = 0; index < contourList.count(); ++index) {
4653 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4654 }
4655 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4656 }
4657#endif
4658
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004659protected:
4660 void setBounds() {
4661 int count = fSegments.count();
4662 if (count == 0) {
4663 SkDebugf("%s empty contour\n", __FUNCTION__);
4664 SkASSERT(0);
4665 // FIXME: delete empty contour?
4666 return;
4667 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004668 fBounds = fSegments.front().bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004669 for (int index = 1; index < count; ++index) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004670 fBounds.add(fSegments[index].bounds());
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004671 }
4672 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004673
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004674private:
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004675 SkTArray<Segment> fSegments;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004676 SkTDArray<Segment*> fSortedSegments;
4677 int fFirstSorted;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004678 SkTDArray<Coincidence> fCoincidences;
4679 SkTDArray<const Contour*> fCrosses;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004680 Bounds fBounds;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004681 bool fContainsIntercepts;
4682 bool fContainsCurves;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004683 bool fDone;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004684 bool fOperand; // true for the second argument to a binary operator
4685 bool fXor;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004686 bool fOppXor;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004687#if DEBUG_DUMP
4688 int fID;
4689#endif
4690};
4691
4692class EdgeBuilder {
4693public:
4694
caryclark@google.comf839c032012-10-26 21:03:50 +00004695EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
4696 : fPath(path.nativePath())
4697 , fContours(contours)
4698{
4699 init();
4700}
4701
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004702EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
caryclark@google.com235f56a2012-09-14 14:19:30 +00004703 : fPath(&path)
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004704 , fContours(contours)
4705{
caryclark@google.comf839c032012-10-26 21:03:50 +00004706 init();
4707}
4708
4709void init() {
4710 fCurrentContour = NULL;
4711 fOperand = false;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004712 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004713#if DEBUG_DUMP
4714 gContourID = 0;
4715 gSegmentID = 0;
4716#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00004717 fSecondHalf = preFetch();
4718}
4719
4720void addOperand(const SkPath& path) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00004721 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
4722 fPathVerbs.pop();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004723 fPath = &path;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004724 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004725 preFetch();
4726}
4727
4728void finish() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004729 walk();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004730 complete();
4731 if (fCurrentContour && !fCurrentContour->segments().count()) {
4732 fContours.pop_back();
4733 }
4734 // correct pointers in contours since fReducePts may have moved as it grew
4735 int cIndex = 0;
4736 int extraCount = fExtra.count();
4737 SkASSERT(extraCount == 0 || fExtra[0] == -1);
4738 int eIndex = 0;
4739 int rIndex = 0;
4740 while (++eIndex < extraCount) {
4741 int offset = fExtra[eIndex];
4742 if (offset < 0) {
4743 ++cIndex;
4744 continue;
4745 }
4746 fCurrentContour = &fContours[cIndex];
4747 rIndex += fCurrentContour->updateSegment(offset - 1,
4748 &fReducePts[rIndex]);
4749 }
4750 fExtra.reset(); // we're done with this
4751}
4752
4753ShapeOpMask xorMask() const {
caryclark@google.com729e1c42012-11-21 21:36:34 +00004754 return fXorMask[fOperand];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004755}
4756
4757protected:
4758
4759void complete() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004760 if (fCurrentContour && fCurrentContour->segments().count()) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004761 fCurrentContour->complete();
4762 fCurrentContour = NULL;
4763 }
4764}
4765
caryclark@google.com235f56a2012-09-14 14:19:30 +00004766// FIXME:remove once we can access path pts directly
4767int preFetch() {
4768 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004769 SkPoint pts[4];
4770 SkPath::Verb verb;
4771 do {
4772 verb = iter.next(pts);
4773 *fPathVerbs.append() = verb;
4774 if (verb == SkPath::kMove_Verb) {
4775 *fPathPts.append() = pts[0];
4776 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
4777 fPathPts.append(verb, &pts[1]);
4778 }
4779 } while (verb != SkPath::kDone_Verb);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004780 return fPathVerbs.count() - 1;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004781}
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004782
caryclark@google.com235f56a2012-09-14 14:19:30 +00004783void walk() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004784 SkPath::Verb reducedVerb;
4785 uint8_t* verbPtr = fPathVerbs.begin();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004786 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004787 const SkPoint* pointsPtr = fPathPts.begin();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004788 const SkPoint* finalCurveStart = NULL;
4789 const SkPoint* finalCurveEnd = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004790 SkPath::Verb verb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004791 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
4792 switch (verb) {
4793 case SkPath::kMove_Verb:
4794 complete();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004795 if (!fCurrentContour) {
4796 fCurrentContour = fContours.push_back_n(1);
caryclark@google.com235f56a2012-09-14 14:19:30 +00004797 fCurrentContour->setOperand(fOperand);
caryclark@google.com729e1c42012-11-21 21:36:34 +00004798 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004799 *fExtra.append() = -1; // start new contour
4800 }
caryclark@google.com59823f72012-08-09 18:17:47 +00004801 finalCurveEnd = pointsPtr++;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004802 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004803 case SkPath::kLine_Verb:
4804 // skip degenerate points
4805 if (pointsPtr[-1].fX != pointsPtr[0].fX
4806 || pointsPtr[-1].fY != pointsPtr[0].fY) {
4807 fCurrentContour->addLine(&pointsPtr[-1]);
4808 }
4809 break;
4810 case SkPath::kQuad_Verb:
rmistry@google.comd6176b02012-08-23 18:14:13 +00004811
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004812 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
4813 if (reducedVerb == 0) {
4814 break; // skip degenerate points
4815 }
4816 if (reducedVerb == 1) {
rmistry@google.comd6176b02012-08-23 18:14:13 +00004817 *fExtra.append() =
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004818 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004819 break;
4820 }
4821 fCurrentContour->addQuad(&pointsPtr[-1]);
4822 break;
4823 case SkPath::kCubic_Verb:
4824 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
4825 if (reducedVerb == 0) {
4826 break; // skip degenerate points
4827 }
4828 if (reducedVerb == 1) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004829 *fExtra.append() =
4830 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004831 break;
4832 }
4833 if (reducedVerb == 2) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004834 *fExtra.append() =
4835 fCurrentContour->addQuad(fReducePts.end() - 3);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004836 break;
4837 }
4838 fCurrentContour->addCubic(&pointsPtr[-1]);
4839 break;
4840 case SkPath::kClose_Verb:
4841 SkASSERT(fCurrentContour);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004842 if (finalCurveStart && finalCurveEnd
4843 && *finalCurveStart != *finalCurveEnd) {
4844 *fReducePts.append() = *finalCurveStart;
4845 *fReducePts.append() = *finalCurveEnd;
4846 *fExtra.append() =
4847 fCurrentContour->addLine(fReducePts.end() - 2);
4848 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004849 complete();
caryclark@google.com31143cf2012-11-09 22:14:19 +00004850 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004851 default:
4852 SkDEBUGFAIL("bad verb");
4853 return;
4854 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004855 finalCurveStart = &pointsPtr[verb - 1];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004856 pointsPtr += verb;
4857 SkASSERT(fCurrentContour);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004858 nextVerb:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004859 if (verbPtr == endOfFirstHalf) {
4860 fOperand = true;
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004861 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004862 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004863}
4864
4865private:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004866 const SkPath* fPath;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004867 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004868 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004869 Contour* fCurrentContour;
4870 SkTArray<Contour>& fContours;
4871 SkTDArray<SkPoint> fReducePts; // segments created on the fly
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004872 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
caryclark@google.com729e1c42012-11-21 21:36:34 +00004873 ShapeOpMask fXorMask[2];
caryclark@google.com235f56a2012-09-14 14:19:30 +00004874 int fSecondHalf;
4875 bool fOperand;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004876};
4877
4878class Work {
4879public:
4880 enum SegmentType {
4881 kHorizontalLine_Segment = -1,
4882 kVerticalLine_Segment = 0,
4883 kLine_Segment = SkPath::kLine_Verb,
4884 kQuad_Segment = SkPath::kQuad_Verb,
4885 kCubic_Segment = SkPath::kCubic_Verb,
4886 };
rmistry@google.comd6176b02012-08-23 18:14:13 +00004887
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004888 void addCoincident(Work& other, const Intersections& ts, bool swap) {
4889 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
4890 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004891
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004892 // FIXME: does it make sense to write otherIndex now if we're going to
4893 // fix it up later?
4894 void addOtherT(int index, double otherT, int otherIndex) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004895 fContour->addOtherT(fIndex, index, otherT, otherIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004896 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004897
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004898 // Avoid collapsing t values that are close to the same since
4899 // we walk ts to describe consecutive intersections. Since a pair of ts can
4900 // be nearly equal, any problems caused by this should be taken care
4901 // of later.
4902 // On the edge or out of range values are negative; add 2 to get end
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004903 int addT(double newT, const Work& other) {
4904 return fContour->addT(fIndex, newT, other.fContour, other.fIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004905 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004906
caryclark@google.com73ca6242013-01-17 21:02:47 +00004907 int addUnsortableT(double newT, const Work& other, bool start) {
4908 return fContour->addUnsortableT(fIndex, newT, other.fContour, other.fIndex, start);
4909 }
4910
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004911 bool advance() {
4912 return ++fIndex < fLast;
4913 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004914
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004915 SkScalar bottom() const {
4916 return bounds().fBottom;
4917 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004918
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004919 const Bounds& bounds() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004920 return fContour->segments()[fIndex].bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004921 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004922
caryclark@google.com73ca6242013-01-17 21:02:47 +00004923#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004924 const SkPoint* cubic() const {
4925 return fCubic;
4926 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00004927#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004928
4929 void init(Contour* contour) {
4930 fContour = contour;
4931 fIndex = 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004932 fLast = contour->segments().count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004933 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004934
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00004935 bool isAdjacent(const Work& next) {
4936 return fContour == next.fContour && fIndex + 1 == next.fIndex;
4937 }
4938
4939 bool isFirstLast(const Work& next) {
4940 return fContour == next.fContour && fIndex == 0
4941 && next.fIndex == fLast - 1;
4942 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004943
4944 SkScalar left() const {
4945 return bounds().fLeft;
4946 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004947
caryclark@google.com73ca6242013-01-17 21:02:47 +00004948#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004949 void promoteToCubic() {
4950 fCubic[0] = pts()[0];
4951 fCubic[2] = pts()[1];
4952 fCubic[3] = pts()[2];
4953 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
4954 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
4955 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
4956 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
4957 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00004958#endif
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004959
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004960 const SkPoint* pts() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004961 return fContour->segments()[fIndex].pts();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004962 }
4963
4964 SkScalar right() const {
4965 return bounds().fRight;
4966 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004967
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004968 ptrdiff_t segmentIndex() const {
4969 return fIndex;
4970 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004971
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004972 SegmentType segmentType() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004973 const Segment& segment = fContour->segments()[fIndex];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004974 SegmentType type = (SegmentType) segment.verb();
4975 if (type != kLine_Segment) {
4976 return type;
4977 }
4978 if (segment.isHorizontal()) {
4979 return kHorizontalLine_Segment;
4980 }
4981 if (segment.isVertical()) {
4982 return kVerticalLine_Segment;
4983 }
4984 return kLine_Segment;
4985 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004986
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004987 bool startAfter(const Work& after) {
4988 fIndex = after.fIndex;
4989 return advance();
4990 }
4991
4992 SkScalar top() const {
4993 return bounds().fTop;
4994 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004995
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004996 SkPath::Verb verb() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004997 return fContour->segments()[fIndex].verb();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004998 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004999
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005000 SkScalar x() const {
5001 return bounds().fLeft;
5002 }
5003
5004 bool xFlipped() const {
5005 return x() != pts()[0].fX;
5006 }
5007
5008 SkScalar y() const {
5009 return bounds().fTop;
5010 }
5011
5012 bool yFlipped() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005013 return y() != pts()[0].fY;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005014 }
5015
5016protected:
5017 Contour* fContour;
caryclark@google.com73ca6242013-01-17 21:02:47 +00005018#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005019 SkPoint fCubic[4];
caryclark@google.com73ca6242013-01-17 21:02:47 +00005020#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005021 int fIndex;
5022 int fLast;
5023};
5024
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005025#if DEBUG_ADD_INTERSECTING_TS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005026static void debugShowLineIntersection(int pts, const Work& wt,
5027 const Work& wn, const double wtTs[2], const double wnTs[2]) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005028 return;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005029 if (!pts) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005030 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n",
5031 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
5032 wt.pts()[1].fX, wt.pts()[1].fY, wn.pts()[0].fX, wn.pts()[0].fY,
5033 wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005034 return;
5035 }
5036 SkPoint wtOutPt, wnOutPt;
5037 LineXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5038 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005039 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005040 __FUNCTION__,
5041 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5042 wt.pts()[1].fX, wt.pts()[1].fY, wtOutPt.fX, wtOutPt.fY);
5043 if (pts == 2) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005044 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005045 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00005046 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005047 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5048 wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
5049 if (pts == 2) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005050 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
5051 }
5052 SkDebugf("\n");
5053}
5054
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005055static void debugShowQuadLineIntersection(int pts, const Work& wt,
5056 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5057 if (!pts) {
5058 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
caryclark@google.com0b7da432012-10-31 19:00:20 +00005059 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005060 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
5061 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005062 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005063 return;
5064 }
5065 SkPoint wtOutPt, wnOutPt;
5066 QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5067 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5068 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5069 __FUNCTION__,
5070 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5071 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
5072 wtOutPt.fX, wtOutPt.fY);
5073 if (pts == 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005074 QuadXYAtT(wt.pts(), wtTs[1], &wtOutPt);
5075 SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", wtTs[1], wtOutPt.fX, wtOutPt.fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005076 }
5077 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5078 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5079 wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
5080 if (pts == 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005081 LineXYAtT(wn.pts(), wnTs[1], &wnOutPt);
5082 SkDebugf(" wnTs[1]=%1.9g (%1.9g,%1.9g)", wnTs[1], wnOutPt.fX, wnOutPt.fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005083 }
5084 SkDebugf("\n");
5085}
5086
caryclark@google.com73ca6242013-01-17 21:02:47 +00005087// FIXME: show more than two intersection points
caryclark@google.coma461ff02012-10-11 12:54:23 +00005088static void debugShowQuadIntersection(int pts, const Work& wt,
5089 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5090 if (!pts) {
5091 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5092 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5093 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
skia.committer@gmail.com5b6f9162012-10-12 02:01:15 +00005094 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.coma461ff02012-10-11 12:54:23 +00005095 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005096 wn.pts()[2].fX, wn.pts()[2].fY );
caryclark@google.coma461ff02012-10-11 12:54:23 +00005097 return;
5098 }
5099 SkPoint wtOutPt, wnOutPt;
5100 QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5101 QuadXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5102 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5103 __FUNCTION__,
5104 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5105 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
5106 wtOutPt.fX, wtOutPt.fY);
5107 if (pts == 2) {
5108 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
5109 }
5110 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5111 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5112 wn.pts()[1].fX, wn.pts()[1].fY, wn.pts()[2].fX, wn.pts()[2].fY,
5113 wnOutPt.fX, wnOutPt.fY);
5114 if (pts == 2) {
5115 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005116 }
caryclark@google.comb9738012012-07-03 19:53:30 +00005117 SkDebugf("\n");
5118}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005119
5120static void debugShowCubicLineIntersection(int pts, const Work& wt,
5121 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5122 if (!pts) {
5123 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5124 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
5125 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5126 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5127 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
5128 return;
5129 }
5130 SkPoint wtOutPt, wnOutPt;
5131 CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5132 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5133 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5134 __FUNCTION__,
5135 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5136 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5137 wtOutPt.fX, wtOutPt.fY);
5138 if (pts == 2) {
5139 CubicXYAtT(wt.pts(), wtTs[1], &wtOutPt);
5140 SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", wtTs[1], wtOutPt.fX, wtOutPt.fY);
5141 }
5142 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5143 wtTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5144 wnOutPt.fX, wnOutPt.fY);
5145 if (pts == 2) {
5146 LineXYAtT(wn.pts(), wnTs[1], &wnOutPt);
5147 SkDebugf(" wnTs[1]=%1.9g (%1.9g,%1.9g)", wnTs[1], wnOutPt.fX, wnOutPt.fY);
5148 }
5149 SkDebugf("\n");
5150}
5151
caryclark@google.com73ca6242013-01-17 21:02:47 +00005152// FIXME: show more than two intersection points
5153static void debugShowCubicQuadIntersection(int pts, const Work& wt,
5154 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5155 if (!pts) {
5156 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5157 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5158 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5159 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5160 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5161 wn.pts()[2].fX, wn.pts()[2].fY );
5162 return;
5163 }
5164 SkPoint wtOutPt, wnOutPt;
5165 CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005166 QuadXYAtT(wn.pts(), wnTs[0], &wnOutPt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005167 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5168 __FUNCTION__,
5169 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5170 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5171 wtOutPt.fX, wtOutPt.fY);
5172 if (pts == 2) {
5173 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
5174 }
5175 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5176 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5177 wn.pts()[2].fX, wn.pts()[2].fY,
5178 wnOutPt.fX, wnOutPt.fY);
5179 if (pts == 2) {
5180 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
5181 }
5182 SkDebugf("\n");
5183}
5184
5185// FIXME: show more than two intersection points
5186static void debugShowCubicIntersection(int pts, const Work& wt,
5187 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5188 if (!pts) {
5189 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5190 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5191 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5192 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5193 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5194 wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY );
5195 return;
5196 }
5197 SkPoint wtOutPt, wnOutPt;
5198 CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5199 CubicXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5200 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5201 __FUNCTION__,
5202 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5203 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5204 wtOutPt.fX, wtOutPt.fY);
5205 if (pts == 2) {
5206 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
5207 }
5208 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5209 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5210 wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY,
5211 wnOutPt.fX, wnOutPt.fY);
5212 if (pts == 2) {
5213 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
5214 }
5215 SkDebugf("\n");
5216}
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005217
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005218#else
5219static void debugShowLineIntersection(int , const Work& ,
5220 const Work& , const double [2], const double [2]) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005221}
caryclark@google.coma461ff02012-10-11 12:54:23 +00005222
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005223static void debugShowQuadLineIntersection(int , const Work& ,
5224 const Work& , const double [2], const double [2]) {
5225}
5226
caryclark@google.coma461ff02012-10-11 12:54:23 +00005227static void debugShowQuadIntersection(int , const Work& ,
5228 const Work& , const double [2], const double [2]) {
5229}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005230
5231static void debugShowCubicLineIntersection(int , const Work& ,
5232 const Work& , const double [2], const double [2]) {
5233}
5234
caryclark@google.com73ca6242013-01-17 21:02:47 +00005235static void debugShowCubicQuadIntersection(int , const Work& ,
5236 const Work& , const double [2], const double [2]) {
5237}
5238
5239static void debugShowCubicIntersection(int , const Work& ,
5240 const Work& , const double [2], const double [2]) {
5241}
5242#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005243
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005244static bool addIntersectTs(Contour* test, Contour* next) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005245
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005246 if (test != next) {
5247 if (test->bounds().fBottom < next->bounds().fTop) {
5248 return false;
5249 }
5250 if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5251 return true;
5252 }
5253 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005254 Work wt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005255 wt.init(test);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005256 bool foundCommonContour = test == next;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005257 do {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005258 Work wn;
5259 wn.init(next);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005260 if (test == next && !wn.startAfter(wt)) {
5261 continue;
5262 }
5263 do {
5264 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5265 continue;
5266 }
5267 int pts;
5268 Intersections ts;
5269 bool swap = false;
5270 switch (wt.segmentType()) {
5271 case Work::kHorizontalLine_Segment:
5272 swap = true;
5273 switch (wn.segmentType()) {
5274 case Work::kHorizontalLine_Segment:
5275 case Work::kVerticalLine_Segment:
5276 case Work::kLine_Segment: {
5277 pts = HLineIntersect(wn.pts(), wt.left(),
5278 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005279 debugShowLineIntersection(pts, wt, wn,
5280 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005281 break;
5282 }
5283 case Work::kQuad_Segment: {
5284 pts = HQuadIntersect(wn.pts(), wt.left(),
5285 wt.right(), wt.y(), wt.xFlipped(), ts);
5286 break;
5287 }
5288 case Work::kCubic_Segment: {
5289 pts = HCubicIntersect(wn.pts(), wt.left(),
5290 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005291 debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005292 break;
5293 }
5294 default:
5295 SkASSERT(0);
5296 }
5297 break;
5298 case Work::kVerticalLine_Segment:
5299 swap = true;
5300 switch (wn.segmentType()) {
5301 case Work::kHorizontalLine_Segment:
5302 case Work::kVerticalLine_Segment:
5303 case Work::kLine_Segment: {
5304 pts = VLineIntersect(wn.pts(), wt.top(),
5305 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005306 debugShowLineIntersection(pts, wt, wn,
5307 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005308 break;
5309 }
5310 case Work::kQuad_Segment: {
5311 pts = VQuadIntersect(wn.pts(), wt.top(),
5312 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5313 break;
5314 }
5315 case Work::kCubic_Segment: {
5316 pts = VCubicIntersect(wn.pts(), wt.top(),
5317 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005318 debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005319 break;
5320 }
5321 default:
5322 SkASSERT(0);
5323 }
5324 break;
5325 case Work::kLine_Segment:
5326 switch (wn.segmentType()) {
5327 case Work::kHorizontalLine_Segment:
5328 pts = HLineIntersect(wt.pts(), wn.left(),
5329 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005330 debugShowLineIntersection(pts, wt, wn,
5331 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005332 break;
5333 case Work::kVerticalLine_Segment:
5334 pts = VLineIntersect(wt.pts(), wn.top(),
5335 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005336 debugShowLineIntersection(pts, wt, wn,
5337 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005338 break;
5339 case Work::kLine_Segment: {
5340 pts = LineIntersect(wt.pts(), wn.pts(), ts);
5341 debugShowLineIntersection(pts, wt, wn,
5342 ts.fT[1], ts.fT[0]);
5343 break;
5344 }
5345 case Work::kQuad_Segment: {
5346 swap = true;
5347 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005348 debugShowQuadLineIntersection(pts, wn, wt,
5349 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005350 break;
5351 }
5352 case Work::kCubic_Segment: {
5353 swap = true;
5354 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005355 debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005356 break;
5357 }
5358 default:
5359 SkASSERT(0);
5360 }
5361 break;
5362 case Work::kQuad_Segment:
5363 switch (wn.segmentType()) {
5364 case Work::kHorizontalLine_Segment:
5365 pts = HQuadIntersect(wt.pts(), wn.left(),
5366 wn.right(), wn.y(), wn.xFlipped(), ts);
5367 break;
5368 case Work::kVerticalLine_Segment:
5369 pts = VQuadIntersect(wt.pts(), wn.top(),
5370 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5371 break;
5372 case Work::kLine_Segment: {
5373 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005374 debugShowQuadLineIntersection(pts, wt, wn,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005375 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005376 break;
5377 }
5378 case Work::kQuad_Segment: {
5379 pts = QuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005380 debugShowQuadIntersection(pts, wt, wn,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005381 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005382 break;
5383 }
5384 case Work::kCubic_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005385 #if APPROXIMATE_CUBICS
5386 swap = true;
5387 pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts);
5388 debugShowCubicQuadIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
5389 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005390 wt.promoteToCubic();
5391 pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005392 debugShowCubicIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005393 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005394 break;
5395 }
5396 default:
5397 SkASSERT(0);
5398 }
5399 break;
5400 case Work::kCubic_Segment:
5401 switch (wn.segmentType()) {
5402 case Work::kHorizontalLine_Segment:
5403 pts = HCubicIntersect(wt.pts(), wn.left(),
5404 wn.right(), wn.y(), wn.xFlipped(), ts);
5405 break;
5406 case Work::kVerticalLine_Segment:
5407 pts = VCubicIntersect(wt.pts(), wn.top(),
5408 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005409 debugShowCubicLineIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005410 break;
5411 case Work::kLine_Segment: {
5412 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005413 debugShowCubicLineIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005414 break;
5415 }
5416 case Work::kQuad_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005417 #if APPROXIMATE_CUBICS
5418 pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts);
5419 debugShowCubicQuadIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
5420 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005421 wn.promoteToCubic();
5422 pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005423 debugShowCubicIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005424 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005425 break;
5426 }
5427 case Work::kCubic_Segment: {
5428 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005429 debugShowCubicIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005430 break;
5431 }
5432 default:
5433 SkASSERT(0);
5434 }
5435 break;
5436 default:
5437 SkASSERT(0);
5438 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005439 if (!foundCommonContour && pts > 0) {
5440 test->addCross(next);
5441 next->addCross(test);
5442 foundCommonContour = true;
5443 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005444 // in addition to recording T values, record matching segment
caryclark@google.com73ca6242013-01-17 21:02:47 +00005445 if (ts.unsortable()) {
5446 bool start = true;
5447 for (int pt = 0; pt < ts.used(); ++pt) {
5448 // FIXME: if unsortable, the other points to the original. This logic is
5449 // untested downstream.
5450 int testTAt = wt.addUnsortableT(ts.fT[swap][pt], wt, start);
5451 wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt);
5452 testTAt = wn.addUnsortableT(ts.fT[!swap][pt], wn, start ^ ts.fFlip);
5453 wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt);
5454 start ^= true;
5455 }
5456 continue;
5457 }
caryclark@google.com32546db2012-08-31 20:55:07 +00005458 if (pts == 2) {
5459 if (wn.segmentType() <= Work::kLine_Segment
5460 && wt.segmentType() <= Work::kLine_Segment) {
5461 wt.addCoincident(wn, ts, swap);
5462 continue;
5463 }
5464 if (wn.segmentType() == Work::kQuad_Segment
5465 && wt.segmentType() == Work::kQuad_Segment
5466 && ts.coincidentUsed() == 2) {
5467 wt.addCoincident(wn, ts, swap);
5468 continue;
5469 }
5470
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00005471 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00005472 for (int pt = 0; pt < pts; ++pt) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005473 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5474 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005475 int testTAt = wt.addT(ts.fT[swap][pt], wn);
5476 int nextTAt = wn.addT(ts.fT[!swap][pt], wt);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005477 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
5478 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005479 }
5480 } while (wn.advance());
5481 } while (wt.advance());
5482 return true;
5483}
5484
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005485// resolve any coincident pairs found while intersecting, and
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005486// see if coincidence is formed by clipping non-concident segments
caryclark@google.com4eeda372012-12-06 21:47:48 +00005487static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005488 int contourCount = contourList.count();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005489#if ONE_PASS_COINCIDENCE_CHECK
caryclark@google.comf25edfe2012-06-01 18:20:10 +00005490 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005491 Contour* contour = contourList[cIndex];
caryclark@google.com7ba591e2012-11-20 14:21:54 +00005492 contour->resolveCoincidence(contourList);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005493 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005494#else
5495 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5496 Contour* contour = contourList[cIndex];
5497 contour->addCoincidentPoints();
5498 }
5499 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5500 Contour* contour = contourList[cIndex];
5501 contour->calcCoincidentWinding();
5502 }
5503#endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005504 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5505 Contour* contour = contourList[cIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00005506 contour->findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005507 }
5508}
5509
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005510static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005511 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005512 SkPoint basePt;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005513 double tAtMid = current->tAtMid(index, endIndex, mid);
5514 current->xyAtT(tAtMid, basePt);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005515 int contourCount = contourList.count();
5516 SkScalar bestY = SK_ScalarMin;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005517 Segment* bestSeg = NULL;
5518 int bestTIndex;
5519 bool bestOpp;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005520 bool hitSomething = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005521 for (int cTest = 0; cTest < contourCount; ++cTest) {
5522 Contour* contour = contourList[cTest];
5523 bool testOpp = contour->operand() ^ current->operand() ^ opp;
5524 if (basePt.fY < contour->bounds().fTop) {
5525 continue;
5526 }
5527 if (bestY > contour->bounds().fBottom) {
5528 continue;
5529 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005530 int segmentCount = contour->segments().count();
5531 for (int test = 0; test < segmentCount; ++test) {
5532 Segment* testSeg = &contour->segments()[test];
5533 SkScalar testY = bestY;
5534 double testHit;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005535 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
5536 testOpp, testSeg == current);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005537 if (testTIndex < 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005538 if (testTIndex == SK_MinS32) {
5539 hitSomething = true;
5540 bestSeg = NULL;
5541 goto abortContours; // vertical encountered, return and try different point
5542 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005543 continue;
5544 }
5545 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005546 double baseT = current->t(index);
5547 double endT = current->t(endIndex);
5548 double newMid = (testHit - baseT) / (endT - baseT);
5549#if DEBUG_WINDING
5550 SkPoint midXY, newXY;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005551 double midT = current->tAtMid(index, endIndex, mid);
5552 current->xyAtT(midT, midXY);
5553 double newMidT = current->tAtMid(index, endIndex, newMid);
5554 current->xyAtT(newMidT, newXY);
caryclark@google.com3586ece2012-12-27 18:46:58 +00005555 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
5556 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
5557 current->debugID(), mid, newMid,
5558 baseT, current->xAtT(index), current->yAtT(index),
5559 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
5560 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
5561 endT, current->xAtT(endIndex), current->yAtT(endIndex));
5562#endif
5563 mid = newMid * 2; // calling loop with divide by 2 before continuing
5564 return SK_MinS32;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005565 }
5566 bestSeg = testSeg;
5567 bestHit = testHit;
5568 bestOpp = testOpp;
5569 bestTIndex = testTIndex;
5570 bestY = testY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005571 }
5572 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005573abortContours:
caryclark@google.com10227bf2012-12-28 22:10:41 +00005574 int result;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005575 if (!bestSeg) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00005576 result = hitSomething ? SK_MinS32 : 0;
5577 } else {
5578 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
5579 current = bestSeg;
5580 index = bestTIndex;
5581 endIndex = bestSeg->nextSpan(bestTIndex, 1);
5582 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
5583 tryAgain = true;
5584 return 0;
5585 }
5586 result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
5587 SkASSERT(bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005588 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005589 double baseT = current->t(index);
5590 double endT = current->t(endIndex);
5591 bestHit = baseT + mid * (endT - baseT);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005592 return result;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005593}
5594
caryclark@google.com24bec792012-08-20 12:43:57 +00005595static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
5596 int contourCount = contourList.count();
5597 Segment* result;
5598 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5599 Contour* contour = contourList[cIndex];
5600 result = contour->undoneSegment(start, end);
5601 if (result) {
5602 return result;
5603 }
5604 }
5605 return NULL;
5606}
5607
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005608#define OLD_FIND_CHASE 1
caryclark@google.com24bec792012-08-20 12:43:57 +00005609
caryclark@google.com31143cf2012-11-09 22:14:19 +00005610static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005611 while (chase.count()) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005612 Span* span;
5613 chase.pop(&span);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005614 const Span& backPtr = span->fOther->span(span->fOtherIndex);
5615 Segment* segment = backPtr.fOther;
5616 tIndex = backPtr.fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005617 SkTDArray<Angle> angles;
5618 int done = 0;
5619 if (segment->activeAngle(tIndex, done, angles)) {
5620 Angle* last = angles.end() - 1;
5621 tIndex = last->start();
5622 endIndex = last->end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005623 #if TRY_ROTATE
5624 *chase.insert(0) = span;
5625 #else
5626 *chase.append() = span;
5627 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005628 return last->segment();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005629 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005630 if (done == angles.count()) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00005631 continue;
5632 }
5633 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005634 bool sortable = Segment::SortAngles(angles, sorted);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005635 int angleCount = sorted.count();
caryclark@google.com03f97062012-08-21 13:13:52 +00005636#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005637 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00005638#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005639 if (!sortable) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005640 continue;
5641 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005642 // find first angle, initialize winding to computed fWindSum
5643 int firstIndex = -1;
5644 const Angle* angle;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005645#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005646 int winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005647 do {
5648 angle = sorted[++firstIndex];
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005649 segment = angle->segment();
5650 winding = segment->windSum(angle);
5651 } while (winding == SK_MinS32);
5652 int spanWinding = segment->spanSign(angle->start(), angle->end());
5653 #if DEBUG_WINDING
caryclark@google.com31143cf2012-11-09 22:14:19 +00005654 SkDebugf("%s winding=%d spanWinding=%d\n",
5655 __FUNCTION__, winding, spanWinding);
caryclark@google.com47580692012-07-23 12:14:49 +00005656 #endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005657 // turn span winding into contour winding
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005658 if (spanWinding * winding < 0) {
5659 winding += spanWinding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005660 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005661 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005662 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005663 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005664 // we care about first sign and whether wind sum indicates this
5665 // edge is inside or outside. Maybe need to pass span winding
5666 // or first winding or something into this function?
5667 // advance to first undone angle, then return it and winding
5668 // (to set whether edges are active or not)
5669 int nextIndex = firstIndex + 1;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005670 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005671 angle = sorted[firstIndex];
caryclark@google.com2ddff932012-08-07 21:25:27 +00005672 winding -= angle->segment()->spanSign(angle);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005673#else
5674 do {
5675 angle = sorted[++firstIndex];
5676 segment = angle->segment();
5677 } while (segment->windSum(angle) == SK_MinS32);
5678 #if DEBUG_SORT
5679 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5680 #endif
5681 int sumWinding = segment->updateWindingReverse(angle);
5682 int nextIndex = firstIndex + 1;
5683 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5684 Segment* first = NULL;
5685#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005686 do {
5687 SkASSERT(nextIndex != firstIndex);
5688 if (nextIndex == angleCount) {
5689 nextIndex = 0;
5690 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005691 angle = sorted[nextIndex];
caryclark@google.com9764cc62012-07-12 19:29:45 +00005692 segment = angle->segment();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005693#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005694 int maxWinding = winding;
caryclark@google.com2ddff932012-08-07 21:25:27 +00005695 winding -= segment->spanSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005696 #if DEBUG_SORT
caryclark@google.com2ddff932012-08-07 21:25:27 +00005697 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
5698 segment->debugID(), maxWinding, winding, angle->sign());
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005699 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005700 tIndex = angle->start();
5701 endIndex = angle->end();
5702 int lesser = SkMin32(tIndex, endIndex);
5703 const Span& nextSpan = segment->span(lesser);
5704 if (!nextSpan.fDone) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005705#if 1
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005706 // FIXME: this be wrong? assign startWinding if edge is in
caryclark@google.com9764cc62012-07-12 19:29:45 +00005707 // same direction. If the direction is opposite, winding to
5708 // assign is flipped sign or +/- 1?
caryclark@google.com59823f72012-08-09 18:17:47 +00005709 if (useInnerWinding(maxWinding, winding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005710 maxWinding = winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005711 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005712 segment->markAndChaseWinding(angle, maxWinding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005713#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005714 break;
5715 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005716#else
5717 int start = angle->start();
5718 int end = angle->end();
5719 int maxWinding;
5720 segment->setUpWinding(start, end, maxWinding, sumWinding);
5721 if (!segment->done(angle)) {
5722 if (!first) {
5723 first = segment;
5724 tIndex = start;
5725 endIndex = end;
5726 }
5727 (void) segment->markAngle(maxWinding, sumWinding, true, angle);
5728 }
5729#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005730 } while (++nextIndex != lastIndex);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005731 #if TRY_ROTATE
5732 *chase.insert(0) = span;
5733 #else
5734 *chase.append() = span;
5735 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005736 return segment;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005737 }
5738 return NULL;
5739}
5740
caryclark@google.com027de222012-07-12 12:52:50 +00005741#if DEBUG_ACTIVE_SPANS
5742static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005743 int index;
5744 for (index = 0; index < contourList.count(); ++ index) {
caryclark@google.com027de222012-07-12 12:52:50 +00005745 contourList[index]->debugShowActiveSpans();
5746 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005747 for (index = 0; index < contourList.count(); ++ index) {
5748 contourList[index]->validateActiveSpans();
5749 }
caryclark@google.com027de222012-07-12 12:52:50 +00005750}
5751#endif
5752
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005753static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005754 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005755 Segment* result;
5756 do {
caryclark@google.comf839c032012-10-26 21:03:50 +00005757 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005758 int contourCount = contourList.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00005759 Segment* topStart = NULL;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005760 done = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00005761 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5762 Contour* contour = contourList[cIndex];
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005763 if (contour->done()) {
5764 continue;
5765 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005766 const Bounds& bounds = contour->bounds();
5767 if (bounds.fBottom < topLeft.fY) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005768 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005769 continue;
5770 }
5771 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005772 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005773 continue;
5774 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005775 contour->topSortableSegment(topLeft, bestXY, topStart);
5776 if (!contour->done()) {
5777 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005778 }
5779 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005780 if (!topStart) {
5781 return NULL;
5782 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005783 topLeft = bestXY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005784 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005785 } while (!result);
5786 return result;
5787}
caryclark@google.com31143cf2012-11-09 22:14:19 +00005788
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005789static int rightAngleWinding(SkTDArray<Contour*>& contourList,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005790 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005791 bool opp) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005792 double test = 0.9;
5793 int contourWinding;
5794 do {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005795 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
5796 tryAgain, test, opp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005797 if (contourWinding != SK_MinS32 || tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005798 return contourWinding;
5799 }
5800 test /= 2;
5801 } while (!approximately_negative(test));
5802 SkASSERT(0); // should be OK to comment out, but interested when this hits
5803 return contourWinding;
5804}
5805
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005806static void skipVertical(SkTDArray<Contour*>& contourList,
5807 Segment*& current, int& index, int& endIndex) {
5808 if (!current->isVertical(index, endIndex)) {
5809 return;
5810 }
5811 int contourCount = contourList.count();
5812 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5813 Contour* contour = contourList[cIndex];
5814 if (contour->done()) {
5815 continue;
5816 }
5817 current = contour->nonVerticalSegment(index, endIndex);
5818 if (current) {
5819 return;
5820 }
5821 }
5822}
5823
caryclark@google.com3586ece2012-12-27 18:46:58 +00005824static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005825 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
5826 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
5827 true);
5828 if (!current) {
5829 return NULL;
5830 }
5831 if (firstContour) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005832 current->initWinding(index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005833 firstContour = false;
5834 return current;
5835 }
5836 int minIndex = SkMin32(index, endIndex);
5837 int sumWinding = current->windSum(minIndex);
5838 if (sumWinding != SK_MinS32) {
5839 return current;
5840 }
5841 sumWinding = current->computeSum(index, endIndex, binary);
5842 if (sumWinding != SK_MinS32) {
5843 return current;
5844 }
5845 int contourWinding;
5846 int oppContourWinding = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005847 // the simple upward projection of the unresolved points hit unsortable angles
5848 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005849 bool tryAgain;
5850 double tHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005851 SkScalar hitDx = 0;
5852 SkScalar hitOppDx = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005853 do {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005854 // if current is vertical, find another candidate which is not
5855 // if only remaining candidates are vertical, then they can be marked done
caryclark@google.com10227bf2012-12-28 22:10:41 +00005856 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005857 skipVertical(contourList, current, index, endIndex);
caryclark@google.com10227bf2012-12-28 22:10:41 +00005858 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005859 tryAgain = false;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005860 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005861 tryAgain, false);
5862 if (tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005863 continue;
5864 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005865 if (!binary) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005866 break;
5867 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005868 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005869 tryAgain, true);
5870 } while (tryAgain);
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00005871
caryclark@google.com3586ece2012-12-27 18:46:58 +00005872 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005873 return current;
5874}
5875
5876// rewrite that abandons keeping local track of winding
caryclark@google.com3586ece2012-12-27 18:46:58 +00005877static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005878 bool firstContour = true;
5879 bool unsortable = false;
5880 bool topUnsortable = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005881 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
5882 do {
5883 int index, endIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005884 bool topDone;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005885 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005886 topUnsortable, topDone, false);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005887 if (!current) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005888 if (topUnsortable || !topDone) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005889 topUnsortable = false;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005890 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005891 topLeft.fX = topLeft.fY = SK_ScalarMin;
5892 continue;
5893 }
5894 break;
5895 }
5896 SkTDArray<Span*> chaseArray;
5897 do {
5898 if (current->activeWinding(index, endIndex)) {
5899 do {
5900 #if DEBUG_ACTIVE_SPANS
5901 if (!unsortable && current->done()) {
5902 debugShowActiveSpans(contourList);
5903 }
5904 #endif
5905 SkASSERT(unsortable || !current->done());
5906 int nextStart = index;
5907 int nextEnd = endIndex;
5908 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
5909 unsortable);
5910 if (!next) {
5911 if (!unsortable && simple.hasMove()
5912 && current->verb() != SkPath::kLine_Verb
5913 && !simple.isClosed()) {
5914 current->addCurveTo(index, endIndex, simple, true);
5915 SkASSERT(simple.isClosed());
5916 }
5917 break;
5918 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005919 #if DEBUG_FLOW
5920 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
5921 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
5922 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
5923 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005924 current->addCurveTo(index, endIndex, simple, true);
5925 current = next;
5926 index = nextStart;
5927 endIndex = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005928 } while (!simple.isClosed() && (!unsortable
caryclark@google.com10227bf2012-12-28 22:10:41 +00005929 || !current->done(SkMin32(index, endIndex))));
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005930 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
5931 SkASSERT(unsortable);
5932 int min = SkMin32(index, endIndex);
5933 if (!current->done(min)) {
5934 current->addCurveTo(index, endIndex, simple, true);
5935 current->markDoneUnary(min);
5936 }
5937 }
5938 simple.close();
5939 } else {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005940 Span* last = current->markAndChaseDoneUnary(index, endIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005941 if (last) {
5942 *chaseArray.append() = last;
5943 }
5944 }
5945 current = findChase(chaseArray, index, endIndex);
5946 #if DEBUG_ACTIVE_SPANS
5947 debugShowActiveSpans(contourList);
5948 #endif
5949 if (!current) {
5950 break;
5951 }
5952 } while (true);
5953 } while (true);
5954 return simple.someAssemblyRequired();
5955}
5956
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005957// returns true if all edges were processed
caryclark@google.comf839c032012-10-26 21:03:50 +00005958static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.com24bec792012-08-20 12:43:57 +00005959 Segment* current;
5960 int start, end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005961 bool unsortable = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005962 bool closable = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00005963 while ((current = findUndone(contourList, start, end))) {
caryclark@google.com24bec792012-08-20 12:43:57 +00005964 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005965 #if DEBUG_ACTIVE_SPANS
5966 if (!unsortable && current->done()) {
5967 debugShowActiveSpans(contourList);
5968 }
5969 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005970 SkASSERT(unsortable || !current->done());
caryclark@google.com24bec792012-08-20 12:43:57 +00005971 int nextStart = start;
5972 int nextEnd = end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005973 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
caryclark@google.com24bec792012-08-20 12:43:57 +00005974 if (!next) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005975 if (!unsortable && simple.hasMove()
caryclark@google.comf839c032012-10-26 21:03:50 +00005976 && current->verb() != SkPath::kLine_Verb
5977 && !simple.isClosed()) {
5978 current->addCurveTo(start, end, simple, true);
5979 SkASSERT(simple.isClosed());
caryclark@google.comc899ad92012-08-23 15:24:42 +00005980 }
caryclark@google.com24bec792012-08-20 12:43:57 +00005981 break;
5982 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005983 #if DEBUG_FLOW
5984 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
5985 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
5986 current->xyAtT(end).fX, current->xyAtT(end).fY);
5987 #endif
caryclark@google.comf839c032012-10-26 21:03:50 +00005988 current->addCurveTo(start, end, simple, true);
caryclark@google.com24bec792012-08-20 12:43:57 +00005989 current = next;
5990 start = nextStart;
5991 end = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005992 } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005993 if (!simple.isClosed()) {
5994 SkASSERT(unsortable);
5995 int min = SkMin32(start, end);
5996 if (!current->done(min)) {
5997 current->addCurveTo(start, end, simple, true);
5998 current->markDone(min, 1);
5999 }
6000 closable = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00006001 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006002 simple.close();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00006003 #if DEBUG_ACTIVE_SPANS
6004 debugShowActiveSpans(contourList);
6005 #endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00006006 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006007 return closable;
caryclark@google.com24bec792012-08-20 12:43:57 +00006008}
6009
caryclark@google.comb45a1b42012-05-18 20:50:33 +00006010static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
6011 int contourCount = contourList.count();
6012 for (int cTest = 0; cTest < contourCount; ++cTest) {
6013 Contour* contour = contourList[cTest];
6014 contour->fixOtherTIndex();
6015 }
6016}
6017
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006018static void sortSegments(SkTDArray<Contour*>& contourList) {
6019 int contourCount = contourList.count();
6020 for (int cTest = 0; cTest < contourCount; ++cTest) {
6021 Contour* contour = contourList[cTest];
6022 contour->sortSegments();
6023 }
6024}
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006025
caryclark@google.com4eeda372012-12-06 21:47:48 +00006026static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
6027 bool evenOdd, bool oppEvenOdd) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006028 int count = contours.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006029 if (count == 0) {
6030 return;
6031 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006032 for (int index = 0; index < count; ++index) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00006033 Contour& contour = contours[index];
6034 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
6035 *list.append() = &contour;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006036 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006037 QSort<Contour>(list.begin(), list.end() - 1);
6038}
6039
caryclark@google.comf839c032012-10-26 21:03:50 +00006040static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006041 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006042}
6043
caryclark@google.com10227bf2012-12-28 22:10:41 +00006044static bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
6045 return distances[one] < distances[two];
6046}
caryclark@google.comf839c032012-10-26 21:03:50 +00006047 /*
6048 check start and end of each contour
6049 if not the same, record them
6050 match them up
6051 connect closest
6052 reassemble contour pieces into new path
6053 */
6054static void assemble(const PathWrapper& path, PathWrapper& simple) {
6055#if DEBUG_PATH_CONSTRUCTION
6056 SkDebugf("%s\n", __FUNCTION__);
6057#endif
6058 SkTArray<Contour> contours;
6059 EdgeBuilder builder(path, contours);
6060 builder.finish();
6061 int count = contours.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006062 int outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006063 SkTDArray<int> runs; // indices of partial contours
caryclark@google.com0b7da432012-10-31 19:00:20 +00006064 for (outer = 0; outer < count; ++outer) {
6065 const Contour& eContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006066 const SkPoint& eStart = eContour.start();
6067 const SkPoint& eEnd = eContour.end();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006068#if DEBUG_ASSEMBLE
6069 SkDebugf("%s contour", __FUNCTION__);
6070 if (!approximatelyEqual(eStart, eEnd)) {
6071 SkDebugf("[%d]", runs.count());
6072 } else {
6073 SkDebugf(" ");
6074 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006075 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006076 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
6077#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006078 if (approximatelyEqual(eStart, eEnd)) {
6079 eContour.toPath(simple);
6080 continue;
6081 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006082 *runs.append() = outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006083 }
6084 count = runs.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006085 if (count == 0) {
6086 return;
6087 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006088 SkTDArray<int> sLink, eLink;
6089 sLink.setCount(count);
6090 eLink.setCount(count);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006091 int rIndex, iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006092 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006093 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006094 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006095 SkTDArray<double> distances;
6096 const int ends = count * 2; // all starts and ends
6097 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
6098 distances.setCount(entries);
6099 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
6100 outer = runs[rIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006101 const Contour& oContour = contours[outer];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006102 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
6103 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
6104 * ends - rIndex - 1;
6105 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
6106 int inner = runs[iIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006107 const Contour& iContour = contours[inner];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006108 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
6109 double dx = iPt.fX - oPt.fX;
6110 double dy = iPt.fY - oPt.fY;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006111 double dist = dx * dx + dy * dy;
caryclark@google.com10227bf2012-12-28 22:10:41 +00006112 distances[row + iIndex] = dist; // oStart distance from iStart
6113 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006114 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006115 SkTDArray<int> sortedDist;
6116 sortedDist.setCount(entries);
6117 for (rIndex = 0; rIndex < entries; ++rIndex) {
6118 sortedDist[rIndex] = rIndex;
6119 }
6120 QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
6121 int remaining = count; // number of start/end pairs
6122 for (rIndex = 0; rIndex < entries; ++rIndex) {
6123 int pair = sortedDist[rIndex];
6124 int row = pair / ends;
6125 int col = pair - row * ends;
6126 int thingOne = row < col ? row : ends - row - 2;
6127 int ndxOne = thingOne >> 1;
6128 bool endOne = thingOne & 1;
6129 int* linkOne = endOne ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006130 if (linkOne[ndxOne] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006131 continue;
6132 }
6133 int thingTwo = row < col ? col : ends - row + col - 1;
6134 int ndxTwo = thingTwo >> 1;
6135 bool endTwo = thingTwo & 1;
6136 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006137 if (linkTwo[ndxTwo] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006138 continue;
6139 }
6140 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
6141 bool flip = endOne == endTwo;
6142 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
6143 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
6144 if (!--remaining) {
6145 break;
6146 }
6147 }
6148 SkASSERT(!remaining);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006149#if DEBUG_ASSEMBLE
6150 for (rIndex = 0; rIndex < count; ++rIndex) {
6151 int s = sLink[rIndex];
6152 int e = eLink[rIndex];
6153 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
6154 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
caryclark@google.comf839c032012-10-26 21:03:50 +00006155 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006156#endif
6157 rIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00006158 do {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006159 bool forward = true;
6160 bool first = true;
6161 int sIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006162 SkASSERT(sIndex != SK_MaxS32);
6163 sLink[rIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006164 int eIndex;
6165 if (sIndex < 0) {
6166 eIndex = sLink[~sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006167 sLink[~sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006168 } else {
6169 eIndex = eLink[sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006170 eLink[sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006171 }
caryclark@google.comaa358312013-01-29 20:28:49 +00006172 SkASSERT(eIndex != SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006173#if DEBUG_ASSEMBLE
6174 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006175 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
6176 eIndex < 0 ? ~eIndex : eIndex);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006177#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006178 do {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006179 outer = runs[rIndex];
6180 const Contour& contour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006181 if (first) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006182 first = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006183 const SkPoint* startPtr = &contour.start();
caryclark@google.comf839c032012-10-26 21:03:50 +00006184 simple.deferredMove(startPtr[0]);
6185 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006186 if (forward) {
6187 contour.toPartialForward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006188 } else {
6189 contour.toPartialBackward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006190 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006191#if DEBUG_ASSEMBLE
6192 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006193 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006194 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
6195#endif
6196 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006197 simple.close();
caryclark@google.comf839c032012-10-26 21:03:50 +00006198 break;
6199 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006200 if (forward) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006201 eIndex = eLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006202 SkASSERT(eIndex != SK_MaxS32);
6203 eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006204 if (eIndex >= 0) {
6205 SkASSERT(sLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006206 sLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006207 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006208 SkASSERT(eLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006209 eLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006210 }
6211 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006212 eIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006213 SkASSERT(eIndex != SK_MaxS32);
6214 sLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006215 if (eIndex >= 0) {
6216 SkASSERT(eLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006217 eLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006218 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006219 SkASSERT(sLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006220 sLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006221 }
6222 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006223 rIndex = eIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006224 if (rIndex < 0) {
6225 forward ^= 1;
6226 rIndex = ~rIndex;
6227 }
6228 } while (true);
6229 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006230 if (sLink[rIndex] != SK_MaxS32) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006231 break;
6232 }
6233 }
6234 } while (rIndex < count);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006235#if DEBUG_ASSEMBLE
6236 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006237 SkASSERT(sLink[rIndex] == SK_MaxS32);
6238 SkASSERT(eLink[rIndex] == SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006239 }
6240#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006241}
6242
6243void simplifyx(const SkPath& path, SkPath& result) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006244 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
caryclark@google.comf839c032012-10-26 21:03:50 +00006245 result.reset();
6246 result.setFillType(SkPath::kEvenOdd_FillType);
6247 PathWrapper simple(result);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006248
6249 // turn path into list of segments
6250 SkTArray<Contour> contours;
6251 // FIXME: add self-intersecting cubics' T values to segment
6252 EdgeBuilder builder(path, contours);
caryclark@google.com235f56a2012-09-14 14:19:30 +00006253 builder.finish();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006254 SkTDArray<Contour*> contourList;
caryclark@google.com4eeda372012-12-06 21:47:48 +00006255 makeContourList(contours, contourList, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006256 Contour** currentPtr = contourList.begin();
6257 if (!currentPtr) {
6258 return;
6259 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006260 Contour** listEnd = contourList.end();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006261 // find all intersections between segments
6262 do {
6263 Contour** nextPtr = currentPtr;
6264 Contour* current = *currentPtr++;
6265 Contour* next;
6266 do {
6267 next = *nextPtr++;
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00006268 } while (addIntersectTs(current, next) && nextPtr != listEnd);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006269 } while (currentPtr != listEnd);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006270 // eat through coincident edges
caryclark@google.com4eeda372012-12-06 21:47:48 +00006271 coincidenceCheck(contourList, 0);
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00006272 fixOtherTIndex(contourList);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006273 sortSegments(contourList);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006274#if DEBUG_ACTIVE_SPANS
6275 debugShowActiveSpans(contourList);
6276#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006277 // construct closed contours
caryclark@google.com3586ece2012-12-27 18:46:58 +00006278 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00006279 : !bridgeXor(contourList, simple))
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006280 { // if some edges could not be resolved, assemble remaining fragments
caryclark@google.comf839c032012-10-26 21:03:50 +00006281 SkPath temp;
6282 temp.setFillType(SkPath::kEvenOdd_FillType);
6283 PathWrapper assembled(temp);
6284 assemble(simple, assembled);
6285 result = *assembled.nativePath();
caryclark@google.com24bec792012-08-20 12:43:57 +00006286 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006287}