blob: 618dc30a266ad26184227894fa8124daec6c5743 [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.com73ca6242013-01-17 21:02:47 +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
218static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000219 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000220 double x, y;
221 xy_at_t(quad, t, x, y);
222 out->fX = SkDoubleToScalar(x);
223 out->fY = SkDoubleToScalar(y);
224}
225
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000226static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
227 MAKE_CONST_QUAD(quad, a);
228 xy_at_t(quad, t, out->x, out->y);
229}
230
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000231static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000232 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000233 double x, y;
234 xy_at_t(cubic, t, x, y);
235 out->fX = SkDoubleToScalar(x);
236 out->fY = SkDoubleToScalar(y);
237}
238
239static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
240 NULL,
241 LineXYAtT,
242 QuadXYAtT,
243 CubicXYAtT
244};
245
246static SkScalar LineXAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000247 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000248 double x;
249 xy_at_t(aLine, t, x, *(double*) 0);
250 return SkDoubleToScalar(x);
251}
252
253static SkScalar QuadXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000254 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000255 double x;
256 xy_at_t(quad, t, x, *(double*) 0);
257 return SkDoubleToScalar(x);
258}
259
260static SkScalar CubicXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000261 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000262 double x;
263 xy_at_t(cubic, t, x, *(double*) 0);
264 return SkDoubleToScalar(x);
265}
266
267static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
268 NULL,
269 LineXAtT,
270 QuadXAtT,
271 CubicXAtT
272};
273
274static SkScalar LineYAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000275 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000276 double y;
277 xy_at_t(aLine, t, *(double*) 0, y);
278 return SkDoubleToScalar(y);
279}
280
281static SkScalar QuadYAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000282 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000283 double y;
284 xy_at_t(quad, t, *(double*) 0, y);
285 return SkDoubleToScalar(y);
286}
287
288static SkScalar CubicYAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000289 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000290 double y;
291 xy_at_t(cubic, t, *(double*) 0, y);
292 return SkDoubleToScalar(y);
293}
294
295static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
296 NULL,
297 LineYAtT,
298 QuadYAtT,
299 CubicYAtT
300};
301
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000302static SkScalar LineDXAtT(const SkPoint a[2], double ) {
303 return a[1].fX - a[0].fX;
304}
305
306static SkScalar QuadDXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000307 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000308 double x = dx_at_t(quad, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000309 return SkDoubleToScalar(x);
310}
311
312static SkScalar CubicDXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000313 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000314 double x = dx_at_t(cubic, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000315 return SkDoubleToScalar(x);
316}
317
318static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
319 NULL,
320 LineDXAtT,
321 QuadDXAtT,
322 CubicDXAtT
323};
324
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000325static SkScalar LineDYAtT(const SkPoint a[2], double ) {
326 return a[1].fY - a[0].fY;
327}
328
329static SkScalar QuadDYAtT(const SkPoint a[3], double t) {
330 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000331 double y = dy_at_t(quad, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000332 return SkDoubleToScalar(y);
333}
334
335static SkScalar CubicDYAtT(const SkPoint a[4], double t) {
336 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000337 double y = dy_at_t(cubic, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000338 return SkDoubleToScalar(y);
339}
340
341static SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = {
342 NULL,
343 LineDYAtT,
344 QuadDYAtT,
345 CubicDYAtT
346};
347
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000348static void LineSubDivide(const SkPoint a[2], double startT, double endT,
349 SkPoint sub[2]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000350 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000351 _Line dst;
352 sub_divide(aLine, startT, endT, dst);
353 sub[0].fX = SkDoubleToScalar(dst[0].x);
354 sub[0].fY = SkDoubleToScalar(dst[0].y);
355 sub[1].fX = SkDoubleToScalar(dst[1].x);
356 sub[1].fY = SkDoubleToScalar(dst[1].y);
357}
358
359static void QuadSubDivide(const SkPoint a[3], double startT, double endT,
360 SkPoint sub[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000361 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000362 Quadratic dst;
363 sub_divide(aQuad, startT, endT, dst);
364 sub[0].fX = SkDoubleToScalar(dst[0].x);
365 sub[0].fY = SkDoubleToScalar(dst[0].y);
366 sub[1].fX = SkDoubleToScalar(dst[1].x);
367 sub[1].fY = SkDoubleToScalar(dst[1].y);
368 sub[2].fX = SkDoubleToScalar(dst[2].x);
369 sub[2].fY = SkDoubleToScalar(dst[2].y);
370}
371
372static void CubicSubDivide(const SkPoint a[4], double startT, double endT,
373 SkPoint sub[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000374 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000375 Cubic dst;
376 sub_divide(aCubic, startT, endT, dst);
377 sub[0].fX = SkDoubleToScalar(dst[0].x);
378 sub[0].fY = SkDoubleToScalar(dst[0].y);
379 sub[1].fX = SkDoubleToScalar(dst[1].x);
380 sub[1].fY = SkDoubleToScalar(dst[1].y);
381 sub[2].fX = SkDoubleToScalar(dst[2].x);
382 sub[2].fY = SkDoubleToScalar(dst[2].y);
383 sub[3].fX = SkDoubleToScalar(dst[3].x);
384 sub[3].fY = SkDoubleToScalar(dst[3].y);
385}
386
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000387static void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
388 SkPoint []) = {
389 NULL,
390 LineSubDivide,
391 QuadSubDivide,
392 CubicSubDivide
393};
394
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000395static void LineSubDivideHD(const SkPoint a[2], double startT, double endT,
caryclark@google.com32546db2012-08-31 20:55:07 +0000396 _Line sub) {
397 MAKE_CONST_LINE(aLine, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000398 _Line dst;
399 sub_divide(aLine, startT, endT, dst);
400 sub[0] = dst[0];
401 sub[1] = dst[1];
402}
403
404static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT,
caryclark@google.com32546db2012-08-31 20:55:07 +0000405 Quadratic sub) {
406 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000407 Quadratic dst;
408 sub_divide(aQuad, startT, endT, dst);
409 sub[0] = dst[0];
410 sub[1] = dst[1];
411 sub[2] = dst[2];
412}
413
414static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT,
caryclark@google.com32546db2012-08-31 20:55:07 +0000415 Cubic sub) {
416 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000417 Cubic dst;
418 sub_divide(aCubic, startT, endT, dst);
419 sub[0] = dst[0];
420 sub[1] = dst[1];
421 sub[2] = dst[2];
422 sub[3] = dst[3];
423}
424
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000425#if DEBUG_UNUSED
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000426static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
427 SkRect& bounds) {
428 SkPoint dst[3];
429 QuadSubDivide(a, startT, endT, dst);
430 bounds.fLeft = bounds.fRight = dst[0].fX;
431 bounds.fTop = bounds.fBottom = dst[0].fY;
432 for (int index = 1; index < 3; ++index) {
433 bounds.growToInclude(dst[index].fX, dst[index].fY);
434 }
435}
436
437static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
438 SkRect& bounds) {
439 SkPoint dst[4];
440 CubicSubDivide(a, startT, endT, dst);
441 bounds.fLeft = bounds.fRight = dst[0].fX;
442 bounds.fTop = bounds.fBottom = dst[0].fY;
443 for (int index = 1; index < 4; ++index) {
444 bounds.growToInclude(dst[index].fX, dst[index].fY);
445 }
446}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000447#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000448
caryclark@google.com15fa1382012-05-07 20:49:36 +0000449static SkPath::Verb QuadReduceOrder(const SkPoint a[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000450 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000451 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000452 Quadratic dst;
453 int order = reduceOrder(aQuad, dst);
caryclark@google.com24bec792012-08-20 12:43:57 +0000454 if (order == 2) { // quad became line
455 for (int index = 0; index < order; ++index) {
456 SkPoint* pt = reducePts.append();
457 pt->fX = SkDoubleToScalar(dst[index].x);
458 pt->fY = SkDoubleToScalar(dst[index].y);
459 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000460 }
461 return (SkPath::Verb) (order - 1);
462}
463
464static SkPath::Verb CubicReduceOrder(const SkPoint a[4],
465 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000466 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000467 Cubic dst;
468 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed);
caryclark@google.com24bec792012-08-20 12:43:57 +0000469 if (order == 2 || order == 3) { // cubic became line or quad
470 for (int index = 0; index < order; ++index) {
471 SkPoint* pt = reducePts.append();
472 pt->fX = SkDoubleToScalar(dst[index].x);
473 pt->fY = SkDoubleToScalar(dst[index].y);
474 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000475 }
476 return (SkPath::Verb) (order - 1);
477}
478
caryclark@google.com15fa1382012-05-07 20:49:36 +0000479static bool QuadIsLinear(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000480 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000481 return isLinear(aQuad, 0, 2);
482}
483
484static bool CubicIsLinear(const SkPoint a[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000485 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000486 return isLinear(aCubic, 0, 3);
487}
488
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000489static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000490 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000491 double x[2];
492 xy_at_t(aLine, startT, x[0], *(double*) 0);
caryclark@google.com495f8e42012-05-31 13:13:11 +0000493 xy_at_t(aLine, endT, x[1], *(double*) 0);
494 return SkMinScalar((float) x[0], (float) x[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000495}
496
497static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000498 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000499 return (float) leftMostT(aQuad, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000500}
501
502static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000503 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000504 return (float) leftMostT(aCubic, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000505}
506
507static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
508 NULL,
509 LineLeftMost,
510 QuadLeftMost,
511 CubicLeftMost
512};
513
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000514#if 0 // currently unused
caryclark@google.com235f56a2012-09-14 14:19:30 +0000515static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
516 Intersections& intersections) {
517 MAKE_CONST_QUAD(aQuad, a);
518 MAKE_CONST_LINE(bLine, b);
519 return intersectRay(aQuad, bLine, intersections);
520}
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000521#endif
522
523static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine,
524 Intersections& intersections) {
525 MAKE_CONST_QUAD(aQuad, a);
526 return intersectRay(aQuad, bLine, intersections);
527}
caryclark@google.com235f56a2012-09-14 14:19:30 +0000528
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000529static bool LineVertical(const SkPoint a[2], double startT, double endT) {
530 MAKE_CONST_LINE(aLine, a);
531 double x[2];
532 xy_at_t(aLine, startT, x[0], *(double*) 0);
533 xy_at_t(aLine, endT, x[1], *(double*) 0);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000534 return AlmostEqualUlps((float) x[0], (float) x[1]);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000535}
536
537static bool QuadVertical(const SkPoint a[3], double startT, double endT) {
538 SkPoint dst[3];
539 QuadSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000540 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000541}
542
543static bool CubicVertical(const SkPoint a[4], double startT, double endT) {
544 SkPoint dst[4];
545 CubicSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000546 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX)
547 && AlmostEqualUlps(dst[2].fX, dst[3].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000548}
549
550static bool (* const SegmentVertical[])(const SkPoint [], double , double) = {
551 NULL,
552 LineVertical,
553 QuadVertical,
554 CubicVertical
555};
556
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000557class Segment;
558
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000559struct Span {
560 Segment* fOther;
561 mutable SkPoint fPt; // lazily computed as needed
562 double fT;
563 double fOtherT; // value at fOther[fOtherIndex].fT
564 int fOtherIndex; // can't be used during intersection
caryclark@google.com31143cf2012-11-09 22:14:19 +0000565 int fWindSum; // accumulated from contours surrounding this one.
566 int fOppSum; // for binary operators: the opposite winding sum
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000567 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
caryclark@google.com57cff8d2012-11-14 21:14:56 +0000568 int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000569 bool fDone; // if set, this span to next higher T has been processed
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000570 bool fUnsortableStart; // set when start is part of an unsortable pair
571 bool fUnsortableEnd; // set when end is part of an unsortable pair
caryclark@google.comf839c032012-10-26 21:03:50 +0000572 bool fTiny; // if set, span may still be considered once for edge following
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000573};
574
caryclark@google.com15fa1382012-05-07 20:49:36 +0000575// sorting angles
576// given angles of {dx dy ddx ddy dddx dddy} sort them
577class Angle {
578public:
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000579 // FIXME: this is bogus for quads and cubics
580 // if the quads and cubics' line from end pt to ctrl pt are coincident,
581 // there's no obvious way to determine the curve ordering from the
582 // derivatives alone. In particular, if one quadratic's coincident tangent
583 // is longer than the other curve, the final control point can place the
584 // longer curve on either side of the shorter one.
585 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
586 // may provide some help, but nothing has been figured out yet.
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000587
caryclark@google.com32546db2012-08-31 20:55:07 +0000588 /*(
589 for quads and cubics, set up a parameterized line (e.g. LineParameters )
590 for points [0] to [1]. See if point [2] is on that line, or on one side
591 or the other. If it both quads' end points are on the same side, choose
592 the shorter tangent. If the tangents are equal, choose the better second
593 tangent angle
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000594
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000595 maybe I could set up LineParameters lazily
caryclark@google.com32546db2012-08-31 20:55:07 +0000596 */
caryclark@google.com15fa1382012-05-07 20:49:36 +0000597 bool operator<(const Angle& rh) const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000598 double y = dy();
599 double ry = rh.dy();
600 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
601 return y < 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000602 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000603 double x = dx();
604 double rx = rh.dx();
605 if (y == 0 && ry == 0 && x * rx < 0) {
606 return x < rx;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000607 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000608 double x_ry = x * ry;
609 double rx_y = rx * y;
610 double cmp = x_ry - rx_y;
caryclark@google.comc899ad92012-08-23 15:24:42 +0000611 if (!approximately_zero(cmp)) {
caryclark@google.com15fa1382012-05-07 20:49:36 +0000612 return cmp < 0;
613 }
caryclark@google.comd1688742012-09-18 20:08:37 +0000614 if (approximately_zero(x_ry) && approximately_zero(rx_y)
615 && !approximately_zero_squared(cmp)) {
616 return cmp < 0;
617 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000618 // at this point, the initial tangent line is coincident
caryclark@google.com31143cf2012-11-09 22:14:19 +0000619 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
620 || !approximately_zero(rh.fSide))) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000621 // FIXME: running demo will trigger this assertion
622 // (don't know if commenting out will trigger further assertion or not)
623 // commenting it out allows demo to run in release, though
624 // SkASSERT(fSide != rh.fSide);
625 return fSide < rh.fSide;
626 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000627 // see if either curve can be lengthened and try the tangent compare again
628 if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
629 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
630 Angle longer = *this;
631 Angle rhLonger = rh;
632 if (longer.lengthen() | rhLonger.lengthen()) {
633 return longer < rhLonger;
634 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000635 #if 0
caryclark@google.coma461ff02012-10-11 12:54:23 +0000636 // what if we extend in the other direction?
637 longer = *this;
638 rhLonger = rh;
639 if (longer.reverseLengthen() | rhLonger.reverseLengthen()) {
640 return longer < rhLonger;
641 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000642 #endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000643 }
caryclark@google.com185c7c42012-10-19 18:26:24 +0000644 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
caryclark@google.com31143cf2012-11-09 22:14:19 +0000645 || (rh.fVerb == SkPath::kLine_Verb
646 && approximately_zero(rx) && approximately_zero(ry))) {
caryclark@google.com185c7c42012-10-19 18:26:24 +0000647 // See general unsortable comment below. This case can happen when
648 // one line has a non-zero change in t but no change in x and y.
649 fUnsortable = true;
650 rh.fUnsortable = true;
651 return this < &rh; // even with no solution, return a stable sort
652 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000653 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
654 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
655 fUnsortable = true;
656 rh.fUnsortable = true;
657 return this < &rh; // even with no solution, return a stable sort
658 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000659 SkASSERT(fVerb == SkPath::kQuad_Verb); // worry about cubics later
660 SkASSERT(rh.fVerb == SkPath::kQuad_Verb);
skia.committer@gmail.comc1ad0222012-09-19 02:01:47 +0000661 // FIXME: until I can think of something better, project a ray from the
caryclark@google.comd1688742012-09-18 20:08:37 +0000662 // end of the shorter tangent to midway between the end points
663 // through both curves and use the resulting angle to sort
caryclark@google.com235f56a2012-09-14 14:19:30 +0000664 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
665 double len = fTangent1.normalSquared();
666 double rlen = rh.fTangent1.normalSquared();
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000667 _Line ray;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000668 Intersections i, ri;
caryclark@google.comd1688742012-09-18 20:08:37 +0000669 int roots, rroots;
670 bool flip = false;
671 do {
672 const Quadratic& q = (len < rlen) ^ flip ? fQ : rh.fQ;
673 double midX = (q[0].x + q[2].x) / 2;
674 double midY = (q[0].y + q[2].y) / 2;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000675 ray[0] = q[1];
676 ray[1].x = midX;
677 ray[1].y = midY;
caryclark@google.comd1688742012-09-18 20:08:37 +0000678 SkASSERT(ray[0] != ray[1]);
679 roots = QuadRayIntersect(fPts, ray, i);
680 rroots = QuadRayIntersect(rh.fPts, ray, ri);
681 } while ((roots == 0 || rroots == 0) && (flip ^= true));
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000682 if (roots == 0 || rroots == 0) {
683 // FIXME: we don't have a solution in this case. The interim solution
684 // is to mark the edges as unsortable, exclude them from this and
685 // future computations, and allow the returned path to be fragmented
686 fUnsortable = true;
687 rh.fUnsortable = true;
688 return this < &rh; // even with no solution, return a stable sort
689 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000690 _Point loc;
691 double best = SK_ScalarInfinity;
692 double dx, dy, dist;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000693 int index;
694 for (index = 0; index < roots; ++index) {
695 QuadXYAtT(fPts, i.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000696 dx = loc.x - ray[0].x;
697 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000698 dist = dx * dx + dy * dy;
699 if (best > dist) {
700 best = dist;
701 }
702 }
703 for (index = 0; index < rroots; ++index) {
704 QuadXYAtT(rh.fPts, ri.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000705 dx = loc.x - ray[0].x;
706 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000707 dist = dx * dx + dy * dy;
708 if (best > dist) {
709 return fSide < 0;
710 }
711 }
712 return fSide > 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000713 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000714
caryclark@google.com47580692012-07-23 12:14:49 +0000715 double dx() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000716 return fTangent1.dx();
caryclark@google.com47580692012-07-23 12:14:49 +0000717 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000718
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000719 double dy() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000720 return fTangent1.dy();
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000721 }
722
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000723 int end() const {
724 return fEnd;
725 }
726
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000727 bool isHorizontal() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000728 return dy() == 0 && fVerb == SkPath::kLine_Verb;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000729 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000730
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000731 bool lengthen() {
732 int newEnd = fEnd;
733 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
734 fEnd = newEnd;
735 setSpans();
736 return true;
737 }
738 return false;
739 }
740
caryclark@google.coma461ff02012-10-11 12:54:23 +0000741 bool reverseLengthen() {
742 if (fReversed) {
743 return false;
744 }
745 int newEnd = fStart;
746 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
747 fEnd = newEnd;
748 fReversed = true;
749 setSpans();
750 return true;
751 }
752 return false;
753 }
754
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000755 void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000756 int start, int end, const SkTDArray<Span>& spans) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000757 fSegment = segment;
758 fStart = start;
759 fEnd = end;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000760 fPts = orig;
761 fVerb = verb;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000762 fSpans = &spans;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000763 fReversed = false;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000764 fUnsortable = false;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000765 setSpans();
766 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000767
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000768
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000769 void setSpans() {
770 double startT = (*fSpans)[fStart].fT;
771 double endT = (*fSpans)[fEnd].fT;
772 switch (fVerb) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000773 case SkPath::kLine_Verb:
774 _Line l;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000775 LineSubDivideHD(fPts, startT, endT, l);
caryclark@google.com32546db2012-08-31 20:55:07 +0000776 // OPTIMIZATION: for pure line compares, we never need fTangent1.c
777 fTangent1.lineEndPoints(l);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000778 fSide = 0;
caryclark@google.com32546db2012-08-31 20:55:07 +0000779 break;
780 case SkPath::kQuad_Verb:
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000781 QuadSubDivideHD(fPts, startT, endT, fQ);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000782 fTangent1.quadEndPoints(fQ, 0, 1);
783 fSide = -fTangent1.pointDistance(fQ[2]); // not normalized -- compare sign only
caryclark@google.com32546db2012-08-31 20:55:07 +0000784 break;
785 case SkPath::kCubic_Verb:
786 Cubic c;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000787 CubicSubDivideHD(fPts, startT, endT, c);
caryclark@google.com32546db2012-08-31 20:55:07 +0000788 fTangent1.cubicEndPoints(c, 0, 1);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000789 fSide = -fTangent1.pointDistance(c[2]); // not normalized -- compare sign only
caryclark@google.com32546db2012-08-31 20:55:07 +0000790 break;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000791 default:
792 SkASSERT(0);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000793 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000794 fUnsortable = dx() == 0 && dy() == 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000795 if (fUnsortable) {
796 return;
797 }
798 SkASSERT(fStart != fEnd);
799 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
800 for (int index = fStart; index != fEnd; index += step) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000801#if 1
802 const Span& thisSpan = (*fSpans)[index];
803 const Span& nextSpan = (*fSpans)[index + step];
804 if (thisSpan.fTiny || thisSpan.fT == nextSpan.fT) {
805 continue;
caryclark@google.comf839c032012-10-26 21:03:50 +0000806 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000807 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
808#if DEBUG_UNSORTABLE
809 if (fUnsortable) {
810 SkPoint iPt, ePt;
811 (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt);
812 (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt);
813 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
814 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
815 }
816#endif
817 return;
818#else
819 if ((*fSpans)[index].fUnsortableStart) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000820 fUnsortable = true;
821 return;
822 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000823#endif
caryclark@google.comf839c032012-10-26 21:03:50 +0000824 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000825#if 1
826#if DEBUG_UNSORTABLE
827 SkPoint iPt, ePt;
828 (*SegmentXYAtT[fVerb])(fPts, startT, &iPt);
829 (*SegmentXYAtT[fVerb])(fPts, endT, &ePt);
830 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
831 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
832#endif
833 fUnsortable = true;
834#endif
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000835 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000836
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000837 Segment* segment() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000838 return const_cast<Segment*>(fSegment);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000839 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000840
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000841 int sign() const {
caryclark@google.com495f8e42012-05-31 13:13:11 +0000842 return SkSign32(fStart - fEnd);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000843 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000844
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000845 const SkTDArray<Span>* spans() const {
846 return fSpans;
847 }
848
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000849 int start() const {
850 return fStart;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000851 }
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +0000852
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000853 bool unsortable() const {
854 return fUnsortable;
855 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000856
caryclark@google.comc899ad92012-08-23 15:24:42 +0000857#if DEBUG_ANGLE
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000858 const SkPoint* pts() const {
859 return fPts;
860 }
861
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000862 SkPath::Verb verb() const {
863 return fVerb;
864 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000865
caryclark@google.comc899ad92012-08-23 15:24:42 +0000866 void debugShow(const SkPoint& a) const {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000867 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
caryclark@google.comc899ad92012-08-23 15:24:42 +0000868 }
869#endif
870
caryclark@google.com15fa1382012-05-07 20:49:36 +0000871private:
caryclark@google.com235f56a2012-09-14 14:19:30 +0000872 const SkPoint* fPts;
873 Quadratic fQ;
874 SkPath::Verb fVerb;
875 double fSide;
876 LineParameters fTangent1;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000877 const SkTDArray<Span>* fSpans;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000878 const Segment* fSegment;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000879 int fStart;
880 int fEnd;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000881 bool fReversed;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000882 mutable bool fUnsortable; // this alone is editable by the less than operator
caryclark@google.com15fa1382012-05-07 20:49:36 +0000883};
884
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000885// Bounds, unlike Rect, does not consider a line to be empty.
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000886struct Bounds : public SkRect {
887 static bool Intersects(const Bounds& a, const Bounds& b) {
888 return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
889 a.fTop <= b.fBottom && b.fTop <= a.fBottom;
890 }
891
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000892 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
893 if (left < fLeft) {
894 fLeft = left;
895 }
896 if (top < fTop) {
897 fTop = top;
898 }
899 if (right > fRight) {
900 fRight = right;
901 }
902 if (bottom > fBottom) {
903 fBottom = bottom;
904 }
905 }
906
907 void add(const Bounds& toAdd) {
908 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
909 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000910
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000911 void add(const SkPoint& pt) {
912 if (pt.fX < fLeft) fLeft = pt.fX;
913 if (pt.fY < fTop) fTop = pt.fY;
914 if (pt.fX > fRight) fRight = pt.fX;
915 if (pt.fY > fBottom) fBottom = pt.fY;
916 }
917
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000918 bool isEmpty() {
919 return fLeft > fRight || fTop > fBottom
caryclark@google.com235f56a2012-09-14 14:19:30 +0000920 || (fLeft == fRight && fTop == fBottom)
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000921 || isnan(fLeft) || isnan(fRight)
922 || isnan(fTop) || isnan(fBottom);
923 }
924
925 void setCubicBounds(const SkPoint a[4]) {
926 _Rect dRect;
caryclark@google.com32546db2012-08-31 20:55:07 +0000927 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000928 dRect.setBounds(cubic);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000929 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
930 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000931 }
932
933 void setQuadBounds(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000934 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000935 _Rect dRect;
936 dRect.setBounds(quad);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000937 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
938 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000939 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000940
941 void setPoint(const SkPoint& pt) {
942 fLeft = fRight = pt.fX;
943 fTop = fBottom = pt.fY;
944 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000945};
946
caryclark@google.com7ba591e2012-11-20 14:21:54 +0000947// OPTIMIZATION: does the following also work, and is it any faster?
948// return outerWinding * innerWinding > 0
949// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
caryclark@google.com2ddff932012-08-07 21:25:27 +0000950static bool useInnerWinding(int outerWinding, int innerWinding) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000951 // SkASSERT(outerWinding != innerWinding);
caryclark@google.com2ddff932012-08-07 21:25:27 +0000952 int absOut = abs(outerWinding);
953 int absIn = abs(innerWinding);
954 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
955 if (outerWinding * innerWinding < 0) {
956#if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +0000957 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
caryclark@google.com2ddff932012-08-07 21:25:27 +0000958 outerWinding, innerWinding, result ? "true" : "false");
959#endif
960 }
961 return result;
962}
963
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000964#define F (false) // discard the edge
965#define T (true) // keep the edge
966
caryclark@google.comd0deb4f2012-12-17 13:58:08 +0000967static const bool gUnaryActiveEdge[2][2] = {
968// from=0 from=1
969// to=0,1 to=0,1
970 {F, T}, {T, F},
971};
972
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000973static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
974// miFrom=0 miFrom=1
975// miTo=0 miTo=1 miTo=0 miTo=1
976// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
977// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
978 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
979 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
980 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
981 {{{{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 +0000982};
983
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000984#undef F
985#undef T
caryclark@google.com235f56a2012-09-14 14:19:30 +0000986
caryclark@google.comf839c032012-10-26 21:03:50 +0000987// wrap path to keep track of whether the contour is initialized and non-empty
988class PathWrapper {
989public:
990 PathWrapper(SkPath& path)
991 : fPathPtr(&path)
caryclark@google.comd0deb4f2012-12-17 13:58:08 +0000992 , fCloses(0)
993 , fMoves(0)
caryclark@google.comf839c032012-10-26 21:03:50 +0000994 {
995 init();
996 }
997
998 void close() {
999 if (!fHasMove) {
1000 return;
1001 }
1002 bool callClose = isClosed();
1003 lineTo();
1004 if (fEmpty) {
1005 return;
1006 }
1007 if (callClose) {
1008 #if DEBUG_PATH_CONSTRUCTION
1009 SkDebugf("path.close();\n");
1010 #endif
1011 fPathPtr->close();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001012 fCloses++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001013 }
1014 init();
1015 }
1016
1017 void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
1018 lineTo();
1019 moveTo();
1020#if DEBUG_PATH_CONSTRUCTION
1021 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
1022 pt1.fX, pt1.fY, pt2.fX, pt2.fY, pt3.fX, pt3.fY);
1023#endif
1024 fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, pt3.fX, pt3.fY);
1025 fDefer[0] = fDefer[1] = pt3;
1026 fEmpty = false;
1027 }
1028
1029 void deferredLine(const SkPoint& pt) {
1030 if (pt == fDefer[1]) {
1031 return;
1032 }
1033 if (changedSlopes(pt)) {
1034 lineTo();
1035 fDefer[0] = fDefer[1];
1036 }
1037 fDefer[1] = pt;
1038 }
1039
1040 void deferredMove(const SkPoint& pt) {
1041 fMoved = true;
1042 fHasMove = true;
1043 fEmpty = true;
1044 fDefer[0] = fDefer[1] = pt;
1045 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001046
caryclark@google.comf839c032012-10-26 21:03:50 +00001047 void deferredMoveLine(const SkPoint& pt) {
1048 if (!fHasMove) {
1049 deferredMove(pt);
1050 }
1051 deferredLine(pt);
1052 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001053
caryclark@google.comf839c032012-10-26 21:03:50 +00001054 bool hasMove() const {
1055 return fHasMove;
1056 }
1057
1058 void init() {
1059 fEmpty = true;
1060 fHasMove = false;
1061 fMoved = false;
1062 }
1063
1064 bool isClosed() const {
1065 return !fEmpty && fFirstPt == fDefer[1];
1066 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001067
caryclark@google.comf839c032012-10-26 21:03:50 +00001068 void lineTo() {
1069 if (fDefer[0] == fDefer[1]) {
1070 return;
1071 }
1072 moveTo();
1073 fEmpty = false;
1074#if DEBUG_PATH_CONSTRUCTION
1075 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
1076#endif
1077 fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
1078 fDefer[0] = fDefer[1];
1079 }
1080
1081 const SkPath* nativePath() const {
1082 return fPathPtr;
1083 }
1084
1085 void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
1086 lineTo();
1087 moveTo();
1088#if DEBUG_PATH_CONSTRUCTION
1089 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
1090 pt1.fX, pt1.fY, pt2.fX, pt2.fY);
1091#endif
1092 fPathPtr->quadTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY);
1093 fDefer[0] = fDefer[1] = pt2;
1094 fEmpty = false;
1095 }
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00001096
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001097 bool someAssemblyRequired() const {
1098 return fCloses < fMoves;
1099 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001100
1101protected:
1102 bool changedSlopes(const SkPoint& pt) const {
1103 if (fDefer[0] == fDefer[1]) {
1104 return false;
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001105 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001106 SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
1107 SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
1108 SkScalar lineDx = pt.fX - fDefer[1].fX;
1109 SkScalar lineDy = pt.fY - fDefer[1].fY;
1110 return deferDx * lineDy != deferDy * lineDx;
1111 }
1112
1113 void moveTo() {
1114 if (!fMoved) {
1115 return;
1116 }
1117 fFirstPt = fDefer[0];
1118#if DEBUG_PATH_CONSTRUCTION
1119 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
1120#endif
1121 fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
1122 fMoved = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001123 fMoves++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001124 }
1125
1126private:
1127 SkPath* fPathPtr;
1128 SkPoint fDefer[2];
1129 SkPoint fFirstPt;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001130 int fCloses;
1131 int fMoves;
caryclark@google.comf839c032012-10-26 21:03:50 +00001132 bool fEmpty;
1133 bool fHasMove;
1134 bool fMoved;
1135};
1136
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001137class Segment {
1138public:
1139 Segment() {
1140#if DEBUG_DUMP
1141 fID = ++gSegmentID;
1142#endif
1143 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00001144
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001145 bool operator<(const Segment& rh) const {
1146 return fBounds.fTop < rh.fBounds.fTop;
1147 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001148
caryclark@google.com4eeda372012-12-06 21:47:48 +00001149 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001150 if (activeAngleInner(index, done, angles)) {
1151 return true;
1152 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001153 int lesser = index;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001154 while (--lesser >= 0 && equalPoints(index, lesser)) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001155 if (activeAngleOther(lesser, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001156 return true;
1157 }
1158 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001159 lesser = index;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001160 do {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001161 if (activeAngleOther(index, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001162 return true;
1163 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001164 } while (++index < fTs.count() && equalPoints(index, lesser));
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001165 return false;
1166 }
1167
caryclark@google.com4eeda372012-12-06 21:47:48 +00001168 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001169 Span* span = &fTs[index];
1170 Segment* other = span->fOther;
1171 int oIndex = span->fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001172 return other->activeAngleInner(oIndex, done, angles);
1173 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001174
caryclark@google.com4eeda372012-12-06 21:47:48 +00001175 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001176 int next = nextExactSpan(index, 1);
caryclark@google.com9764cc62012-07-12 19:29:45 +00001177 if (next > 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001178 Span& upSpan = fTs[index];
1179 if (upSpan.fWindValue || upSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001180 addAngle(angles, index, next);
caryclark@google.comf839c032012-10-26 21:03:50 +00001181 if (upSpan.fDone || upSpan.fUnsortableEnd) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001182 done++;
1183 } else if (upSpan.fWindSum != SK_MinS32) {
1184 return true;
1185 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001186 } else if (!upSpan.fDone) {
1187 upSpan.fDone = true;
1188 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001189 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001190 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001191 int prev = nextExactSpan(index, -1);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001192 // edge leading into junction
caryclark@google.com9764cc62012-07-12 19:29:45 +00001193 if (prev >= 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001194 Span& downSpan = fTs[prev];
1195 if (downSpan.fWindValue || downSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001196 addAngle(angles, index, prev);
1197 if (downSpan.fDone) {
1198 done++;
1199 } else if (downSpan.fWindSum != SK_MinS32) {
1200 return true;
1201 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001202 } else if (!downSpan.fDone) {
1203 downSpan.fDone = true;
1204 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001205 }
1206 }
1207 return false;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001208 }
1209
caryclark@google.comf839c032012-10-26 21:03:50 +00001210 void activeLeftTop(SkPoint& result) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001211 SkASSERT(!done());
1212 int count = fTs.count();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001213 result.fX = result.fY = SK_ScalarMax;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001214 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00001215 bool lastUnsortable = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001216 for (int index = 0; index < count; ++index) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001217 const Span& span = fTs[index];
1218 if (span.fUnsortableStart | lastUnsortable) {
1219 goto next;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001220 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001221 if (!span.fDone | !lastDone) {
1222 const SkPoint& xy = xyAtT(index);
1223 if (result.fY < xy.fY) {
1224 goto next;
1225 }
1226 if (result.fY == xy.fY && result.fX < xy.fX) {
1227 goto next;
1228 }
1229 result = xy;
1230 }
1231 next:
1232 lastDone = span.fDone;
1233 lastUnsortable = span.fUnsortableEnd;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001234 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001235 }
1236
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001237 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
1238 int sumMiWinding = updateWinding(endIndex, index);
1239 int sumSuWinding = updateOppWinding(endIndex, index);
1240 if (fOperand) {
1241 SkTSwap<int>(sumMiWinding, sumSuWinding);
1242 }
1243 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1244 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001245 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001246 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001247
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001248 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00001249 int& sumMiWinding, int& sumSuWinding,
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001250 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
1251 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1252 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001253 bool miFrom;
1254 bool miTo;
1255 bool suFrom;
1256 bool suTo;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001257 if (operand()) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001258 miFrom = (oppMaxWinding & xorMiMask) != 0;
1259 miTo = (oppSumWinding & xorMiMask) != 0;
1260 suFrom = (maxWinding & xorSuMask) != 0;
1261 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001262 } else {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001263 miFrom = (maxWinding & xorMiMask) != 0;
1264 miTo = (sumWinding & xorMiMask) != 0;
1265 suFrom = (oppMaxWinding & xorSuMask) != 0;
1266 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001267 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001268 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
1269 SkASSERT(result != -1);
1270 return result;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001271 }
1272
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001273 bool activeWinding(int index, int endIndex) {
1274 int sumWinding = updateWinding(endIndex, index);
1275 int maxWinding;
1276 return activeWinding(index, endIndex, maxWinding, sumWinding);
1277 }
1278
1279 bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
1280 setUpWinding(index, endIndex, maxWinding, sumWinding);
1281 bool from = maxWinding != 0;
1282 bool to = sumWinding != 0;
1283 bool result = gUnaryActiveEdge[from][to];
1284 SkASSERT(result != -1);
1285 return result;
1286 }
1287
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001288 void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001289 SkASSERT(start != end);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001290 Angle* angle = angles.append();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001291#if DEBUG_ANGLE
caryclark@google.com31143cf2012-11-09 22:14:19 +00001292 if (angles.count() > 1 && !fTs[start].fTiny) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001293 SkPoint angle0Pt, newPt;
1294 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
1295 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
1296 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
caryclark@google.com6d0032a2013-01-04 19:41:13 +00001297 SkASSERT(AlmostEqualUlps(angle0Pt.fX, newPt.fX));
1298 SkASSERT(AlmostEqualUlps(angle0Pt.fY, newPt.fY));
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001299 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001300#endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001301 angle->set(fPts, fVerb, this, start, end, fTs);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001302 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001303
caryclark@google.com2ddff932012-08-07 21:25:27 +00001304 void addCancelOutsides(double tStart, double oStart, Segment& other,
caryclark@google.comcc905052012-07-25 20:59:42 +00001305 double oEnd) {
1306 int tIndex = -1;
1307 int tCount = fTs.count();
1308 int oIndex = -1;
1309 int oCount = other.fTs.count();
caryclark@google.comcc905052012-07-25 20:59:42 +00001310 do {
1311 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001312 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001313 int tIndexStart = tIndex;
1314 do {
1315 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001316 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001317 int oIndexStart = oIndex;
1318 double nextT;
1319 do {
1320 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001321 } while (nextT < 1 && approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001322 double oNextT;
1323 do {
1324 oNextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001325 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001326 // at this point, spans before and after are at:
1327 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1328 // if tIndexStart == 0, no prior span
1329 // if nextT == 1, no following span
rmistry@google.comd6176b02012-08-23 18:14:13 +00001330
caryclark@google.comcc905052012-07-25 20:59:42 +00001331 // advance the span with zero winding
1332 // if the following span exists (not past the end, non-zero winding)
1333 // connect the two edges
1334 if (!fTs[tIndexStart].fWindValue) {
1335 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1336 #if DEBUG_CONCIDENT
1337 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1338 __FUNCTION__, fID, other.fID, tIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001339 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
1340 xyAtT(tIndexStart).fY);
caryclark@google.comcc905052012-07-25 20:59:42 +00001341 #endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001342 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001343 }
1344 if (nextT < 1 && fTs[tIndex].fWindValue) {
1345 #if DEBUG_CONCIDENT
1346 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1347 __FUNCTION__, fID, other.fID, tIndex,
1348 fTs[tIndex].fT, xyAtT(tIndex).fX,
1349 xyAtT(tIndex).fY);
1350 #endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001351 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001352 }
1353 } else {
1354 SkASSERT(!other.fTs[oIndexStart].fWindValue);
1355 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1356 #if DEBUG_CONCIDENT
1357 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1358 __FUNCTION__, fID, other.fID, oIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001359 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
1360 other.xyAtT(oIndexStart).fY);
1361 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
caryclark@google.comcc905052012-07-25 20:59:42 +00001362 #endif
caryclark@google.comcc905052012-07-25 20:59:42 +00001363 }
1364 if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1365 #if DEBUG_CONCIDENT
1366 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1367 __FUNCTION__, fID, other.fID, oIndex,
1368 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1369 other.xyAtT(oIndex).fY);
1370 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1371 #endif
1372 }
1373 }
1374 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001375
caryclark@google.comcc905052012-07-25 20:59:42 +00001376 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1377 double oEnd) {
1378 // walk this to outsideTs[0]
1379 // walk other to outsideTs[1]
1380 // if either is > 0, add a pointer to the other, copying adjacent winding
1381 int tIndex = -1;
1382 int oIndex = -1;
1383 double tStart = outsideTs[0];
1384 double oStart = outsideTs[1];
1385 do {
1386 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001387 } while (!approximately_negative(tStart - fTs[tIndex].fT));
caryclark@google.comcc905052012-07-25 20:59:42 +00001388 do {
1389 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001390 } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001391 if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001392 addTPair(tStart, other, oStart, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001393 }
1394 tStart = fTs[tIndex].fT;
1395 oStart = other.fTs[oIndex].fT;
1396 do {
1397 double nextT;
1398 do {
1399 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001400 } while (approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001401 tStart = nextT;
1402 do {
1403 nextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001404 } while (approximately_negative(nextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001405 oStart = nextT;
caryclark@google.com4eeda372012-12-06 21:47:48 +00001406 if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001407 break;
1408 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00001409 addTPair(tStart, other, oStart, false);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001410 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001411 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001412
caryclark@google.com4eeda372012-12-06 21:47:48 +00001413 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
1414 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001415 fBounds.setCubicBounds(pts);
1416 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001417
caryclark@google.comf839c032012-10-26 21:03:50 +00001418 /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001419 SkPoint edge[4];
caryclark@google.comf839c032012-10-26 21:03:50 +00001420 const SkPoint* ePtr;
1421 int lastT = fTs.count() - 1;
1422 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1423 ePtr = fPts;
1424 } else {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001425 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
caryclark@google.comf839c032012-10-26 21:03:50 +00001426 (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
1427 ePtr = edge;
1428 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001429 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001430 bool reverse = ePtr == fPts && start != 0;
1431 if (reverse) {
1432 path.deferredMoveLine(ePtr[fVerb]);
1433 switch (fVerb) {
1434 case SkPath::kLine_Verb:
1435 path.deferredLine(ePtr[0]);
1436 break;
1437 case SkPath::kQuad_Verb:
1438 path.quadTo(ePtr[1], ePtr[0]);
1439 break;
1440 case SkPath::kCubic_Verb:
1441 path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1442 break;
1443 default:
1444 SkASSERT(0);
1445 }
1446 // return ePtr[0];
1447 } else {
1448 path.deferredMoveLine(ePtr[0]);
1449 switch (fVerb) {
1450 case SkPath::kLine_Verb:
1451 path.deferredLine(ePtr[1]);
1452 break;
1453 case SkPath::kQuad_Verb:
1454 path.quadTo(ePtr[1], ePtr[2]);
1455 break;
1456 case SkPath::kCubic_Verb:
1457 path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1458 break;
1459 default:
1460 SkASSERT(0);
1461 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001462 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001463 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001464 // return ePtr[fVerb];
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001465 }
1466
caryclark@google.com4eeda372012-12-06 21:47:48 +00001467 void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
1468 init(pts, SkPath::kLine_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001469 fBounds.set(pts, 2);
1470 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001471
caryclark@google.comf839c032012-10-26 21:03:50 +00001472#if 0
1473 const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001474 const SkPoint& pt = xyAtT(tIndex);
1475 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001476 path.deferredMove(pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001477 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00001478 return pt;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001479 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001480#endif
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001481
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001482 // add 2 to edge or out of range values to get T extremes
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001483 void addOtherT(int index, double otherT, int otherIndex) {
1484 Span& span = fTs[index];
caryclark@google.comf839c032012-10-26 21:03:50 +00001485 #if PIN_ADD_T
caryclark@google.com185c7c42012-10-19 18:26:24 +00001486 if (precisely_less_than_zero(otherT)) {
1487 otherT = 0;
1488 } else if (precisely_greater_than_one(otherT)) {
1489 otherT = 1;
1490 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001491 #endif
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001492 span.fOtherT = otherT;
1493 span.fOtherIndex = otherIndex;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001494 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001495
caryclark@google.com4eeda372012-12-06 21:47:48 +00001496 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
1497 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001498 fBounds.setQuadBounds(pts);
1499 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001500
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001501 // Defer all coincident edge processing until
1502 // after normal intersections have been computed
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001503
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001504// no need to be tricky; insert in normal T order
1505// resolve overlapping ts when considering coincidence later
1506
1507 // add non-coincident intersection. Resulting edges are sorted in T.
1508 int addT(double newT, Segment* other) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001509 // FIXME: in the pathological case where there is a ton of intercepts,
1510 // binary search?
1511 int insertedAt = -1;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001512 size_t tCount = fTs.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00001513 #if PIN_ADD_T
caryclark@google.comc899ad92012-08-23 15:24:42 +00001514 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
caryclark@google.com185c7c42012-10-19 18:26:24 +00001515 if (precisely_less_than_zero(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001516 newT = 0;
caryclark@google.com185c7c42012-10-19 18:26:24 +00001517 } else if (precisely_greater_than_one(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001518 newT = 1;
1519 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001520 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001521 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001522 // OPTIMIZATION: if there are three or more identical Ts, then
1523 // the fourth and following could be further insertion-sorted so
1524 // that all the edges are clockwise or counterclockwise.
1525 // This could later limit segment tests to the two adjacent
1526 // neighbors, although it doesn't help with determining which
1527 // circular direction to go in.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001528 if (newT < fTs[index].fT) {
1529 insertedAt = index;
1530 break;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001531 }
1532 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001533 Span* span;
1534 if (insertedAt >= 0) {
1535 span = fTs.insert(insertedAt);
1536 } else {
1537 insertedAt = tCount;
1538 span = fTs.append();
1539 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001540 span->fT = newT;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001541 span->fOther = other;
caryclark@google.com27c449a2012-07-27 18:26:38 +00001542 span->fPt.fX = SK_ScalarNaN;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001543 span->fWindSum = SK_MinS32;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001544 span->fOppSum = SK_MinS32;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001545 span->fWindValue = 1;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001546 span->fOppValue = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00001547 span->fTiny = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001548 if ((span->fDone = newT == 1)) {
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00001549 ++fDoneSpans;
rmistry@google.comd6176b02012-08-23 18:14:13 +00001550 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001551 span->fUnsortableStart = false;
1552 span->fUnsortableEnd = false;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001553 int less = -1;
1554 while (&span[less + 1] - fTs.begin() > 0 && !span[less].fDone
1555 && !precisely_negative(newT - span[less].fT)
1556 // && approximately_negative(newT - span[less].fT)
1557 && xyAtT(&span[less]) == xyAtT(span)) {
1558 span[less].fTiny = true;
1559 span[less].fDone = true;
1560 if (approximately_negative(newT - span[less].fT)) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00001561 if (approximately_greater_than_one(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001562 span[less].fUnsortableStart = true;
1563 span[less - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001564 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001565 if (approximately_less_than_zero(span[less].fT)) {
1566 span[less + 1].fUnsortableStart = true;
1567 span[less].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001568 }
1569 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001570 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001571 --less;
caryclark@google.comf839c032012-10-26 21:03:50 +00001572 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001573 int more = 1;
1574 while (fTs.end() - &span[more - 1] > 1 && !span[more - 1].fDone
1575 && !precisely_negative(span[more].fT - newT)
1576 // && approximately_negative(span[more].fT - newT)
1577 && xyAtT(&span[more]) == xyAtT(span)) {
1578 span[more - 1].fTiny = true;
1579 span[more - 1].fDone = true;
1580 if (approximately_negative(span[more].fT - newT)) {
1581 if (approximately_greater_than_one(span[more].fT)) {
1582 span[more + 1].fUnsortableStart = true;
1583 span[more].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001584 }
1585 if (approximately_less_than_zero(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001586 span[more].fUnsortableStart = true;
1587 span[more - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001588 }
1589 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001590 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001591 ++more;
caryclark@google.comf839c032012-10-26 21:03:50 +00001592 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001593 return insertedAt;
1594 }
1595
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001596 // set spans from start to end to decrement by one
1597 // note this walks other backwards
1598 // FIMXE: there's probably an edge case that can be constructed where
1599 // two span in one segment are separated by float epsilon on one span but
1600 // not the other, if one segment is very small. For this
1601 // case the counts asserted below may or may not be enough to separate the
caryclark@google.com2ddff932012-08-07 21:25:27 +00001602 // spans. Even if the counts work out, what if the spans aren't correctly
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001603 // sorted? It feels better in such a case to match the span's other span
1604 // pointer since both coincident segments must contain the same spans.
1605 void addTCancel(double startT, double endT, Segment& other,
1606 double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001607 SkASSERT(!approximately_negative(endT - startT));
1608 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00001609 bool binary = fOperand != other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001610 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001611 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001612 ++index;
1613 }
caryclark@google.comb9738012012-07-03 19:53:30 +00001614 int oIndex = other.fTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001615 while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001616 ;
caryclark@google.com59823f72012-08-09 18:17:47 +00001617 double tRatio = (oEndT - oStartT) / (endT - startT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001618 Span* test = &fTs[index];
1619 Span* oTest = &other.fTs[oIndex];
caryclark@google.com18063442012-07-25 12:05:18 +00001620 SkTDArray<double> outsideTs;
1621 SkTDArray<double> oOutsideTs;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001622 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001623 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
caryclark@google.comcc905052012-07-25 20:59:42 +00001624 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.com200c2112012-08-03 15:05:04 +00001625 double testT = test->fT;
1626 double oTestT = oTest->fT;
1627 Span* span = test;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001628 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001629 if (decrement) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001630 decrementSpan(span);
caryclark@google.com200c2112012-08-03 15:05:04 +00001631 } else if (track && span->fT < 1 && oTestT < 1) {
1632 TrackOutside(outsideTs, span->fT, oTestT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001633 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001634 span = &fTs[++index];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001635 } while (approximately_negative(span->fT - testT));
caryclark@google.com200c2112012-08-03 15:05:04 +00001636 Span* oSpan = oTest;
caryclark@google.com59823f72012-08-09 18:17:47 +00001637 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1638 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1639 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001640 while (approximately_negative(otherTMatchStart - oSpan->fT)
1641 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
caryclark@google.com03f97062012-08-21 13:13:52 +00001642 #ifdef SK_DEBUG
caryclark@google.com59823f72012-08-09 18:17:47 +00001643 SkASSERT(originalWindValue == oSpan->fWindValue);
caryclark@google.com03f97062012-08-21 13:13:52 +00001644 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001645 if (decrement) {
caryclark@google.com200c2112012-08-03 15:05:04 +00001646 other.decrementSpan(oSpan);
1647 } else if (track && oSpan->fT < 1 && testT < 1) {
1648 TrackOutside(oOutsideTs, oSpan->fT, testT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001649 }
1650 if (!oIndex) {
1651 break;
1652 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001653 oSpan = &other.fTs[--oIndex];
rmistry@google.comd6176b02012-08-23 18:14:13 +00001654 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001655 test = span;
1656 oTest = oSpan;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001657 } while (!approximately_negative(endT - test->fT));
1658 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
caryclark@google.com18063442012-07-25 12:05:18 +00001659 // FIXME: determine if canceled edges need outside ts added
caryclark@google.comcc905052012-07-25 20:59:42 +00001660 if (!done() && outsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001661 double tStart = outsideTs[0];
1662 double oStart = outsideTs[1];
1663 addCancelOutsides(tStart, oStart, other, oEndT);
1664 int count = outsideTs.count();
1665 if (count > 2) {
1666 double tStart = outsideTs[count - 2];
1667 double oStart = outsideTs[count - 1];
1668 addCancelOutsides(tStart, oStart, other, oEndT);
1669 }
caryclark@google.com18063442012-07-25 12:05:18 +00001670 }
caryclark@google.comcc905052012-07-25 20:59:42 +00001671 if (!other.done() && oOutsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001672 double tStart = oOutsideTs[0];
1673 double oStart = oOutsideTs[1];
1674 other.addCancelOutsides(tStart, oStart, *this, endT);
caryclark@google.com18063442012-07-25 12:05:18 +00001675 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001676 }
skia.committer@gmail.com15dd3002013-01-18 07:07:28 +00001677
caryclark@google.com73ca6242013-01-17 21:02:47 +00001678 int addUnsortableT(double newT, Segment* other, bool start) {
1679 int result = addT(newT, other);
1680 Span* span = &fTs[result];
1681 if (start) {
1682 if (result > 0) {
1683 span[result - 1].fUnsortableEnd = true;
1684 }
1685 span[result].fUnsortableStart = true;
1686 } else {
1687 span[result].fUnsortableEnd = true;
1688 if (result + 1 < fTs.count()) {
1689 span[result + 1].fUnsortableStart = true;
1690 }
1691 }
1692 return result;
1693 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00001694
caryclark@google.com4eeda372012-12-06 21:47:48 +00001695 int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1696 SkTDArray<double>& outsideTs) {
1697 int oWindValue = oTest->fWindValue;
1698 int oOppValue = oTest->fOppValue;
1699 if (opp) {
1700 SkTSwap<int>(oWindValue, oOppValue);
1701 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001702 Span* const test = &fTs[index];
1703 Span* end = test;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001704 const double oStartT = oTest->fT;
1705 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001706 if (bumpSpan(end, oWindValue, oOppValue)) {
1707 TrackOutside(outsideTs, end->fT, oStartT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001708 }
1709 end = &fTs[++index];
1710 } while (approximately_negative(end->fT - test->fT));
1711 return index;
1712 }
1713
1714 // because of the order in which coincidences are resolved, this and other
1715 // may not have the same intermediate points. Compute the corresponding
1716 // intermediate T values (using this as the master, other as the follower)
1717 // and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com4eeda372012-12-06 21:47:48 +00001718 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1719 SkTDArray<double>& oOutsideTs) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001720 Span* const oTest = &fTs[oIndex];
1721 Span* oEnd = oTest;
1722 const double startT = test->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001723 const double oStartT = oTest->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001724 while (!approximately_negative(oEndT - oEnd->fT)
caryclark@google.com4eeda372012-12-06 21:47:48 +00001725 && approximately_negative(oEnd->fT - oStartT)) {
1726 zeroSpan(oEnd);
1727 TrackOutside(oOutsideTs, oEnd->fT, startT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001728 oEnd = &fTs[++oIndex];
1729 }
1730 return oIndex;
1731 }
1732
1733 // FIXME: need to test this case:
1734 // contourA has two segments that are coincident
1735 // contourB has two segments that are coincident in the same place
1736 // each ends up with +2/0 pairs for winding count
1737 // since logic below doesn't transfer count (only increments/decrements) can this be
1738 // resolved to +4/0 ?
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001739
1740 // set spans from start to end to increment the greater by one and decrement
1741 // the lesser
caryclark@google.com4eeda372012-12-06 21:47:48 +00001742 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001743 SkASSERT(!approximately_negative(endT - startT));
1744 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001745 bool opp = fOperand ^ other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001746 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001747 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001748 ++index;
1749 }
1750 int oIndex = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001751 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001752 ++oIndex;
1753 }
1754 Span* test = &fTs[index];
1755 Span* oTest = &other.fTs[oIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001756 SkTDArray<double> outsideTs;
1757 SkTDArray<double> oOutsideTs;
1758 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001759 // if either span has an opposite value and the operands don't match, resolve first
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001760 // SkASSERT(!test->fDone || !oTest->fDone);
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001761 if (test->fDone || oTest->fDone) {
1762 index = advanceCoincidentThis(oTest, opp, index);
1763 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
1764 } else {
1765 index = bumpCoincidentThis(oTest, opp, index, outsideTs);
1766 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
1767 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001768 test = &fTs[index];
1769 oTest = &other.fTs[oIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001770 } while (!approximately_negative(endT - test->fT));
1771 SkASSERT(approximately_negative(oTest->fT - oEndT));
1772 SkASSERT(approximately_negative(oEndT - oTest->fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001773 if (!done() && outsideTs.count()) {
1774 addCoinOutsides(outsideTs, other, oEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001775 }
1776 if (!other.done() && oOutsideTs.count()) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001777 other.addCoinOutsides(oOutsideTs, *this, endT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001778 }
1779 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001780
caryclark@google.comcc905052012-07-25 20:59:42 +00001781 // FIXME: this doesn't prevent the same span from being added twice
1782 // fix in caller, assert here?
caryclark@google.com2ddff932012-08-07 21:25:27 +00001783 void addTPair(double t, Segment& other, double otherT, bool borrowWind) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001784 int tCount = fTs.count();
1785 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1786 const Span& span = fTs[tIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001787 if (!approximately_negative(span.fT - t)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001788 break;
1789 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001790 if (approximately_negative(span.fT - t) && span.fOther == &other
1791 && approximately_equal(span.fOtherT, otherT)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001792#if DEBUG_ADD_T_PAIR
1793 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1794 __FUNCTION__, fID, t, other.fID, otherT);
1795#endif
1796 return;
1797 }
1798 }
caryclark@google.com47580692012-07-23 12:14:49 +00001799#if DEBUG_ADD_T_PAIR
1800 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1801 __FUNCTION__, fID, t, other.fID, otherT);
1802#endif
caryclark@google.comb9738012012-07-03 19:53:30 +00001803 int insertedAt = addT(t, &other);
1804 int otherInsertedAt = other.addT(otherT, this);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001805 addOtherT(insertedAt, otherT, otherInsertedAt);
caryclark@google.comb9738012012-07-03 19:53:30 +00001806 other.addOtherT(otherInsertedAt, t, insertedAt);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001807 matchWindingValue(insertedAt, t, borrowWind);
1808 other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001809 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001810
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001811 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001812 // add edge leading into junction
caryclark@google.com4eeda372012-12-06 21:47:48 +00001813 int min = SkMin32(end, start);
1814 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001815 addAngle(angles, end, start);
1816 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001817 // add edge leading away from junction
caryclark@google.com495f8e42012-05-31 13:13:11 +00001818 int step = SkSign32(end - start);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001819 int tIndex = nextExactSpan(end, step);
caryclark@google.com4eeda372012-12-06 21:47:48 +00001820 min = SkMin32(end, tIndex);
1821 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001822 addAngle(angles, end, tIndex);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001823 }
1824 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001825
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001826 int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
1827 Span* const test = &fTs[index];
1828 Span* end = test;
1829 do {
1830 end = &fTs[++index];
1831 } while (approximately_negative(end->fT - test->fT));
1832 return index;
1833 }
1834
1835 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
1836 Span* const oTest = &fTs[oIndex];
1837 Span* oEnd = oTest;
1838 const double oStartT = oTest->fT;
1839 while (!approximately_negative(oEndT - oEnd->fT)
1840 && approximately_negative(oEnd->fT - oStartT)) {
1841 oEnd = &fTs[++oIndex];
1842 }
1843 return oIndex;
1844 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00001845
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001846 bool betweenTs(int lesser, double testT, int greater) {
1847 if (lesser > greater) {
1848 SkTSwap<int>(lesser, greater);
1849 }
1850 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
1851 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001852
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001853 const Bounds& bounds() const {
1854 return fBounds;
1855 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001856
caryclark@google.com31143cf2012-11-09 22:14:19 +00001857 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001858 double referenceT = fTs[index].fT;
1859 int lesser = index;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001860 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
1861 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00001862 buildAnglesInner(lesser, angles);
1863 }
1864 do {
1865 buildAnglesInner(index, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001866 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
1867 && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001868 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001869
1870 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
1871 Span* span = &fTs[index];
1872 Segment* other = span->fOther;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001873 // if there is only one live crossing, and no coincidence, continue
1874 // in the same direction
1875 // if there is coincidence, the only choice may be to reverse direction
1876 // find edge on either side of intersection
1877 int oIndex = span->fOtherIndex;
1878 // if done == -1, prior span has already been processed
1879 int step = 1;
caryclark@google.coma461ff02012-10-11 12:54:23 +00001880 int next = other->nextExactSpan(oIndex, step);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001881 if (next < 0) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001882 step = -step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00001883 next = other->nextExactSpan(oIndex, step);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001884 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001885 // add candidate into and away from junction
1886 other->addTwoAngles(next, oIndex, angles);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001887 }
1888
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001889 int computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001890 SkTDArray<Angle> angles;
1891 addTwoAngles(startIndex, endIndex, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001892 buildAngles(endIndex, angles, false);
caryclark@google.comd1688742012-09-18 20:08:37 +00001893 // OPTIMIZATION: check all angles to see if any have computed wind sum
1894 // before sorting (early exit if none)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001895 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001896 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00001897#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00001898 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00001899#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001900 if (!sortable) {
1901 return SK_MinS32;
1902 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001903 int angleCount = angles.count();
1904 const Angle* angle;
1905 const Segment* base;
1906 int winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001907 int oWinding;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001908 int firstIndex = 0;
1909 do {
1910 angle = sorted[firstIndex];
1911 base = angle->segment();
1912 winding = base->windSum(angle);
1913 if (winding != SK_MinS32) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001914 oWinding = base->oppSum(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001915 break;
1916 }
1917 if (++firstIndex == angleCount) {
1918 return SK_MinS32;
1919 }
1920 } while (true);
1921 // turn winding into contourWinding
caryclark@google.com2ddff932012-08-07 21:25:27 +00001922 int spanWinding = base->spanSign(angle);
1923 bool inner = useInnerWinding(winding + spanWinding, winding);
1924 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00001925 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
caryclark@google.com59823f72012-08-09 18:17:47 +00001926 spanWinding, winding, angle->sign(), inner,
caryclark@google.com2ddff932012-08-07 21:25:27 +00001927 inner ? winding + spanWinding : winding);
1928 #endif
1929 if (inner) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001930 winding += spanWinding;
1931 }
1932 #if DEBUG_SORT
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001933 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001934 #endif
1935 int nextIndex = firstIndex + 1;
1936 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com2ddff932012-08-07 21:25:27 +00001937 winding -= base->spanSign(angle);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001938 oWinding -= base->oppSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001939 do {
1940 if (nextIndex == angleCount) {
1941 nextIndex = 0;
1942 }
1943 angle = sorted[nextIndex];
1944 Segment* segment = angle->segment();
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001945 bool opp = base->fOperand ^ segment->fOperand;
1946 int maxWinding, oMaxWinding;
1947 int spanSign = segment->spanSign(angle);
1948 int oppoSign = segment->oppSign(angle);
1949 if (opp) {
1950 oMaxWinding = oWinding;
1951 oWinding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00001952 maxWinding = winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001953 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001954 winding -= oppoSign;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001955 }
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001956 } else {
1957 maxWinding = winding;
1958 winding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00001959 oMaxWinding = oWinding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001960 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001961 oWinding -= oppoSign;
1962 }
1963 }
1964 if (segment->windSum(angle) == SK_MinS32) {
1965 if (opp) {
1966 if (useInnerWinding(oMaxWinding, oWinding)) {
1967 oMaxWinding = oWinding;
1968 }
1969 if (oppoSign && useInnerWinding(maxWinding, winding)) {
1970 maxWinding = winding;
1971 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001972 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001973 } else {
1974 if (useInnerWinding(maxWinding, winding)) {
1975 maxWinding = winding;
1976 }
1977 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
1978 oMaxWinding = oWinding;
1979 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001980 (void) segment->markAndChaseWinding(angle, maxWinding,
1981 binary ? oMaxWinding : 0);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001982 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001983 }
1984 } while (++nextIndex != lastIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00001985 int minIndex = SkMin32(startIndex, endIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00001986 return windSum(minIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001987 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001988
caryclark@google.com3586ece2012-12-27 18:46:58 +00001989 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
caryclark@google.com10227bf2012-12-28 22:10:41 +00001990 double mid, bool opp, bool current) const {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001991 SkScalar bottom = fBounds.fBottom;
caryclark@google.com10227bf2012-12-28 22:10:41 +00001992 int bestTIndex = -1;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001993 if (bottom <= bestY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00001994 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001995 }
1996 SkScalar top = fBounds.fTop;
1997 if (top >= basePt.fY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00001998 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001999 }
2000 if (fBounds.fLeft > basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002001 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002002 }
2003 if (fBounds.fRight < basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002004 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002005 }
2006 if (fBounds.fLeft == fBounds.fRight) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002007 // if vertical, and directly above test point, wait for another one
caryclark@google.com6d0032a2013-01-04 19:41:13 +00002008 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002009 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002010 // intersect ray starting at basePt with edge
2011 Intersections intersections;
2012 // OPTIMIZE: use specialty function that intersects ray with curve,
2013 // returning t values only for curve (we don't care about t on ray)
2014 int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
2015 if (pts == 0 || (current && pts == 1)) {
2016 return bestTIndex;
2017 }
2018 if (current) {
2019 SkASSERT(pts > 1);
2020 int closestIdx = 0;
2021 double closest = fabs(intersections.fT[0][0] - mid);
2022 for (int idx = 1; idx < pts; ++idx) {
2023 double test = fabs(intersections.fT[0][idx] - mid);
2024 if (closest > test) {
2025 closestIdx = idx;
2026 closest = test;
2027 }
2028 }
2029 if (closestIdx < pts - 1) {
2030 intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
2031 }
2032 --pts;
2033 }
2034 double bestT = -1;
2035 for (int index = 0; index < pts; ++index) {
2036 double foundT = intersections.fT[0][index];
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002037 if (approximately_less_than_zero(foundT)
2038 || approximately_greater_than_one(foundT)) {
2039 continue;
2040 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002041 SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
2042 if (approximately_negative(testY - bestY)
2043 || approximately_negative(basePt.fY - testY)) {
caryclark@google.com47580692012-07-23 12:14:49 +00002044 continue;
2045 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002046 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002047 return SK_MinS32; // if the intersection is edge on, wait for another one
caryclark@google.com10227bf2012-12-28 22:10:41 +00002048 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002049 if (fVerb > SkPath::kLine_Verb) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002050 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
2051 if (approximately_zero(dx)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002052 return SK_MinS32; // hit vertical, wait for another one
caryclark@google.com3586ece2012-12-27 18:46:58 +00002053 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00002054 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002055 bestY = testY;
2056 bestT = foundT;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002057 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002058 if (bestT < 0) {
2059 return bestTIndex;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002060 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002061 SkASSERT(bestT >= 0);
2062 SkASSERT(bestT <= 1);
2063 int start;
2064 int end = 0;
2065 do {
2066 start = end;
2067 end = nextSpan(start, 1);
2068 } while (fTs[end].fT < bestT);
2069 // FIXME: see next candidate for a better pattern to find the next start/end pair
2070 while (start + 1 < end && fTs[start].fDone) {
2071 ++start;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002072 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002073 if (!isCanceled(start)) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002074 hitT = bestT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002075 bestTIndex = start;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002076 hitSomething = true;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002077 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002078 return bestTIndex;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002079 }
caryclark@google.com18063442012-07-25 12:05:18 +00002080
caryclark@google.com4eeda372012-12-06 21:47:48 +00002081 void decrementSpan(Span* span) {
caryclark@google.com18063442012-07-25 12:05:18 +00002082 SkASSERT(span->fWindValue > 0);
2083 if (--(span->fWindValue) == 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002084 if (!span->fOppValue && !span->fDone) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002085 span->fDone = true;
2086 ++fDoneSpans;
2087 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002088 }
2089 }
2090
2091 bool bumpSpan(Span* span, int windDelta, int oppDelta) {
2092 SkASSERT(!span->fDone);
2093 span->fWindValue += windDelta;
2094 SkASSERT(span->fWindValue >= 0);
2095 span->fOppValue += oppDelta;
2096 SkASSERT(span->fOppValue >= 0);
2097 if (fXor) {
2098 span->fWindValue &= 1;
2099 }
2100 if (fOppXor) {
2101 span->fOppValue &= 1;
2102 }
2103 if (!span->fWindValue && !span->fOppValue) {
2104 span->fDone = true;
2105 ++fDoneSpans;
caryclark@google.com18063442012-07-25 12:05:18 +00002106 return true;
2107 }
2108 return false;
2109 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002110
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002111 // OPTIMIZE
2112 // when the edges are initially walked, they don't automatically get the prior and next
2113 // 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 +00002114 // and would additionally remove the need for similar checks in condition edges. It would
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002115 // also allow intersection code to assume end of segment intersections (maybe?)
2116 bool complete() const {
2117 int count = fTs.count();
2118 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
2119 }
caryclark@google.com18063442012-07-25 12:05:18 +00002120
caryclark@google.com15fa1382012-05-07 20:49:36 +00002121 bool done() const {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002122 SkASSERT(fDoneSpans <= fTs.count());
2123 return fDoneSpans == fTs.count();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002124 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002125
caryclark@google.comf839c032012-10-26 21:03:50 +00002126 bool done(int min) const {
2127 return fTs[min].fDone;
2128 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002129
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002130 bool done(const Angle* angle) const {
2131 return done(SkMin32(angle->start(), angle->end()));
caryclark@google.com47580692012-07-23 12:14:49 +00002132 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00002133
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002134 bool equalPoints(int greaterTIndex, int lesserTIndex) {
2135 SkASSERT(greaterTIndex >= lesserTIndex);
2136 double greaterT = fTs[greaterTIndex].fT;
2137 double lesserT = fTs[lesserTIndex].fT;
2138 if (greaterT == lesserT) {
2139 return true;
2140 }
2141 if (!approximately_negative(greaterT - lesserT)) {
2142 return false;
2143 }
2144 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2145 }
2146
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002147 /*
2148 The M and S variable name parts stand for the operators.
2149 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2150 Su stands for Subtrahend
2151 The Opp variable name part designates that the value is for the Opposite operator.
2152 Opposite values result from combining coincident spans.
2153 */
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002154
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002155 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2156 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002157 const int startIndex = nextStart;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002158 const int endIndex = nextEnd;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002159 SkASSERT(startIndex != endIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002160 const int count = fTs.count();
2161 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2162 const int step = SkSign32(endIndex - startIndex);
2163 const int end = nextExactSpan(startIndex, step);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002164 SkASSERT(end >= 0);
2165 Span* endSpan = &fTs[end];
2166 Segment* other;
2167 if (isSimple(end)) {
2168 // mark the smaller of startIndex, endIndex done, and all adjacent
2169 // spans with the same T value (but not 'other' spans)
2170 #if DEBUG_WINDING
2171 SkDebugf("%s simple\n", __FUNCTION__);
2172 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002173 int min = SkMin32(startIndex, endIndex);
2174 if (fTs[min].fDone) {
2175 return NULL;
2176 }
2177 markDoneBinary(min);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002178 other = endSpan->fOther;
2179 nextStart = endSpan->fOtherIndex;
2180 double startT = other->fTs[nextStart].fT;
2181 nextEnd = nextStart;
2182 do {
2183 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002184 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002185 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002186 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2187 return other;
2188 }
2189 // more than one viable candidate -- measure angles to find best
2190 SkTDArray<Angle> angles;
2191 SkASSERT(startIndex - endIndex != 0);
2192 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2193 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002194 buildAngles(end, angles, true);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002195 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002196 bool sortable = SortAngles(angles, sorted);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002197 int angleCount = angles.count();
2198 int firstIndex = findStartingEdge(sorted, startIndex, end);
2199 SkASSERT(firstIndex >= 0);
2200 #if DEBUG_SORT
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002201 debugShowSort(__FUNCTION__, sorted, firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002202 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002203 if (!sortable) {
2204 unsortable = true;
2205 return NULL;
2206 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002207 SkASSERT(sorted[firstIndex]->segment() == this);
2208 #if DEBUG_WINDING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002209 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2210 sorted[firstIndex]->sign());
caryclark@google.com235f56a2012-09-14 14:19:30 +00002211 #endif
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002212 int sumMiWinding = updateWinding(endIndex, startIndex);
2213 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2214 if (operand()) {
2215 SkTSwap<int>(sumMiWinding, sumSuWinding);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002216 }
2217 int nextIndex = firstIndex + 1;
2218 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2219 const Angle* foundAngle = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002220 bool foundDone = false;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002221 // iterate through the angle, and compute everyone's winding
caryclark@google.com235f56a2012-09-14 14:19:30 +00002222 Segment* nextSegment;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002223 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002224 SkASSERT(nextIndex != firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002225 if (nextIndex == angleCount) {
2226 nextIndex = 0;
2227 }
2228 const Angle* nextAngle = sorted[nextIndex];
2229 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002230 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2231 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2232 nextAngle->end(), op, sumMiWinding, sumSuWinding,
2233 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
2234 if (activeAngle && (!foundAngle || foundDone)) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002235 foundAngle = nextAngle;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002236 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002237 }
2238 if (nextSegment->done()) {
2239 continue;
2240 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002241 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2242 continue;
2243 }
2244 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2245 oppSumWinding, activeAngle, nextAngle);
2246 if (last) {
2247 *chase.append() = last;
2248#if DEBUG_WINDING
2249 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2250 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2251#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002252 }
2253 } while (++nextIndex != lastIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002254 markDoneBinary(SkMin32(startIndex, endIndex));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002255 if (!foundAngle) {
2256 return NULL;
2257 }
2258 nextStart = foundAngle->start();
2259 nextEnd = foundAngle->end();
2260 nextSegment = foundAngle->segment();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002261
caryclark@google.com235f56a2012-09-14 14:19:30 +00002262 #if DEBUG_WINDING
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002263 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2264 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002265 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002266 return nextSegment;
2267 }
caryclark@google.com47580692012-07-23 12:14:49 +00002268
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002269 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2270 bool& unsortable) {
2271 const int startIndex = nextStart;
2272 const int endIndex = nextEnd;
2273 SkASSERT(startIndex != endIndex);
2274 const int count = fTs.count();
2275 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2276 const int step = SkSign32(endIndex - startIndex);
2277 const int end = nextExactSpan(startIndex, step);
2278 SkASSERT(end >= 0);
2279 Span* endSpan = &fTs[end];
2280 Segment* other;
2281 if (isSimple(end)) {
2282 // mark the smaller of startIndex, endIndex done, and all adjacent
2283 // spans with the same T value (but not 'other' spans)
2284 #if DEBUG_WINDING
2285 SkDebugf("%s simple\n", __FUNCTION__);
2286 #endif
2287 int min = SkMin32(startIndex, endIndex);
2288 if (fTs[min].fDone) {
2289 return NULL;
2290 }
2291 markDoneUnary(min);
2292 other = endSpan->fOther;
2293 nextStart = endSpan->fOtherIndex;
2294 double startT = other->fTs[nextStart].fT;
2295 nextEnd = nextStart;
2296 do {
2297 nextEnd += step;
2298 }
2299 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2300 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2301 return other;
2302 }
2303 // more than one viable candidate -- measure angles to find best
2304 SkTDArray<Angle> angles;
2305 SkASSERT(startIndex - endIndex != 0);
2306 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2307 addTwoAngles(startIndex, end, angles);
2308 buildAngles(end, angles, true);
2309 SkTDArray<Angle*> sorted;
2310 bool sortable = SortAngles(angles, sorted);
2311 int angleCount = angles.count();
2312 int firstIndex = findStartingEdge(sorted, startIndex, end);
2313 SkASSERT(firstIndex >= 0);
2314 #if DEBUG_SORT
2315 debugShowSort(__FUNCTION__, sorted, firstIndex);
2316 #endif
2317 if (!sortable) {
2318 unsortable = true;
2319 return NULL;
2320 }
2321 SkASSERT(sorted[firstIndex]->segment() == this);
2322 #if DEBUG_WINDING
2323 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2324 sorted[firstIndex]->sign());
2325 #endif
2326 int sumWinding = updateWinding(endIndex, startIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002327 int nextIndex = firstIndex + 1;
2328 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2329 const Angle* foundAngle = NULL;
2330 bool foundDone = false;
2331 // iterate through the angle, and compute everyone's winding
2332 Segment* nextSegment;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002333 int activeCount = 0;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002334 do {
2335 SkASSERT(nextIndex != firstIndex);
2336 if (nextIndex == angleCount) {
2337 nextIndex = 0;
2338 }
2339 const Angle* nextAngle = sorted[nextIndex];
2340 nextSegment = nextAngle->segment();
2341 int maxWinding;
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00002342 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002343 maxWinding, sumWinding);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002344 if (activeAngle) {
2345 ++activeCount;
2346 if (!foundAngle || (foundDone && activeCount & 1)) {
2347 if (nextSegment->tiny(nextAngle)) {
2348 unsortable = true;
2349 return NULL;
2350 }
2351 foundAngle = nextAngle;
2352 foundDone = nextSegment->done(nextAngle);
2353 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002354 }
2355 if (nextSegment->done()) {
2356 continue;
2357 }
2358 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2359 continue;
2360 }
2361 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2362 if (last) {
2363 *chase.append() = last;
2364#if DEBUG_WINDING
2365 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2366 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2367#endif
2368 }
2369 } while (++nextIndex != lastIndex);
2370 markDoneUnary(SkMin32(startIndex, endIndex));
2371 if (!foundAngle) {
2372 return NULL;
2373 }
2374 nextStart = foundAngle->start();
2375 nextEnd = foundAngle->end();
2376 nextSegment = foundAngle->segment();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002377 #if DEBUG_WINDING
2378 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2379 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2380 #endif
2381 return nextSegment;
2382 }
2383
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002384 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002385 const int startIndex = nextStart;
2386 const int endIndex = nextEnd;
2387 SkASSERT(startIndex != endIndex);
2388 int count = fTs.count();
2389 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2390 : startIndex > 0);
2391 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002392 int end = nextExactSpan(startIndex, step);
caryclark@google.com24bec792012-08-20 12:43:57 +00002393 SkASSERT(end >= 0);
2394 Span* endSpan = &fTs[end];
2395 Segment* other;
caryclark@google.com24bec792012-08-20 12:43:57 +00002396 if (isSimple(end)) {
2397 #if DEBUG_WINDING
2398 SkDebugf("%s simple\n", __FUNCTION__);
2399 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002400 int min = SkMin32(startIndex, endIndex);
2401 if (fTs[min].fDone) {
2402 return NULL;
2403 }
2404 markDone(min, 1);
caryclark@google.com24bec792012-08-20 12:43:57 +00002405 other = endSpan->fOther;
2406 nextStart = endSpan->fOtherIndex;
2407 double startT = other->fTs[nextStart].fT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002408 #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 +00002409 SkDEBUGCODE(bool firstLoop = true;)
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002410 if ((approximately_less_than_zero(startT) && step < 0)
2411 || (approximately_greater_than_one(startT) && step > 0)) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002412 step = -step;
2413 SkDEBUGCODE(firstLoop = false;)
2414 }
2415 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002416 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002417 nextEnd = nextStart;
2418 do {
2419 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002420 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002421 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002422 #if 01
caryclark@google.com24bec792012-08-20 12:43:57 +00002423 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2424 break;
2425 }
caryclark@google.com03f97062012-08-21 13:13:52 +00002426 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00002427 SkASSERT(firstLoop);
caryclark@google.com03f97062012-08-21 13:13:52 +00002428 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002429 SkDEBUGCODE(firstLoop = false;)
2430 step = -step;
2431 } while (true);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002432 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002433 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2434 return other;
2435 }
2436 SkTDArray<Angle> angles;
2437 SkASSERT(startIndex - endIndex != 0);
2438 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2439 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002440 buildAngles(end, angles, false);
caryclark@google.com24bec792012-08-20 12:43:57 +00002441 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002442 bool sortable = SortAngles(angles, sorted);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002443 if (!sortable) {
2444 unsortable = true;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002445 #if DEBUG_SORT
2446 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
2447 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002448 return NULL;
2449 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002450 int angleCount = angles.count();
2451 int firstIndex = findStartingEdge(sorted, startIndex, end);
2452 SkASSERT(firstIndex >= 0);
2453 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002454 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
caryclark@google.com24bec792012-08-20 12:43:57 +00002455 #endif
2456 SkASSERT(sorted[firstIndex]->segment() == this);
2457 int nextIndex = firstIndex + 1;
2458 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002459 const Angle* foundAngle = NULL;
2460 bool foundDone = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002461 Segment* nextSegment;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002462 int activeCount = 0;
caryclark@google.com24bec792012-08-20 12:43:57 +00002463 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002464 SkASSERT(nextIndex != firstIndex);
caryclark@google.com24bec792012-08-20 12:43:57 +00002465 if (nextIndex == angleCount) {
2466 nextIndex = 0;
2467 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002468 const Angle* nextAngle = sorted[nextIndex];
caryclark@google.com24bec792012-08-20 12:43:57 +00002469 nextSegment = nextAngle->segment();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002470 ++activeCount;
2471 if (!foundAngle || (foundDone && activeCount & 1)) {
2472 if (nextSegment->tiny(nextAngle)) {
2473 unsortable = true;
2474 return NULL;
2475 }
2476 foundAngle = nextAngle;
2477 foundDone = nextSegment->done(nextAngle);
2478 }
2479 if (nextSegment->done()) {
2480 continue;
caryclark@google.com24bec792012-08-20 12:43:57 +00002481 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002482 } while (++nextIndex != lastIndex);
2483 markDone(SkMin32(startIndex, endIndex), 1);
2484 if (!foundAngle) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002485 return NULL;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002486 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002487 nextStart = foundAngle->start();
2488 nextEnd = foundAngle->end();
2489 nextSegment = foundAngle->segment();
2490 #if DEBUG_WINDING
2491 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2492 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2493 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002494 return nextSegment;
2495 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002496
2497 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2498 int angleCount = sorted.count();
2499 int firstIndex = -1;
2500 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2501 const Angle* angle = sorted[angleIndex];
2502 if (angle->segment() == this && angle->start() == end &&
2503 angle->end() == start) {
2504 firstIndex = angleIndex;
2505 break;
2506 }
2507 }
2508 return firstIndex;
2509 }
2510
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002511 // FIXME: this is tricky code; needs its own unit test
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002512 // note that fOtherIndex isn't computed yet, so it can't be used here
caryclark@google.com4eeda372012-12-06 21:47:48 +00002513 void findTooCloseToCall() {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002514 int count = fTs.count();
2515 if (count < 3) { // require t=0, x, 1 at minimum
2516 return;
2517 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002518 int matchIndex = 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002519 int moCount;
2520 Span* match;
2521 Segment* mOther;
2522 do {
2523 match = &fTs[matchIndex];
2524 mOther = match->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002525 // FIXME: allow quads, cubics to be near coincident?
2526 if (mOther->fVerb == SkPath::kLine_Verb) {
2527 moCount = mOther->fTs.count();
2528 if (moCount >= 3) {
2529 break;
2530 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002531 }
2532 if (++matchIndex >= count) {
2533 return;
2534 }
2535 } while (true); // require t=0, x, 1 at minimum
caryclark@google.com15fa1382012-05-07 20:49:36 +00002536 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002537 const SkPoint* matchPt = &xyAtT(match);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002538 // look for a pair of nearby T values that map to the same (x,y) value
2539 // if found, see if the pair of other segments share a common point. If
2540 // so, the span from here to there is coincident.
caryclark@google.com15fa1382012-05-07 20:49:36 +00002541 for (int index = matchIndex + 1; index < count; ++index) {
2542 Span* test = &fTs[index];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002543 if (test->fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002544 continue;
2545 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002546 Segment* tOther = test->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002547 if (tOther->fVerb != SkPath::kLine_Verb) {
2548 continue; // FIXME: allow quads, cubics to be near coincident?
2549 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002550 int toCount = tOther->fTs.count();
2551 if (toCount < 3) { // require t=0, x, 1 at minimum
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002552 continue;
2553 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002554 const SkPoint* testPt = &xyAtT(test);
2555 if (*matchPt != *testPt) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002556 matchIndex = index;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002557 moCount = toCount;
2558 match = test;
2559 mOther = tOther;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002560 matchPt = testPt;
2561 continue;
2562 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002563 int moStart = -1;
2564 int moEnd = -1;
2565 double moStartT, moEndT;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002566 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002567 Span& moSpan = mOther->fTs[moIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002568 if (moSpan.fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002569 continue;
2570 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002571 if (moSpan.fOther == this) {
2572 if (moSpan.fOtherT == match->fT) {
2573 moStart = moIndex;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002574 moStartT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002575 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002576 continue;
2577 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002578 if (moSpan.fOther == tOther) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002579 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002580 moStart = -1;
2581 break;
2582 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002583 SkASSERT(moEnd == -1);
2584 moEnd = moIndex;
2585 moEndT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002586 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002587 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002588 if (moStart < 0 || moEnd < 0) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002589 continue;
2590 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002591 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002592 if (approximately_equal(moStartT, moEndT)) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002593 continue;
2594 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002595 int toStart = -1;
2596 int toEnd = -1;
2597 double toStartT, toEndT;
2598 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2599 Span& toSpan = tOther->fTs[toIndex];
caryclark@google.comc899ad92012-08-23 15:24:42 +00002600 if (toSpan.fDone) {
2601 continue;
2602 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002603 if (toSpan.fOther == this) {
2604 if (toSpan.fOtherT == test->fT) {
2605 toStart = toIndex;
2606 toStartT = toSpan.fT;
2607 }
2608 continue;
2609 }
2610 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002611 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002612 moStart = -1;
2613 break;
2614 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002615 SkASSERT(toEnd == -1);
2616 toEnd = toIndex;
2617 toEndT = toSpan.fT;
2618 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002619 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002620 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2621 if (toStart <= 0 || toEnd <= 0) {
2622 continue;
2623 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002624 if (approximately_equal(toStartT, toEndT)) {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002625 continue;
2626 }
2627 // test to see if the segment between there and here is linear
2628 if (!mOther->isLinear(moStart, moEnd)
2629 || !tOther->isLinear(toStart, toEnd)) {
2630 continue;
2631 }
caryclark@google.comc899ad92012-08-23 15:24:42 +00002632 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002633 if (flipped) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002634 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002635 } else {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002636 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002637 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002638 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002639 }
2640
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002641 // start here;
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00002642 // either:
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002643 // a) mark spans with either end unsortable as done, or
2644 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2645 // when encountering an unsortable span
2646
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002647 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2648 // and use more concise logic like the old edge walker code?
2649 // FIXME: this needs to deal with coincident edges
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002650 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002651 // iterate through T intersections and return topmost
2652 // topmost tangent from y-min to first pt is closer to horizontal
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002653 SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002654 int firstT = -1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002655 SkPoint topPt;
2656 topPt.fY = SK_ScalarMax;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002657 int count = fTs.count();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002658 // see if either end is not done since we want smaller Y of the pair
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002659 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002660 bool lastUnsortable = false;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002661 for (int index = 0; index < count; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002662 const Span& span = fTs[index];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002663 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002664 goto next;
2665 }
2666 if (!span.fDone | !lastDone) {
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002667 const SkPoint& intercept = xyAtT(&span);
2668 if (topPt.fY > intercept.fY || (topPt.fY == intercept.fY
2669 && topPt.fX > intercept.fX)) {
2670 topPt = intercept;
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002671 firstT = index;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002672 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002673 }
caryclark@google.comf839c032012-10-26 21:03:50 +00002674 next:
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002675 lastDone = span.fDone;
caryclark@google.comf839c032012-10-26 21:03:50 +00002676 lastUnsortable = span.fUnsortableEnd;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002677 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002678 SkASSERT(firstT >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002679 // sort the edges to find the leftmost
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002680 int step = 1;
2681 int end = nextSpan(firstT, step);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002682 if (end == -1) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002683 step = -1;
2684 end = nextSpan(firstT, step);
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00002685 SkASSERT(end != -1);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002686 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002687 // if the topmost T is not on end, or is three-way or more, find left
2688 // look for left-ness from tLeft to firstT (matching y of other)
2689 SkTDArray<Angle> angles;
2690 SkASSERT(firstT - end != 0);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002691 addTwoAngles(end, firstT, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002692 buildAngles(firstT, angles, true);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002693 SkTDArray<Angle*> sorted;
caryclark@google.comf839c032012-10-26 21:03:50 +00002694 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002695 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002696 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002697 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002698 if (onlySortable && !sortable) {
2699 unsortable = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002700 return NULL;
2701 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002702 // skip edges that have already been processed
2703 firstT = -1;
2704 Segment* leftSegment;
2705 do {
2706 const Angle* angle = sorted[++firstT];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002707 SkASSERT(!onlySortable || !angle->unsortable());
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002708 leftSegment = angle->segment();
2709 tIndex = angle->end();
2710 endIndex = angle->start();
2711 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002712 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002713 return leftSegment;
2714 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002715
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002716 // FIXME: not crazy about this
2717 // when the intersections are performed, the other index is into an
2718 // incomplete array. as the array grows, the indices become incorrect
2719 // while the following fixes the indices up again, it isn't smart about
2720 // skipping segments whose indices are already correct
2721 // assuming we leave the code that wrote the index in the first place
2722 void fixOtherTIndex() {
2723 int iCount = fTs.count();
2724 for (int i = 0; i < iCount; ++i) {
2725 Span& iSpan = fTs[i];
2726 double oT = iSpan.fOtherT;
2727 Segment* other = iSpan.fOther;
2728 int oCount = other->fTs.count();
2729 for (int o = 0; o < oCount; ++o) {
2730 Span& oSpan = other->fTs[o];
2731 if (oT == oSpan.fT && this == oSpan.fOther) {
2732 iSpan.fOtherIndex = o;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002733 break;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002734 }
2735 }
2736 }
2737 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002738
caryclark@google.com4eeda372012-12-06 21:47:48 +00002739 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002740 fDoneSpans = 0;
2741 fOperand = operand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00002742 fXor = evenOdd;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002743 fPts = pts;
2744 fVerb = verb;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002745 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00002746
caryclark@google.com3586ece2012-12-27 18:46:58 +00002747 void initWinding(int start, int end) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002748 int local = spanSign(start, end);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002749 int oppLocal = oppSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002750 (void) markAndChaseWinding(start, end, local, oppLocal);
caryclark@google.com73ca6242013-01-17 21:02:47 +00002751 // OPTIMIZATION: the reverse mark and chase could skip the first marking
2752 (void) markAndChaseWinding(end, start, local, oppLocal);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002753 }
2754
caryclark@google.com3586ece2012-12-27 18:46:58 +00002755 void initWinding(int start, int end, int winding, int oppWinding) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002756 int local = spanSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002757 if (local * winding >= 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002758 winding += local;
2759 }
2760 int oppLocal = oppSign(start, end);
2761 if (oppLocal * oppWinding >= 0) {
2762 oppWinding += oppLocal;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002763 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002764 (void) markAndChaseWinding(start, end, winding, oppWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002765 }
2766
caryclark@google.com3586ece2012-12-27 18:46:58 +00002767/*
2768when we start with a vertical intersect, we try to use the dx to determine if the edge is to
2769the 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 +00002770sign or not. However, this isn't enough.
2771If 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 +00002772If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
2773from 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 +00002774the same winding is shared by both.
caryclark@google.com3586ece2012-12-27 18:46:58 +00002775*/
2776 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
2777 SkScalar hitOppDx) {
2778 SkASSERT(hitDx || !winding);
2779 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
2780 SkASSERT(dx);
2781 int windVal = windValue(SkMin32(start, end));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002782 #if DEBUG_WINDING_AT_T
2783 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
2784 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
2785 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002786 if (!winding) {
2787 winding = dx < 0 ? windVal : -windVal;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002788 } else if (winding * dx < 0) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00002789 int sideWind = winding + (dx < 0 ? windVal : -windVal);
2790 if (abs(winding) < abs(sideWind)) {
2791 winding = sideWind;
2792 }
2793 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002794 #if DEBUG_WINDING_AT_T
2795 SkDebugf(" winding=%d\n", winding);
2796 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002797 int oppLocal = oppSign(start, end);
2798 SkASSERT(hitOppDx || !oppWind || !oppLocal);
2799 int oppWindVal = oppValue(SkMin32(start, end));
2800 if (!oppWind) {
2801 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
2802 } else if (hitOppDx * dx >= 0) {
2803 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
2804 if (abs(oppWind) < abs(oppSideWind)) {
2805 oppWind = oppSideWind;
2806 }
2807 }
2808 (void) markAndChaseWinding(start, end, winding, oppWind);
2809 }
2810
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002811 bool intersected() const {
2812 return fTs.count() > 0;
2813 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002814
caryclark@google.com10227bf2012-12-28 22:10:41 +00002815 bool isCanceled(int tIndex) const {
2816 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
2817 }
2818
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002819 bool isConnected(int startIndex, int endIndex) const {
2820 return fTs[startIndex].fWindSum != SK_MinS32
2821 || fTs[endIndex].fWindSum != SK_MinS32;
2822 }
2823
caryclark@google.com235f56a2012-09-14 14:19:30 +00002824 bool isHorizontal() const {
2825 return fBounds.fTop == fBounds.fBottom;
2826 }
2827
caryclark@google.com15fa1382012-05-07 20:49:36 +00002828 bool isLinear(int start, int end) const {
2829 if (fVerb == SkPath::kLine_Verb) {
2830 return true;
2831 }
2832 if (fVerb == SkPath::kQuad_Verb) {
2833 SkPoint qPart[3];
2834 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
2835 return QuadIsLinear(qPart);
2836 } else {
2837 SkASSERT(fVerb == SkPath::kCubic_Verb);
2838 SkPoint cPart[4];
2839 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
2840 return CubicIsLinear(cPart);
2841 }
2842 }
caryclark@google.comb9738012012-07-03 19:53:30 +00002843
2844 // OPTIMIZE: successive calls could start were the last leaves off
2845 // or calls could specialize to walk forwards or backwards
2846 bool isMissing(double startT) const {
2847 size_t tCount = fTs.count();
2848 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002849 if (approximately_zero(startT - fTs[index].fT)) {
caryclark@google.comb9738012012-07-03 19:53:30 +00002850 return false;
2851 }
2852 }
2853 return true;
2854 }
2855
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002856 bool isSimple(int end) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002857 int count = fTs.count();
2858 if (count == 2) {
2859 return true;
2860 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002861 double t = fTs[end].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002862 if (approximately_less_than_zero(t)) {
2863 return !approximately_less_than_zero(fTs[1].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002864 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002865 if (approximately_greater_than_one(t)) {
2866 return !approximately_greater_than_one(fTs[count - 2].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002867 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002868 return false;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002869 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002870
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002871 bool isVertical() const {
2872 return fBounds.fLeft == fBounds.fRight;
2873 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00002874
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002875 bool isVertical(int start, int end) const {
2876 return (*SegmentVertical[fVerb])(fPts, start, end);
2877 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002878
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002879 SkScalar leftMost(int start, int end) const {
2880 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
2881 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002882
caryclark@google.com495f8e42012-05-31 13:13:11 +00002883 // this span is excluded by the winding rule -- chase the ends
2884 // as long as they are unambiguous to mark connections as done
2885 // and give them the same winding value
caryclark@google.com59823f72012-08-09 18:17:47 +00002886 Span* markAndChaseDone(const Angle* angle, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002887 int index = angle->start();
2888 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00002889 return markAndChaseDone(index, endIndex, winding);
2890 }
2891
caryclark@google.com31143cf2012-11-09 22:14:19 +00002892 Span* markAndChaseDone(int index, int endIndex, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002893 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002894 int min = SkMin32(index, endIndex);
2895 markDone(min, winding);
2896 Span* last;
2897 Segment* other = this;
2898 while ((other = other->nextChase(index, step, min, last))) {
2899 other->markDone(min, winding);
2900 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002901 return last;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002902 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002903
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002904 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
2905 int index = angle->start();
2906 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00002907 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002908 int min = SkMin32(index, endIndex);
2909 markDoneBinary(min, winding, oppWinding);
2910 Span* last;
2911 Segment* other = this;
2912 while ((other = other->nextChase(index, step, min, last))) {
2913 other->markDoneBinary(min, winding, oppWinding);
2914 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002915 return last;
2916 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002917
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002918 Span* markAndChaseDoneBinary(int index, int endIndex) {
2919 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002920 int min = SkMin32(index, endIndex);
2921 markDoneBinary(min);
2922 Span* last;
2923 Segment* other = this;
2924 while ((other = other->nextChase(index, step, min, last))) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002925 if (other->done()) {
2926 return NULL;
2927 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002928 other->markDoneBinary(min);
2929 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00002930 return last;
2931 }
2932
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002933 Span* markAndChaseDoneUnary(int index, int endIndex) {
2934 int step = SkSign32(endIndex - index);
2935 int min = SkMin32(index, endIndex);
2936 markDoneUnary(min);
2937 Span* last;
2938 Segment* other = this;
2939 while ((other = other->nextChase(index, step, min, last))) {
2940 if (other->done()) {
2941 return NULL;
2942 }
2943 other->markDoneUnary(min);
2944 }
2945 return last;
2946 }
2947
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002948 Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
2949 int index = angle->start();
2950 int endIndex = angle->end();
2951 return markAndChaseDone(index, endIndex, winding);
2952 }
2953
caryclark@google.com4eeda372012-12-06 21:47:48 +00002954 Span* markAndChaseWinding(const Angle* angle, const int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002955 int index = angle->start();
2956 int endIndex = angle->end();
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002957 int step = SkSign32(endIndex - index);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002958 int min = SkMin32(index, endIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00002959 markWinding(min, winding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002960 Span* last;
2961 Segment* other = this;
2962 while ((other = other->nextChase(index, step, min, last))) {
2963 if (other->fTs[min].fWindSum != SK_MinS32) {
2964 SkASSERT(other->fTs[min].fWindSum == winding);
2965 return NULL;
2966 }
2967 other->markWinding(min, winding);
2968 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002969 return last;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002970 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002971
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002972 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00002973 int min = SkMin32(index, endIndex);
2974 int step = SkSign32(endIndex - index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002975 markWinding(min, winding, oppWinding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002976 Span* last;
2977 Segment* other = this;
2978 while ((other = other->nextChase(index, step, min, last))) {
2979 if (other->fTs[min].fWindSum != SK_MinS32) {
2980 SkASSERT(other->fTs[min].fWindSum == winding);
2981 return NULL;
2982 }
2983 other->markWinding(min, winding, oppWinding);
2984 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00002985 return last;
2986 }
2987
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002988 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
2989 int start = angle->start();
2990 int end = angle->end();
2991 return markAndChaseWinding(start, end, winding, oppWinding);
2992 }
2993
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002994 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
2995 SkASSERT(angle->segment() == this);
2996 if (useInnerWinding(maxWinding, sumWinding)) {
2997 maxWinding = sumWinding;
2998 }
2999 Span* last;
3000 if (activeAngle) {
3001 last = markAndChaseWinding(angle, maxWinding);
3002 } else {
3003 last = markAndChaseDoneUnary(angle, maxWinding);
3004 }
3005 return last;
3006 }
3007
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003008 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
3009 bool activeAngle, const Angle* angle) {
3010 SkASSERT(angle->segment() == this);
3011 if (useInnerWinding(maxWinding, sumWinding)) {
3012 maxWinding = sumWinding;
3013 }
3014 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
3015 oppMaxWinding = oppSumWinding;
3016 }
3017 Span* last;
3018 if (activeAngle) {
3019 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3020 } else {
3021 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
3022 }
3023 return last;
3024 }
3025
caryclark@google.com495f8e42012-05-31 13:13:11 +00003026 // FIXME: this should also mark spans with equal (x,y)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003027 // This may be called when the segment is already marked done. While this
3028 // wastes time, it shouldn't do any more than spin through the T spans.
rmistry@google.comd6176b02012-08-23 18:14:13 +00003029 // OPTIMIZATION: abort on first done found (assuming that this code is
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003030 // always called to mark segments done).
caryclark@google.com59823f72012-08-09 18:17:47 +00003031 void markDone(int index, int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003032 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003033 SkASSERT(winding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003034 double referenceT = fTs[index].fT;
3035 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003036 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3037 markOneDone(__FUNCTION__, lesser, winding);
3038 }
3039 do {
3040 markOneDone(__FUNCTION__, index, winding);
3041 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003042 }
3043
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003044 void markDoneBinary(int index, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003045 // SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003046 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003047 double referenceT = fTs[index].fT;
3048 int lesser = index;
3049 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003050 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003051 }
3052 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003053 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
3054 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3055 }
3056
3057 void markDoneBinary(int index) {
3058 double referenceT = fTs[index].fT;
3059 int lesser = index;
3060 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3061 markOneDoneBinary(__FUNCTION__, lesser);
3062 }
3063 do {
3064 markOneDoneBinary(__FUNCTION__, index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003065 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003066 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00003067
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003068 void markDoneUnary(int index, int winding) {
3069 // SkASSERT(!done());
3070 SkASSERT(winding);
3071 double referenceT = fTs[index].fT;
3072 int lesser = index;
3073 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3074 markOneDoneUnary(__FUNCTION__, lesser, winding);
3075 }
3076 do {
3077 markOneDoneUnary(__FUNCTION__, index, winding);
3078 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3079 }
3080
3081 void markDoneUnary(int index) {
3082 double referenceT = fTs[index].fT;
3083 int lesser = index;
3084 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3085 markOneDoneUnary(__FUNCTION__, lesser);
3086 }
3087 do {
3088 markOneDoneUnary(__FUNCTION__, index);
3089 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3090 }
3091
caryclark@google.com24bec792012-08-20 12:43:57 +00003092 void markOneDone(const char* funName, int tIndex, int winding) {
3093 Span* span = markOneWinding(funName, tIndex, winding);
3094 if (!span) {
3095 return;
3096 }
3097 span->fDone = true;
3098 fDoneSpans++;
3099 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003100
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003101 void markOneDoneBinary(const char* funName, int tIndex) {
3102 Span* span = verifyOneWinding(funName, tIndex);
3103 if (!span) {
3104 return;
3105 }
3106 span->fDone = true;
3107 fDoneSpans++;
3108 }
3109
3110 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003111 Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
3112 if (!span) {
3113 return;
3114 }
3115 span->fDone = true;
3116 fDoneSpans++;
3117 }
3118
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003119 void markOneDoneUnary(const char* funName, int tIndex) {
3120 Span* span = verifyOneWindingU(funName, tIndex);
3121 if (!span) {
3122 return;
3123 }
3124 span->fDone = true;
3125 fDoneSpans++;
3126 }
3127
3128 void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3129 Span* span = markOneWinding(funName, tIndex, winding);
3130 if (!span) {
3131 return;
3132 }
3133 span->fDone = true;
3134 fDoneSpans++;
3135 }
3136
caryclark@google.com24bec792012-08-20 12:43:57 +00003137 Span* markOneWinding(const char* funName, int tIndex, int winding) {
3138 Span& span = fTs[tIndex];
3139 if (span.fDone) {
3140 return NULL;
3141 }
3142 #if DEBUG_MARK_DONE
3143 debugShowNewWinding(funName, span, winding);
3144 #endif
3145 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com03f97062012-08-21 13:13:52 +00003146 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00003147 SkASSERT(abs(winding) <= gDebugMaxWindSum);
caryclark@google.com03f97062012-08-21 13:13:52 +00003148 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00003149 span.fWindSum = winding;
3150 return &span;
3151 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003152
caryclark@google.com31143cf2012-11-09 22:14:19 +00003153 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
3154 Span& span = fTs[tIndex];
3155 if (span.fDone) {
3156 return NULL;
3157 }
3158 #if DEBUG_MARK_DONE
3159 debugShowNewWinding(funName, span, winding, oppWinding);
3160 #endif
3161 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3162 #ifdef SK_DEBUG
3163 SkASSERT(abs(winding) <= gDebugMaxWindSum);
3164 #endif
3165 span.fWindSum = winding;
3166 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3167 #ifdef SK_DEBUG
3168 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
3169 #endif
3170 span.fOppSum = oppWinding;
3171 return &span;
3172 }
3173
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003174 Span* verifyOneWinding(const char* funName, int tIndex) {
3175 Span& span = fTs[tIndex];
3176 if (span.fDone) {
3177 return NULL;
3178 }
3179 #if DEBUG_MARK_DONE
3180 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3181 #endif
3182 SkASSERT(span.fWindSum != SK_MinS32);
3183 SkASSERT(span.fOppSum != SK_MinS32);
3184 return &span;
3185 }
3186
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003187 Span* verifyOneWindingU(const char* funName, int tIndex) {
3188 Span& span = fTs[tIndex];
3189 if (span.fDone) {
3190 return NULL;
3191 }
3192 #if DEBUG_MARK_DONE
3193 debugShowNewWinding(funName, span, span.fWindSum);
3194 #endif
3195 SkASSERT(span.fWindSum != SK_MinS32);
3196 return &span;
3197 }
3198
caryclark@google.comf839c032012-10-26 21:03:50 +00003199 // note that just because a span has one end that is unsortable, that's
3200 // not enough to mark it done. The other end may be sortable, allowing the
3201 // span to be added.
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003202 // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003203 void markUnsortable(int start, int end) {
3204 Span* span = &fTs[start];
3205 if (start < end) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003206#if DEBUG_UNSORTABLE
3207 SkDebugf("%s start id=%d [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fID, start,
3208 xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003209#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003210 span->fUnsortableStart = true;
3211 } else {
3212 --span;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003213#if DEBUG_UNSORTABLE
3214 SkDebugf("%s end id=%d [%d] (%1.9g,%1.9g) next:(%1.9g,%1.9g)\n", __FUNCTION__, fID,
3215 start - 1, xAtT(start - 1), yAtT(start - 1), xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003216#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003217 span->fUnsortableEnd = true;
3218 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003219 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003220 return;
3221 }
3222 span->fDone = true;
3223 fDoneSpans++;
3224 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003225
caryclark@google.com59823f72012-08-09 18:17:47 +00003226 void markWinding(int index, int winding) {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003227 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003228 SkASSERT(winding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003229 double referenceT = fTs[index].fT;
3230 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003231 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3232 markOneWinding(__FUNCTION__, lesser, winding);
3233 }
3234 do {
3235 markOneWinding(__FUNCTION__, index, winding);
3236 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003237 }
3238
3239 void markWinding(int index, int winding, int oppWinding) {
3240 // SkASSERT(!done());
caryclark@google.com4eeda372012-12-06 21:47:48 +00003241 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003242 double referenceT = fTs[index].fT;
3243 int lesser = index;
3244 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3245 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003246 }
3247 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003248 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3249 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003250 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003251
caryclark@google.com2ddff932012-08-07 21:25:27 +00003252 void matchWindingValue(int tIndex, double t, bool borrowWind) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003253 int nextDoorWind = SK_MaxS32;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003254 int nextOppWind = SK_MaxS32;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003255 if (tIndex > 0) {
3256 const Span& below = fTs[tIndex - 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003257 if (approximately_negative(t - below.fT)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003258 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003259 nextOppWind = below.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003260 }
3261 }
3262 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3263 const Span& above = fTs[tIndex + 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003264 if (approximately_negative(above.fT - t)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003265 nextDoorWind = above.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003266 nextOppWind = above.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003267 }
3268 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003269 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3270 const Span& below = fTs[tIndex - 1];
3271 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003272 nextOppWind = below.fOppValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003273 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003274 if (nextDoorWind != SK_MaxS32) {
3275 Span& newSpan = fTs[tIndex];
3276 newSpan.fWindValue = nextDoorWind;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003277 newSpan.fOppValue = nextOppWind;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003278 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003279 newSpan.fDone = true;
3280 ++fDoneSpans;
3281 }
3282 }
3283 }
3284
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003285 bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3286 // find bounds
3287 Bounds bounds;
3288 bounds.setPoint(xyAtT(index));
3289 bounds.add(xyAtT(endIndex));
3290 SkScalar width = bounds.width();
3291 SkScalar height = bounds.height();
3292 if (width > height) {
3293 if (approximately_negative(width)) {
3294 unsortable = true; // edge is too small to resolve meaningfully
3295 }
3296 return false;
3297 } else {
3298 if (approximately_negative(height)) {
3299 unsortable = true; // edge is too small to resolve meaningfully
3300 }
3301 return true;
3302 }
3303 }
3304
caryclark@google.com9764cc62012-07-12 19:29:45 +00003305 // return span if when chasing, two or more radiating spans are not done
3306 // OPTIMIZATION: ? multiple spans is detected when there is only one valid
3307 // candidate and the remaining spans have windValue == 0 (canceled by
3308 // coincidence). The coincident edges could either be removed altogether,
3309 // or this code could be more complicated in detecting this case. Worth it?
3310 bool multipleSpans(int end) const {
3311 return end > 0 && end < fTs.count() - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00003312 }
3313
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003314 bool nextCandidate(int& start, int& end) const {
caryclark@google.com10227bf2012-12-28 22:10:41 +00003315 while (fTs[end].fDone) {
3316 if (fTs[end].fT == 1) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003317 return false;
3318 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00003319 ++end;
3320 }
3321 start = end;
3322 end = nextExactSpan(start, 1);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003323 return true;
3324 }
3325
caryclark@google.com4eeda372012-12-06 21:47:48 +00003326 Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
3327 int end = nextExactSpan(index, step);
3328 SkASSERT(end >= 0);
3329 if (multipleSpans(end)) {
3330 last = &fTs[end];
3331 return NULL;
3332 }
3333 const Span& endSpan = fTs[end];
3334 Segment* other = endSpan.fOther;
3335 index = endSpan.fOtherIndex;
3336 int otherEnd = other->nextExactSpan(index, step);
3337 min = SkMin32(index, otherEnd);
3338 return other;
3339 }
3340
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003341 // This has callers for two different situations: one establishes the end
3342 // of the current span, and one establishes the beginning of the next span
3343 // (thus the name). When this is looking for the end of the current span,
3344 // coincidence is found when the beginning Ts contain -step and the end
3345 // contains step. When it is looking for the beginning of the next, the
3346 // first Ts found can be ignored and the last Ts should contain -step.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003347 // OPTIMIZATION: probably should split into two functions
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003348 int nextSpan(int from, int step) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003349 const Span& fromSpan = fTs[from];
caryclark@google.com495f8e42012-05-31 13:13:11 +00003350 int count = fTs.count();
3351 int to = from;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003352 while (step > 0 ? ++to < count : --to >= 0) {
3353 const Span& span = fTs[to];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003354 if (approximately_zero(span.fT - fromSpan.fT)) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003355 continue;
3356 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003357 return to;
3358 }
3359 return -1;
3360 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +00003361
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003362 // FIXME
3363 // this returns at any difference in T, vs. a preset minimum. It may be
3364 // that all callers to nextSpan should use this instead.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003365 // OPTIMIZATION splitting this into separate loops for up/down steps
3366 // would allow using precisely_negative instead of precisely_zero
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003367 int nextExactSpan(int from, int step) const {
3368 const Span& fromSpan = fTs[from];
3369 int count = fTs.count();
3370 int to = from;
3371 while (step > 0 ? ++to < count : --to >= 0) {
3372 const Span& span = fTs[to];
caryclark@google.coma461ff02012-10-11 12:54:23 +00003373 if (precisely_zero(span.fT - fromSpan.fT)) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003374 continue;
3375 }
3376 return to;
3377 }
3378 return -1;
3379 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003380
caryclark@google.com235f56a2012-09-14 14:19:30 +00003381 bool operand() const {
3382 return fOperand;
3383 }
3384
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003385 int oppSign(const Angle* angle) const {
3386 SkASSERT(angle->segment() == this);
3387 return oppSign(angle->start(), angle->end());
3388 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003389
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003390 int oppSign(int startIndex, int endIndex) const {
3391 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3392 : fTs[endIndex].fOppValue;
3393#if DEBUG_WIND_BUMP
3394 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3395#endif
3396 return result;
3397 }
3398
caryclark@google.com31143cf2012-11-09 22:14:19 +00003399 int oppSum(int tIndex) const {
3400 return fTs[tIndex].fOppSum;
3401 }
3402
3403 int oppSum(const Angle* angle) const {
3404 int lesser = SkMin32(angle->start(), angle->end());
3405 return fTs[lesser].fOppSum;
caryclark@google.com235f56a2012-09-14 14:19:30 +00003406 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003407
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003408 int oppValue(int tIndex) const {
3409 return fTs[tIndex].fOppValue;
3410 }
3411
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003412 int oppValue(const Angle* angle) const {
3413 int lesser = SkMin32(angle->start(), angle->end());
3414 return fTs[lesser].fOppValue;
3415 }
3416
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003417 const SkPoint* pts() const {
3418 return fPts;
3419 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003420
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003421 void reset() {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003422 init(NULL, (SkPath::Verb) -1, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003423 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3424 fTs.reset();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003425 }
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +00003426
caryclark@google.com4eeda372012-12-06 21:47:48 +00003427 void setOppXor(bool isOppXor) {
3428 fOppXor = isOppXor;
3429 }
3430
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003431 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3432 int deltaSum = spanSign(index, endIndex);
3433 maxWinding = sumWinding;
3434 sumWinding = sumWinding -= deltaSum;
3435 }
3436
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003437 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3438 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3439 int deltaSum = spanSign(index, endIndex);
3440 int oppDeltaSum = oppSign(index, endIndex);
3441 if (operand()) {
3442 maxWinding = sumSuWinding;
3443 sumWinding = sumSuWinding -= deltaSum;
3444 oppMaxWinding = sumMiWinding;
3445 oppSumWinding = sumMiWinding -= oppDeltaSum;
3446 } else {
3447 maxWinding = sumMiWinding;
3448 sumWinding = sumMiWinding -= deltaSum;
3449 oppMaxWinding = sumSuWinding;
3450 oppSumWinding = sumSuWinding -= oppDeltaSum;
3451 }
3452 }
3453
caryclark@google.comf839c032012-10-26 21:03:50 +00003454 // This marks all spans unsortable so that this info is available for early
3455 // exclusion in find top and others. This could be optimized to only mark
3456 // adjacent spans that unsortable. However, this makes it difficult to later
3457 // determine starting points for edge detection in find top and the like.
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003458 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
caryclark@google.comf839c032012-10-26 21:03:50 +00003459 bool sortable = true;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003460 int angleCount = angles.count();
3461 int angleIndex;
3462 angleList.setReserve(angleCount);
3463 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003464 Angle& angle = angles[angleIndex];
caryclark@google.comf839c032012-10-26 21:03:50 +00003465 *angleList.append() = &angle;
3466 sortable &= !angle.unsortable();
3467 }
3468 if (sortable) {
3469 QSort<Angle>(angleList.begin(), angleList.end() - 1);
3470 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3471 if (angles[angleIndex].unsortable()) {
3472 sortable = false;
3473 break;
3474 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003475 }
3476 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003477 if (!sortable) {
3478 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3479 Angle& angle = angles[angleIndex];
3480 angle.segment()->markUnsortable(angle.start(), angle.end());
3481 }
3482 }
3483 return sortable;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003484 }
3485
caryclark@google.com1577e8f2012-05-22 17:01:14 +00003486 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003487 const Span& span(int tIndex) const {
3488 return fTs[tIndex];
3489 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003490
caryclark@google.com235f56a2012-09-14 14:19:30 +00003491 int spanSign(const Angle* angle) const {
3492 SkASSERT(angle->segment() == this);
3493 return spanSign(angle->start(), angle->end());
3494 }
3495
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003496 int spanSign(int startIndex, int endIndex) const {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003497 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3498 : fTs[endIndex].fWindValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003499#if DEBUG_WIND_BUMP
3500 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3501#endif
3502 return result;
3503 }
3504
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003505 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003506 double t(int tIndex) const {
3507 return fTs[tIndex].fT;
3508 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003509
caryclark@google.com10227bf2012-12-28 22:10:41 +00003510 double tAtMid(int start, int end, double mid) const {
3511 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
3512 }
3513
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003514 bool tiny(const Angle* angle) const {
3515 int start = angle->start();
3516 int end = angle->end();
caryclark@google.comf839c032012-10-26 21:03:50 +00003517 const Span& mSpan = fTs[SkMin32(start, end)];
3518 return mSpan.fTiny;
3519 }
3520
caryclark@google.com18063442012-07-25 12:05:18 +00003521 static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3522 double start) {
3523 int outCount = outsideTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003524 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
caryclark@google.com18063442012-07-25 12:05:18 +00003525 *outsideTs.append() = end;
3526 *outsideTs.append() = start;
3527 }
3528 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003529
caryclark@google.com24bec792012-08-20 12:43:57 +00003530 void undoneSpan(int& start, int& end) {
3531 size_t tCount = fTs.count();
3532 size_t index;
3533 for (index = 0; index < tCount; ++index) {
3534 if (!fTs[index].fDone) {
3535 break;
3536 }
3537 }
3538 SkASSERT(index < tCount - 1);
3539 start = index;
3540 double startT = fTs[index].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003541 while (approximately_negative(fTs[++index].fT - startT))
caryclark@google.com24bec792012-08-20 12:43:57 +00003542 SkASSERT(index < tCount);
3543 SkASSERT(index < tCount);
3544 end = index;
3545 }
caryclark@google.com18063442012-07-25 12:05:18 +00003546
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003547 bool unsortable(int index) const {
3548 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3549 }
3550
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003551 void updatePts(const SkPoint pts[]) {
3552 fPts = pts;
3553 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003554
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003555 int updateOppWinding(int index, int endIndex) const {
3556 int lesser = SkMin32(index, endIndex);
3557 int oppWinding = oppSum(lesser);
3558 int oppSpanWinding = oppSign(index, endIndex);
3559 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)) {
3560 oppWinding -= oppSpanWinding;
3561 }
3562 return oppWinding;
3563 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003564
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003565 int updateOppWinding(const Angle* angle) const {
3566 int startIndex = angle->start();
3567 int endIndex = angle->end();
3568 return updateOppWinding(endIndex, startIndex);
3569 }
3570
3571 int updateOppWindingReverse(const Angle* angle) const {
3572 int startIndex = angle->start();
3573 int endIndex = angle->end();
3574 return updateOppWinding(startIndex, endIndex);
3575 }
3576
3577 int updateWinding(int index, int endIndex) const {
3578 int lesser = SkMin32(index, endIndex);
3579 int winding = windSum(lesser);
3580 int spanWinding = spanSign(index, endIndex);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003581 if (winding && useInnerWinding(winding - spanWinding, winding)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003582 winding -= spanWinding;
3583 }
3584 return winding;
3585 }
3586
3587 int updateWinding(const Angle* angle) const {
3588 int startIndex = angle->start();
3589 int endIndex = angle->end();
3590 return updateWinding(endIndex, startIndex);
3591 }
3592
3593 int updateWindingReverse(const Angle* angle) const {
3594 int startIndex = angle->start();
3595 int endIndex = angle->end();
3596 return updateWinding(startIndex, endIndex);
3597 }
3598
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003599 SkPath::Verb verb() const {
3600 return fVerb;
3601 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003602
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003603 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003604 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3605 return SK_MinS32;
3606 }
3607 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3608 SkASSERT(winding != SK_MinS32);
3609 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003610 #if DEBUG_WINDING_AT_T
3611 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003612 #endif
3613 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark@google.com3586ece2012-12-27 18:46:58 +00003614 dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003615 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3616 dx = fPts[2].fX - fPts[1].fX - dx;
3617 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003618 if (dx == 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003619 #if DEBUG_WINDING_AT_T
3620 SkDebugf(" dx=0 winding=SK_MinS32\n");
3621 #endif
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003622 return SK_MinS32;
3623 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003624 if (winding * dx > 0) { // if same signs, result is negative
3625 winding += dx > 0 ? -windVal : windVal;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003626 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003627 #if DEBUG_WINDING_AT_T
3628 SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding);
3629 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003630 return winding;
3631 }
3632
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003633 int windSum(int tIndex) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003634 return fTs[tIndex].fWindSum;
3635 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003636
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003637 int windSum(const Angle* angle) const {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003638 int start = angle->start();
3639 int end = angle->end();
3640 int index = SkMin32(start, end);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003641 return windSum(index);
caryclark@google.com495f8e42012-05-31 13:13:11 +00003642 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003643
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003644 int windValue(int tIndex) const {
3645 return fTs[tIndex].fWindValue;
3646 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003647
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003648 int windValue(const Angle* angle) const {
3649 int start = angle->start();
3650 int end = angle->end();
3651 int index = SkMin32(start, end);
3652 return windValue(index);
3653 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00003654
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003655 int windValueAt(double t) const {
3656 int count = fTs.count();
3657 for (int index = 0; index < count; ++index) {
3658 if (fTs[index].fT == t) {
3659 return fTs[index].fWindValue;
3660 }
3661 }
3662 SkASSERT(0);
3663 return 0;
3664 }
3665
caryclark@google.com3586ece2012-12-27 18:46:58 +00003666 SkScalar xAtT(int index) const {
3667 return xAtT(&fTs[index]);
3668 }
3669
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003670 SkScalar xAtT(const Span* span) const {
3671 return xyAtT(span).fX;
3672 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003673
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003674 const SkPoint& xyAtT(int index) const {
3675 return xyAtT(&fTs[index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003676 }
3677
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003678 const SkPoint& xyAtT(const Span* span) const {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003679 if (SkScalarIsNaN(span->fPt.fX)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003680 if (span->fT == 0) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003681 span->fPt = fPts[0];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003682 } else if (span->fT == 1) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003683 span->fPt = fPts[fVerb];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003684 } else {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003685 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003686 }
3687 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00003688 return span->fPt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003689 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003690
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003691 // used only by right angle winding finding
caryclark@google.com10227bf2012-12-28 22:10:41 +00003692 void xyAtT(double mid, SkPoint& pt) const {
3693 (*SegmentXYAtT[fVerb])(fPts, mid, &pt);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003694 }
3695
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003696 SkScalar yAtT(int index) const {
3697 return yAtT(&fTs[index]);
3698 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003699
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003700 SkScalar yAtT(const Span* span) const {
3701 return xyAtT(span).fY;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003702 }
3703
caryclark@google.com4eeda372012-12-06 21:47:48 +00003704 void zeroCoincidentOpp(Span* oTest, int index) {
3705 Span* const test = &fTs[index];
3706 Span* end = test;
3707 do {
3708 end->fOppValue = 0;
3709 end = &fTs[++index];
3710 } while (approximately_negative(end->fT - test->fT));
3711 }
3712
3713 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
3714 Span* const oTest = &fTs[oIndex];
3715 Span* oEnd = oTest;
3716 const double startT = test->fT;
3717 const double oStartT = oTest->fT;
3718 double otherTMatch = (test->fT - startT) * tRatio + oStartT;
3719 while (!approximately_negative(oEndT - oEnd->fT)
3720 && approximately_negative(oEnd->fT - otherTMatch)) {
3721 oEnd->fOppValue = 0;
3722 oEnd = &fTs[++oIndex];
3723 }
3724 }
3725
3726 void zeroSpan(Span* span) {
3727 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
caryclark@google.com6ec15262012-11-16 20:16:50 +00003728 span->fWindValue = 0;
caryclark@google.com729e1c42012-11-21 21:36:34 +00003729 span->fOppValue = 0;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003730 SkASSERT(!span->fDone);
3731 span->fDone = true;
3732 ++fDoneSpans;
caryclark@google.com6ec15262012-11-16 20:16:50 +00003733 }
3734
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003735#if DEBUG_DUMP
3736 void dump() const {
3737 const char className[] = "Segment";
3738 const int tab = 4;
3739 for (int i = 0; i < fTs.count(); ++i) {
3740 SkPoint out;
3741 (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
3742 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003743 " otherT=%1.9g windSum=%d\n",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003744 tab + sizeof(className), className, fID,
3745 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003746 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003747 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00003748 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003749 tab + sizeof(className), className, fID,
caryclark@google.com15fa1382012-05-07 20:49:36 +00003750 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003751 }
3752#endif
3753
caryclark@google.com47580692012-07-23 12:14:49 +00003754#if DEBUG_CONCIDENT
caryclark@google.comcc905052012-07-25 20:59:42 +00003755 // assert if pair has not already been added
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003756 void debugAddTPair(double t, const Segment& other, double otherT) const {
caryclark@google.comcc905052012-07-25 20:59:42 +00003757 for (int i = 0; i < fTs.count(); ++i) {
3758 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
3759 return;
3760 }
3761 }
3762 SkASSERT(0);
3763 }
3764#endif
3765
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003766#if DEBUG_DUMP
3767 int debugID() const {
3768 return fID;
3769 }
3770#endif
3771
caryclark@google.com24bec792012-08-20 12:43:57 +00003772#if DEBUG_WINDING
3773 void debugShowSums() const {
3774 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
3775 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
3776 for (int i = 0; i < fTs.count(); ++i) {
3777 const Span& span = fTs[i];
3778 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
3779 if (span.fWindSum == SK_MinS32) {
3780 SkDebugf("?");
3781 } else {
3782 SkDebugf("%d", span.fWindSum);
3783 }
3784 SkDebugf("]");
3785 }
3786 SkDebugf("\n");
3787 }
3788#endif
3789
caryclark@google.comcc905052012-07-25 20:59:42 +00003790#if DEBUG_CONCIDENT
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003791 void debugShowTs() const {
caryclark@google.com24bec792012-08-20 12:43:57 +00003792 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003793 int lastWind = -1;
3794 int lastOpp = -1;
3795 double lastT = -1;
3796 int i;
3797 for (i = 0; i < fTs.count(); ++i) {
3798 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
3799 || lastOpp != fTs[i].fOppValue;
3800 if (change && lastWind >= 0) {
3801 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3802 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3803 }
3804 if (change) {
3805 SkDebugf(" [o=%d", fTs[i].fOther->fID);
3806 lastWind = fTs[i].fWindValue;
3807 lastOpp = fTs[i].fOppValue;
3808 lastT = fTs[i].fT;
3809 } else {
3810 SkDebugf(",%d", fTs[i].fOther->fID);
3811 }
3812 }
3813 if (i <= 0) {
3814 return;
3815 }
3816 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3817 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3818 if (fOperand) {
3819 SkDebugf(" operand");
3820 }
3821 if (done()) {
3822 SkDebugf(" done");
caryclark@google.com47580692012-07-23 12:14:49 +00003823 }
3824 SkDebugf("\n");
3825 }
3826#endif
3827
caryclark@google.com027de222012-07-12 12:52:50 +00003828#if DEBUG_ACTIVE_SPANS
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003829 void debugShowActiveSpans() const {
caryclark@google.com027de222012-07-12 12:52:50 +00003830 if (done()) {
3831 return;
3832 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003833#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3834 int lastId = -1;
3835 double lastT = -1;
3836#endif
caryclark@google.com027de222012-07-12 12:52:50 +00003837 for (int i = 0; i < fTs.count(); ++i) {
3838 if (fTs[i].fDone) {
3839 continue;
3840 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003841#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3842 if (lastId == fID && lastT == fTs[i].fT) {
3843 continue;
3844 }
3845 lastId = fID;
3846 lastT = fTs[i].fT;
3847#endif
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003848 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com027de222012-07-12 12:52:50 +00003849 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3850 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3851 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3852 }
3853 const Span* span = &fTs[i];
rmistry@google.comd6176b02012-08-23 18:14:13 +00003854 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
caryclark@google.com0c803d02012-08-06 11:15:47 +00003855 xAtT(span), yAtT(span));
caryclark@google.com027de222012-07-12 12:52:50 +00003856 const Segment* other = fTs[i].fOther;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003857 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
3858 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
3859 if (fTs[i].fWindSum == SK_MinS32) {
3860 SkDebugf("?");
3861 } else {
3862 SkDebugf("%d", fTs[i].fWindSum);
3863 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003864 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
caryclark@google.com027de222012-07-12 12:52:50 +00003865 }
3866 }
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +00003867
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003868 // This isn't useful yet -- but leaving it in for now in case i think of something
3869 // to use it for
3870 void validateActiveSpans() const {
3871 if (done()) {
3872 return;
3873 }
3874 int tCount = fTs.count();
3875 for (int index = 0; index < tCount; ++index) {
3876 if (fTs[index].fDone) {
3877 continue;
3878 }
3879 // count number of connections which are not done
3880 int first = index;
3881 double baseT = fTs[index].fT;
3882 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
3883 --first;
3884 }
3885 int last = index;
3886 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
3887 ++last;
3888 }
3889 int connections = 0;
3890 connections += first > 0 && !fTs[first - 1].fDone;
3891 for (int test = first; test <= last; ++test) {
3892 connections += !fTs[test].fDone;
3893 const Segment* other = fTs[test].fOther;
3894 int oIndex = fTs[test].fOtherIndex;
3895 connections += !other->fTs[oIndex].fDone;
3896 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
3897 }
3898 // SkASSERT(!(connections & 1));
3899 }
3900 }
caryclark@google.com027de222012-07-12 12:52:50 +00003901#endif
3902
caryclark@google.com0c803d02012-08-06 11:15:47 +00003903#if DEBUG_MARK_DONE
3904 void debugShowNewWinding(const char* fun, const Span& span, int winding) {
3905 const SkPoint& pt = xyAtT(&span);
3906 SkDebugf("%s id=%d", fun, fID);
3907 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3908 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3909 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3910 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003911 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3912 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3913 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d windSum=",
3914 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, winding);
caryclark@google.com0c803d02012-08-06 11:15:47 +00003915 if (span.fWindSum == SK_MinS32) {
3916 SkDebugf("?");
3917 } else {
3918 SkDebugf("%d", span.fWindSum);
3919 }
3920 SkDebugf(" windValue=%d\n", span.fWindValue);
3921 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003922
3923 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
3924 const SkPoint& pt = xyAtT(&span);
3925 SkDebugf("%s id=%d", fun, fID);
3926 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3927 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3928 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3929 }
3930 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3931 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3932 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=",
3933 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
3934 winding, oppWinding);
3935 if (span.fOppSum == SK_MinS32) {
3936 SkDebugf("?");
3937 } else {
3938 SkDebugf("%d", span.fOppSum);
3939 }
3940 SkDebugf(" windSum=");
3941 if (span.fWindSum == SK_MinS32) {
3942 SkDebugf("?");
3943 } else {
3944 SkDebugf("%d", span.fWindSum);
3945 }
3946 SkDebugf(" windValue=%d\n", span.fWindValue);
3947 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003948#endif
3949
caryclark@google.com47580692012-07-23 12:14:49 +00003950#if DEBUG_SORT
caryclark@google.com03f97062012-08-21 13:13:52 +00003951 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
caryclark@google.com31143cf2012-11-09 22:14:19 +00003952 const int contourWinding, const int oppContourWinding) const {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003953 SkASSERT(angles[first]->segment() == this);
caryclark@google.com200c2112012-08-03 15:05:04 +00003954 SkASSERT(angles.count() > 1);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003955 int lastSum = contourWinding;
caryclark@google.com31143cf2012-11-09 22:14:19 +00003956 int oppLastSum = oppContourWinding;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003957 const Angle* firstAngle = angles[first];
3958 int windSum = lastSum - spanSign(firstAngle);
3959 int oppoSign = oppSign(firstAngle);
3960 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.com31143cf2012-11-09 22:14:19 +00003961 SkDebugf("%s %s contourWinding=%d oppContourWinding=%d sign=%d\n", fun, __FUNCTION__,
3962 contourWinding, oppContourWinding, spanSign(angles[first]));
caryclark@google.comafe56de2012-07-24 18:11:03 +00003963 int index = first;
3964 bool firstTime = true;
caryclark@google.com47580692012-07-23 12:14:49 +00003965 do {
3966 const Angle& angle = *angles[index];
3967 const Segment& segment = *angle.segment();
3968 int start = angle.start();
3969 int end = angle.end();
3970 const Span& sSpan = segment.fTs[start];
3971 const Span& eSpan = segment.fTs[end];
3972 const Span& mSpan = segment.fTs[SkMin32(start, end)];
caryclark@google.com31143cf2012-11-09 22:14:19 +00003973 bool opp = segment.fOperand ^ fOperand;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003974 if (!firstTime) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003975 oppoSign = segment.oppSign(&angle);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003976 if (opp) {
3977 oppLastSum = oppWindSum;
3978 oppWindSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003979 if (oppoSign) {
3980 lastSum = windSum;
3981 windSum -= oppoSign;
3982 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003983 } else {
3984 lastSum = windSum;
3985 windSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003986 if (oppoSign) {
3987 oppLastSum = oppWindSum;
3988 oppWindSum -= oppoSign;
3989 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003990 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00003991 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003992 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 +00003993 " sign=%d windValue=%d windSum=",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003994 __FUNCTION__, index, angle.unsortable() ? "*** UNSORTABLE *** " : "",
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003995 segment.fID, kLVerbStr[segment.fVerb],
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003996 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
3997 segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(),
3998 mSpan.fWindValue);
3999 if (mSpan.fWindSum == SK_MinS32) {
4000 SkDebugf("?");
4001 } else {
4002 SkDebugf("%d", mSpan.fWindSum);
4003 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004004 int last, wind;
4005 if (opp) {
4006 last = oppLastSum;
4007 wind = oppWindSum;
4008 } else {
4009 last = lastSum;
4010 wind = windSum;
4011 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004012 if (!oppoSign) {
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00004013 SkDebugf(" %d->%d (max=%d)", last, wind,
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004014 useInnerWinding(last, wind) ? wind : last);
4015 } else {
4016 SkDebugf(" %d->%d (%d->%d)", last, wind, opp ? lastSum : oppLastSum,
4017 opp ? windSum : oppWindSum);
4018 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004019 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004020#if false && DEBUG_ANGLE
caryclark@google.comc899ad92012-08-23 15:24:42 +00004021 angle.debugShow(segment.xyAtT(&sSpan));
4022#endif
caryclark@google.com47580692012-07-23 12:14:49 +00004023 ++index;
4024 if (index == angles.count()) {
4025 index = 0;
4026 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004027 if (firstTime) {
4028 firstTime = false;
4029 }
caryclark@google.com47580692012-07-23 12:14:49 +00004030 } while (index != first);
4031 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00004032
4033 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
4034 const Angle* firstAngle = angles[first];
4035 const Segment* segment = firstAngle->segment();
4036 int winding = segment->updateWinding(firstAngle);
4037 int oppWinding = segment->updateOppWinding(firstAngle);
4038 debugShowSort(fun, angles, first, winding, oppWinding);
4039 }
4040
caryclark@google.com47580692012-07-23 12:14:49 +00004041#endif
4042
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004043#if DEBUG_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004044 static char as_digit(int value) {
4045 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
4046 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004047#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004048
caryclark@google.com729e1c42012-11-21 21:36:34 +00004049#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004050 int debugShowWindingValues(int slotCount, int ofInterest) const {
4051 if (!(1 << fID & ofInterest)) {
4052 return 0;
4053 }
4054 int sum = 0;
4055 SkTDArray<char> slots;
4056 slots.setCount(slotCount * 2);
4057 memset(slots.begin(), ' ', slotCount * 2);
4058 for (int i = 0; i < fTs.count(); ++i) {
4059 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
4060 // continue;
4061 // }
4062 sum += fTs[i].fWindValue;
4063 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
4064 sum += fTs[i].fOppValue;
4065 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
4066 }
4067 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
4068 slots.begin() + slotCount);
4069 return sum;
4070 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004071#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004072
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004073private:
4074 const SkPoint* fPts;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004075 Bounds fBounds;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004076 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
caryclark@google.com4eeda372012-12-06 21:47:48 +00004077 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
caryclark@google.com24bec792012-08-20 12:43:57 +00004078 int fDoneSpans; // quick check that segment is finished
caryclark@google.com4eeda372012-12-06 21:47:48 +00004079 // OPTIMIZATION: force the following to be byte-sized
4080 SkPath::Verb fVerb;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004081 bool fOperand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004082 bool fXor; // set if original contour had even-odd fill
4083 bool fOppXor; // set if opposite operand had even-odd fill
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004084#if DEBUG_DUMP
4085 int fID;
4086#endif
4087};
4088
caryclark@google.comb9738012012-07-03 19:53:30 +00004089class Contour;
4090
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004091struct Coincidence {
caryclark@google.comb9738012012-07-03 19:53:30 +00004092 Contour* fContours[2];
4093 int fSegments[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004094 double fTs[2][2];
4095};
4096
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004097class Contour {
4098public:
4099 Contour() {
4100 reset();
4101#if DEBUG_DUMP
4102 fID = ++gContourID;
4103#endif
4104 }
4105
4106 bool operator<(const Contour& rh) const {
4107 return fBounds.fTop == rh.fBounds.fTop
4108 ? fBounds.fLeft < rh.fBounds.fLeft
4109 : fBounds.fTop < rh.fBounds.fTop;
4110 }
4111
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004112 void addCoincident(int index, Contour* other, int otherIndex,
4113 const Intersections& ts, bool swap) {
4114 Coincidence& coincidence = *fCoincidences.append();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004115 coincidence.fContours[0] = this; // FIXME: no need to store
caryclark@google.comb9738012012-07-03 19:53:30 +00004116 coincidence.fContours[1] = other;
4117 coincidence.fSegments[0] = index;
4118 coincidence.fSegments[1] = otherIndex;
caryclark@google.com32546db2012-08-31 20:55:07 +00004119 if (fSegments[index].verb() == SkPath::kLine_Verb &&
4120 other->fSegments[otherIndex].verb() == SkPath::kLine_Verb) {
4121 // FIXME: coincident lines use legacy Ts instead of coincident Ts
4122 coincidence.fTs[swap][0] = ts.fT[0][0];
4123 coincidence.fTs[swap][1] = ts.fT[0][1];
4124 coincidence.fTs[!swap][0] = ts.fT[1][0];
4125 coincidence.fTs[!swap][1] = ts.fT[1][1];
4126 } else if (fSegments[index].verb() == SkPath::kQuad_Verb &&
4127 other->fSegments[otherIndex].verb() == SkPath::kQuad_Verb) {
4128 coincidence.fTs[swap][0] = ts.fCoincidentT[0][0];
4129 coincidence.fTs[swap][1] = ts.fCoincidentT[0][1];
4130 coincidence.fTs[!swap][0] = ts.fCoincidentT[1][0];
4131 coincidence.fTs[!swap][1] = ts.fCoincidentT[1][1];
4132 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004133 }
4134
4135 void addCross(const Contour* crosser) {
4136#ifdef DEBUG_CROSS
4137 for (int index = 0; index < fCrosses.count(); ++index) {
4138 SkASSERT(fCrosses[index] != crosser);
4139 }
4140#endif
4141 *fCrosses.append() = crosser;
4142 }
4143
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004144 void addCubic(const SkPoint pts[4]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004145 fSegments.push_back().addCubic(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004146 fContainsCurves = true;
4147 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004148
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004149 int addLine(const SkPoint pts[2]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004150 fSegments.push_back().addLine(pts, fOperand, fXor);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004151 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004152 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004153
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004154 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
4155 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
4156 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004157
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004158 int addQuad(const SkPoint pts[3]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004159 fSegments.push_back().addQuad(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004160 fContainsCurves = true;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004161 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004162 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004163
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004164 int addT(int segIndex, double newT, Contour* other, int otherIndex) {
4165 containsIntercepts();
4166 return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex]);
4167 }
4168
caryclark@google.com73ca6242013-01-17 21:02:47 +00004169 int addUnsortableT(int segIndex, double newT, Contour* other, int otherIndex, bool start) {
4170 return fSegments[segIndex].addUnsortableT(newT, &other->fSegments[otherIndex], start);
4171 }
4172
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004173 const Bounds& bounds() const {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004174 return fBounds;
4175 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004176
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004177 void complete() {
4178 setBounds();
4179 fContainsIntercepts = false;
4180 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004181
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004182 void containsIntercepts() {
4183 fContainsIntercepts = true;
4184 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004185
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004186 bool crosses(const Contour* crosser) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004187 for (int index = 0; index < fCrosses.count(); ++index) {
4188 if (fCrosses[index] == crosser) {
4189 return true;
4190 }
4191 }
4192 return false;
4193 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004194
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004195 bool done() const {
4196 return fDone;
4197 }
4198
caryclark@google.comf839c032012-10-26 21:03:50 +00004199 const SkPoint& end() const {
4200 const Segment& segment = fSegments.back();
4201 return segment.pts()[segment.verb()];
4202 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004203
caryclark@google.com4eeda372012-12-06 21:47:48 +00004204 void findTooCloseToCall() {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004205 int segmentCount = fSegments.count();
4206 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004207 fSegments[sIndex].findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004208 }
4209 }
4210
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004211 void fixOtherTIndex() {
4212 int segmentCount = fSegments.count();
4213 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4214 fSegments[sIndex].fixOtherTIndex();
4215 }
4216 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004217
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004218 Segment* nonVerticalSegment(int& start, int& end) {
4219 int segmentCount = fSortedSegments.count();
4220 SkASSERT(segmentCount > 0);
4221 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4222 Segment* testSegment = fSortedSegments[sortedIndex];
4223 if (testSegment->done()) {
4224 continue;
4225 }
4226 start = end = 0;
4227 while (testSegment->nextCandidate(start, end)) {
4228 if (!testSegment->isVertical(start, end)) {
4229 return testSegment;
4230 }
4231 }
4232 }
4233 return NULL;
4234 }
4235
caryclark@google.com31143cf2012-11-09 22:14:19 +00004236 bool operand() const {
4237 return fOperand;
4238 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004239
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004240 void reset() {
4241 fSegments.reset();
4242 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004243 fContainsCurves = fContainsIntercepts = fDone = false;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004244 }
caryclark@google.comb9738012012-07-03 19:53:30 +00004245
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004246 void resolveCoincidence(SkTDArray<Contour*>& contourList) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004247 int count = fCoincidences.count();
4248 for (int index = 0; index < count; ++index) {
4249 Coincidence& coincidence = fCoincidences[index];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004250 SkASSERT(coincidence.fContours[0] == this);
caryclark@google.comb9738012012-07-03 19:53:30 +00004251 int thisIndex = coincidence.fSegments[0];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004252 Segment& thisOne = fSegments[thisIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004253 Contour* otherContour = coincidence.fContours[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004254 int otherIndex = coincidence.fSegments[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004255 Segment& other = otherContour->fSegments[otherIndex];
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004256 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004257 continue;
4258 }
caryclark@google.com47580692012-07-23 12:14:49 +00004259 #if DEBUG_CONCIDENT
4260 thisOne.debugShowTs();
4261 other.debugShowTs();
4262 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004263 double startT = coincidence.fTs[0][0];
4264 double endT = coincidence.fTs[0][1];
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004265 bool cancelers = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004266 if (startT > endT) {
4267 SkTSwap<double>(startT, endT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004268 cancelers ^= true; // FIXME: just assign true
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004269 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004270 SkASSERT(!approximately_negative(endT - startT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004271 double oStartT = coincidence.fTs[1][0];
4272 double oEndT = coincidence.fTs[1][1];
4273 if (oStartT > oEndT) {
4274 SkTSwap<double>(oStartT, oEndT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004275 cancelers ^= true;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004276 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004277 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00004278 bool opp = fOperand ^ otherContour->fOperand;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004279 if (cancelers && !opp) {
4280 // make sure startT and endT have t entries
caryclark@google.com2ddff932012-08-07 21:25:27 +00004281 if (startT > 0 || oEndT < 1
4282 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
4283 thisOne.addTPair(startT, other, oEndT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004284 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00004285 if (oStartT > 0 || endT < 1
4286 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
4287 other.addTPair(oStartT, thisOne, endT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004288 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004289 if (!thisOne.done() && !other.done()) {
4290 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4291 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004292 } else {
caryclark@google.com200c2112012-08-03 15:05:04 +00004293 if (startT > 0 || oStartT > 0
4294 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00004295 thisOne.addTPair(startT, other, oStartT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004296 }
caryclark@google.com200c2112012-08-03 15:05:04 +00004297 if (endT < 1 || oEndT < 1
4298 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00004299 other.addTPair(oEndT, thisOne, endT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004300 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004301 if (!thisOne.done() && !other.done()) {
4302 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4303 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004304 }
caryclark@google.com47580692012-07-23 12:14:49 +00004305 #if DEBUG_CONCIDENT
4306 thisOne.debugShowTs();
4307 other.debugShowTs();
4308 #endif
caryclark@google.com729e1c42012-11-21 21:36:34 +00004309 #if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004310 debugShowWindingValues(contourList);
4311 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004312 }
4313 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004314
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004315 // first pass, add missing T values
4316 // second pass, determine winding values of overlaps
4317 void addCoincidentPoints() {
4318 int count = fCoincidences.count();
4319 for (int index = 0; index < count; ++index) {
4320 Coincidence& coincidence = fCoincidences[index];
4321 SkASSERT(coincidence.fContours[0] == this);
4322 int thisIndex = coincidence.fSegments[0];
4323 Segment& thisOne = fSegments[thisIndex];
4324 Contour* otherContour = coincidence.fContours[1];
4325 int otherIndex = coincidence.fSegments[1];
4326 Segment& other = otherContour->fSegments[otherIndex];
4327 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
4328 // OPTIMIZATION: remove from array
4329 continue;
4330 }
4331 #if DEBUG_CONCIDENT
4332 thisOne.debugShowTs();
4333 other.debugShowTs();
4334 #endif
4335 double startT = coincidence.fTs[0][0];
4336 double endT = coincidence.fTs[0][1];
4337 bool cancelers;
4338 if ((cancelers = startT > endT)) {
4339 SkTSwap<double>(startT, endT);
4340 }
4341 SkASSERT(!approximately_negative(endT - startT));
4342 double oStartT = coincidence.fTs[1][0];
4343 double oEndT = coincidence.fTs[1][1];
4344 if (oStartT > oEndT) {
4345 SkTSwap<double>(oStartT, oEndT);
4346 cancelers ^= true;
4347 }
4348 SkASSERT(!approximately_negative(oEndT - oStartT));
4349 bool opp = fOperand ^ otherContour->fOperand;
4350 if (cancelers && !opp) {
4351 // make sure startT and endT have t entries
4352 if (startT > 0 || oEndT < 1
4353 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
4354 thisOne.addTPair(startT, other, oEndT, true);
4355 }
4356 if (oStartT > 0 || endT < 1
4357 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
4358 other.addTPair(oStartT, thisOne, endT, true);
4359 }
4360 } else {
4361 if (startT > 0 || oStartT > 0
4362 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
4363 thisOne.addTPair(startT, other, oStartT, true);
4364 }
4365 if (endT < 1 || oEndT < 1
4366 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
4367 other.addTPair(oEndT, thisOne, endT, true);
4368 }
4369 }
4370 #if DEBUG_CONCIDENT
4371 thisOne.debugShowTs();
4372 other.debugShowTs();
4373 #endif
4374 }
4375 }
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00004376
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004377 void calcCoincidentWinding() {
4378 int count = fCoincidences.count();
4379 for (int index = 0; index < count; ++index) {
4380 Coincidence& coincidence = fCoincidences[index];
4381 SkASSERT(coincidence.fContours[0] == this);
4382 int thisIndex = coincidence.fSegments[0];
4383 Segment& thisOne = fSegments[thisIndex];
4384 if (thisOne.done()) {
4385 continue;
4386 }
4387 Contour* otherContour = coincidence.fContours[1];
4388 int otherIndex = coincidence.fSegments[1];
4389 Segment& other = otherContour->fSegments[otherIndex];
4390 if (other.done()) {
4391 continue;
4392 }
4393 double startT = coincidence.fTs[0][0];
4394 double endT = coincidence.fTs[0][1];
4395 bool cancelers;
4396 if ((cancelers = startT > endT)) {
4397 SkTSwap<double>(startT, endT);
4398 }
4399 SkASSERT(!approximately_negative(endT - startT));
4400 double oStartT = coincidence.fTs[1][0];
4401 double oEndT = coincidence.fTs[1][1];
4402 if (oStartT > oEndT) {
4403 SkTSwap<double>(oStartT, oEndT);
4404 cancelers ^= true;
4405 }
4406 SkASSERT(!approximately_negative(oEndT - oStartT));
4407 bool opp = fOperand ^ otherContour->fOperand;
4408 if (cancelers && !opp) {
4409 // make sure startT and endT have t entries
4410 if (!thisOne.done() && !other.done()) {
4411 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4412 }
4413 } else {
4414 if (!thisOne.done() && !other.done()) {
4415 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4416 }
4417 }
4418 #if DEBUG_CONCIDENT
4419 thisOne.debugShowTs();
4420 other.debugShowTs();
4421 #endif
4422 }
4423 }
4424
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004425 SkTArray<Segment>& segments() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004426 return fSegments;
4427 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004428
caryclark@google.com235f56a2012-09-14 14:19:30 +00004429 void setOperand(bool isOp) {
4430 fOperand = isOp;
4431 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00004432
caryclark@google.com4eeda372012-12-06 21:47:48 +00004433 void setOppXor(bool isOppXor) {
4434 fOppXor = isOppXor;
4435 int segmentCount = fSegments.count();
4436 for (int test = 0; test < segmentCount; ++test) {
4437 fSegments[test].setOppXor(isOppXor);
4438 }
4439 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004440
caryclark@google.com235f56a2012-09-14 14:19:30 +00004441 void setXor(bool isXor) {
4442 fXor = isXor;
4443 }
4444
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004445 void sortSegments() {
4446 int segmentCount = fSegments.count();
4447 fSortedSegments.setReserve(segmentCount);
4448 for (int test = 0; test < segmentCount; ++test) {
4449 *fSortedSegments.append() = &fSegments[test];
4450 }
4451 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4452 fFirstSorted = 0;
4453 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004454
caryclark@google.comf839c032012-10-26 21:03:50 +00004455 const SkPoint& start() const {
4456 return fSegments.front().pts()[0];
4457 }
4458
4459 void toPath(PathWrapper& path) const {
4460 int segmentCount = fSegments.count();
4461 const SkPoint& pt = fSegments.front().pts()[0];
4462 path.deferredMove(pt);
4463 for (int test = 0; test < segmentCount; ++test) {
4464 fSegments[test].addCurveTo(0, 1, path, true);
4465 }
4466 path.close();
4467 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004468
caryclark@google.comf839c032012-10-26 21:03:50 +00004469 void toPartialBackward(PathWrapper& path) const {
4470 int segmentCount = fSegments.count();
4471 for (int test = segmentCount - 1; test >= 0; --test) {
4472 fSegments[test].addCurveTo(1, 0, path, true);
4473 }
4474 }
4475
4476 void toPartialForward(PathWrapper& path) const {
4477 int segmentCount = fSegments.count();
4478 for (int test = 0; test < segmentCount; ++test) {
4479 fSegments[test].addCurveTo(0, 1, path, true);
4480 }
4481 }
4482
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004483 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004484 int segmentCount = fSortedSegments.count();
4485 SkASSERT(segmentCount > 0);
caryclark@google.comf839c032012-10-26 21:03:50 +00004486 int sortedIndex = fFirstSorted;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004487 fDone = true; // may be cleared below
caryclark@google.comf839c032012-10-26 21:03:50 +00004488 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4489 Segment* testSegment = fSortedSegments[sortedIndex];
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004490 if (testSegment->done()) {
caryclark@google.comf839c032012-10-26 21:03:50 +00004491 if (sortedIndex == fFirstSorted) {
4492 ++fFirstSorted;
4493 }
4494 continue;
4495 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004496 fDone = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00004497 SkPoint testXY;
4498 testSegment->activeLeftTop(testXY);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004499 if (topStart) {
4500 if (testXY.fY < topLeft.fY) {
4501 continue;
4502 }
4503 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4504 continue;
4505 }
4506 if (bestXY.fY < testXY.fY) {
4507 continue;
4508 }
4509 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4510 continue;
4511 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004512 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004513 topStart = testSegment;
caryclark@google.comf839c032012-10-26 21:03:50 +00004514 bestXY = testXY;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004515 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004516 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004517
caryclark@google.com24bec792012-08-20 12:43:57 +00004518 Segment* undoneSegment(int& start, int& end) {
4519 int segmentCount = fSegments.count();
4520 for (int test = 0; test < segmentCount; ++test) {
4521 Segment* testSegment = &fSegments[test];
4522 if (testSegment->done()) {
4523 continue;
4524 }
4525 testSegment->undoneSpan(start, end);
4526 return testSegment;
4527 }
4528 return NULL;
4529 }
4530
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004531 int updateSegment(int index, const SkPoint* pts) {
4532 Segment& segment = fSegments[index];
4533 segment.updatePts(pts);
4534 return segment.verb() + 1;
4535 }
4536
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004537#if DEBUG_TEST
4538 SkTArray<Segment>& debugSegments() {
4539 return fSegments;
4540 }
4541#endif
4542
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004543#if DEBUG_DUMP
4544 void dump() {
4545 int i;
4546 const char className[] = "Contour";
4547 const int tab = 4;
4548 SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4549 for (i = 0; i < fSegments.count(); ++i) {
4550 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4551 className, i);
4552 fSegments[i].dump();
4553 }
4554 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4555 tab + sizeof(className), className,
4556 fBounds.fLeft, fBounds.fTop,
4557 fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004558 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4559 className, fContainsIntercepts);
4560 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4561 className, fContainsCurves);
4562 }
4563#endif
4564
caryclark@google.com027de222012-07-12 12:52:50 +00004565#if DEBUG_ACTIVE_SPANS
4566 void debugShowActiveSpans() {
4567 for (int index = 0; index < fSegments.count(); ++index) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004568 fSegments[index].debugShowActiveSpans();
caryclark@google.com027de222012-07-12 12:52:50 +00004569 }
4570 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004571
4572 void validateActiveSpans() {
4573 for (int index = 0; index < fSegments.count(); ++index) {
4574 fSegments[index].validateActiveSpans();
4575 }
4576 }
caryclark@google.com027de222012-07-12 12:52:50 +00004577#endif
4578
caryclark@google.com729e1c42012-11-21 21:36:34 +00004579#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004580 int debugShowWindingValues(int totalSegments, int ofInterest) {
4581 int count = fSegments.count();
4582 int sum = 0;
4583 for (int index = 0; index < count; ++index) {
4584 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4585 }
4586 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4587 return sum;
4588 }
4589
4590 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4591 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4592 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4593 int ofInterest = 1 << 5 | 1 << 8;
4594 int total = 0;
4595 int index;
4596 for (index = 0; index < contourList.count(); ++index) {
4597 total += contourList[index]->segments().count();
4598 }
4599 int sum = 0;
4600 for (index = 0; index < contourList.count(); ++index) {
4601 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4602 }
4603 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4604 }
4605#endif
4606
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004607protected:
4608 void setBounds() {
4609 int count = fSegments.count();
4610 if (count == 0) {
4611 SkDebugf("%s empty contour\n", __FUNCTION__);
4612 SkASSERT(0);
4613 // FIXME: delete empty contour?
4614 return;
4615 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004616 fBounds = fSegments.front().bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004617 for (int index = 1; index < count; ++index) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004618 fBounds.add(fSegments[index].bounds());
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004619 }
4620 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004621
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004622private:
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004623 SkTArray<Segment> fSegments;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004624 SkTDArray<Segment*> fSortedSegments;
4625 int fFirstSorted;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004626 SkTDArray<Coincidence> fCoincidences;
4627 SkTDArray<const Contour*> fCrosses;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004628 Bounds fBounds;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004629 bool fContainsIntercepts;
4630 bool fContainsCurves;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004631 bool fDone;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004632 bool fOperand; // true for the second argument to a binary operator
4633 bool fXor;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004634 bool fOppXor;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004635#if DEBUG_DUMP
4636 int fID;
4637#endif
4638};
4639
4640class EdgeBuilder {
4641public:
4642
caryclark@google.comf839c032012-10-26 21:03:50 +00004643EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
4644 : fPath(path.nativePath())
4645 , fContours(contours)
4646{
4647 init();
4648}
4649
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004650EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
caryclark@google.com235f56a2012-09-14 14:19:30 +00004651 : fPath(&path)
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004652 , fContours(contours)
4653{
caryclark@google.comf839c032012-10-26 21:03:50 +00004654 init();
4655}
4656
4657void init() {
4658 fCurrentContour = NULL;
4659 fOperand = false;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004660 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004661#if DEBUG_DUMP
4662 gContourID = 0;
4663 gSegmentID = 0;
4664#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00004665 fSecondHalf = preFetch();
4666}
4667
4668void addOperand(const SkPath& path) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00004669 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
4670 fPathVerbs.pop();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004671 fPath = &path;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004672 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004673 preFetch();
4674}
4675
4676void finish() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004677 walk();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004678 complete();
4679 if (fCurrentContour && !fCurrentContour->segments().count()) {
4680 fContours.pop_back();
4681 }
4682 // correct pointers in contours since fReducePts may have moved as it grew
4683 int cIndex = 0;
4684 int extraCount = fExtra.count();
4685 SkASSERT(extraCount == 0 || fExtra[0] == -1);
4686 int eIndex = 0;
4687 int rIndex = 0;
4688 while (++eIndex < extraCount) {
4689 int offset = fExtra[eIndex];
4690 if (offset < 0) {
4691 ++cIndex;
4692 continue;
4693 }
4694 fCurrentContour = &fContours[cIndex];
4695 rIndex += fCurrentContour->updateSegment(offset - 1,
4696 &fReducePts[rIndex]);
4697 }
4698 fExtra.reset(); // we're done with this
4699}
4700
4701ShapeOpMask xorMask() const {
caryclark@google.com729e1c42012-11-21 21:36:34 +00004702 return fXorMask[fOperand];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004703}
4704
4705protected:
4706
4707void complete() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004708 if (fCurrentContour && fCurrentContour->segments().count()) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004709 fCurrentContour->complete();
4710 fCurrentContour = NULL;
4711 }
4712}
4713
caryclark@google.com235f56a2012-09-14 14:19:30 +00004714// FIXME:remove once we can access path pts directly
4715int preFetch() {
4716 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004717 SkPoint pts[4];
4718 SkPath::Verb verb;
4719 do {
4720 verb = iter.next(pts);
4721 *fPathVerbs.append() = verb;
4722 if (verb == SkPath::kMove_Verb) {
4723 *fPathPts.append() = pts[0];
4724 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
4725 fPathPts.append(verb, &pts[1]);
4726 }
4727 } while (verb != SkPath::kDone_Verb);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004728 return fPathVerbs.count() - 1;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004729}
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004730
caryclark@google.com235f56a2012-09-14 14:19:30 +00004731void walk() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004732 SkPath::Verb reducedVerb;
4733 uint8_t* verbPtr = fPathVerbs.begin();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004734 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004735 const SkPoint* pointsPtr = fPathPts.begin();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004736 const SkPoint* finalCurveStart = NULL;
4737 const SkPoint* finalCurveEnd = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004738 SkPath::Verb verb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004739 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
4740 switch (verb) {
4741 case SkPath::kMove_Verb:
4742 complete();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004743 if (!fCurrentContour) {
4744 fCurrentContour = fContours.push_back_n(1);
caryclark@google.com235f56a2012-09-14 14:19:30 +00004745 fCurrentContour->setOperand(fOperand);
caryclark@google.com729e1c42012-11-21 21:36:34 +00004746 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004747 *fExtra.append() = -1; // start new contour
4748 }
caryclark@google.com59823f72012-08-09 18:17:47 +00004749 finalCurveEnd = pointsPtr++;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004750 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004751 case SkPath::kLine_Verb:
4752 // skip degenerate points
4753 if (pointsPtr[-1].fX != pointsPtr[0].fX
4754 || pointsPtr[-1].fY != pointsPtr[0].fY) {
4755 fCurrentContour->addLine(&pointsPtr[-1]);
4756 }
4757 break;
4758 case SkPath::kQuad_Verb:
rmistry@google.comd6176b02012-08-23 18:14:13 +00004759
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004760 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
4761 if (reducedVerb == 0) {
4762 break; // skip degenerate points
4763 }
4764 if (reducedVerb == 1) {
rmistry@google.comd6176b02012-08-23 18:14:13 +00004765 *fExtra.append() =
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004766 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004767 break;
4768 }
4769 fCurrentContour->addQuad(&pointsPtr[-1]);
4770 break;
4771 case SkPath::kCubic_Verb:
4772 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
4773 if (reducedVerb == 0) {
4774 break; // skip degenerate points
4775 }
4776 if (reducedVerb == 1) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004777 *fExtra.append() =
4778 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004779 break;
4780 }
4781 if (reducedVerb == 2) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004782 *fExtra.append() =
4783 fCurrentContour->addQuad(fReducePts.end() - 3);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004784 break;
4785 }
4786 fCurrentContour->addCubic(&pointsPtr[-1]);
4787 break;
4788 case SkPath::kClose_Verb:
4789 SkASSERT(fCurrentContour);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004790 if (finalCurveStart && finalCurveEnd
4791 && *finalCurveStart != *finalCurveEnd) {
4792 *fReducePts.append() = *finalCurveStart;
4793 *fReducePts.append() = *finalCurveEnd;
4794 *fExtra.append() =
4795 fCurrentContour->addLine(fReducePts.end() - 2);
4796 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004797 complete();
caryclark@google.com31143cf2012-11-09 22:14:19 +00004798 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004799 default:
4800 SkDEBUGFAIL("bad verb");
4801 return;
4802 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004803 finalCurveStart = &pointsPtr[verb - 1];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004804 pointsPtr += verb;
4805 SkASSERT(fCurrentContour);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004806 nextVerb:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004807 if (verbPtr == endOfFirstHalf) {
4808 fOperand = true;
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004809 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004810 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004811}
4812
4813private:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004814 const SkPath* fPath;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004815 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004816 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004817 Contour* fCurrentContour;
4818 SkTArray<Contour>& fContours;
4819 SkTDArray<SkPoint> fReducePts; // segments created on the fly
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004820 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
caryclark@google.com729e1c42012-11-21 21:36:34 +00004821 ShapeOpMask fXorMask[2];
caryclark@google.com235f56a2012-09-14 14:19:30 +00004822 int fSecondHalf;
4823 bool fOperand;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004824};
4825
4826class Work {
4827public:
4828 enum SegmentType {
4829 kHorizontalLine_Segment = -1,
4830 kVerticalLine_Segment = 0,
4831 kLine_Segment = SkPath::kLine_Verb,
4832 kQuad_Segment = SkPath::kQuad_Verb,
4833 kCubic_Segment = SkPath::kCubic_Verb,
4834 };
rmistry@google.comd6176b02012-08-23 18:14:13 +00004835
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004836 void addCoincident(Work& other, const Intersections& ts, bool swap) {
4837 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
4838 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004839
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004840 // FIXME: does it make sense to write otherIndex now if we're going to
4841 // fix it up later?
4842 void addOtherT(int index, double otherT, int otherIndex) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004843 fContour->addOtherT(fIndex, index, otherT, otherIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004844 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004845
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004846 // Avoid collapsing t values that are close to the same since
4847 // we walk ts to describe consecutive intersections. Since a pair of ts can
4848 // be nearly equal, any problems caused by this should be taken care
4849 // of later.
4850 // On the edge or out of range values are negative; add 2 to get end
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004851 int addT(double newT, const Work& other) {
4852 return fContour->addT(fIndex, newT, other.fContour, other.fIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004853 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004854
caryclark@google.com73ca6242013-01-17 21:02:47 +00004855 int addUnsortableT(double newT, const Work& other, bool start) {
4856 return fContour->addUnsortableT(fIndex, newT, other.fContour, other.fIndex, start);
4857 }
4858
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004859 bool advance() {
4860 return ++fIndex < fLast;
4861 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004862
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004863 SkScalar bottom() const {
4864 return bounds().fBottom;
4865 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004866
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004867 const Bounds& bounds() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004868 return fContour->segments()[fIndex].bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004869 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004870
caryclark@google.com73ca6242013-01-17 21:02:47 +00004871#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004872 const SkPoint* cubic() const {
4873 return fCubic;
4874 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00004875#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004876
4877 void init(Contour* contour) {
4878 fContour = contour;
4879 fIndex = 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004880 fLast = contour->segments().count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004881 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004882
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00004883 bool isAdjacent(const Work& next) {
4884 return fContour == next.fContour && fIndex + 1 == next.fIndex;
4885 }
4886
4887 bool isFirstLast(const Work& next) {
4888 return fContour == next.fContour && fIndex == 0
4889 && next.fIndex == fLast - 1;
4890 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004891
4892 SkScalar left() const {
4893 return bounds().fLeft;
4894 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004895
caryclark@google.com73ca6242013-01-17 21:02:47 +00004896#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004897 void promoteToCubic() {
4898 fCubic[0] = pts()[0];
4899 fCubic[2] = pts()[1];
4900 fCubic[3] = pts()[2];
4901 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
4902 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
4903 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
4904 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
4905 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00004906#endif
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004907
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004908 const SkPoint* pts() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004909 return fContour->segments()[fIndex].pts();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004910 }
4911
4912 SkScalar right() const {
4913 return bounds().fRight;
4914 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004915
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004916 ptrdiff_t segmentIndex() const {
4917 return fIndex;
4918 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004919
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004920 SegmentType segmentType() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004921 const Segment& segment = fContour->segments()[fIndex];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004922 SegmentType type = (SegmentType) segment.verb();
4923 if (type != kLine_Segment) {
4924 return type;
4925 }
4926 if (segment.isHorizontal()) {
4927 return kHorizontalLine_Segment;
4928 }
4929 if (segment.isVertical()) {
4930 return kVerticalLine_Segment;
4931 }
4932 return kLine_Segment;
4933 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004934
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004935 bool startAfter(const Work& after) {
4936 fIndex = after.fIndex;
4937 return advance();
4938 }
4939
4940 SkScalar top() const {
4941 return bounds().fTop;
4942 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004943
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004944 SkPath::Verb verb() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004945 return fContour->segments()[fIndex].verb();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004946 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004947
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004948 SkScalar x() const {
4949 return bounds().fLeft;
4950 }
4951
4952 bool xFlipped() const {
4953 return x() != pts()[0].fX;
4954 }
4955
4956 SkScalar y() const {
4957 return bounds().fTop;
4958 }
4959
4960 bool yFlipped() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004961 return y() != pts()[0].fY;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004962 }
4963
4964protected:
4965 Contour* fContour;
caryclark@google.com73ca6242013-01-17 21:02:47 +00004966#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004967 SkPoint fCubic[4];
caryclark@google.com73ca6242013-01-17 21:02:47 +00004968#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004969 int fIndex;
4970 int fLast;
4971};
4972
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00004973#if DEBUG_ADD_INTERSECTING_TS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004974static void debugShowLineIntersection(int pts, const Work& wt,
4975 const Work& wn, const double wtTs[2], const double wnTs[2]) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004976 return;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004977 if (!pts) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004978 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n",
4979 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
4980 wt.pts()[1].fX, wt.pts()[1].fY, wn.pts()[0].fX, wn.pts()[0].fY,
4981 wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004982 return;
4983 }
4984 SkPoint wtOutPt, wnOutPt;
4985 LineXYAtT(wt.pts(), wtTs[0], &wtOutPt);
4986 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
caryclark@google.coma461ff02012-10-11 12:54:23 +00004987 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 +00004988 __FUNCTION__,
4989 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
4990 wt.pts()[1].fX, wt.pts()[1].fY, wtOutPt.fX, wtOutPt.fY);
4991 if (pts == 2) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00004992 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004993 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00004994 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004995 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
4996 wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
4997 if (pts == 2) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00004998 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
4999 }
5000 SkDebugf("\n");
5001}
5002
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005003static void debugShowQuadLineIntersection(int pts, const Work& wt,
5004 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5005 if (!pts) {
5006 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
caryclark@google.com0b7da432012-10-31 19:00:20 +00005007 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005008 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
5009 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005010 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005011 return;
5012 }
5013 SkPoint wtOutPt, wnOutPt;
5014 QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5015 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5016 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5017 __FUNCTION__,
5018 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5019 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
5020 wtOutPt.fX, wtOutPt.fY);
5021 if (pts == 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005022 QuadXYAtT(wt.pts(), wtTs[1], &wtOutPt);
5023 SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", wtTs[1], wtOutPt.fX, wtOutPt.fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005024 }
5025 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5026 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5027 wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
5028 if (pts == 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005029 LineXYAtT(wn.pts(), wnTs[1], &wnOutPt);
5030 SkDebugf(" wnTs[1]=%1.9g (%1.9g,%1.9g)", wnTs[1], wnOutPt.fX, wnOutPt.fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005031 }
5032 SkDebugf("\n");
5033}
5034
caryclark@google.com73ca6242013-01-17 21:02:47 +00005035// FIXME: show more than two intersection points
caryclark@google.coma461ff02012-10-11 12:54:23 +00005036static void debugShowQuadIntersection(int pts, const Work& wt,
5037 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5038 if (!pts) {
5039 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5040 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5041 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
skia.committer@gmail.com5b6f9162012-10-12 02:01:15 +00005042 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.coma461ff02012-10-11 12:54:23 +00005043 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005044 wn.pts()[2].fX, wn.pts()[2].fY );
caryclark@google.coma461ff02012-10-11 12:54:23 +00005045 return;
5046 }
5047 SkPoint wtOutPt, wnOutPt;
5048 QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5049 QuadXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5050 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5051 __FUNCTION__,
5052 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5053 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
5054 wtOutPt.fX, wtOutPt.fY);
5055 if (pts == 2) {
5056 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
5057 }
5058 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5059 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5060 wn.pts()[1].fX, wn.pts()[1].fY, wn.pts()[2].fX, wn.pts()[2].fY,
5061 wnOutPt.fX, wnOutPt.fY);
5062 if (pts == 2) {
5063 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005064 }
caryclark@google.comb9738012012-07-03 19:53:30 +00005065 SkDebugf("\n");
5066}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005067
5068static void debugShowCubicLineIntersection(int pts, const Work& wt,
5069 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5070 if (!pts) {
5071 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5072 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
5073 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5074 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5075 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
5076 return;
5077 }
5078 SkPoint wtOutPt, wnOutPt;
5079 CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5080 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5081 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)",
5082 __FUNCTION__,
5083 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5084 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5085 wtOutPt.fX, wtOutPt.fY);
5086 if (pts == 2) {
5087 CubicXYAtT(wt.pts(), wtTs[1], &wtOutPt);
5088 SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", wtTs[1], wtOutPt.fX, wtOutPt.fY);
5089 }
5090 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5091 wtTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5092 wnOutPt.fX, wnOutPt.fY);
5093 if (pts == 2) {
5094 LineXYAtT(wn.pts(), wnTs[1], &wnOutPt);
5095 SkDebugf(" wnTs[1]=%1.9g (%1.9g,%1.9g)", wnTs[1], wnOutPt.fX, wnOutPt.fY);
5096 }
5097 SkDebugf("\n");
5098}
5099
5100#if APPROXIMATE_CUBICS
5101// FIXME: show more than two intersection points
5102static void debugShowCubicQuadIntersection(int pts, const Work& wt,
5103 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5104 if (!pts) {
5105 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5106 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5107 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5108 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5109 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5110 wn.pts()[2].fX, wn.pts()[2].fY );
5111 return;
5112 }
5113 SkPoint wtOutPt, wnOutPt;
5114 CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5115 CubicXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5116 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)",
5117 __FUNCTION__,
5118 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5119 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5120 wtOutPt.fX, wtOutPt.fY);
5121 if (pts == 2) {
5122 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
5123 }
5124 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5125 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5126 wn.pts()[2].fX, wn.pts()[2].fY,
5127 wnOutPt.fX, wnOutPt.fY);
5128 if (pts == 2) {
5129 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
5130 }
5131 SkDebugf("\n");
5132}
5133
5134// FIXME: show more than two intersection points
5135static void debugShowCubicIntersection(int pts, const Work& wt,
5136 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5137 if (!pts) {
5138 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5139 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5140 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5141 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5142 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5143 wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY );
5144 return;
5145 }
5146 SkPoint wtOutPt, wnOutPt;
5147 CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5148 CubicXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5149 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)",
5150 __FUNCTION__,
5151 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5152 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5153 wtOutPt.fX, wtOutPt.fY);
5154 if (pts == 2) {
5155 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
5156 }
5157 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5158 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5159 wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY,
5160 wnOutPt.fX, wnOutPt.fY);
5161 if (pts == 2) {
5162 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
5163 }
5164 SkDebugf("\n");
5165}
5166#endif
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005167#else
5168static void debugShowLineIntersection(int , const Work& ,
5169 const Work& , const double [2], const double [2]) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005170}
caryclark@google.coma461ff02012-10-11 12:54:23 +00005171
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005172static void debugShowQuadLineIntersection(int , const Work& ,
5173 const Work& , const double [2], const double [2]) {
5174}
5175
caryclark@google.coma461ff02012-10-11 12:54:23 +00005176static void debugShowQuadIntersection(int , const Work& ,
5177 const Work& , const double [2], const double [2]) {
5178}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005179
5180static void debugShowCubicLineIntersection(int , const Work& ,
5181 const Work& , const double [2], const double [2]) {
5182}
5183
5184#if APPROXIMATE_CUBICS
5185static void debugShowCubicQuadIntersection(int , const Work& ,
5186 const Work& , const double [2], const double [2]) {
5187}
5188
5189static void debugShowCubicIntersection(int , const Work& ,
5190 const Work& , const double [2], const double [2]) {
5191}
5192#endif
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005193#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005194
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005195static bool addIntersectTs(Contour* test, Contour* next) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005196
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005197 if (test != next) {
5198 if (test->bounds().fBottom < next->bounds().fTop) {
5199 return false;
5200 }
5201 if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5202 return true;
5203 }
5204 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005205 Work wt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005206 wt.init(test);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005207 bool foundCommonContour = test == next;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005208 do {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005209 Work wn;
5210 wn.init(next);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005211 if (test == next && !wn.startAfter(wt)) {
5212 continue;
5213 }
5214 do {
5215 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5216 continue;
5217 }
5218 int pts;
5219 Intersections ts;
5220 bool swap = false;
5221 switch (wt.segmentType()) {
5222 case Work::kHorizontalLine_Segment:
5223 swap = true;
5224 switch (wn.segmentType()) {
5225 case Work::kHorizontalLine_Segment:
5226 case Work::kVerticalLine_Segment:
5227 case Work::kLine_Segment: {
5228 pts = HLineIntersect(wn.pts(), wt.left(),
5229 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005230 debugShowLineIntersection(pts, wt, wn,
5231 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005232 break;
5233 }
5234 case Work::kQuad_Segment: {
5235 pts = HQuadIntersect(wn.pts(), wt.left(),
5236 wt.right(), wt.y(), wt.xFlipped(), ts);
5237 break;
5238 }
5239 case Work::kCubic_Segment: {
5240 pts = HCubicIntersect(wn.pts(), wt.left(),
5241 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005242 debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005243 break;
5244 }
5245 default:
5246 SkASSERT(0);
5247 }
5248 break;
5249 case Work::kVerticalLine_Segment:
5250 swap = true;
5251 switch (wn.segmentType()) {
5252 case Work::kHorizontalLine_Segment:
5253 case Work::kVerticalLine_Segment:
5254 case Work::kLine_Segment: {
5255 pts = VLineIntersect(wn.pts(), wt.top(),
5256 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005257 debugShowLineIntersection(pts, wt, wn,
5258 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005259 break;
5260 }
5261 case Work::kQuad_Segment: {
5262 pts = VQuadIntersect(wn.pts(), wt.top(),
5263 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5264 break;
5265 }
5266 case Work::kCubic_Segment: {
5267 pts = VCubicIntersect(wn.pts(), wt.top(),
5268 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005269 debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005270 break;
5271 }
5272 default:
5273 SkASSERT(0);
5274 }
5275 break;
5276 case Work::kLine_Segment:
5277 switch (wn.segmentType()) {
5278 case Work::kHorizontalLine_Segment:
5279 pts = HLineIntersect(wt.pts(), wn.left(),
5280 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005281 debugShowLineIntersection(pts, wt, wn,
5282 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005283 break;
5284 case Work::kVerticalLine_Segment:
5285 pts = VLineIntersect(wt.pts(), wn.top(),
5286 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005287 debugShowLineIntersection(pts, wt, wn,
5288 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005289 break;
5290 case Work::kLine_Segment: {
5291 pts = LineIntersect(wt.pts(), wn.pts(), ts);
5292 debugShowLineIntersection(pts, wt, wn,
5293 ts.fT[1], ts.fT[0]);
5294 break;
5295 }
5296 case Work::kQuad_Segment: {
5297 swap = true;
5298 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005299 debugShowQuadLineIntersection(pts, wn, wt,
5300 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005301 break;
5302 }
5303 case Work::kCubic_Segment: {
5304 swap = true;
5305 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005306 debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005307 break;
5308 }
5309 default:
5310 SkASSERT(0);
5311 }
5312 break;
5313 case Work::kQuad_Segment:
5314 switch (wn.segmentType()) {
5315 case Work::kHorizontalLine_Segment:
5316 pts = HQuadIntersect(wt.pts(), wn.left(),
5317 wn.right(), wn.y(), wn.xFlipped(), ts);
5318 break;
5319 case Work::kVerticalLine_Segment:
5320 pts = VQuadIntersect(wt.pts(), wn.top(),
5321 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5322 break;
5323 case Work::kLine_Segment: {
5324 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005325 debugShowQuadLineIntersection(pts, wt, wn,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005326 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005327 break;
5328 }
5329 case Work::kQuad_Segment: {
5330 pts = QuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005331 debugShowQuadIntersection(pts, wt, wn,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005332 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005333 break;
5334 }
5335 case Work::kCubic_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005336 #if APPROXIMATE_CUBICS
5337 swap = true;
5338 pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts);
5339 debugShowCubicQuadIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
5340 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005341 wt.promoteToCubic();
5342 pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005343 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005344 break;
5345 }
5346 default:
5347 SkASSERT(0);
5348 }
5349 break;
5350 case Work::kCubic_Segment:
5351 switch (wn.segmentType()) {
5352 case Work::kHorizontalLine_Segment:
5353 pts = HCubicIntersect(wt.pts(), wn.left(),
5354 wn.right(), wn.y(), wn.xFlipped(), ts);
5355 break;
5356 case Work::kVerticalLine_Segment:
5357 pts = VCubicIntersect(wt.pts(), wn.top(),
5358 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005359 debugShowCubicLineIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005360 break;
5361 case Work::kLine_Segment: {
5362 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005363 debugShowCubicLineIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005364 break;
5365 }
5366 case Work::kQuad_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005367 #if APPROXIMATE_CUBICS
5368 pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts);
5369 debugShowCubicQuadIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
5370 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005371 wn.promoteToCubic();
5372 pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005373 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005374 break;
5375 }
5376 case Work::kCubic_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005377 #if APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005378 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005379 debugShowCubicIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
5380 #else
5381 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
5382 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005383 break;
5384 }
5385 default:
5386 SkASSERT(0);
5387 }
5388 break;
5389 default:
5390 SkASSERT(0);
5391 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005392 if (!foundCommonContour && pts > 0) {
5393 test->addCross(next);
5394 next->addCross(test);
5395 foundCommonContour = true;
5396 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005397 // in addition to recording T values, record matching segment
caryclark@google.com73ca6242013-01-17 21:02:47 +00005398 if (ts.unsortable()) {
5399 bool start = true;
5400 for (int pt = 0; pt < ts.used(); ++pt) {
5401 // FIXME: if unsortable, the other points to the original. This logic is
5402 // untested downstream.
5403 int testTAt = wt.addUnsortableT(ts.fT[swap][pt], wt, start);
5404 wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt);
5405 testTAt = wn.addUnsortableT(ts.fT[!swap][pt], wn, start ^ ts.fFlip);
5406 wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt);
5407 start ^= true;
5408 }
5409 continue;
5410 }
caryclark@google.com32546db2012-08-31 20:55:07 +00005411 if (pts == 2) {
5412 if (wn.segmentType() <= Work::kLine_Segment
5413 && wt.segmentType() <= Work::kLine_Segment) {
5414 wt.addCoincident(wn, ts, swap);
5415 continue;
5416 }
5417 if (wn.segmentType() == Work::kQuad_Segment
5418 && wt.segmentType() == Work::kQuad_Segment
5419 && ts.coincidentUsed() == 2) {
5420 wt.addCoincident(wn, ts, swap);
5421 continue;
5422 }
5423
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00005424 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00005425 for (int pt = 0; pt < pts; ++pt) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005426 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5427 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005428 int testTAt = wt.addT(ts.fT[swap][pt], wn);
5429 int nextTAt = wn.addT(ts.fT[!swap][pt], wt);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005430 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
5431 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005432 }
5433 } while (wn.advance());
5434 } while (wt.advance());
5435 return true;
5436}
5437
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005438// resolve any coincident pairs found while intersecting, and
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005439// see if coincidence is formed by clipping non-concident segments
caryclark@google.com4eeda372012-12-06 21:47:48 +00005440static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005441 int contourCount = contourList.count();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005442#if ONE_PASS_COINCIDENCE_CHECK
caryclark@google.comf25edfe2012-06-01 18:20:10 +00005443 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005444 Contour* contour = contourList[cIndex];
caryclark@google.com7ba591e2012-11-20 14:21:54 +00005445 contour->resolveCoincidence(contourList);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005446 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005447#else
5448 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5449 Contour* contour = contourList[cIndex];
5450 contour->addCoincidentPoints();
5451 }
5452 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5453 Contour* contour = contourList[cIndex];
5454 contour->calcCoincidentWinding();
5455 }
5456#endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005457 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5458 Contour* contour = contourList[cIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00005459 contour->findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005460 }
5461}
5462
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005463static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005464 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005465 SkPoint basePt;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005466 double tAtMid = current->tAtMid(index, endIndex, mid);
5467 current->xyAtT(tAtMid, basePt);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005468 int contourCount = contourList.count();
5469 SkScalar bestY = SK_ScalarMin;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005470 Segment* bestSeg = NULL;
5471 int bestTIndex;
5472 bool bestOpp;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005473 bool hitSomething = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005474 for (int cTest = 0; cTest < contourCount; ++cTest) {
5475 Contour* contour = contourList[cTest];
5476 bool testOpp = contour->operand() ^ current->operand() ^ opp;
5477 if (basePt.fY < contour->bounds().fTop) {
5478 continue;
5479 }
5480 if (bestY > contour->bounds().fBottom) {
5481 continue;
5482 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005483 int segmentCount = contour->segments().count();
5484 for (int test = 0; test < segmentCount; ++test) {
5485 Segment* testSeg = &contour->segments()[test];
5486 SkScalar testY = bestY;
5487 double testHit;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005488 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
5489 testOpp, testSeg == current);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005490 if (testTIndex < 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005491 if (testTIndex == SK_MinS32) {
5492 hitSomething = true;
5493 bestSeg = NULL;
5494 goto abortContours; // vertical encountered, return and try different point
5495 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005496 continue;
5497 }
5498 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005499 double baseT = current->t(index);
5500 double endT = current->t(endIndex);
5501 double newMid = (testHit - baseT) / (endT - baseT);
5502#if DEBUG_WINDING
5503 SkPoint midXY, newXY;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005504 double midT = current->tAtMid(index, endIndex, mid);
5505 current->xyAtT(midT, midXY);
5506 double newMidT = current->tAtMid(index, endIndex, newMid);
5507 current->xyAtT(newMidT, newXY);
caryclark@google.com3586ece2012-12-27 18:46:58 +00005508 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
5509 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
5510 current->debugID(), mid, newMid,
5511 baseT, current->xAtT(index), current->yAtT(index),
5512 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
5513 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
5514 endT, current->xAtT(endIndex), current->yAtT(endIndex));
5515#endif
5516 mid = newMid * 2; // calling loop with divide by 2 before continuing
5517 return SK_MinS32;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005518 }
5519 bestSeg = testSeg;
5520 bestHit = testHit;
5521 bestOpp = testOpp;
5522 bestTIndex = testTIndex;
5523 bestY = testY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005524 }
5525 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005526abortContours:
caryclark@google.com10227bf2012-12-28 22:10:41 +00005527 int result;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005528 if (!bestSeg) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00005529 result = hitSomething ? SK_MinS32 : 0;
5530 } else {
5531 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
5532 current = bestSeg;
5533 index = bestTIndex;
5534 endIndex = bestSeg->nextSpan(bestTIndex, 1);
5535 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
5536 tryAgain = true;
5537 return 0;
5538 }
5539 result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
5540 SkASSERT(bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005541 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005542 double baseT = current->t(index);
5543 double endT = current->t(endIndex);
5544 bestHit = baseT + mid * (endT - baseT);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005545 return result;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005546}
5547
caryclark@google.com24bec792012-08-20 12:43:57 +00005548static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
5549 int contourCount = contourList.count();
5550 Segment* result;
5551 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5552 Contour* contour = contourList[cIndex];
5553 result = contour->undoneSegment(start, end);
5554 if (result) {
5555 return result;
5556 }
5557 }
5558 return NULL;
5559}
5560
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005561#define OLD_FIND_CHASE 1
caryclark@google.com24bec792012-08-20 12:43:57 +00005562
caryclark@google.com31143cf2012-11-09 22:14:19 +00005563static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005564 while (chase.count()) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005565 Span* span;
5566 chase.pop(&span);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005567 const Span& backPtr = span->fOther->span(span->fOtherIndex);
5568 Segment* segment = backPtr.fOther;
5569 tIndex = backPtr.fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005570 SkTDArray<Angle> angles;
5571 int done = 0;
5572 if (segment->activeAngle(tIndex, done, angles)) {
5573 Angle* last = angles.end() - 1;
5574 tIndex = last->start();
5575 endIndex = last->end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005576 #if TRY_ROTATE
5577 *chase.insert(0) = span;
5578 #else
5579 *chase.append() = span;
5580 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005581 return last->segment();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005582 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005583 if (done == angles.count()) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00005584 continue;
5585 }
5586 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005587 bool sortable = Segment::SortAngles(angles, sorted);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005588 int angleCount = sorted.count();
caryclark@google.com03f97062012-08-21 13:13:52 +00005589#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005590 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00005591#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005592 if (!sortable) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005593 continue;
5594 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005595 // find first angle, initialize winding to computed fWindSum
5596 int firstIndex = -1;
5597 const Angle* angle;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005598#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005599 int winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005600 do {
5601 angle = sorted[++firstIndex];
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005602 segment = angle->segment();
5603 winding = segment->windSum(angle);
5604 } while (winding == SK_MinS32);
5605 int spanWinding = segment->spanSign(angle->start(), angle->end());
5606 #if DEBUG_WINDING
caryclark@google.com31143cf2012-11-09 22:14:19 +00005607 SkDebugf("%s winding=%d spanWinding=%d\n",
5608 __FUNCTION__, winding, spanWinding);
caryclark@google.com47580692012-07-23 12:14:49 +00005609 #endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005610 // turn span winding into contour winding
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005611 if (spanWinding * winding < 0) {
5612 winding += spanWinding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005613 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005614 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005615 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005616 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005617 // we care about first sign and whether wind sum indicates this
5618 // edge is inside or outside. Maybe need to pass span winding
5619 // or first winding or something into this function?
5620 // advance to first undone angle, then return it and winding
5621 // (to set whether edges are active or not)
5622 int nextIndex = firstIndex + 1;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005623 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005624 angle = sorted[firstIndex];
caryclark@google.com2ddff932012-08-07 21:25:27 +00005625 winding -= angle->segment()->spanSign(angle);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005626#else
5627 do {
5628 angle = sorted[++firstIndex];
5629 segment = angle->segment();
5630 } while (segment->windSum(angle) == SK_MinS32);
5631 #if DEBUG_SORT
5632 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5633 #endif
5634 int sumWinding = segment->updateWindingReverse(angle);
5635 int nextIndex = firstIndex + 1;
5636 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5637 Segment* first = NULL;
5638#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005639 do {
5640 SkASSERT(nextIndex != firstIndex);
5641 if (nextIndex == angleCount) {
5642 nextIndex = 0;
5643 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005644 angle = sorted[nextIndex];
caryclark@google.com9764cc62012-07-12 19:29:45 +00005645 segment = angle->segment();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005646#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005647 int maxWinding = winding;
caryclark@google.com2ddff932012-08-07 21:25:27 +00005648 winding -= segment->spanSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005649 #if DEBUG_SORT
caryclark@google.com2ddff932012-08-07 21:25:27 +00005650 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
5651 segment->debugID(), maxWinding, winding, angle->sign());
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005652 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005653 tIndex = angle->start();
5654 endIndex = angle->end();
5655 int lesser = SkMin32(tIndex, endIndex);
5656 const Span& nextSpan = segment->span(lesser);
5657 if (!nextSpan.fDone) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005658#if 1
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005659 // FIXME: this be wrong? assign startWinding if edge is in
caryclark@google.com9764cc62012-07-12 19:29:45 +00005660 // same direction. If the direction is opposite, winding to
5661 // assign is flipped sign or +/- 1?
caryclark@google.com59823f72012-08-09 18:17:47 +00005662 if (useInnerWinding(maxWinding, winding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005663 maxWinding = winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005664 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005665 segment->markAndChaseWinding(angle, maxWinding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005666#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005667 break;
5668 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005669#else
5670 int start = angle->start();
5671 int end = angle->end();
5672 int maxWinding;
5673 segment->setUpWinding(start, end, maxWinding, sumWinding);
5674 if (!segment->done(angle)) {
5675 if (!first) {
5676 first = segment;
5677 tIndex = start;
5678 endIndex = end;
5679 }
5680 (void) segment->markAngle(maxWinding, sumWinding, true, angle);
5681 }
5682#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005683 } while (++nextIndex != lastIndex);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005684 #if TRY_ROTATE
5685 *chase.insert(0) = span;
5686 #else
5687 *chase.append() = span;
5688 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005689 return segment;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005690 }
5691 return NULL;
5692}
5693
caryclark@google.com027de222012-07-12 12:52:50 +00005694#if DEBUG_ACTIVE_SPANS
5695static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005696 int index;
5697 for (index = 0; index < contourList.count(); ++ index) {
caryclark@google.com027de222012-07-12 12:52:50 +00005698 contourList[index]->debugShowActiveSpans();
5699 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005700 for (index = 0; index < contourList.count(); ++ index) {
5701 contourList[index]->validateActiveSpans();
5702 }
caryclark@google.com027de222012-07-12 12:52:50 +00005703}
5704#endif
5705
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005706static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005707 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005708 Segment* result;
5709 do {
caryclark@google.comf839c032012-10-26 21:03:50 +00005710 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005711 int contourCount = contourList.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00005712 Segment* topStart = NULL;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005713 done = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00005714 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5715 Contour* contour = contourList[cIndex];
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005716 if (contour->done()) {
5717 continue;
5718 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005719 const Bounds& bounds = contour->bounds();
5720 if (bounds.fBottom < topLeft.fY) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005721 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005722 continue;
5723 }
5724 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005725 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005726 continue;
5727 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005728 contour->topSortableSegment(topLeft, bestXY, topStart);
5729 if (!contour->done()) {
5730 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005731 }
5732 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005733 if (!topStart) {
5734 return NULL;
5735 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005736 topLeft = bestXY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005737 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005738 } while (!result);
5739 return result;
5740}
caryclark@google.com31143cf2012-11-09 22:14:19 +00005741
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005742static int rightAngleWinding(SkTDArray<Contour*>& contourList,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005743 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005744 bool opp) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005745 double test = 0.9;
5746 int contourWinding;
5747 do {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005748 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
5749 tryAgain, test, opp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005750 if (contourWinding != SK_MinS32 || tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005751 return contourWinding;
5752 }
5753 test /= 2;
5754 } while (!approximately_negative(test));
5755 SkASSERT(0); // should be OK to comment out, but interested when this hits
5756 return contourWinding;
5757}
5758
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005759static void skipVertical(SkTDArray<Contour*>& contourList,
5760 Segment*& current, int& index, int& endIndex) {
5761 if (!current->isVertical(index, endIndex)) {
5762 return;
5763 }
5764 int contourCount = contourList.count();
5765 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5766 Contour* contour = contourList[cIndex];
5767 if (contour->done()) {
5768 continue;
5769 }
5770 current = contour->nonVerticalSegment(index, endIndex);
5771 if (current) {
5772 return;
5773 }
5774 }
5775}
5776
caryclark@google.com3586ece2012-12-27 18:46:58 +00005777static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005778 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
5779 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
5780 true);
5781 if (!current) {
5782 return NULL;
5783 }
5784 if (firstContour) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005785 current->initWinding(index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005786 firstContour = false;
5787 return current;
5788 }
5789 int minIndex = SkMin32(index, endIndex);
5790 int sumWinding = current->windSum(minIndex);
5791 if (sumWinding != SK_MinS32) {
5792 return current;
5793 }
5794 sumWinding = current->computeSum(index, endIndex, binary);
5795 if (sumWinding != SK_MinS32) {
5796 return current;
5797 }
5798 int contourWinding;
5799 int oppContourWinding = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005800 // the simple upward projection of the unresolved points hit unsortable angles
5801 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005802 bool tryAgain;
5803 double tHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005804 SkScalar hitDx = 0;
5805 SkScalar hitOppDx = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005806 do {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005807 // if current is vertical, find another candidate which is not
5808 // if only remaining candidates are vertical, then they can be marked done
caryclark@google.com10227bf2012-12-28 22:10:41 +00005809 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005810 skipVertical(contourList, current, index, endIndex);
caryclark@google.com10227bf2012-12-28 22:10:41 +00005811 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005812 tryAgain = false;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005813 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005814 tryAgain, false);
5815 if (tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005816 continue;
5817 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005818 if (!binary) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005819 break;
5820 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005821 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005822 tryAgain, true);
5823 } while (tryAgain);
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00005824
caryclark@google.com3586ece2012-12-27 18:46:58 +00005825 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005826 return current;
5827}
5828
5829// rewrite that abandons keeping local track of winding
caryclark@google.com3586ece2012-12-27 18:46:58 +00005830static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005831 bool firstContour = true;
5832 bool unsortable = false;
5833 bool topUnsortable = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005834 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
5835 do {
5836 int index, endIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005837 bool topDone;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005838 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005839 topUnsortable, topDone, false);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005840 if (!current) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005841 if (topUnsortable || !topDone) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005842 topUnsortable = false;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005843 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005844 topLeft.fX = topLeft.fY = SK_ScalarMin;
5845 continue;
5846 }
5847 break;
5848 }
5849 SkTDArray<Span*> chaseArray;
5850 do {
5851 if (current->activeWinding(index, endIndex)) {
5852 do {
5853 #if DEBUG_ACTIVE_SPANS
5854 if (!unsortable && current->done()) {
5855 debugShowActiveSpans(contourList);
5856 }
5857 #endif
5858 SkASSERT(unsortable || !current->done());
5859 int nextStart = index;
5860 int nextEnd = endIndex;
5861 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
5862 unsortable);
5863 if (!next) {
5864 if (!unsortable && simple.hasMove()
5865 && current->verb() != SkPath::kLine_Verb
5866 && !simple.isClosed()) {
5867 current->addCurveTo(index, endIndex, simple, true);
5868 SkASSERT(simple.isClosed());
5869 }
5870 break;
5871 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005872 #if DEBUG_FLOW
5873 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
5874 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
5875 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
5876 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005877 current->addCurveTo(index, endIndex, simple, true);
5878 current = next;
5879 index = nextStart;
5880 endIndex = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005881 } while (!simple.isClosed() && (!unsortable
caryclark@google.com10227bf2012-12-28 22:10:41 +00005882 || !current->done(SkMin32(index, endIndex))));
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005883 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
5884 SkASSERT(unsortable);
5885 int min = SkMin32(index, endIndex);
5886 if (!current->done(min)) {
5887 current->addCurveTo(index, endIndex, simple, true);
5888 current->markDoneUnary(min);
5889 }
5890 }
5891 simple.close();
5892 } else {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005893 Span* last = current->markAndChaseDoneUnary(index, endIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005894 if (last) {
5895 *chaseArray.append() = last;
5896 }
5897 }
5898 current = findChase(chaseArray, index, endIndex);
5899 #if DEBUG_ACTIVE_SPANS
5900 debugShowActiveSpans(contourList);
5901 #endif
5902 if (!current) {
5903 break;
5904 }
5905 } while (true);
5906 } while (true);
5907 return simple.someAssemblyRequired();
5908}
5909
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005910// returns true if all edges were processed
caryclark@google.comf839c032012-10-26 21:03:50 +00005911static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.com24bec792012-08-20 12:43:57 +00005912 Segment* current;
5913 int start, end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005914 bool unsortable = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005915 bool closable = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00005916 while ((current = findUndone(contourList, start, end))) {
caryclark@google.com24bec792012-08-20 12:43:57 +00005917 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005918 #if DEBUG_ACTIVE_SPANS
5919 if (!unsortable && current->done()) {
5920 debugShowActiveSpans(contourList);
5921 }
5922 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005923 SkASSERT(unsortable || !current->done());
caryclark@google.com24bec792012-08-20 12:43:57 +00005924 int nextStart = start;
5925 int nextEnd = end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005926 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
caryclark@google.com24bec792012-08-20 12:43:57 +00005927 if (!next) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005928 if (!unsortable && simple.hasMove()
caryclark@google.comf839c032012-10-26 21:03:50 +00005929 && current->verb() != SkPath::kLine_Verb
5930 && !simple.isClosed()) {
5931 current->addCurveTo(start, end, simple, true);
5932 SkASSERT(simple.isClosed());
caryclark@google.comc899ad92012-08-23 15:24:42 +00005933 }
caryclark@google.com24bec792012-08-20 12:43:57 +00005934 break;
5935 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005936 #if DEBUG_FLOW
5937 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
5938 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
5939 current->xyAtT(end).fX, current->xyAtT(end).fY);
5940 #endif
caryclark@google.comf839c032012-10-26 21:03:50 +00005941 current->addCurveTo(start, end, simple, true);
caryclark@google.com24bec792012-08-20 12:43:57 +00005942 current = next;
5943 start = nextStart;
5944 end = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005945 } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005946 if (!simple.isClosed()) {
5947 SkASSERT(unsortable);
5948 int min = SkMin32(start, end);
5949 if (!current->done(min)) {
5950 current->addCurveTo(start, end, simple, true);
5951 current->markDone(min, 1);
5952 }
5953 closable = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00005954 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005955 simple.close();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005956 #if DEBUG_ACTIVE_SPANS
5957 debugShowActiveSpans(contourList);
5958 #endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00005959 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005960 return closable;
caryclark@google.com24bec792012-08-20 12:43:57 +00005961}
5962
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005963static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
5964 int contourCount = contourList.count();
5965 for (int cTest = 0; cTest < contourCount; ++cTest) {
5966 Contour* contour = contourList[cTest];
5967 contour->fixOtherTIndex();
5968 }
5969}
5970
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005971static void sortSegments(SkTDArray<Contour*>& contourList) {
5972 int contourCount = contourList.count();
5973 for (int cTest = 0; cTest < contourCount; ++cTest) {
5974 Contour* contour = contourList[cTest];
5975 contour->sortSegments();
5976 }
5977}
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005978
caryclark@google.com4eeda372012-12-06 21:47:48 +00005979static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
5980 bool evenOdd, bool oppEvenOdd) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005981 int count = contours.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005982 if (count == 0) {
5983 return;
5984 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005985 for (int index = 0; index < count; ++index) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00005986 Contour& contour = contours[index];
5987 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
5988 *list.append() = &contour;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005989 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005990 QSort<Contour>(list.begin(), list.end() - 1);
5991}
5992
caryclark@google.comf839c032012-10-26 21:03:50 +00005993static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005994 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005995}
5996
caryclark@google.com10227bf2012-12-28 22:10:41 +00005997static bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
5998 return distances[one] < distances[two];
5999}
caryclark@google.comf839c032012-10-26 21:03:50 +00006000 /*
6001 check start and end of each contour
6002 if not the same, record them
6003 match them up
6004 connect closest
6005 reassemble contour pieces into new path
6006 */
6007static void assemble(const PathWrapper& path, PathWrapper& simple) {
6008#if DEBUG_PATH_CONSTRUCTION
6009 SkDebugf("%s\n", __FUNCTION__);
6010#endif
6011 SkTArray<Contour> contours;
6012 EdgeBuilder builder(path, contours);
6013 builder.finish();
6014 int count = contours.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006015 int outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006016 SkTDArray<int> runs; // indices of partial contours
caryclark@google.com0b7da432012-10-31 19:00:20 +00006017 for (outer = 0; outer < count; ++outer) {
6018 const Contour& eContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006019 const SkPoint& eStart = eContour.start();
6020 const SkPoint& eEnd = eContour.end();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006021#if DEBUG_ASSEMBLE
6022 SkDebugf("%s contour", __FUNCTION__);
6023 if (!approximatelyEqual(eStart, eEnd)) {
6024 SkDebugf("[%d]", runs.count());
6025 } else {
6026 SkDebugf(" ");
6027 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006028 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006029 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
6030#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006031 if (approximatelyEqual(eStart, eEnd)) {
6032 eContour.toPath(simple);
6033 continue;
6034 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006035 *runs.append() = outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006036 }
6037 count = runs.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006038 if (count == 0) {
6039 return;
6040 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006041 SkTDArray<int> sLink, eLink;
6042 sLink.setCount(count);
6043 eLink.setCount(count);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006044 int rIndex, iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006045 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006046 sLink[rIndex] = eLink[rIndex] = INT_MAX;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006047 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006048 SkTDArray<double> distances;
6049 const int ends = count * 2; // all starts and ends
6050 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
6051 distances.setCount(entries);
6052 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
6053 outer = runs[rIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006054 const Contour& oContour = contours[outer];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006055 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
6056 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
6057 * ends - rIndex - 1;
6058 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
6059 int inner = runs[iIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006060 const Contour& iContour = contours[inner];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006061 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
6062 double dx = iPt.fX - oPt.fX;
6063 double dy = iPt.fY - oPt.fY;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006064 double dist = dx * dx + dy * dy;
caryclark@google.com10227bf2012-12-28 22:10:41 +00006065 distances[row + iIndex] = dist; // oStart distance from iStart
6066 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006067 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006068 SkTDArray<int> sortedDist;
6069 sortedDist.setCount(entries);
6070 for (rIndex = 0; rIndex < entries; ++rIndex) {
6071 sortedDist[rIndex] = rIndex;
6072 }
6073 QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
6074 int remaining = count; // number of start/end pairs
6075 for (rIndex = 0; rIndex < entries; ++rIndex) {
6076 int pair = sortedDist[rIndex];
6077 int row = pair / ends;
6078 int col = pair - row * ends;
6079 int thingOne = row < col ? row : ends - row - 2;
6080 int ndxOne = thingOne >> 1;
6081 bool endOne = thingOne & 1;
6082 int* linkOne = endOne ? eLink.begin() : sLink.begin();
6083 if (linkOne[ndxOne] != INT_MAX) {
6084 continue;
6085 }
6086 int thingTwo = row < col ? col : ends - row + col - 1;
6087 int ndxTwo = thingTwo >> 1;
6088 bool endTwo = thingTwo & 1;
6089 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
6090 if (linkTwo[ndxTwo] != INT_MAX) {
6091 continue;
6092 }
6093 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
6094 bool flip = endOne == endTwo;
6095 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
6096 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
6097 if (!--remaining) {
6098 break;
6099 }
6100 }
6101 SkASSERT(!remaining);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006102#if DEBUG_ASSEMBLE
6103 for (rIndex = 0; rIndex < count; ++rIndex) {
6104 int s = sLink[rIndex];
6105 int e = eLink[rIndex];
6106 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
6107 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
caryclark@google.comf839c032012-10-26 21:03:50 +00006108 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006109#endif
6110 rIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00006111 do {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006112 bool forward = true;
6113 bool first = true;
6114 int sIndex = sLink[rIndex];
6115 SkASSERT(sIndex != INT_MAX);
6116 sLink[rIndex] = INT_MAX;
6117 int eIndex;
6118 if (sIndex < 0) {
6119 eIndex = sLink[~sIndex];
6120 sLink[~sIndex] = INT_MAX;
6121 } else {
6122 eIndex = eLink[sIndex];
6123 eLink[sIndex] = INT_MAX;
6124 }
6125 SkASSERT(eIndex != INT_MAX);
6126#if DEBUG_ASSEMBLE
6127 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006128 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
6129 eIndex < 0 ? ~eIndex : eIndex);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006130#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006131 do {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006132 outer = runs[rIndex];
6133 const Contour& contour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006134 if (first) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006135 first = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006136 const SkPoint* startPtr = &contour.start();
caryclark@google.comf839c032012-10-26 21:03:50 +00006137 simple.deferredMove(startPtr[0]);
6138 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006139 if (forward) {
6140 contour.toPartialForward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006141 } else {
6142 contour.toPartialBackward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006143 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006144#if DEBUG_ASSEMBLE
6145 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006146 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006147 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
6148#endif
6149 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006150 simple.close();
caryclark@google.comf839c032012-10-26 21:03:50 +00006151 break;
6152 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006153 if (forward) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006154 eIndex = eLink[rIndex];
6155 SkASSERT(eIndex != INT_MAX);
caryclark@google.comf839c032012-10-26 21:03:50 +00006156 eLink[rIndex] = INT_MAX;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006157 if (eIndex >= 0) {
6158 SkASSERT(sLink[eIndex] == rIndex);
6159 sLink[eIndex] = INT_MAX;
caryclark@google.comf839c032012-10-26 21:03:50 +00006160 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006161 SkASSERT(eLink[~eIndex] == ~rIndex);
6162 eLink[~eIndex] = INT_MAX;
caryclark@google.comf839c032012-10-26 21:03:50 +00006163 }
6164 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006165 eIndex = sLink[rIndex];
6166 SkASSERT(eIndex != INT_MAX);
caryclark@google.comf839c032012-10-26 21:03:50 +00006167 sLink[rIndex] = INT_MAX;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006168 if (eIndex >= 0) {
6169 SkASSERT(eLink[eIndex] == rIndex);
6170 eLink[eIndex] = INT_MAX;
caryclark@google.comf839c032012-10-26 21:03:50 +00006171 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006172 SkASSERT(sLink[~eIndex] == ~rIndex);
6173 sLink[~eIndex] = INT_MAX;
caryclark@google.comf839c032012-10-26 21:03:50 +00006174 }
6175 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006176 rIndex = eIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006177 if (rIndex < 0) {
6178 forward ^= 1;
6179 rIndex = ~rIndex;
6180 }
6181 } while (true);
6182 for (rIndex = 0; rIndex < count; ++rIndex) {
6183 if (sLink[rIndex] != INT_MAX) {
6184 break;
6185 }
6186 }
6187 } while (rIndex < count);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006188#if DEBUG_ASSEMBLE
6189 for (rIndex = 0; rIndex < count; ++rIndex) {
6190 SkASSERT(sLink[rIndex] == INT_MAX);
6191 SkASSERT(eLink[rIndex] == INT_MAX);
6192 }
6193#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006194}
6195
6196void simplifyx(const SkPath& path, SkPath& result) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006197 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
caryclark@google.comf839c032012-10-26 21:03:50 +00006198 result.reset();
6199 result.setFillType(SkPath::kEvenOdd_FillType);
6200 PathWrapper simple(result);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006201
6202 // turn path into list of segments
6203 SkTArray<Contour> contours;
6204 // FIXME: add self-intersecting cubics' T values to segment
6205 EdgeBuilder builder(path, contours);
caryclark@google.com235f56a2012-09-14 14:19:30 +00006206 builder.finish();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006207 SkTDArray<Contour*> contourList;
caryclark@google.com4eeda372012-12-06 21:47:48 +00006208 makeContourList(contours, contourList, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006209 Contour** currentPtr = contourList.begin();
6210 if (!currentPtr) {
6211 return;
6212 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006213 Contour** listEnd = contourList.end();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006214 // find all intersections between segments
6215 do {
6216 Contour** nextPtr = currentPtr;
6217 Contour* current = *currentPtr++;
6218 Contour* next;
6219 do {
6220 next = *nextPtr++;
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00006221 } while (addIntersectTs(current, next) && nextPtr != listEnd);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006222 } while (currentPtr != listEnd);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006223 // eat through coincident edges
caryclark@google.com4eeda372012-12-06 21:47:48 +00006224 coincidenceCheck(contourList, 0);
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00006225 fixOtherTIndex(contourList);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006226 sortSegments(contourList);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006227#if DEBUG_ACTIVE_SPANS
6228 debugShowActiveSpans(contourList);
6229#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006230 // construct closed contours
caryclark@google.com3586ece2012-12-27 18:46:58 +00006231 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00006232 : !bridgeXor(contourList, simple))
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006233 { // if some edges could not be resolved, assemble remaining fragments
caryclark@google.comf839c032012-10-26 21:03:50 +00006234 SkPath temp;
6235 temp.setFillType(SkPath::kEvenOdd_FillType);
6236 PathWrapper assembled(temp);
6237 assemble(simple, assembled);
6238 result = *assembled.nativePath();
caryclark@google.com24bec792012-08-20 12:43:57 +00006239 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006240}