blob: 9b4ebc44813b3fc494f2b7f8850564a1dfa6b3eb [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.com86adc0d2013-01-30 12:50:38 +000034#define FORCE_RELEASE 1 // 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.comaa358312013-01-29 20:28:49 +0000395static void LineSubDivideHD(const SkPoint a[2], double startT, double endT, _Line& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000396 MAKE_CONST_LINE(aLine, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000397 sub_divide(aLine, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000398}
399
caryclark@google.comaa358312013-01-29 20:28:49 +0000400static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT, Quadratic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000401 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000402 sub_divide(aQuad, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000403}
404
caryclark@google.comaa358312013-01-29 20:28:49 +0000405static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT, Cubic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000406 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000407 sub_divide(aCubic, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000408}
409
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000410#if DEBUG_UNUSED
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000411static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
412 SkRect& bounds) {
413 SkPoint dst[3];
414 QuadSubDivide(a, startT, endT, dst);
415 bounds.fLeft = bounds.fRight = dst[0].fX;
416 bounds.fTop = bounds.fBottom = dst[0].fY;
417 for (int index = 1; index < 3; ++index) {
418 bounds.growToInclude(dst[index].fX, dst[index].fY);
419 }
420}
421
422static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
423 SkRect& bounds) {
424 SkPoint dst[4];
425 CubicSubDivide(a, startT, endT, dst);
426 bounds.fLeft = bounds.fRight = dst[0].fX;
427 bounds.fTop = bounds.fBottom = dst[0].fY;
428 for (int index = 1; index < 4; ++index) {
429 bounds.growToInclude(dst[index].fX, dst[index].fY);
430 }
431}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000432#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000433
caryclark@google.com15fa1382012-05-07 20:49:36 +0000434static SkPath::Verb QuadReduceOrder(const SkPoint a[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000435 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000436 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000437 Quadratic dst;
438 int order = reduceOrder(aQuad, dst);
caryclark@google.com24bec792012-08-20 12:43:57 +0000439 if (order == 2) { // quad became line
440 for (int index = 0; index < order; ++index) {
441 SkPoint* pt = reducePts.append();
442 pt->fX = SkDoubleToScalar(dst[index].x);
443 pt->fY = SkDoubleToScalar(dst[index].y);
444 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000445 }
446 return (SkPath::Verb) (order - 1);
447}
448
449static SkPath::Verb CubicReduceOrder(const SkPoint a[4],
450 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000451 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000452 Cubic dst;
453 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed);
caryclark@google.com24bec792012-08-20 12:43:57 +0000454 if (order == 2 || order == 3) { // cubic became line or quad
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
caryclark@google.com15fa1382012-05-07 20:49:36 +0000464static bool QuadIsLinear(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000465 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000466 return isLinear(aQuad, 0, 2);
467}
468
469static bool CubicIsLinear(const SkPoint a[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000470 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000471 return isLinear(aCubic, 0, 3);
472}
473
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000474static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000475 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000476 double x[2];
477 xy_at_t(aLine, startT, x[0], *(double*) 0);
caryclark@google.com495f8e42012-05-31 13:13:11 +0000478 xy_at_t(aLine, endT, x[1], *(double*) 0);
479 return SkMinScalar((float) x[0], (float) x[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000480}
481
482static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000483 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000484 return (float) leftMostT(aQuad, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000485}
486
487static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000488 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000489 return (float) leftMostT(aCubic, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000490}
491
492static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
493 NULL,
494 LineLeftMost,
495 QuadLeftMost,
496 CubicLeftMost
497};
498
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000499#if 0 // currently unused
caryclark@google.com235f56a2012-09-14 14:19:30 +0000500static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
501 Intersections& intersections) {
502 MAKE_CONST_QUAD(aQuad, a);
503 MAKE_CONST_LINE(bLine, b);
504 return intersectRay(aQuad, bLine, intersections);
505}
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000506#endif
507
508static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine,
509 Intersections& intersections) {
510 MAKE_CONST_QUAD(aQuad, a);
511 return intersectRay(aQuad, bLine, intersections);
512}
caryclark@google.com235f56a2012-09-14 14:19:30 +0000513
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000514static bool LineVertical(const SkPoint a[2], double startT, double endT) {
515 MAKE_CONST_LINE(aLine, a);
516 double x[2];
517 xy_at_t(aLine, startT, x[0], *(double*) 0);
518 xy_at_t(aLine, endT, x[1], *(double*) 0);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000519 return AlmostEqualUlps((float) x[0], (float) x[1]);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000520}
521
522static bool QuadVertical(const SkPoint a[3], double startT, double endT) {
523 SkPoint dst[3];
524 QuadSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000525 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000526}
527
528static bool CubicVertical(const SkPoint a[4], double startT, double endT) {
529 SkPoint dst[4];
530 CubicSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000531 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX)
532 && AlmostEqualUlps(dst[2].fX, dst[3].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000533}
534
535static bool (* const SegmentVertical[])(const SkPoint [], double , double) = {
536 NULL,
537 LineVertical,
538 QuadVertical,
539 CubicVertical
540};
541
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000542class Segment;
543
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000544struct Span {
545 Segment* fOther;
546 mutable SkPoint fPt; // lazily computed as needed
547 double fT;
548 double fOtherT; // value at fOther[fOtherIndex].fT
549 int fOtherIndex; // can't be used during intersection
caryclark@google.com31143cf2012-11-09 22:14:19 +0000550 int fWindSum; // accumulated from contours surrounding this one.
551 int fOppSum; // for binary operators: the opposite winding sum
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000552 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
caryclark@google.com57cff8d2012-11-14 21:14:56 +0000553 int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000554 bool fDone; // if set, this span to next higher T has been processed
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000555 bool fUnsortableStart; // set when start is part of an unsortable pair
556 bool fUnsortableEnd; // set when end is part of an unsortable pair
caryclark@google.comf839c032012-10-26 21:03:50 +0000557 bool fTiny; // if set, span may still be considered once for edge following
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000558};
559
caryclark@google.com15fa1382012-05-07 20:49:36 +0000560// sorting angles
561// given angles of {dx dy ddx ddy dddx dddy} sort them
562class Angle {
563public:
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000564 // FIXME: this is bogus for quads and cubics
565 // if the quads and cubics' line from end pt to ctrl pt are coincident,
566 // there's no obvious way to determine the curve ordering from the
567 // derivatives alone. In particular, if one quadratic's coincident tangent
568 // is longer than the other curve, the final control point can place the
569 // longer curve on either side of the shorter one.
570 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
571 // may provide some help, but nothing has been figured out yet.
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000572
caryclark@google.com32546db2012-08-31 20:55:07 +0000573 /*(
574 for quads and cubics, set up a parameterized line (e.g. LineParameters )
575 for points [0] to [1]. See if point [2] is on that line, or on one side
576 or the other. If it both quads' end points are on the same side, choose
577 the shorter tangent. If the tangents are equal, choose the better second
578 tangent angle
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000579
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000580 maybe I could set up LineParameters lazily
caryclark@google.com32546db2012-08-31 20:55:07 +0000581 */
caryclark@google.com15fa1382012-05-07 20:49:36 +0000582 bool operator<(const Angle& rh) const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000583 double y = dy();
584 double ry = rh.dy();
585 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
586 return y < 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000587 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000588 double x = dx();
589 double rx = rh.dx();
590 if (y == 0 && ry == 0 && x * rx < 0) {
591 return x < rx;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000592 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000593 double x_ry = x * ry;
594 double rx_y = rx * y;
595 double cmp = x_ry - rx_y;
caryclark@google.comc899ad92012-08-23 15:24:42 +0000596 if (!approximately_zero(cmp)) {
caryclark@google.com15fa1382012-05-07 20:49:36 +0000597 return cmp < 0;
598 }
caryclark@google.comd1688742012-09-18 20:08:37 +0000599 if (approximately_zero(x_ry) && approximately_zero(rx_y)
600 && !approximately_zero_squared(cmp)) {
601 return cmp < 0;
602 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000603 // at this point, the initial tangent line is coincident
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000604 // see if edges curl away from each other
caryclark@google.com31143cf2012-11-09 22:14:19 +0000605 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
606 || !approximately_zero(rh.fSide))) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000607 // FIXME: running demo will trigger this assertion
608 // (don't know if commenting out will trigger further assertion or not)
609 // commenting it out allows demo to run in release, though
610 // SkASSERT(fSide != rh.fSide);
611 return fSide < rh.fSide;
612 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000613 // see if either curve can be lengthened and try the tangent compare again
614 if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
615 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
616 Angle longer = *this;
617 Angle rhLonger = rh;
618 if (longer.lengthen() | rhLonger.lengthen()) {
619 return longer < rhLonger;
620 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000621 #if 0
caryclark@google.coma461ff02012-10-11 12:54:23 +0000622 // what if we extend in the other direction?
623 longer = *this;
624 rhLonger = rh;
625 if (longer.reverseLengthen() | rhLonger.reverseLengthen()) {
626 return longer < rhLonger;
627 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000628 #endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000629 }
caryclark@google.com185c7c42012-10-19 18:26:24 +0000630 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
caryclark@google.com31143cf2012-11-09 22:14:19 +0000631 || (rh.fVerb == SkPath::kLine_Verb
632 && approximately_zero(rx) && approximately_zero(ry))) {
caryclark@google.com185c7c42012-10-19 18:26:24 +0000633 // See general unsortable comment below. This case can happen when
634 // one line has a non-zero change in t but no change in x and y.
635 fUnsortable = true;
636 rh.fUnsortable = true;
637 return this < &rh; // even with no solution, return a stable sort
638 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000639 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
640 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
641 fUnsortable = true;
642 rh.fUnsortable = true;
643 return this < &rh; // even with no solution, return a stable sort
644 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000645 SkASSERT(fVerb == SkPath::kQuad_Verb); // worry about cubics later
646 SkASSERT(rh.fVerb == SkPath::kQuad_Verb);
skia.committer@gmail.comc1ad0222012-09-19 02:01:47 +0000647 // FIXME: until I can think of something better, project a ray from the
caryclark@google.comd1688742012-09-18 20:08:37 +0000648 // end of the shorter tangent to midway between the end points
649 // through both curves and use the resulting angle to sort
caryclark@google.com235f56a2012-09-14 14:19:30 +0000650 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
651 double len = fTangent1.normalSquared();
652 double rlen = rh.fTangent1.normalSquared();
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000653 _Line ray;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000654 Intersections i, ri;
caryclark@google.comd1688742012-09-18 20:08:37 +0000655 int roots, rroots;
656 bool flip = false;
657 do {
658 const Quadratic& q = (len < rlen) ^ flip ? fQ : rh.fQ;
659 double midX = (q[0].x + q[2].x) / 2;
660 double midY = (q[0].y + q[2].y) / 2;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000661 ray[0] = q[1];
662 ray[1].x = midX;
663 ray[1].y = midY;
caryclark@google.comd1688742012-09-18 20:08:37 +0000664 SkASSERT(ray[0] != ray[1]);
665 roots = QuadRayIntersect(fPts, ray, i);
666 rroots = QuadRayIntersect(rh.fPts, ray, ri);
667 } while ((roots == 0 || rroots == 0) && (flip ^= true));
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000668 if (roots == 0 || rroots == 0) {
669 // FIXME: we don't have a solution in this case. The interim solution
670 // is to mark the edges as unsortable, exclude them from this and
671 // future computations, and allow the returned path to be fragmented
672 fUnsortable = true;
673 rh.fUnsortable = true;
674 return this < &rh; // even with no solution, return a stable sort
675 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000676 _Point loc;
677 double best = SK_ScalarInfinity;
678 double dx, dy, dist;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000679 int index;
680 for (index = 0; index < roots; ++index) {
681 QuadXYAtT(fPts, i.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000682 dx = loc.x - ray[0].x;
683 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000684 dist = dx * dx + dy * dy;
685 if (best > dist) {
686 best = dist;
687 }
688 }
689 for (index = 0; index < rroots; ++index) {
690 QuadXYAtT(rh.fPts, ri.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000691 dx = loc.x - ray[0].x;
692 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000693 dist = dx * dx + dy * dy;
694 if (best > dist) {
695 return fSide < 0;
696 }
697 }
698 return fSide > 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000699 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000700
caryclark@google.com47580692012-07-23 12:14:49 +0000701 double dx() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000702 return fTangent1.dx();
caryclark@google.com47580692012-07-23 12:14:49 +0000703 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000704
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000705 double dy() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000706 return fTangent1.dy();
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000707 }
708
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000709 int end() const {
710 return fEnd;
711 }
712
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000713 bool isHorizontal() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000714 return dy() == 0 && fVerb == SkPath::kLine_Verb;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000715 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000716
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000717 bool lengthen() {
718 int newEnd = fEnd;
719 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
720 fEnd = newEnd;
721 setSpans();
722 return true;
723 }
724 return false;
725 }
726
caryclark@google.coma461ff02012-10-11 12:54:23 +0000727 bool reverseLengthen() {
728 if (fReversed) {
729 return false;
730 }
731 int newEnd = fStart;
732 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
733 fEnd = newEnd;
734 fReversed = true;
735 setSpans();
736 return true;
737 }
738 return false;
739 }
740
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000741 void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000742 int start, int end, const SkTDArray<Span>& spans) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000743 fSegment = segment;
744 fStart = start;
745 fEnd = end;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000746 fPts = orig;
747 fVerb = verb;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000748 fSpans = &spans;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000749 fReversed = false;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000750 fUnsortable = false;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000751 setSpans();
752 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000753
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000754
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000755 void setSpans() {
756 double startT = (*fSpans)[fStart].fT;
757 double endT = (*fSpans)[fEnd].fT;
758 switch (fVerb) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000759 case SkPath::kLine_Verb:
760 _Line l;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000761 LineSubDivideHD(fPts, startT, endT, l);
caryclark@google.com32546db2012-08-31 20:55:07 +0000762 // OPTIMIZATION: for pure line compares, we never need fTangent1.c
763 fTangent1.lineEndPoints(l);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000764 fSide = 0;
caryclark@google.com32546db2012-08-31 20:55:07 +0000765 break;
766 case SkPath::kQuad_Verb:
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000767 QuadSubDivideHD(fPts, startT, endT, fQ);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000768 fTangent1.quadEndPoints(fQ, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000769 #if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
770 if (dx() == 0 && dy() == 0) {
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000771 SkDebugf("*** %s quad is line\n", __FUNCTION__);
caryclark@google.comaa358312013-01-29 20:28:49 +0000772 fTangent1.quadEndPoints(fQ);
773 }
774 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +0000775 fSide = -fTangent1.pointDistance(fQ[2]); // not normalized -- compare sign only
caryclark@google.com32546db2012-08-31 20:55:07 +0000776 break;
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000777 case SkPath::kCubic_Verb: {
caryclark@google.com32546db2012-08-31 20:55:07 +0000778 Cubic c;
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000779 int nextC = 2;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000780 CubicSubDivideHD(fPts, startT, endT, c);
caryclark@google.com32546db2012-08-31 20:55:07 +0000781 fTangent1.cubicEndPoints(c, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000782 if (dx() == 0 && dy() == 0) {
783 fTangent1.cubicEndPoints(c, 0, 2);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000784 nextC = 3;
caryclark@google.comaa358312013-01-29 20:28:49 +0000785 #if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
786 if (dx() == 0 && dy() == 0) {
787 SkDebugf("*** %s cubic is line\n");
788 fTangent1.cubicEndPoints(c, 0, 3);
789 }
790 #endif
791 }
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000792 fSide = -fTangent1.pointDistance(c[nextC]); // not normalized -- compare sign only
793 if (nextC == 2 && approximately_zero(fSide)) {
794 fSide = -fTangent1.pointDistance(c[3]);
795 }
796 } break;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000797 default:
798 SkASSERT(0);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000799 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000800 fUnsortable = dx() == 0 && dy() == 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000801 if (fUnsortable) {
802 return;
803 }
804 SkASSERT(fStart != fEnd);
805 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
806 for (int index = fStart; index != fEnd; index += step) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000807#if 1
808 const Span& thisSpan = (*fSpans)[index];
809 const Span& nextSpan = (*fSpans)[index + step];
810 if (thisSpan.fTiny || thisSpan.fT == nextSpan.fT) {
811 continue;
caryclark@google.comf839c032012-10-26 21:03:50 +0000812 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000813 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
814#if DEBUG_UNSORTABLE
815 if (fUnsortable) {
816 SkPoint iPt, ePt;
817 (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt);
818 (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt);
819 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
820 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
821 }
822#endif
823 return;
824#else
825 if ((*fSpans)[index].fUnsortableStart) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000826 fUnsortable = true;
827 return;
828 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000829#endif
caryclark@google.comf839c032012-10-26 21:03:50 +0000830 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000831#if 1
832#if DEBUG_UNSORTABLE
833 SkPoint iPt, ePt;
834 (*SegmentXYAtT[fVerb])(fPts, startT, &iPt);
835 (*SegmentXYAtT[fVerb])(fPts, endT, &ePt);
836 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
837 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
838#endif
839 fUnsortable = true;
840#endif
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000841 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000842
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000843 Segment* segment() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000844 return const_cast<Segment*>(fSegment);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000845 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000846
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000847 int sign() const {
caryclark@google.com495f8e42012-05-31 13:13:11 +0000848 return SkSign32(fStart - fEnd);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000849 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000850
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000851 const SkTDArray<Span>* spans() const {
852 return fSpans;
853 }
854
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000855 int start() const {
856 return fStart;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000857 }
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +0000858
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000859 bool unsortable() const {
860 return fUnsortable;
861 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000862
caryclark@google.comc899ad92012-08-23 15:24:42 +0000863#if DEBUG_ANGLE
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000864 const SkPoint* pts() const {
865 return fPts;
866 }
867
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000868 SkPath::Verb verb() const {
869 return fVerb;
870 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000871
caryclark@google.comc899ad92012-08-23 15:24:42 +0000872 void debugShow(const SkPoint& a) const {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000873 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
caryclark@google.comc899ad92012-08-23 15:24:42 +0000874 }
875#endif
876
caryclark@google.com15fa1382012-05-07 20:49:36 +0000877private:
caryclark@google.com235f56a2012-09-14 14:19:30 +0000878 const SkPoint* fPts;
879 Quadratic fQ;
880 SkPath::Verb fVerb;
881 double fSide;
882 LineParameters fTangent1;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000883 const SkTDArray<Span>* fSpans;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000884 const Segment* fSegment;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000885 int fStart;
886 int fEnd;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000887 bool fReversed;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000888 mutable bool fUnsortable; // this alone is editable by the less than operator
caryclark@google.com15fa1382012-05-07 20:49:36 +0000889};
890
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000891// Bounds, unlike Rect, does not consider a line to be empty.
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000892struct Bounds : public SkRect {
893 static bool Intersects(const Bounds& a, const Bounds& b) {
894 return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
895 a.fTop <= b.fBottom && b.fTop <= a.fBottom;
896 }
897
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000898 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
899 if (left < fLeft) {
900 fLeft = left;
901 }
902 if (top < fTop) {
903 fTop = top;
904 }
905 if (right > fRight) {
906 fRight = right;
907 }
908 if (bottom > fBottom) {
909 fBottom = bottom;
910 }
911 }
912
913 void add(const Bounds& toAdd) {
914 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
915 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000916
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000917 void add(const SkPoint& pt) {
918 if (pt.fX < fLeft) fLeft = pt.fX;
919 if (pt.fY < fTop) fTop = pt.fY;
920 if (pt.fX > fRight) fRight = pt.fX;
921 if (pt.fY > fBottom) fBottom = pt.fY;
922 }
923
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000924 bool isEmpty() {
925 return fLeft > fRight || fTop > fBottom
caryclark@google.com235f56a2012-09-14 14:19:30 +0000926 || (fLeft == fRight && fTop == fBottom)
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000927 || isnan(fLeft) || isnan(fRight)
928 || isnan(fTop) || isnan(fBottom);
929 }
930
931 void setCubicBounds(const SkPoint a[4]) {
932 _Rect dRect;
caryclark@google.com32546db2012-08-31 20:55:07 +0000933 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000934 dRect.setBounds(cubic);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000935 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
936 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000937 }
938
939 void setQuadBounds(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000940 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000941 _Rect dRect;
942 dRect.setBounds(quad);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000943 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
944 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000945 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000946
947 void setPoint(const SkPoint& pt) {
948 fLeft = fRight = pt.fX;
949 fTop = fBottom = pt.fY;
950 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000951};
952
caryclark@google.com7ba591e2012-11-20 14:21:54 +0000953// OPTIMIZATION: does the following also work, and is it any faster?
954// return outerWinding * innerWinding > 0
955// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
caryclark@google.com2ddff932012-08-07 21:25:27 +0000956static bool useInnerWinding(int outerWinding, int innerWinding) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000957 // SkASSERT(outerWinding != innerWinding);
caryclark@google.com2ddff932012-08-07 21:25:27 +0000958 int absOut = abs(outerWinding);
959 int absIn = abs(innerWinding);
960 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
961 if (outerWinding * innerWinding < 0) {
962#if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +0000963 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
caryclark@google.com2ddff932012-08-07 21:25:27 +0000964 outerWinding, innerWinding, result ? "true" : "false");
965#endif
966 }
967 return result;
968}
969
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000970#define F (false) // discard the edge
971#define T (true) // keep the edge
972
caryclark@google.comd0deb4f2012-12-17 13:58:08 +0000973static const bool gUnaryActiveEdge[2][2] = {
974// from=0 from=1
975// to=0,1 to=0,1
976 {F, T}, {T, F},
977};
978
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000979static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
980// miFrom=0 miFrom=1
981// miTo=0 miTo=1 miTo=0 miTo=1
982// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
983// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
984 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
985 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
986 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
987 {{{{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 +0000988};
989
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000990#undef F
991#undef T
caryclark@google.com235f56a2012-09-14 14:19:30 +0000992
caryclark@google.comf839c032012-10-26 21:03:50 +0000993// wrap path to keep track of whether the contour is initialized and non-empty
994class PathWrapper {
995public:
996 PathWrapper(SkPath& path)
997 : fPathPtr(&path)
caryclark@google.comd0deb4f2012-12-17 13:58:08 +0000998 , fCloses(0)
999 , fMoves(0)
caryclark@google.comf839c032012-10-26 21:03:50 +00001000 {
1001 init();
1002 }
1003
1004 void close() {
1005 if (!fHasMove) {
1006 return;
1007 }
1008 bool callClose = isClosed();
1009 lineTo();
1010 if (fEmpty) {
1011 return;
1012 }
1013 if (callClose) {
1014 #if DEBUG_PATH_CONSTRUCTION
1015 SkDebugf("path.close();\n");
1016 #endif
1017 fPathPtr->close();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001018 fCloses++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001019 }
1020 init();
1021 }
1022
1023 void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
1024 lineTo();
1025 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001026 fDefer[1] = pt3;
1027 nudge();
1028 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001029#if DEBUG_PATH_CONSTRUCTION
1030 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001031 pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001032#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001033 fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001034 fEmpty = false;
1035 }
1036
1037 void deferredLine(const SkPoint& pt) {
1038 if (pt == fDefer[1]) {
1039 return;
1040 }
1041 if (changedSlopes(pt)) {
1042 lineTo();
1043 fDefer[0] = fDefer[1];
1044 }
1045 fDefer[1] = pt;
1046 }
1047
1048 void deferredMove(const SkPoint& pt) {
1049 fMoved = true;
1050 fHasMove = true;
1051 fEmpty = true;
1052 fDefer[0] = fDefer[1] = pt;
1053 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001054
caryclark@google.comf839c032012-10-26 21:03:50 +00001055 void deferredMoveLine(const SkPoint& pt) {
1056 if (!fHasMove) {
1057 deferredMove(pt);
1058 }
1059 deferredLine(pt);
1060 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001061
caryclark@google.comf839c032012-10-26 21:03:50 +00001062 bool hasMove() const {
1063 return fHasMove;
1064 }
1065
1066 void init() {
1067 fEmpty = true;
1068 fHasMove = false;
1069 fMoved = false;
1070 }
1071
1072 bool isClosed() const {
1073 return !fEmpty && fFirstPt == fDefer[1];
1074 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001075
caryclark@google.comf839c032012-10-26 21:03:50 +00001076 void lineTo() {
1077 if (fDefer[0] == fDefer[1]) {
1078 return;
1079 }
1080 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001081 nudge();
caryclark@google.comf839c032012-10-26 21:03:50 +00001082 fEmpty = false;
1083#if DEBUG_PATH_CONSTRUCTION
1084 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
1085#endif
1086 fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
1087 fDefer[0] = fDefer[1];
1088 }
1089
1090 const SkPath* nativePath() const {
1091 return fPathPtr;
1092 }
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +00001093
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001094 void nudge() {
1095 if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX)
1096 || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) {
1097 return;
1098 }
1099 fDefer[1] = fFirstPt;
1100 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001101
1102 void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
1103 lineTo();
1104 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001105 fDefer[1] = pt2;
1106 nudge();
1107 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001108#if DEBUG_PATH_CONSTRUCTION
1109 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001110 pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001111#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001112 fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001113 fEmpty = false;
1114 }
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00001115
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001116 bool someAssemblyRequired() const {
1117 return fCloses < fMoves;
1118 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001119
1120protected:
1121 bool changedSlopes(const SkPoint& pt) const {
1122 if (fDefer[0] == fDefer[1]) {
1123 return false;
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001124 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001125 SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
1126 SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
1127 SkScalar lineDx = pt.fX - fDefer[1].fX;
1128 SkScalar lineDy = pt.fY - fDefer[1].fY;
1129 return deferDx * lineDy != deferDy * lineDx;
1130 }
1131
1132 void moveTo() {
1133 if (!fMoved) {
1134 return;
1135 }
1136 fFirstPt = fDefer[0];
1137#if DEBUG_PATH_CONSTRUCTION
1138 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
1139#endif
1140 fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
1141 fMoved = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001142 fMoves++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001143 }
1144
1145private:
1146 SkPath* fPathPtr;
1147 SkPoint fDefer[2];
1148 SkPoint fFirstPt;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001149 int fCloses;
1150 int fMoves;
caryclark@google.comf839c032012-10-26 21:03:50 +00001151 bool fEmpty;
1152 bool fHasMove;
1153 bool fMoved;
1154};
1155
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001156class Segment {
1157public:
1158 Segment() {
1159#if DEBUG_DUMP
1160 fID = ++gSegmentID;
1161#endif
1162 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00001163
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001164 bool operator<(const Segment& rh) const {
1165 return fBounds.fTop < rh.fBounds.fTop;
1166 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001167
caryclark@google.com4eeda372012-12-06 21:47:48 +00001168 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001169 if (activeAngleInner(index, done, angles)) {
1170 return true;
1171 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001172 int lesser = index;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001173 while (--lesser >= 0 && equalPoints(index, lesser)) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001174 if (activeAngleOther(lesser, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001175 return true;
1176 }
1177 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001178 lesser = index;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001179 do {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001180 if (activeAngleOther(index, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001181 return true;
1182 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001183 } while (++index < fTs.count() && equalPoints(index, lesser));
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001184 return false;
1185 }
1186
caryclark@google.com4eeda372012-12-06 21:47:48 +00001187 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001188 Span* span = &fTs[index];
1189 Segment* other = span->fOther;
1190 int oIndex = span->fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001191 return other->activeAngleInner(oIndex, done, angles);
1192 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001193
caryclark@google.com4eeda372012-12-06 21:47:48 +00001194 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001195 int next = nextExactSpan(index, 1);
caryclark@google.com9764cc62012-07-12 19:29:45 +00001196 if (next > 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001197 Span& upSpan = fTs[index];
1198 if (upSpan.fWindValue || upSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001199 addAngle(angles, index, next);
caryclark@google.comf839c032012-10-26 21:03:50 +00001200 if (upSpan.fDone || upSpan.fUnsortableEnd) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001201 done++;
1202 } else if (upSpan.fWindSum != SK_MinS32) {
1203 return true;
1204 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001205 } else if (!upSpan.fDone) {
1206 upSpan.fDone = true;
1207 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001208 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001209 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001210 int prev = nextExactSpan(index, -1);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001211 // edge leading into junction
caryclark@google.com9764cc62012-07-12 19:29:45 +00001212 if (prev >= 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001213 Span& downSpan = fTs[prev];
1214 if (downSpan.fWindValue || downSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001215 addAngle(angles, index, prev);
1216 if (downSpan.fDone) {
1217 done++;
1218 } else if (downSpan.fWindSum != SK_MinS32) {
1219 return true;
1220 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001221 } else if (!downSpan.fDone) {
1222 downSpan.fDone = true;
1223 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001224 }
1225 }
1226 return false;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001227 }
1228
caryclark@google.comf839c032012-10-26 21:03:50 +00001229 void activeLeftTop(SkPoint& result) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001230 SkASSERT(!done());
1231 int count = fTs.count();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001232 result.fX = result.fY = SK_ScalarMax;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001233 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00001234 bool lastUnsortable = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001235 for (int index = 0; index < count; ++index) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001236 const Span& span = fTs[index];
1237 if (span.fUnsortableStart | lastUnsortable) {
1238 goto next;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001239 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001240 if (!span.fDone | !lastDone) {
1241 const SkPoint& xy = xyAtT(index);
1242 if (result.fY < xy.fY) {
1243 goto next;
1244 }
1245 if (result.fY == xy.fY && result.fX < xy.fX) {
1246 goto next;
1247 }
1248 result = xy;
1249 }
1250 next:
1251 lastDone = span.fDone;
1252 lastUnsortable = span.fUnsortableEnd;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001253 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001254 }
1255
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001256 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
1257 int sumMiWinding = updateWinding(endIndex, index);
1258 int sumSuWinding = updateOppWinding(endIndex, index);
1259 if (fOperand) {
1260 SkTSwap<int>(sumMiWinding, sumSuWinding);
1261 }
1262 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1263 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001264 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001265 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001266
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001267 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00001268 int& sumMiWinding, int& sumSuWinding,
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001269 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
1270 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1271 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001272 bool miFrom;
1273 bool miTo;
1274 bool suFrom;
1275 bool suTo;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001276 if (operand()) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001277 miFrom = (oppMaxWinding & xorMiMask) != 0;
1278 miTo = (oppSumWinding & xorMiMask) != 0;
1279 suFrom = (maxWinding & xorSuMask) != 0;
1280 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001281 } else {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001282 miFrom = (maxWinding & xorMiMask) != 0;
1283 miTo = (sumWinding & xorMiMask) != 0;
1284 suFrom = (oppMaxWinding & xorSuMask) != 0;
1285 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001286 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001287 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
1288 SkASSERT(result != -1);
1289 return result;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001290 }
1291
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001292 bool activeWinding(int index, int endIndex) {
1293 int sumWinding = updateWinding(endIndex, index);
1294 int maxWinding;
1295 return activeWinding(index, endIndex, maxWinding, sumWinding);
1296 }
1297
1298 bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
1299 setUpWinding(index, endIndex, maxWinding, sumWinding);
1300 bool from = maxWinding != 0;
1301 bool to = sumWinding != 0;
1302 bool result = gUnaryActiveEdge[from][to];
1303 SkASSERT(result != -1);
1304 return result;
1305 }
1306
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001307 void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001308 SkASSERT(start != end);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001309 Angle* angle = angles.append();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001310#if DEBUG_ANGLE
caryclark@google.com31143cf2012-11-09 22:14:19 +00001311 if (angles.count() > 1 && !fTs[start].fTiny) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001312 SkPoint angle0Pt, newPt;
1313 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
1314 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
1315 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
caryclark@google.com6d0032a2013-01-04 19:41:13 +00001316 SkASSERT(AlmostEqualUlps(angle0Pt.fX, newPt.fX));
1317 SkASSERT(AlmostEqualUlps(angle0Pt.fY, newPt.fY));
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001318 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001319#endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001320 angle->set(fPts, fVerb, this, start, end, fTs);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001321 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001322
caryclark@google.com2ddff932012-08-07 21:25:27 +00001323 void addCancelOutsides(double tStart, double oStart, Segment& other,
caryclark@google.comcc905052012-07-25 20:59:42 +00001324 double oEnd) {
1325 int tIndex = -1;
1326 int tCount = fTs.count();
1327 int oIndex = -1;
1328 int oCount = other.fTs.count();
caryclark@google.comcc905052012-07-25 20:59:42 +00001329 do {
1330 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001331 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001332 int tIndexStart = tIndex;
1333 do {
1334 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001335 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001336 int oIndexStart = oIndex;
1337 double nextT;
1338 do {
1339 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001340 } while (nextT < 1 && approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001341 double oNextT;
1342 do {
1343 oNextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001344 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001345 // at this point, spans before and after are at:
1346 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1347 // if tIndexStart == 0, no prior span
1348 // if nextT == 1, no following span
rmistry@google.comd6176b02012-08-23 18:14:13 +00001349
caryclark@google.comcc905052012-07-25 20:59:42 +00001350 // advance the span with zero winding
1351 // if the following span exists (not past the end, non-zero winding)
1352 // connect the two edges
1353 if (!fTs[tIndexStart].fWindValue) {
1354 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1355 #if DEBUG_CONCIDENT
1356 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1357 __FUNCTION__, fID, other.fID, tIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001358 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
1359 xyAtT(tIndexStart).fY);
caryclark@google.comcc905052012-07-25 20:59:42 +00001360 #endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001361 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001362 }
1363 if (nextT < 1 && fTs[tIndex].fWindValue) {
1364 #if DEBUG_CONCIDENT
1365 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1366 __FUNCTION__, fID, other.fID, tIndex,
1367 fTs[tIndex].fT, xyAtT(tIndex).fX,
1368 xyAtT(tIndex).fY);
1369 #endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001370 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001371 }
1372 } else {
1373 SkASSERT(!other.fTs[oIndexStart].fWindValue);
1374 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1375 #if DEBUG_CONCIDENT
1376 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1377 __FUNCTION__, fID, other.fID, oIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001378 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
1379 other.xyAtT(oIndexStart).fY);
1380 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
caryclark@google.comcc905052012-07-25 20:59:42 +00001381 #endif
caryclark@google.comcc905052012-07-25 20:59:42 +00001382 }
1383 if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1384 #if DEBUG_CONCIDENT
1385 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1386 __FUNCTION__, fID, other.fID, oIndex,
1387 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1388 other.xyAtT(oIndex).fY);
1389 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1390 #endif
1391 }
1392 }
1393 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001394
caryclark@google.comcc905052012-07-25 20:59:42 +00001395 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1396 double oEnd) {
1397 // walk this to outsideTs[0]
1398 // walk other to outsideTs[1]
1399 // if either is > 0, add a pointer to the other, copying adjacent winding
1400 int tIndex = -1;
1401 int oIndex = -1;
1402 double tStart = outsideTs[0];
1403 double oStart = outsideTs[1];
1404 do {
1405 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001406 } while (!approximately_negative(tStart - fTs[tIndex].fT));
caryclark@google.comcc905052012-07-25 20:59:42 +00001407 do {
1408 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001409 } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001410 if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001411 addTPair(tStart, other, oStart, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001412 }
1413 tStart = fTs[tIndex].fT;
1414 oStart = other.fTs[oIndex].fT;
1415 do {
1416 double nextT;
1417 do {
1418 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001419 } while (approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001420 tStart = nextT;
1421 do {
1422 nextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001423 } while (approximately_negative(nextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001424 oStart = nextT;
caryclark@google.com4eeda372012-12-06 21:47:48 +00001425 if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001426 break;
1427 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00001428 addTPair(tStart, other, oStart, false);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001429 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001430 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001431
caryclark@google.com4eeda372012-12-06 21:47:48 +00001432 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
1433 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001434 fBounds.setCubicBounds(pts);
1435 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001436
caryclark@google.comf839c032012-10-26 21:03:50 +00001437 /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001438 SkPoint edge[4];
caryclark@google.comf839c032012-10-26 21:03:50 +00001439 const SkPoint* ePtr;
1440 int lastT = fTs.count() - 1;
1441 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1442 ePtr = fPts;
1443 } else {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001444 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
caryclark@google.comf839c032012-10-26 21:03:50 +00001445 (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
1446 ePtr = edge;
1447 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001448 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001449 bool reverse = ePtr == fPts && start != 0;
1450 if (reverse) {
1451 path.deferredMoveLine(ePtr[fVerb]);
1452 switch (fVerb) {
1453 case SkPath::kLine_Verb:
1454 path.deferredLine(ePtr[0]);
1455 break;
1456 case SkPath::kQuad_Verb:
1457 path.quadTo(ePtr[1], ePtr[0]);
1458 break;
1459 case SkPath::kCubic_Verb:
1460 path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1461 break;
1462 default:
1463 SkASSERT(0);
1464 }
1465 // return ePtr[0];
1466 } else {
1467 path.deferredMoveLine(ePtr[0]);
1468 switch (fVerb) {
1469 case SkPath::kLine_Verb:
1470 path.deferredLine(ePtr[1]);
1471 break;
1472 case SkPath::kQuad_Verb:
1473 path.quadTo(ePtr[1], ePtr[2]);
1474 break;
1475 case SkPath::kCubic_Verb:
1476 path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1477 break;
1478 default:
1479 SkASSERT(0);
1480 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001481 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001482 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001483 // return ePtr[fVerb];
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001484 }
1485
caryclark@google.com4eeda372012-12-06 21:47:48 +00001486 void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
1487 init(pts, SkPath::kLine_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001488 fBounds.set(pts, 2);
1489 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001490
caryclark@google.comf839c032012-10-26 21:03:50 +00001491#if 0
1492 const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001493 const SkPoint& pt = xyAtT(tIndex);
1494 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001495 path.deferredMove(pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001496 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00001497 return pt;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001498 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001499#endif
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001500
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001501 // add 2 to edge or out of range values to get T extremes
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001502 void addOtherT(int index, double otherT, int otherIndex) {
1503 Span& span = fTs[index];
caryclark@google.comf839c032012-10-26 21:03:50 +00001504 #if PIN_ADD_T
caryclark@google.com185c7c42012-10-19 18:26:24 +00001505 if (precisely_less_than_zero(otherT)) {
1506 otherT = 0;
1507 } else if (precisely_greater_than_one(otherT)) {
1508 otherT = 1;
1509 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001510 #endif
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001511 span.fOtherT = otherT;
1512 span.fOtherIndex = otherIndex;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001513 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001514
caryclark@google.com4eeda372012-12-06 21:47:48 +00001515 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
1516 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001517 fBounds.setQuadBounds(pts);
1518 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001519
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001520 // Defer all coincident edge processing until
1521 // after normal intersections have been computed
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001522
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001523// no need to be tricky; insert in normal T order
1524// resolve overlapping ts when considering coincidence later
1525
1526 // add non-coincident intersection. Resulting edges are sorted in T.
1527 int addT(double newT, Segment* other) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001528 // FIXME: in the pathological case where there is a ton of intercepts,
1529 // binary search?
1530 int insertedAt = -1;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001531 size_t tCount = fTs.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00001532 #if PIN_ADD_T
caryclark@google.comc899ad92012-08-23 15:24:42 +00001533 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
caryclark@google.com185c7c42012-10-19 18:26:24 +00001534 if (precisely_less_than_zero(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001535 newT = 0;
caryclark@google.com185c7c42012-10-19 18:26:24 +00001536 } else if (precisely_greater_than_one(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001537 newT = 1;
1538 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001539 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001540 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001541 // OPTIMIZATION: if there are three or more identical Ts, then
1542 // the fourth and following could be further insertion-sorted so
1543 // that all the edges are clockwise or counterclockwise.
1544 // This could later limit segment tests to the two adjacent
1545 // neighbors, although it doesn't help with determining which
1546 // circular direction to go in.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001547 if (newT < fTs[index].fT) {
1548 insertedAt = index;
1549 break;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001550 }
1551 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001552 Span* span;
1553 if (insertedAt >= 0) {
1554 span = fTs.insert(insertedAt);
1555 } else {
1556 insertedAt = tCount;
1557 span = fTs.append();
1558 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001559 span->fT = newT;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001560 span->fOther = other;
caryclark@google.com27c449a2012-07-27 18:26:38 +00001561 span->fPt.fX = SK_ScalarNaN;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001562 span->fWindSum = SK_MinS32;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001563 span->fOppSum = SK_MinS32;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001564 span->fWindValue = 1;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001565 span->fOppValue = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00001566 span->fTiny = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001567 if ((span->fDone = newT == 1)) {
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00001568 ++fDoneSpans;
rmistry@google.comd6176b02012-08-23 18:14:13 +00001569 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001570 span->fUnsortableStart = false;
1571 span->fUnsortableEnd = false;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001572 int less = -1;
1573 while (&span[less + 1] - fTs.begin() > 0 && !span[less].fDone
1574 && !precisely_negative(newT - span[less].fT)
1575 // && approximately_negative(newT - span[less].fT)
1576 && xyAtT(&span[less]) == xyAtT(span)) {
1577 span[less].fTiny = true;
1578 span[less].fDone = true;
1579 if (approximately_negative(newT - span[less].fT)) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00001580 if (approximately_greater_than_one(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001581 span[less].fUnsortableStart = true;
1582 span[less - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001583 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001584 if (approximately_less_than_zero(span[less].fT)) {
1585 span[less + 1].fUnsortableStart = true;
1586 span[less].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001587 }
1588 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001589 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001590 --less;
caryclark@google.comf839c032012-10-26 21:03:50 +00001591 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001592 int more = 1;
1593 while (fTs.end() - &span[more - 1] > 1 && !span[more - 1].fDone
1594 && !precisely_negative(span[more].fT - newT)
1595 // && approximately_negative(span[more].fT - newT)
1596 && xyAtT(&span[more]) == xyAtT(span)) {
1597 span[more - 1].fTiny = true;
1598 span[more - 1].fDone = true;
1599 if (approximately_negative(span[more].fT - newT)) {
1600 if (approximately_greater_than_one(span[more].fT)) {
1601 span[more + 1].fUnsortableStart = true;
1602 span[more].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001603 }
1604 if (approximately_less_than_zero(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001605 span[more].fUnsortableStart = true;
1606 span[more - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001607 }
1608 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001609 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001610 ++more;
caryclark@google.comf839c032012-10-26 21:03:50 +00001611 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001612 return insertedAt;
1613 }
1614
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001615 // set spans from start to end to decrement by one
1616 // note this walks other backwards
1617 // FIMXE: there's probably an edge case that can be constructed where
1618 // two span in one segment are separated by float epsilon on one span but
1619 // not the other, if one segment is very small. For this
1620 // case the counts asserted below may or may not be enough to separate the
caryclark@google.com2ddff932012-08-07 21:25:27 +00001621 // spans. Even if the counts work out, what if the spans aren't correctly
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001622 // sorted? It feels better in such a case to match the span's other span
1623 // pointer since both coincident segments must contain the same spans.
1624 void addTCancel(double startT, double endT, Segment& other,
1625 double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001626 SkASSERT(!approximately_negative(endT - startT));
1627 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00001628 bool binary = fOperand != other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001629 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001630 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001631 ++index;
1632 }
caryclark@google.comb9738012012-07-03 19:53:30 +00001633 int oIndex = other.fTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001634 while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001635 ;
caryclark@google.com59823f72012-08-09 18:17:47 +00001636 double tRatio = (oEndT - oStartT) / (endT - startT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001637 Span* test = &fTs[index];
1638 Span* oTest = &other.fTs[oIndex];
caryclark@google.com18063442012-07-25 12:05:18 +00001639 SkTDArray<double> outsideTs;
1640 SkTDArray<double> oOutsideTs;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001641 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001642 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
caryclark@google.comcc905052012-07-25 20:59:42 +00001643 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.com200c2112012-08-03 15:05:04 +00001644 double testT = test->fT;
1645 double oTestT = oTest->fT;
1646 Span* span = test;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001647 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001648 if (decrement) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001649 decrementSpan(span);
caryclark@google.com200c2112012-08-03 15:05:04 +00001650 } else if (track && span->fT < 1 && oTestT < 1) {
1651 TrackOutside(outsideTs, span->fT, oTestT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001652 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001653 span = &fTs[++index];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001654 } while (approximately_negative(span->fT - testT));
caryclark@google.com200c2112012-08-03 15:05:04 +00001655 Span* oSpan = oTest;
caryclark@google.com59823f72012-08-09 18:17:47 +00001656 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1657 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1658 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001659 while (approximately_negative(otherTMatchStart - oSpan->fT)
1660 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
caryclark@google.com03f97062012-08-21 13:13:52 +00001661 #ifdef SK_DEBUG
caryclark@google.com59823f72012-08-09 18:17:47 +00001662 SkASSERT(originalWindValue == oSpan->fWindValue);
caryclark@google.com03f97062012-08-21 13:13:52 +00001663 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001664 if (decrement) {
caryclark@google.com200c2112012-08-03 15:05:04 +00001665 other.decrementSpan(oSpan);
1666 } else if (track && oSpan->fT < 1 && testT < 1) {
1667 TrackOutside(oOutsideTs, oSpan->fT, testT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001668 }
1669 if (!oIndex) {
1670 break;
1671 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001672 oSpan = &other.fTs[--oIndex];
rmistry@google.comd6176b02012-08-23 18:14:13 +00001673 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001674 test = span;
1675 oTest = oSpan;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001676 } while (!approximately_negative(endT - test->fT));
1677 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
caryclark@google.com18063442012-07-25 12:05:18 +00001678 // FIXME: determine if canceled edges need outside ts added
caryclark@google.comcc905052012-07-25 20:59:42 +00001679 if (!done() && outsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001680 double tStart = outsideTs[0];
1681 double oStart = outsideTs[1];
1682 addCancelOutsides(tStart, oStart, other, oEndT);
1683 int count = outsideTs.count();
1684 if (count > 2) {
1685 double tStart = outsideTs[count - 2];
1686 double oStart = outsideTs[count - 1];
1687 addCancelOutsides(tStart, oStart, other, oEndT);
1688 }
caryclark@google.com18063442012-07-25 12:05:18 +00001689 }
caryclark@google.comcc905052012-07-25 20:59:42 +00001690 if (!other.done() && oOutsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001691 double tStart = oOutsideTs[0];
1692 double oStart = oOutsideTs[1];
1693 other.addCancelOutsides(tStart, oStart, *this, endT);
caryclark@google.com18063442012-07-25 12:05:18 +00001694 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001695 }
skia.committer@gmail.com15dd3002013-01-18 07:07:28 +00001696
caryclark@google.com73ca6242013-01-17 21:02:47 +00001697 int addUnsortableT(double newT, Segment* other, bool start) {
1698 int result = addT(newT, other);
1699 Span* span = &fTs[result];
1700 if (start) {
1701 if (result > 0) {
1702 span[result - 1].fUnsortableEnd = true;
1703 }
1704 span[result].fUnsortableStart = true;
1705 } else {
1706 span[result].fUnsortableEnd = true;
1707 if (result + 1 < fTs.count()) {
1708 span[result + 1].fUnsortableStart = true;
1709 }
1710 }
1711 return result;
1712 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00001713
caryclark@google.com4eeda372012-12-06 21:47:48 +00001714 int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1715 SkTDArray<double>& outsideTs) {
1716 int oWindValue = oTest->fWindValue;
1717 int oOppValue = oTest->fOppValue;
1718 if (opp) {
1719 SkTSwap<int>(oWindValue, oOppValue);
1720 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001721 Span* const test = &fTs[index];
1722 Span* end = test;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001723 const double oStartT = oTest->fT;
1724 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001725 if (bumpSpan(end, oWindValue, oOppValue)) {
1726 TrackOutside(outsideTs, end->fT, oStartT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001727 }
1728 end = &fTs[++index];
1729 } while (approximately_negative(end->fT - test->fT));
1730 return index;
1731 }
1732
1733 // because of the order in which coincidences are resolved, this and other
1734 // may not have the same intermediate points. Compute the corresponding
1735 // intermediate T values (using this as the master, other as the follower)
1736 // and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com4eeda372012-12-06 21:47:48 +00001737 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1738 SkTDArray<double>& oOutsideTs) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001739 Span* const oTest = &fTs[oIndex];
1740 Span* oEnd = oTest;
1741 const double startT = test->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001742 const double oStartT = oTest->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001743 while (!approximately_negative(oEndT - oEnd->fT)
caryclark@google.com4eeda372012-12-06 21:47:48 +00001744 && approximately_negative(oEnd->fT - oStartT)) {
1745 zeroSpan(oEnd);
1746 TrackOutside(oOutsideTs, oEnd->fT, startT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001747 oEnd = &fTs[++oIndex];
1748 }
1749 return oIndex;
1750 }
1751
1752 // FIXME: need to test this case:
1753 // contourA has two segments that are coincident
1754 // contourB has two segments that are coincident in the same place
1755 // each ends up with +2/0 pairs for winding count
1756 // since logic below doesn't transfer count (only increments/decrements) can this be
1757 // resolved to +4/0 ?
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001758
1759 // set spans from start to end to increment the greater by one and decrement
1760 // the lesser
caryclark@google.com4eeda372012-12-06 21:47:48 +00001761 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001762 SkASSERT(!approximately_negative(endT - startT));
1763 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001764 bool opp = fOperand ^ other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001765 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001766 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001767 ++index;
1768 }
1769 int oIndex = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001770 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001771 ++oIndex;
1772 }
1773 Span* test = &fTs[index];
1774 Span* oTest = &other.fTs[oIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001775 SkTDArray<double> outsideTs;
1776 SkTDArray<double> oOutsideTs;
1777 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001778 // if either span has an opposite value and the operands don't match, resolve first
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001779 // SkASSERT(!test->fDone || !oTest->fDone);
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001780 if (test->fDone || oTest->fDone) {
1781 index = advanceCoincidentThis(oTest, opp, index);
1782 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
1783 } else {
1784 index = bumpCoincidentThis(oTest, opp, index, outsideTs);
1785 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
1786 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001787 test = &fTs[index];
1788 oTest = &other.fTs[oIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001789 } while (!approximately_negative(endT - test->fT));
1790 SkASSERT(approximately_negative(oTest->fT - oEndT));
1791 SkASSERT(approximately_negative(oEndT - oTest->fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001792 if (!done() && outsideTs.count()) {
1793 addCoinOutsides(outsideTs, other, oEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001794 }
1795 if (!other.done() && oOutsideTs.count()) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001796 other.addCoinOutsides(oOutsideTs, *this, endT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001797 }
1798 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001799
caryclark@google.comcc905052012-07-25 20:59:42 +00001800 // FIXME: this doesn't prevent the same span from being added twice
caryclark@google.comaa358312013-01-29 20:28:49 +00001801 // fix in caller, SkASSERT here?
caryclark@google.com2ddff932012-08-07 21:25:27 +00001802 void addTPair(double t, Segment& other, double otherT, bool borrowWind) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001803 int tCount = fTs.count();
1804 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1805 const Span& span = fTs[tIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001806 if (!approximately_negative(span.fT - t)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001807 break;
1808 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001809 if (approximately_negative(span.fT - t) && span.fOther == &other
1810 && approximately_equal(span.fOtherT, otherT)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001811#if DEBUG_ADD_T_PAIR
1812 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1813 __FUNCTION__, fID, t, other.fID, otherT);
1814#endif
1815 return;
1816 }
1817 }
caryclark@google.com47580692012-07-23 12:14:49 +00001818#if DEBUG_ADD_T_PAIR
1819 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1820 __FUNCTION__, fID, t, other.fID, otherT);
1821#endif
caryclark@google.comb9738012012-07-03 19:53:30 +00001822 int insertedAt = addT(t, &other);
1823 int otherInsertedAt = other.addT(otherT, this);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001824 addOtherT(insertedAt, otherT, otherInsertedAt);
caryclark@google.comb9738012012-07-03 19:53:30 +00001825 other.addOtherT(otherInsertedAt, t, insertedAt);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001826 matchWindingValue(insertedAt, t, borrowWind);
1827 other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001828 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001829
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001830 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001831 // add edge leading into junction
caryclark@google.com4eeda372012-12-06 21:47:48 +00001832 int min = SkMin32(end, start);
1833 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001834 addAngle(angles, end, start);
1835 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001836 // add edge leading away from junction
caryclark@google.com495f8e42012-05-31 13:13:11 +00001837 int step = SkSign32(end - start);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001838 int tIndex = nextExactSpan(end, step);
caryclark@google.com4eeda372012-12-06 21:47:48 +00001839 min = SkMin32(end, tIndex);
1840 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001841 addAngle(angles, end, tIndex);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001842 }
1843 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001844
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001845 int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
1846 Span* const test = &fTs[index];
1847 Span* end = test;
1848 do {
1849 end = &fTs[++index];
1850 } while (approximately_negative(end->fT - test->fT));
1851 return index;
1852 }
1853
1854 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
1855 Span* const oTest = &fTs[oIndex];
1856 Span* oEnd = oTest;
1857 const double oStartT = oTest->fT;
1858 while (!approximately_negative(oEndT - oEnd->fT)
1859 && approximately_negative(oEnd->fT - oStartT)) {
1860 oEnd = &fTs[++oIndex];
1861 }
1862 return oIndex;
1863 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00001864
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001865 bool betweenTs(int lesser, double testT, int greater) {
1866 if (lesser > greater) {
1867 SkTSwap<int>(lesser, greater);
1868 }
1869 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
1870 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001871
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001872 const Bounds& bounds() const {
1873 return fBounds;
1874 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001875
caryclark@google.com31143cf2012-11-09 22:14:19 +00001876 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001877 double referenceT = fTs[index].fT;
1878 int lesser = index;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001879 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
1880 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00001881 buildAnglesInner(lesser, angles);
1882 }
1883 do {
1884 buildAnglesInner(index, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001885 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
1886 && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001887 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001888
1889 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
1890 Span* span = &fTs[index];
1891 Segment* other = span->fOther;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001892 // if there is only one live crossing, and no coincidence, continue
1893 // in the same direction
1894 // if there is coincidence, the only choice may be to reverse direction
1895 // find edge on either side of intersection
1896 int oIndex = span->fOtherIndex;
1897 // if done == -1, prior span has already been processed
1898 int step = 1;
caryclark@google.coma461ff02012-10-11 12:54:23 +00001899 int next = other->nextExactSpan(oIndex, step);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001900 if (next < 0) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001901 step = -step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00001902 next = other->nextExactSpan(oIndex, step);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001903 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001904 // add candidate into and away from junction
1905 other->addTwoAngles(next, oIndex, angles);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001906 }
1907
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001908 int computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001909 SkTDArray<Angle> angles;
1910 addTwoAngles(startIndex, endIndex, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001911 buildAngles(endIndex, angles, false);
caryclark@google.comd1688742012-09-18 20:08:37 +00001912 // OPTIMIZATION: check all angles to see if any have computed wind sum
1913 // before sorting (early exit if none)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001914 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001915 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00001916#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00001917 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00001918#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001919 if (!sortable) {
1920 return SK_MinS32;
1921 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001922 int angleCount = angles.count();
1923 const Angle* angle;
1924 const Segment* base;
1925 int winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001926 int oWinding;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001927 int firstIndex = 0;
1928 do {
1929 angle = sorted[firstIndex];
1930 base = angle->segment();
1931 winding = base->windSum(angle);
1932 if (winding != SK_MinS32) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001933 oWinding = base->oppSum(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001934 break;
1935 }
1936 if (++firstIndex == angleCount) {
1937 return SK_MinS32;
1938 }
1939 } while (true);
1940 // turn winding into contourWinding
caryclark@google.com2ddff932012-08-07 21:25:27 +00001941 int spanWinding = base->spanSign(angle);
1942 bool inner = useInnerWinding(winding + spanWinding, winding);
1943 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00001944 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
caryclark@google.com59823f72012-08-09 18:17:47 +00001945 spanWinding, winding, angle->sign(), inner,
caryclark@google.com2ddff932012-08-07 21:25:27 +00001946 inner ? winding + spanWinding : winding);
1947 #endif
1948 if (inner) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001949 winding += spanWinding;
1950 }
1951 #if DEBUG_SORT
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001952 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001953 #endif
1954 int nextIndex = firstIndex + 1;
1955 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com2ddff932012-08-07 21:25:27 +00001956 winding -= base->spanSign(angle);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001957 oWinding -= base->oppSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001958 do {
1959 if (nextIndex == angleCount) {
1960 nextIndex = 0;
1961 }
1962 angle = sorted[nextIndex];
1963 Segment* segment = angle->segment();
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001964 bool opp = base->fOperand ^ segment->fOperand;
1965 int maxWinding, oMaxWinding;
1966 int spanSign = segment->spanSign(angle);
1967 int oppoSign = segment->oppSign(angle);
1968 if (opp) {
1969 oMaxWinding = oWinding;
1970 oWinding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00001971 maxWinding = winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001972 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001973 winding -= oppoSign;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001974 }
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001975 } else {
1976 maxWinding = winding;
1977 winding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00001978 oMaxWinding = oWinding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001979 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001980 oWinding -= oppoSign;
1981 }
1982 }
1983 if (segment->windSum(angle) == SK_MinS32) {
1984 if (opp) {
1985 if (useInnerWinding(oMaxWinding, oWinding)) {
1986 oMaxWinding = oWinding;
1987 }
1988 if (oppoSign && useInnerWinding(maxWinding, winding)) {
1989 maxWinding = winding;
1990 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001991 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001992 } else {
1993 if (useInnerWinding(maxWinding, winding)) {
1994 maxWinding = winding;
1995 }
1996 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
1997 oMaxWinding = oWinding;
1998 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001999 (void) segment->markAndChaseWinding(angle, maxWinding,
2000 binary ? oMaxWinding : 0);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002001 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002002 }
2003 } while (++nextIndex != lastIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002004 int minIndex = SkMin32(startIndex, endIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002005 return windSum(minIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002006 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002007
caryclark@google.com3586ece2012-12-27 18:46:58 +00002008 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
caryclark@google.com10227bf2012-12-28 22:10:41 +00002009 double mid, bool opp, bool current) const {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002010 SkScalar bottom = fBounds.fBottom;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002011 int bestTIndex = -1;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002012 if (bottom <= bestY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002013 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002014 }
2015 SkScalar top = fBounds.fTop;
2016 if (top >= basePt.fY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002017 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002018 }
2019 if (fBounds.fLeft > basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002020 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002021 }
2022 if (fBounds.fRight < basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002023 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002024 }
2025 if (fBounds.fLeft == fBounds.fRight) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002026 // if vertical, and directly above test point, wait for another one
caryclark@google.com6d0032a2013-01-04 19:41:13 +00002027 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002028 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002029 // intersect ray starting at basePt with edge
2030 Intersections intersections;
2031 // OPTIMIZE: use specialty function that intersects ray with curve,
2032 // returning t values only for curve (we don't care about t on ray)
2033 int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
2034 if (pts == 0 || (current && pts == 1)) {
2035 return bestTIndex;
2036 }
2037 if (current) {
2038 SkASSERT(pts > 1);
2039 int closestIdx = 0;
2040 double closest = fabs(intersections.fT[0][0] - mid);
2041 for (int idx = 1; idx < pts; ++idx) {
2042 double test = fabs(intersections.fT[0][idx] - mid);
2043 if (closest > test) {
2044 closestIdx = idx;
2045 closest = test;
2046 }
2047 }
2048 if (closestIdx < pts - 1) {
2049 intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
2050 }
2051 --pts;
2052 }
2053 double bestT = -1;
2054 for (int index = 0; index < pts; ++index) {
2055 double foundT = intersections.fT[0][index];
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002056 if (approximately_less_than_zero(foundT)
2057 || approximately_greater_than_one(foundT)) {
2058 continue;
2059 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002060 SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
2061 if (approximately_negative(testY - bestY)
2062 || approximately_negative(basePt.fY - testY)) {
caryclark@google.com47580692012-07-23 12:14:49 +00002063 continue;
2064 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002065 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002066 return SK_MinS32; // if the intersection is edge on, wait for another one
caryclark@google.com10227bf2012-12-28 22:10:41 +00002067 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002068 if (fVerb > SkPath::kLine_Verb) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002069 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
2070 if (approximately_zero(dx)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002071 return SK_MinS32; // hit vertical, wait for another one
caryclark@google.com3586ece2012-12-27 18:46:58 +00002072 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00002073 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002074 bestY = testY;
2075 bestT = foundT;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002076 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002077 if (bestT < 0) {
2078 return bestTIndex;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002079 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002080 SkASSERT(bestT >= 0);
2081 SkASSERT(bestT <= 1);
2082 int start;
2083 int end = 0;
2084 do {
2085 start = end;
2086 end = nextSpan(start, 1);
2087 } while (fTs[end].fT < bestT);
2088 // FIXME: see next candidate for a better pattern to find the next start/end pair
2089 while (start + 1 < end && fTs[start].fDone) {
2090 ++start;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002091 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002092 if (!isCanceled(start)) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002093 hitT = bestT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002094 bestTIndex = start;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002095 hitSomething = true;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002096 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002097 return bestTIndex;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002098 }
caryclark@google.com18063442012-07-25 12:05:18 +00002099
caryclark@google.com4eeda372012-12-06 21:47:48 +00002100 void decrementSpan(Span* span) {
caryclark@google.com18063442012-07-25 12:05:18 +00002101 SkASSERT(span->fWindValue > 0);
2102 if (--(span->fWindValue) == 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002103 if (!span->fOppValue && !span->fDone) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002104 span->fDone = true;
2105 ++fDoneSpans;
2106 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002107 }
2108 }
2109
2110 bool bumpSpan(Span* span, int windDelta, int oppDelta) {
2111 SkASSERT(!span->fDone);
2112 span->fWindValue += windDelta;
2113 SkASSERT(span->fWindValue >= 0);
2114 span->fOppValue += oppDelta;
2115 SkASSERT(span->fOppValue >= 0);
2116 if (fXor) {
2117 span->fWindValue &= 1;
2118 }
2119 if (fOppXor) {
2120 span->fOppValue &= 1;
2121 }
2122 if (!span->fWindValue && !span->fOppValue) {
2123 span->fDone = true;
2124 ++fDoneSpans;
caryclark@google.com18063442012-07-25 12:05:18 +00002125 return true;
2126 }
2127 return false;
2128 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002129
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002130 // OPTIMIZE
2131 // when the edges are initially walked, they don't automatically get the prior and next
2132 // 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 +00002133 // and would additionally remove the need for similar checks in condition edges. It would
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002134 // also allow intersection code to assume end of segment intersections (maybe?)
2135 bool complete() const {
2136 int count = fTs.count();
2137 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
2138 }
caryclark@google.com18063442012-07-25 12:05:18 +00002139
caryclark@google.com15fa1382012-05-07 20:49:36 +00002140 bool done() const {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002141 SkASSERT(fDoneSpans <= fTs.count());
2142 return fDoneSpans == fTs.count();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002143 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002144
caryclark@google.comf839c032012-10-26 21:03:50 +00002145 bool done(int min) const {
2146 return fTs[min].fDone;
2147 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002148
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002149 bool done(const Angle* angle) const {
2150 return done(SkMin32(angle->start(), angle->end()));
caryclark@google.com47580692012-07-23 12:14:49 +00002151 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00002152
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002153 bool equalPoints(int greaterTIndex, int lesserTIndex) {
2154 SkASSERT(greaterTIndex >= lesserTIndex);
2155 double greaterT = fTs[greaterTIndex].fT;
2156 double lesserT = fTs[lesserTIndex].fT;
2157 if (greaterT == lesserT) {
2158 return true;
2159 }
2160 if (!approximately_negative(greaterT - lesserT)) {
2161 return false;
2162 }
2163 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2164 }
2165
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002166 /*
2167 The M and S variable name parts stand for the operators.
2168 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2169 Su stands for Subtrahend
2170 The Opp variable name part designates that the value is for the Opposite operator.
2171 Opposite values result from combining coincident spans.
2172 */
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002173
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002174 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2175 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002176 const int startIndex = nextStart;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002177 const int endIndex = nextEnd;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002178 SkASSERT(startIndex != endIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002179 const int count = fTs.count();
2180 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2181 const int step = SkSign32(endIndex - startIndex);
2182 const int end = nextExactSpan(startIndex, step);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002183 SkASSERT(end >= 0);
2184 Span* endSpan = &fTs[end];
2185 Segment* other;
2186 if (isSimple(end)) {
2187 // mark the smaller of startIndex, endIndex done, and all adjacent
2188 // spans with the same T value (but not 'other' spans)
2189 #if DEBUG_WINDING
2190 SkDebugf("%s simple\n", __FUNCTION__);
2191 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002192 int min = SkMin32(startIndex, endIndex);
2193 if (fTs[min].fDone) {
2194 return NULL;
2195 }
2196 markDoneBinary(min);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002197 other = endSpan->fOther;
2198 nextStart = endSpan->fOtherIndex;
2199 double startT = other->fTs[nextStart].fT;
2200 nextEnd = nextStart;
2201 do {
2202 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002203 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002204 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002205 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2206 return other;
2207 }
2208 // more than one viable candidate -- measure angles to find best
2209 SkTDArray<Angle> angles;
2210 SkASSERT(startIndex - endIndex != 0);
2211 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2212 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002213 buildAngles(end, angles, true);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002214 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002215 bool sortable = SortAngles(angles, sorted);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002216 int angleCount = angles.count();
2217 int firstIndex = findStartingEdge(sorted, startIndex, end);
2218 SkASSERT(firstIndex >= 0);
2219 #if DEBUG_SORT
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002220 debugShowSort(__FUNCTION__, sorted, firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002221 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002222 if (!sortable) {
2223 unsortable = true;
2224 return NULL;
2225 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002226 SkASSERT(sorted[firstIndex]->segment() == this);
2227 #if DEBUG_WINDING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002228 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2229 sorted[firstIndex]->sign());
caryclark@google.com235f56a2012-09-14 14:19:30 +00002230 #endif
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002231 int sumMiWinding = updateWinding(endIndex, startIndex);
2232 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2233 if (operand()) {
2234 SkTSwap<int>(sumMiWinding, sumSuWinding);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002235 }
2236 int nextIndex = firstIndex + 1;
2237 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2238 const Angle* foundAngle = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002239 bool foundDone = false;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002240 // iterate through the angle, and compute everyone's winding
caryclark@google.com235f56a2012-09-14 14:19:30 +00002241 Segment* nextSegment;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002242 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002243 SkASSERT(nextIndex != firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002244 if (nextIndex == angleCount) {
2245 nextIndex = 0;
2246 }
2247 const Angle* nextAngle = sorted[nextIndex];
2248 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002249 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2250 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2251 nextAngle->end(), op, sumMiWinding, sumSuWinding,
2252 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
2253 if (activeAngle && (!foundAngle || foundDone)) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002254 foundAngle = nextAngle;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002255 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002256 }
2257 if (nextSegment->done()) {
2258 continue;
2259 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002260 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2261 continue;
2262 }
2263 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2264 oppSumWinding, activeAngle, nextAngle);
2265 if (last) {
2266 *chase.append() = last;
2267#if DEBUG_WINDING
2268 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2269 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2270#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002271 }
2272 } while (++nextIndex != lastIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002273 markDoneBinary(SkMin32(startIndex, endIndex));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002274 if (!foundAngle) {
2275 return NULL;
2276 }
2277 nextStart = foundAngle->start();
2278 nextEnd = foundAngle->end();
2279 nextSegment = foundAngle->segment();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002280
caryclark@google.com235f56a2012-09-14 14:19:30 +00002281 #if DEBUG_WINDING
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002282 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2283 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002284 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002285 return nextSegment;
2286 }
caryclark@google.com47580692012-07-23 12:14:49 +00002287
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002288 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2289 bool& unsortable) {
2290 const int startIndex = nextStart;
2291 const int endIndex = nextEnd;
2292 SkASSERT(startIndex != endIndex);
2293 const int count = fTs.count();
2294 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2295 const int step = SkSign32(endIndex - startIndex);
2296 const int end = nextExactSpan(startIndex, step);
2297 SkASSERT(end >= 0);
2298 Span* endSpan = &fTs[end];
2299 Segment* other;
2300 if (isSimple(end)) {
2301 // mark the smaller of startIndex, endIndex done, and all adjacent
2302 // spans with the same T value (but not 'other' spans)
2303 #if DEBUG_WINDING
2304 SkDebugf("%s simple\n", __FUNCTION__);
2305 #endif
2306 int min = SkMin32(startIndex, endIndex);
2307 if (fTs[min].fDone) {
2308 return NULL;
2309 }
2310 markDoneUnary(min);
2311 other = endSpan->fOther;
2312 nextStart = endSpan->fOtherIndex;
2313 double startT = other->fTs[nextStart].fT;
2314 nextEnd = nextStart;
2315 do {
2316 nextEnd += step;
2317 }
2318 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2319 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2320 return other;
2321 }
2322 // more than one viable candidate -- measure angles to find best
2323 SkTDArray<Angle> angles;
2324 SkASSERT(startIndex - endIndex != 0);
2325 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2326 addTwoAngles(startIndex, end, angles);
2327 buildAngles(end, angles, true);
2328 SkTDArray<Angle*> sorted;
2329 bool sortable = SortAngles(angles, sorted);
2330 int angleCount = angles.count();
2331 int firstIndex = findStartingEdge(sorted, startIndex, end);
2332 SkASSERT(firstIndex >= 0);
2333 #if DEBUG_SORT
2334 debugShowSort(__FUNCTION__, sorted, firstIndex);
2335 #endif
2336 if (!sortable) {
2337 unsortable = true;
2338 return NULL;
2339 }
2340 SkASSERT(sorted[firstIndex]->segment() == this);
2341 #if DEBUG_WINDING
2342 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2343 sorted[firstIndex]->sign());
2344 #endif
2345 int sumWinding = updateWinding(endIndex, startIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002346 int nextIndex = firstIndex + 1;
2347 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2348 const Angle* foundAngle = NULL;
2349 bool foundDone = false;
2350 // iterate through the angle, and compute everyone's winding
2351 Segment* nextSegment;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002352 int activeCount = 0;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002353 do {
2354 SkASSERT(nextIndex != firstIndex);
2355 if (nextIndex == angleCount) {
2356 nextIndex = 0;
2357 }
2358 const Angle* nextAngle = sorted[nextIndex];
2359 nextSegment = nextAngle->segment();
2360 int maxWinding;
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00002361 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002362 maxWinding, sumWinding);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002363 if (activeAngle) {
2364 ++activeCount;
2365 if (!foundAngle || (foundDone && activeCount & 1)) {
2366 if (nextSegment->tiny(nextAngle)) {
2367 unsortable = true;
2368 return NULL;
2369 }
2370 foundAngle = nextAngle;
2371 foundDone = nextSegment->done(nextAngle);
2372 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002373 }
2374 if (nextSegment->done()) {
2375 continue;
2376 }
2377 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2378 continue;
2379 }
2380 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2381 if (last) {
2382 *chase.append() = last;
2383#if DEBUG_WINDING
2384 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2385 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2386#endif
2387 }
2388 } while (++nextIndex != lastIndex);
2389 markDoneUnary(SkMin32(startIndex, endIndex));
2390 if (!foundAngle) {
2391 return NULL;
2392 }
2393 nextStart = foundAngle->start();
2394 nextEnd = foundAngle->end();
2395 nextSegment = foundAngle->segment();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002396 #if DEBUG_WINDING
2397 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2398 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2399 #endif
2400 return nextSegment;
2401 }
2402
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002403 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002404 const int startIndex = nextStart;
2405 const int endIndex = nextEnd;
2406 SkASSERT(startIndex != endIndex);
2407 int count = fTs.count();
2408 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2409 : startIndex > 0);
2410 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002411 int end = nextExactSpan(startIndex, step);
caryclark@google.com24bec792012-08-20 12:43:57 +00002412 SkASSERT(end >= 0);
2413 Span* endSpan = &fTs[end];
2414 Segment* other;
caryclark@google.com24bec792012-08-20 12:43:57 +00002415 if (isSimple(end)) {
2416 #if DEBUG_WINDING
2417 SkDebugf("%s simple\n", __FUNCTION__);
2418 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002419 int min = SkMin32(startIndex, endIndex);
2420 if (fTs[min].fDone) {
2421 return NULL;
2422 }
2423 markDone(min, 1);
caryclark@google.com24bec792012-08-20 12:43:57 +00002424 other = endSpan->fOther;
2425 nextStart = endSpan->fOtherIndex;
2426 double startT = other->fTs[nextStart].fT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002427 #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 +00002428 SkDEBUGCODE(bool firstLoop = true;)
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002429 if ((approximately_less_than_zero(startT) && step < 0)
2430 || (approximately_greater_than_one(startT) && step > 0)) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002431 step = -step;
2432 SkDEBUGCODE(firstLoop = false;)
2433 }
2434 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002435 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002436 nextEnd = nextStart;
2437 do {
2438 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002439 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002440 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002441 #if 01
caryclark@google.com24bec792012-08-20 12:43:57 +00002442 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2443 break;
2444 }
caryclark@google.com03f97062012-08-21 13:13:52 +00002445 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00002446 SkASSERT(firstLoop);
caryclark@google.com03f97062012-08-21 13:13:52 +00002447 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002448 SkDEBUGCODE(firstLoop = false;)
2449 step = -step;
2450 } while (true);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002451 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002452 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2453 return other;
2454 }
2455 SkTDArray<Angle> angles;
2456 SkASSERT(startIndex - endIndex != 0);
2457 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2458 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002459 buildAngles(end, angles, false);
caryclark@google.com24bec792012-08-20 12:43:57 +00002460 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002461 bool sortable = SortAngles(angles, sorted);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002462 if (!sortable) {
2463 unsortable = true;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002464 #if DEBUG_SORT
2465 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
2466 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002467 return NULL;
2468 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002469 int angleCount = angles.count();
2470 int firstIndex = findStartingEdge(sorted, startIndex, end);
2471 SkASSERT(firstIndex >= 0);
2472 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002473 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
caryclark@google.com24bec792012-08-20 12:43:57 +00002474 #endif
2475 SkASSERT(sorted[firstIndex]->segment() == this);
2476 int nextIndex = firstIndex + 1;
2477 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002478 const Angle* foundAngle = NULL;
2479 bool foundDone = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002480 Segment* nextSegment;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002481 int activeCount = 0;
caryclark@google.com24bec792012-08-20 12:43:57 +00002482 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002483 SkASSERT(nextIndex != firstIndex);
caryclark@google.com24bec792012-08-20 12:43:57 +00002484 if (nextIndex == angleCount) {
2485 nextIndex = 0;
2486 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002487 const Angle* nextAngle = sorted[nextIndex];
caryclark@google.com24bec792012-08-20 12:43:57 +00002488 nextSegment = nextAngle->segment();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002489 ++activeCount;
2490 if (!foundAngle || (foundDone && activeCount & 1)) {
2491 if (nextSegment->tiny(nextAngle)) {
2492 unsortable = true;
2493 return NULL;
2494 }
2495 foundAngle = nextAngle;
2496 foundDone = nextSegment->done(nextAngle);
2497 }
2498 if (nextSegment->done()) {
2499 continue;
caryclark@google.com24bec792012-08-20 12:43:57 +00002500 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002501 } while (++nextIndex != lastIndex);
2502 markDone(SkMin32(startIndex, endIndex), 1);
2503 if (!foundAngle) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002504 return NULL;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002505 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002506 nextStart = foundAngle->start();
2507 nextEnd = foundAngle->end();
2508 nextSegment = foundAngle->segment();
2509 #if DEBUG_WINDING
2510 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2511 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2512 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002513 return nextSegment;
2514 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002515
2516 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2517 int angleCount = sorted.count();
2518 int firstIndex = -1;
2519 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2520 const Angle* angle = sorted[angleIndex];
2521 if (angle->segment() == this && angle->start() == end &&
2522 angle->end() == start) {
2523 firstIndex = angleIndex;
2524 break;
2525 }
2526 }
2527 return firstIndex;
2528 }
2529
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002530 // FIXME: this is tricky code; needs its own unit test
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002531 // note that fOtherIndex isn't computed yet, so it can't be used here
caryclark@google.com4eeda372012-12-06 21:47:48 +00002532 void findTooCloseToCall() {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002533 int count = fTs.count();
2534 if (count < 3) { // require t=0, x, 1 at minimum
2535 return;
2536 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002537 int matchIndex = 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002538 int moCount;
2539 Span* match;
2540 Segment* mOther;
2541 do {
2542 match = &fTs[matchIndex];
2543 mOther = match->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002544 // FIXME: allow quads, cubics to be near coincident?
2545 if (mOther->fVerb == SkPath::kLine_Verb) {
2546 moCount = mOther->fTs.count();
2547 if (moCount >= 3) {
2548 break;
2549 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002550 }
2551 if (++matchIndex >= count) {
2552 return;
2553 }
2554 } while (true); // require t=0, x, 1 at minimum
caryclark@google.com15fa1382012-05-07 20:49:36 +00002555 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002556 const SkPoint* matchPt = &xyAtT(match);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002557 // look for a pair of nearby T values that map to the same (x,y) value
2558 // if found, see if the pair of other segments share a common point. If
2559 // so, the span from here to there is coincident.
caryclark@google.com15fa1382012-05-07 20:49:36 +00002560 for (int index = matchIndex + 1; index < count; ++index) {
2561 Span* test = &fTs[index];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002562 if (test->fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002563 continue;
2564 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002565 Segment* tOther = test->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002566 if (tOther->fVerb != SkPath::kLine_Verb) {
2567 continue; // FIXME: allow quads, cubics to be near coincident?
2568 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002569 int toCount = tOther->fTs.count();
2570 if (toCount < 3) { // require t=0, x, 1 at minimum
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002571 continue;
2572 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002573 const SkPoint* testPt = &xyAtT(test);
2574 if (*matchPt != *testPt) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002575 matchIndex = index;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002576 moCount = toCount;
2577 match = test;
2578 mOther = tOther;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002579 matchPt = testPt;
2580 continue;
2581 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002582 int moStart = -1;
2583 int moEnd = -1;
2584 double moStartT, moEndT;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002585 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002586 Span& moSpan = mOther->fTs[moIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002587 if (moSpan.fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002588 continue;
2589 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002590 if (moSpan.fOther == this) {
2591 if (moSpan.fOtherT == match->fT) {
2592 moStart = moIndex;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002593 moStartT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002594 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002595 continue;
2596 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002597 if (moSpan.fOther == tOther) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002598 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002599 moStart = -1;
2600 break;
2601 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002602 SkASSERT(moEnd == -1);
2603 moEnd = moIndex;
2604 moEndT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002605 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002606 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002607 if (moStart < 0 || moEnd < 0) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002608 continue;
2609 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002610 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002611 if (approximately_equal(moStartT, moEndT)) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002612 continue;
2613 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002614 int toStart = -1;
2615 int toEnd = -1;
2616 double toStartT, toEndT;
2617 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2618 Span& toSpan = tOther->fTs[toIndex];
caryclark@google.comc899ad92012-08-23 15:24:42 +00002619 if (toSpan.fDone) {
2620 continue;
2621 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002622 if (toSpan.fOther == this) {
2623 if (toSpan.fOtherT == test->fT) {
2624 toStart = toIndex;
2625 toStartT = toSpan.fT;
2626 }
2627 continue;
2628 }
2629 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002630 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002631 moStart = -1;
2632 break;
2633 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002634 SkASSERT(toEnd == -1);
2635 toEnd = toIndex;
2636 toEndT = toSpan.fT;
2637 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002638 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002639 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2640 if (toStart <= 0 || toEnd <= 0) {
2641 continue;
2642 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002643 if (approximately_equal(toStartT, toEndT)) {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002644 continue;
2645 }
2646 // test to see if the segment between there and here is linear
2647 if (!mOther->isLinear(moStart, moEnd)
2648 || !tOther->isLinear(toStart, toEnd)) {
2649 continue;
2650 }
caryclark@google.comc899ad92012-08-23 15:24:42 +00002651 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002652 if (flipped) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002653 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002654 } else {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002655 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002656 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002657 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002658 }
2659
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002660 // start here;
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00002661 // either:
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002662 // a) mark spans with either end unsortable as done, or
2663 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2664 // when encountering an unsortable span
2665
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002666 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2667 // and use more concise logic like the old edge walker code?
2668 // FIXME: this needs to deal with coincident edges
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002669 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002670 // iterate through T intersections and return topmost
2671 // topmost tangent from y-min to first pt is closer to horizontal
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002672 SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002673 int firstT = -1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002674 SkPoint topPt;
2675 topPt.fY = SK_ScalarMax;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002676 int count = fTs.count();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002677 // see if either end is not done since we want smaller Y of the pair
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002678 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002679 bool lastUnsortable = false;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002680 for (int index = 0; index < count; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002681 const Span& span = fTs[index];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002682 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002683 goto next;
2684 }
2685 if (!span.fDone | !lastDone) {
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002686 const SkPoint& intercept = xyAtT(&span);
2687 if (topPt.fY > intercept.fY || (topPt.fY == intercept.fY
2688 && topPt.fX > intercept.fX)) {
2689 topPt = intercept;
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002690 firstT = index;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002691 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002692 }
caryclark@google.comf839c032012-10-26 21:03:50 +00002693 next:
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002694 lastDone = span.fDone;
caryclark@google.comf839c032012-10-26 21:03:50 +00002695 lastUnsortable = span.fUnsortableEnd;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002696 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002697 SkASSERT(firstT >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002698 // sort the edges to find the leftmost
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002699 int step = 1;
2700 int end = nextSpan(firstT, step);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002701 if (end == -1) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002702 step = -1;
2703 end = nextSpan(firstT, step);
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00002704 SkASSERT(end != -1);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002705 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002706 // if the topmost T is not on end, or is three-way or more, find left
2707 // look for left-ness from tLeft to firstT (matching y of other)
2708 SkTDArray<Angle> angles;
2709 SkASSERT(firstT - end != 0);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002710 addTwoAngles(end, firstT, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002711 buildAngles(firstT, angles, true);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002712 SkTDArray<Angle*> sorted;
caryclark@google.comf839c032012-10-26 21:03:50 +00002713 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002714 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002715 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002716 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002717 if (onlySortable && !sortable) {
2718 unsortable = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002719 return NULL;
2720 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002721 // skip edges that have already been processed
2722 firstT = -1;
2723 Segment* leftSegment;
2724 do {
2725 const Angle* angle = sorted[++firstT];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002726 SkASSERT(!onlySortable || !angle->unsortable());
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002727 leftSegment = angle->segment();
2728 tIndex = angle->end();
2729 endIndex = angle->start();
2730 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002731 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002732 return leftSegment;
2733 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002734
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002735 // FIXME: not crazy about this
2736 // when the intersections are performed, the other index is into an
2737 // incomplete array. as the array grows, the indices become incorrect
2738 // while the following fixes the indices up again, it isn't smart about
2739 // skipping segments whose indices are already correct
2740 // assuming we leave the code that wrote the index in the first place
2741 void fixOtherTIndex() {
2742 int iCount = fTs.count();
2743 for (int i = 0; i < iCount; ++i) {
2744 Span& iSpan = fTs[i];
2745 double oT = iSpan.fOtherT;
2746 Segment* other = iSpan.fOther;
2747 int oCount = other->fTs.count();
2748 for (int o = 0; o < oCount; ++o) {
2749 Span& oSpan = other->fTs[o];
2750 if (oT == oSpan.fT && this == oSpan.fOther) {
2751 iSpan.fOtherIndex = o;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002752 break;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002753 }
2754 }
2755 }
2756 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002757
caryclark@google.com4eeda372012-12-06 21:47:48 +00002758 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002759 fDoneSpans = 0;
2760 fOperand = operand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00002761 fXor = evenOdd;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002762 fPts = pts;
2763 fVerb = verb;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002764 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00002765
caryclark@google.com3586ece2012-12-27 18:46:58 +00002766 void initWinding(int start, int end) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002767 int local = spanSign(start, end);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002768 int oppLocal = oppSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002769 (void) markAndChaseWinding(start, end, local, oppLocal);
caryclark@google.com73ca6242013-01-17 21:02:47 +00002770 // OPTIMIZATION: the reverse mark and chase could skip the first marking
2771 (void) markAndChaseWinding(end, start, local, oppLocal);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002772 }
2773
caryclark@google.com3586ece2012-12-27 18:46:58 +00002774 void initWinding(int start, int end, int winding, int oppWinding) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002775 int local = spanSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002776 if (local * winding >= 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002777 winding += local;
2778 }
2779 int oppLocal = oppSign(start, end);
2780 if (oppLocal * oppWinding >= 0) {
2781 oppWinding += oppLocal;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002782 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002783 (void) markAndChaseWinding(start, end, winding, oppWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002784 }
2785
caryclark@google.com3586ece2012-12-27 18:46:58 +00002786/*
2787when we start with a vertical intersect, we try to use the dx to determine if the edge is to
2788the 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 +00002789sign or not. However, this isn't enough.
2790If 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 +00002791If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
2792from 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 +00002793the same winding is shared by both.
caryclark@google.com3586ece2012-12-27 18:46:58 +00002794*/
2795 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
2796 SkScalar hitOppDx) {
2797 SkASSERT(hitDx || !winding);
2798 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
2799 SkASSERT(dx);
2800 int windVal = windValue(SkMin32(start, end));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002801 #if DEBUG_WINDING_AT_T
2802 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
2803 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
2804 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002805 if (!winding) {
2806 winding = dx < 0 ? windVal : -windVal;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002807 } else if (winding * dx < 0) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00002808 int sideWind = winding + (dx < 0 ? windVal : -windVal);
2809 if (abs(winding) < abs(sideWind)) {
2810 winding = sideWind;
2811 }
2812 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002813 #if DEBUG_WINDING_AT_T
2814 SkDebugf(" winding=%d\n", winding);
2815 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002816 int oppLocal = oppSign(start, end);
2817 SkASSERT(hitOppDx || !oppWind || !oppLocal);
2818 int oppWindVal = oppValue(SkMin32(start, end));
2819 if (!oppWind) {
2820 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
2821 } else if (hitOppDx * dx >= 0) {
2822 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
2823 if (abs(oppWind) < abs(oppSideWind)) {
2824 oppWind = oppSideWind;
2825 }
2826 }
2827 (void) markAndChaseWinding(start, end, winding, oppWind);
2828 }
2829
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002830 bool intersected() const {
2831 return fTs.count() > 0;
2832 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002833
caryclark@google.com10227bf2012-12-28 22:10:41 +00002834 bool isCanceled(int tIndex) const {
2835 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
2836 }
2837
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002838 bool isConnected(int startIndex, int endIndex) const {
2839 return fTs[startIndex].fWindSum != SK_MinS32
2840 || fTs[endIndex].fWindSum != SK_MinS32;
2841 }
2842
caryclark@google.com235f56a2012-09-14 14:19:30 +00002843 bool isHorizontal() const {
2844 return fBounds.fTop == fBounds.fBottom;
2845 }
2846
caryclark@google.com15fa1382012-05-07 20:49:36 +00002847 bool isLinear(int start, int end) const {
2848 if (fVerb == SkPath::kLine_Verb) {
2849 return true;
2850 }
2851 if (fVerb == SkPath::kQuad_Verb) {
2852 SkPoint qPart[3];
2853 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
2854 return QuadIsLinear(qPart);
2855 } else {
2856 SkASSERT(fVerb == SkPath::kCubic_Verb);
2857 SkPoint cPart[4];
2858 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
2859 return CubicIsLinear(cPart);
2860 }
2861 }
caryclark@google.comb9738012012-07-03 19:53:30 +00002862
2863 // OPTIMIZE: successive calls could start were the last leaves off
2864 // or calls could specialize to walk forwards or backwards
2865 bool isMissing(double startT) const {
2866 size_t tCount = fTs.count();
2867 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002868 if (approximately_zero(startT - fTs[index].fT)) {
caryclark@google.comb9738012012-07-03 19:53:30 +00002869 return false;
2870 }
2871 }
2872 return true;
2873 }
2874
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002875 bool isSimple(int end) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002876 int count = fTs.count();
2877 if (count == 2) {
2878 return true;
2879 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002880 double t = fTs[end].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002881 if (approximately_less_than_zero(t)) {
2882 return !approximately_less_than_zero(fTs[1].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002883 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002884 if (approximately_greater_than_one(t)) {
2885 return !approximately_greater_than_one(fTs[count - 2].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002886 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002887 return false;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002888 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002889
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002890 bool isVertical() const {
2891 return fBounds.fLeft == fBounds.fRight;
2892 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00002893
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002894 bool isVertical(int start, int end) const {
2895 return (*SegmentVertical[fVerb])(fPts, start, end);
2896 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002897
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002898 SkScalar leftMost(int start, int end) const {
2899 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
2900 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002901
caryclark@google.com495f8e42012-05-31 13:13:11 +00002902 // this span is excluded by the winding rule -- chase the ends
2903 // as long as they are unambiguous to mark connections as done
2904 // and give them the same winding value
caryclark@google.com59823f72012-08-09 18:17:47 +00002905 Span* markAndChaseDone(const Angle* angle, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002906 int index = angle->start();
2907 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00002908 return markAndChaseDone(index, endIndex, winding);
2909 }
2910
caryclark@google.com31143cf2012-11-09 22:14:19 +00002911 Span* markAndChaseDone(int index, int endIndex, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002912 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002913 int min = SkMin32(index, endIndex);
2914 markDone(min, winding);
2915 Span* last;
2916 Segment* other = this;
2917 while ((other = other->nextChase(index, step, min, last))) {
2918 other->markDone(min, winding);
2919 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002920 return last;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002921 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002922
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002923 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
2924 int index = angle->start();
2925 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00002926 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002927 int min = SkMin32(index, endIndex);
2928 markDoneBinary(min, winding, oppWinding);
2929 Span* last;
2930 Segment* other = this;
2931 while ((other = other->nextChase(index, step, min, last))) {
2932 other->markDoneBinary(min, winding, oppWinding);
2933 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002934 return last;
2935 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002936
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002937 Span* markAndChaseDoneBinary(int index, int endIndex) {
2938 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002939 int min = SkMin32(index, endIndex);
2940 markDoneBinary(min);
2941 Span* last;
2942 Segment* other = this;
2943 while ((other = other->nextChase(index, step, min, last))) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002944 if (other->done()) {
2945 return NULL;
2946 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002947 other->markDoneBinary(min);
2948 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00002949 return last;
2950 }
2951
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002952 Span* markAndChaseDoneUnary(int index, int endIndex) {
2953 int step = SkSign32(endIndex - index);
2954 int min = SkMin32(index, endIndex);
2955 markDoneUnary(min);
2956 Span* last;
2957 Segment* other = this;
2958 while ((other = other->nextChase(index, step, min, last))) {
2959 if (other->done()) {
2960 return NULL;
2961 }
2962 other->markDoneUnary(min);
2963 }
2964 return last;
2965 }
2966
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002967 Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
2968 int index = angle->start();
2969 int endIndex = angle->end();
2970 return markAndChaseDone(index, endIndex, winding);
2971 }
2972
caryclark@google.com4eeda372012-12-06 21:47:48 +00002973 Span* markAndChaseWinding(const Angle* angle, const int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002974 int index = angle->start();
2975 int endIndex = angle->end();
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002976 int step = SkSign32(endIndex - index);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002977 int min = SkMin32(index, endIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00002978 markWinding(min, winding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002979 Span* last;
2980 Segment* other = this;
2981 while ((other = other->nextChase(index, step, min, last))) {
2982 if (other->fTs[min].fWindSum != SK_MinS32) {
2983 SkASSERT(other->fTs[min].fWindSum == winding);
2984 return NULL;
2985 }
2986 other->markWinding(min, winding);
2987 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002988 return last;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002989 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002990
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002991 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00002992 int min = SkMin32(index, endIndex);
2993 int step = SkSign32(endIndex - index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002994 markWinding(min, winding, oppWinding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002995 Span* last;
2996 Segment* other = this;
2997 while ((other = other->nextChase(index, step, min, last))) {
2998 if (other->fTs[min].fWindSum != SK_MinS32) {
2999 SkASSERT(other->fTs[min].fWindSum == winding);
3000 return NULL;
3001 }
3002 other->markWinding(min, winding, oppWinding);
3003 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003004 return last;
3005 }
3006
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003007 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
3008 int start = angle->start();
3009 int end = angle->end();
3010 return markAndChaseWinding(start, end, winding, oppWinding);
3011 }
3012
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003013 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
3014 SkASSERT(angle->segment() == this);
3015 if (useInnerWinding(maxWinding, sumWinding)) {
3016 maxWinding = sumWinding;
3017 }
3018 Span* last;
3019 if (activeAngle) {
3020 last = markAndChaseWinding(angle, maxWinding);
3021 } else {
3022 last = markAndChaseDoneUnary(angle, maxWinding);
3023 }
3024 return last;
3025 }
3026
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003027 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
3028 bool activeAngle, const Angle* angle) {
3029 SkASSERT(angle->segment() == this);
3030 if (useInnerWinding(maxWinding, sumWinding)) {
3031 maxWinding = sumWinding;
3032 }
3033 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
3034 oppMaxWinding = oppSumWinding;
3035 }
3036 Span* last;
3037 if (activeAngle) {
3038 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3039 } else {
3040 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
3041 }
3042 return last;
3043 }
3044
caryclark@google.com495f8e42012-05-31 13:13:11 +00003045 // FIXME: this should also mark spans with equal (x,y)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003046 // This may be called when the segment is already marked done. While this
3047 // wastes time, it shouldn't do any more than spin through the T spans.
rmistry@google.comd6176b02012-08-23 18:14:13 +00003048 // OPTIMIZATION: abort on first done found (assuming that this code is
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003049 // always called to mark segments done).
caryclark@google.com59823f72012-08-09 18:17:47 +00003050 void markDone(int index, int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003051 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003052 SkASSERT(winding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003053 double referenceT = fTs[index].fT;
3054 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003055 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3056 markOneDone(__FUNCTION__, lesser, winding);
3057 }
3058 do {
3059 markOneDone(__FUNCTION__, index, winding);
3060 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003061 }
3062
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003063 void markDoneBinary(int index, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003064 // SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003065 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003066 double referenceT = fTs[index].fT;
3067 int lesser = index;
3068 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003069 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003070 }
3071 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003072 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
3073 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3074 }
3075
3076 void markDoneBinary(int index) {
3077 double referenceT = fTs[index].fT;
3078 int lesser = index;
3079 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3080 markOneDoneBinary(__FUNCTION__, lesser);
3081 }
3082 do {
3083 markOneDoneBinary(__FUNCTION__, index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003084 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003085 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00003086
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003087 void markDoneUnary(int index, int winding) {
3088 // SkASSERT(!done());
3089 SkASSERT(winding);
3090 double referenceT = fTs[index].fT;
3091 int lesser = index;
3092 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3093 markOneDoneUnary(__FUNCTION__, lesser, winding);
3094 }
3095 do {
3096 markOneDoneUnary(__FUNCTION__, index, winding);
3097 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3098 }
3099
3100 void markDoneUnary(int index) {
3101 double referenceT = fTs[index].fT;
3102 int lesser = index;
3103 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3104 markOneDoneUnary(__FUNCTION__, lesser);
3105 }
3106 do {
3107 markOneDoneUnary(__FUNCTION__, index);
3108 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3109 }
3110
caryclark@google.com24bec792012-08-20 12:43:57 +00003111 void markOneDone(const char* funName, int tIndex, int winding) {
3112 Span* span = markOneWinding(funName, tIndex, winding);
3113 if (!span) {
3114 return;
3115 }
3116 span->fDone = true;
3117 fDoneSpans++;
3118 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003119
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003120 void markOneDoneBinary(const char* funName, int tIndex) {
3121 Span* span = verifyOneWinding(funName, tIndex);
3122 if (!span) {
3123 return;
3124 }
3125 span->fDone = true;
3126 fDoneSpans++;
3127 }
3128
3129 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003130 Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
3131 if (!span) {
3132 return;
3133 }
3134 span->fDone = true;
3135 fDoneSpans++;
3136 }
3137
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003138 void markOneDoneUnary(const char* funName, int tIndex) {
3139 Span* span = verifyOneWindingU(funName, tIndex);
3140 if (!span) {
3141 return;
3142 }
3143 span->fDone = true;
3144 fDoneSpans++;
3145 }
3146
3147 void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3148 Span* span = markOneWinding(funName, tIndex, winding);
3149 if (!span) {
3150 return;
3151 }
3152 span->fDone = true;
3153 fDoneSpans++;
3154 }
3155
caryclark@google.com24bec792012-08-20 12:43:57 +00003156 Span* markOneWinding(const char* funName, int tIndex, int winding) {
3157 Span& span = fTs[tIndex];
3158 if (span.fDone) {
3159 return NULL;
3160 }
3161 #if DEBUG_MARK_DONE
3162 debugShowNewWinding(funName, span, winding);
3163 #endif
3164 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com03f97062012-08-21 13:13:52 +00003165 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00003166 SkASSERT(abs(winding) <= gDebugMaxWindSum);
caryclark@google.com03f97062012-08-21 13:13:52 +00003167 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00003168 span.fWindSum = winding;
3169 return &span;
3170 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003171
caryclark@google.com31143cf2012-11-09 22:14:19 +00003172 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
3173 Span& span = fTs[tIndex];
3174 if (span.fDone) {
3175 return NULL;
3176 }
3177 #if DEBUG_MARK_DONE
3178 debugShowNewWinding(funName, span, winding, oppWinding);
3179 #endif
3180 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3181 #ifdef SK_DEBUG
3182 SkASSERT(abs(winding) <= gDebugMaxWindSum);
3183 #endif
3184 span.fWindSum = winding;
3185 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3186 #ifdef SK_DEBUG
3187 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
3188 #endif
3189 span.fOppSum = oppWinding;
3190 return &span;
3191 }
3192
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003193 Span* verifyOneWinding(const char* funName, int tIndex) {
3194 Span& span = fTs[tIndex];
3195 if (span.fDone) {
3196 return NULL;
3197 }
3198 #if DEBUG_MARK_DONE
3199 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3200 #endif
3201 SkASSERT(span.fWindSum != SK_MinS32);
3202 SkASSERT(span.fOppSum != SK_MinS32);
3203 return &span;
3204 }
3205
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003206 Span* verifyOneWindingU(const char* funName, int tIndex) {
3207 Span& span = fTs[tIndex];
3208 if (span.fDone) {
3209 return NULL;
3210 }
3211 #if DEBUG_MARK_DONE
3212 debugShowNewWinding(funName, span, span.fWindSum);
3213 #endif
3214 SkASSERT(span.fWindSum != SK_MinS32);
3215 return &span;
3216 }
3217
caryclark@google.comf839c032012-10-26 21:03:50 +00003218 // note that just because a span has one end that is unsortable, that's
3219 // not enough to mark it done. The other end may be sortable, allowing the
3220 // span to be added.
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003221 // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003222 void markUnsortable(int start, int end) {
3223 Span* span = &fTs[start];
3224 if (start < end) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003225#if DEBUG_UNSORTABLE
3226 SkDebugf("%s start id=%d [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fID, start,
3227 xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003228#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003229 span->fUnsortableStart = true;
3230 } else {
3231 --span;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003232#if DEBUG_UNSORTABLE
3233 SkDebugf("%s end id=%d [%d] (%1.9g,%1.9g) next:(%1.9g,%1.9g)\n", __FUNCTION__, fID,
3234 start - 1, xAtT(start - 1), yAtT(start - 1), xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003235#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003236 span->fUnsortableEnd = true;
3237 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003238 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003239 return;
3240 }
3241 span->fDone = true;
3242 fDoneSpans++;
3243 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003244
caryclark@google.com59823f72012-08-09 18:17:47 +00003245 void markWinding(int index, int winding) {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003246 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003247 SkASSERT(winding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003248 double referenceT = fTs[index].fT;
3249 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003250 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3251 markOneWinding(__FUNCTION__, lesser, winding);
3252 }
3253 do {
3254 markOneWinding(__FUNCTION__, index, winding);
3255 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003256 }
3257
3258 void markWinding(int index, int winding, int oppWinding) {
3259 // SkASSERT(!done());
caryclark@google.com4eeda372012-12-06 21:47:48 +00003260 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003261 double referenceT = fTs[index].fT;
3262 int lesser = index;
3263 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3264 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003265 }
3266 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003267 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3268 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003269 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003270
caryclark@google.com2ddff932012-08-07 21:25:27 +00003271 void matchWindingValue(int tIndex, double t, bool borrowWind) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003272 int nextDoorWind = SK_MaxS32;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003273 int nextOppWind = SK_MaxS32;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003274 if (tIndex > 0) {
3275 const Span& below = fTs[tIndex - 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003276 if (approximately_negative(t - below.fT)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003277 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003278 nextOppWind = below.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003279 }
3280 }
3281 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3282 const Span& above = fTs[tIndex + 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003283 if (approximately_negative(above.fT - t)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003284 nextDoorWind = above.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003285 nextOppWind = above.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003286 }
3287 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003288 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3289 const Span& below = fTs[tIndex - 1];
3290 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003291 nextOppWind = below.fOppValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003292 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003293 if (nextDoorWind != SK_MaxS32) {
3294 Span& newSpan = fTs[tIndex];
3295 newSpan.fWindValue = nextDoorWind;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003296 newSpan.fOppValue = nextOppWind;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003297 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003298 newSpan.fDone = true;
3299 ++fDoneSpans;
3300 }
3301 }
3302 }
3303
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003304 bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3305 // find bounds
3306 Bounds bounds;
3307 bounds.setPoint(xyAtT(index));
3308 bounds.add(xyAtT(endIndex));
3309 SkScalar width = bounds.width();
3310 SkScalar height = bounds.height();
3311 if (width > height) {
3312 if (approximately_negative(width)) {
3313 unsortable = true; // edge is too small to resolve meaningfully
3314 }
3315 return false;
3316 } else {
3317 if (approximately_negative(height)) {
3318 unsortable = true; // edge is too small to resolve meaningfully
3319 }
3320 return true;
3321 }
3322 }
3323
caryclark@google.com9764cc62012-07-12 19:29:45 +00003324 // return span if when chasing, two or more radiating spans are not done
3325 // OPTIMIZATION: ? multiple spans is detected when there is only one valid
3326 // candidate and the remaining spans have windValue == 0 (canceled by
3327 // coincidence). The coincident edges could either be removed altogether,
3328 // or this code could be more complicated in detecting this case. Worth it?
3329 bool multipleSpans(int end) const {
3330 return end > 0 && end < fTs.count() - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00003331 }
3332
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003333 bool nextCandidate(int& start, int& end) const {
caryclark@google.com10227bf2012-12-28 22:10:41 +00003334 while (fTs[end].fDone) {
3335 if (fTs[end].fT == 1) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003336 return false;
3337 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00003338 ++end;
3339 }
3340 start = end;
3341 end = nextExactSpan(start, 1);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003342 return true;
3343 }
3344
caryclark@google.com4eeda372012-12-06 21:47:48 +00003345 Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
3346 int end = nextExactSpan(index, step);
3347 SkASSERT(end >= 0);
3348 if (multipleSpans(end)) {
3349 last = &fTs[end];
3350 return NULL;
3351 }
3352 const Span& endSpan = fTs[end];
3353 Segment* other = endSpan.fOther;
3354 index = endSpan.fOtherIndex;
caryclark@google.comaa358312013-01-29 20:28:49 +00003355 SkASSERT(index >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003356 int otherEnd = other->nextExactSpan(index, step);
caryclark@google.comaa358312013-01-29 20:28:49 +00003357 SkASSERT(otherEnd >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003358 min = SkMin32(index, otherEnd);
3359 return other;
3360 }
3361
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003362 // This has callers for two different situations: one establishes the end
3363 // of the current span, and one establishes the beginning of the next span
3364 // (thus the name). When this is looking for the end of the current span,
3365 // coincidence is found when the beginning Ts contain -step and the end
3366 // contains step. When it is looking for the beginning of the next, the
3367 // first Ts found can be ignored and the last Ts should contain -step.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003368 // OPTIMIZATION: probably should split into two functions
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003369 int nextSpan(int from, int step) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003370 const Span& fromSpan = fTs[from];
caryclark@google.com495f8e42012-05-31 13:13:11 +00003371 int count = fTs.count();
3372 int to = from;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003373 while (step > 0 ? ++to < count : --to >= 0) {
3374 const Span& span = fTs[to];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003375 if (approximately_zero(span.fT - fromSpan.fT)) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003376 continue;
3377 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003378 return to;
3379 }
3380 return -1;
3381 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +00003382
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003383 // FIXME
3384 // this returns at any difference in T, vs. a preset minimum. It may be
3385 // that all callers to nextSpan should use this instead.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003386 // OPTIMIZATION splitting this into separate loops for up/down steps
3387 // would allow using precisely_negative instead of precisely_zero
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003388 int nextExactSpan(int from, int step) const {
3389 const Span& fromSpan = fTs[from];
3390 int count = fTs.count();
3391 int to = from;
3392 while (step > 0 ? ++to < count : --to >= 0) {
3393 const Span& span = fTs[to];
caryclark@google.coma461ff02012-10-11 12:54:23 +00003394 if (precisely_zero(span.fT - fromSpan.fT)) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003395 continue;
3396 }
3397 return to;
3398 }
3399 return -1;
3400 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003401
caryclark@google.com235f56a2012-09-14 14:19:30 +00003402 bool operand() const {
3403 return fOperand;
3404 }
3405
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003406 int oppSign(const Angle* angle) const {
3407 SkASSERT(angle->segment() == this);
3408 return oppSign(angle->start(), angle->end());
3409 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003410
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003411 int oppSign(int startIndex, int endIndex) const {
3412 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3413 : fTs[endIndex].fOppValue;
3414#if DEBUG_WIND_BUMP
3415 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3416#endif
3417 return result;
3418 }
3419
caryclark@google.com31143cf2012-11-09 22:14:19 +00003420 int oppSum(int tIndex) const {
3421 return fTs[tIndex].fOppSum;
3422 }
3423
3424 int oppSum(const Angle* angle) const {
3425 int lesser = SkMin32(angle->start(), angle->end());
3426 return fTs[lesser].fOppSum;
caryclark@google.com235f56a2012-09-14 14:19:30 +00003427 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003428
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003429 int oppValue(int tIndex) const {
3430 return fTs[tIndex].fOppValue;
3431 }
3432
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003433 int oppValue(const Angle* angle) const {
3434 int lesser = SkMin32(angle->start(), angle->end());
3435 return fTs[lesser].fOppValue;
3436 }
3437
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003438 const SkPoint* pts() const {
3439 return fPts;
3440 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003441
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003442 void reset() {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003443 init(NULL, (SkPath::Verb) -1, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003444 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3445 fTs.reset();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003446 }
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +00003447
caryclark@google.com4eeda372012-12-06 21:47:48 +00003448 void setOppXor(bool isOppXor) {
3449 fOppXor = isOppXor;
3450 }
3451
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003452 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3453 int deltaSum = spanSign(index, endIndex);
3454 maxWinding = sumWinding;
3455 sumWinding = sumWinding -= deltaSum;
3456 }
3457
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003458 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3459 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3460 int deltaSum = spanSign(index, endIndex);
3461 int oppDeltaSum = oppSign(index, endIndex);
3462 if (operand()) {
3463 maxWinding = sumSuWinding;
3464 sumWinding = sumSuWinding -= deltaSum;
3465 oppMaxWinding = sumMiWinding;
3466 oppSumWinding = sumMiWinding -= oppDeltaSum;
3467 } else {
3468 maxWinding = sumMiWinding;
3469 sumWinding = sumMiWinding -= deltaSum;
3470 oppMaxWinding = sumSuWinding;
3471 oppSumWinding = sumSuWinding -= oppDeltaSum;
3472 }
3473 }
3474
caryclark@google.comf839c032012-10-26 21:03:50 +00003475 // This marks all spans unsortable so that this info is available for early
3476 // exclusion in find top and others. This could be optimized to only mark
3477 // adjacent spans that unsortable. However, this makes it difficult to later
3478 // determine starting points for edge detection in find top and the like.
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003479 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
caryclark@google.comf839c032012-10-26 21:03:50 +00003480 bool sortable = true;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003481 int angleCount = angles.count();
3482 int angleIndex;
3483 angleList.setReserve(angleCount);
3484 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003485 Angle& angle = angles[angleIndex];
caryclark@google.comf839c032012-10-26 21:03:50 +00003486 *angleList.append() = &angle;
3487 sortable &= !angle.unsortable();
3488 }
3489 if (sortable) {
3490 QSort<Angle>(angleList.begin(), angleList.end() - 1);
3491 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3492 if (angles[angleIndex].unsortable()) {
3493 sortable = false;
3494 break;
3495 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003496 }
3497 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003498 if (!sortable) {
3499 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3500 Angle& angle = angles[angleIndex];
3501 angle.segment()->markUnsortable(angle.start(), angle.end());
3502 }
3503 }
3504 return sortable;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003505 }
3506
caryclark@google.com1577e8f2012-05-22 17:01:14 +00003507 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003508 const Span& span(int tIndex) const {
3509 return fTs[tIndex];
3510 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003511
caryclark@google.com235f56a2012-09-14 14:19:30 +00003512 int spanSign(const Angle* angle) const {
3513 SkASSERT(angle->segment() == this);
3514 return spanSign(angle->start(), angle->end());
3515 }
3516
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003517 int spanSign(int startIndex, int endIndex) const {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003518 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3519 : fTs[endIndex].fWindValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003520#if DEBUG_WIND_BUMP
3521 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3522#endif
3523 return result;
3524 }
3525
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003526 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003527 double t(int tIndex) const {
3528 return fTs[tIndex].fT;
3529 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003530
caryclark@google.com10227bf2012-12-28 22:10:41 +00003531 double tAtMid(int start, int end, double mid) const {
3532 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
3533 }
3534
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003535 bool tiny(const Angle* angle) const {
3536 int start = angle->start();
3537 int end = angle->end();
caryclark@google.comf839c032012-10-26 21:03:50 +00003538 const Span& mSpan = fTs[SkMin32(start, end)];
3539 return mSpan.fTiny;
3540 }
3541
caryclark@google.com18063442012-07-25 12:05:18 +00003542 static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3543 double start) {
3544 int outCount = outsideTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003545 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
caryclark@google.com18063442012-07-25 12:05:18 +00003546 *outsideTs.append() = end;
3547 *outsideTs.append() = start;
3548 }
3549 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003550
caryclark@google.com24bec792012-08-20 12:43:57 +00003551 void undoneSpan(int& start, int& end) {
3552 size_t tCount = fTs.count();
3553 size_t index;
3554 for (index = 0; index < tCount; ++index) {
3555 if (!fTs[index].fDone) {
3556 break;
3557 }
3558 }
3559 SkASSERT(index < tCount - 1);
3560 start = index;
3561 double startT = fTs[index].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003562 while (approximately_negative(fTs[++index].fT - startT))
caryclark@google.com24bec792012-08-20 12:43:57 +00003563 SkASSERT(index < tCount);
3564 SkASSERT(index < tCount);
3565 end = index;
3566 }
caryclark@google.com18063442012-07-25 12:05:18 +00003567
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003568 bool unsortable(int index) const {
3569 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3570 }
3571
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003572 void updatePts(const SkPoint pts[]) {
3573 fPts = pts;
3574 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003575
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003576 int updateOppWinding(int index, int endIndex) const {
3577 int lesser = SkMin32(index, endIndex);
3578 int oppWinding = oppSum(lesser);
3579 int oppSpanWinding = oppSign(index, endIndex);
3580 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)) {
3581 oppWinding -= oppSpanWinding;
3582 }
3583 return oppWinding;
3584 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003585
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003586 int updateOppWinding(const Angle* angle) const {
3587 int startIndex = angle->start();
3588 int endIndex = angle->end();
3589 return updateOppWinding(endIndex, startIndex);
3590 }
3591
3592 int updateOppWindingReverse(const Angle* angle) const {
3593 int startIndex = angle->start();
3594 int endIndex = angle->end();
3595 return updateOppWinding(startIndex, endIndex);
3596 }
3597
3598 int updateWinding(int index, int endIndex) const {
3599 int lesser = SkMin32(index, endIndex);
3600 int winding = windSum(lesser);
3601 int spanWinding = spanSign(index, endIndex);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003602 if (winding && useInnerWinding(winding - spanWinding, winding)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003603 winding -= spanWinding;
3604 }
3605 return winding;
3606 }
3607
3608 int updateWinding(const Angle* angle) const {
3609 int startIndex = angle->start();
3610 int endIndex = angle->end();
3611 return updateWinding(endIndex, startIndex);
3612 }
3613
3614 int updateWindingReverse(const Angle* angle) const {
3615 int startIndex = angle->start();
3616 int endIndex = angle->end();
3617 return updateWinding(startIndex, endIndex);
3618 }
3619
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003620 SkPath::Verb verb() const {
3621 return fVerb;
3622 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003623
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003624 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003625 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3626 return SK_MinS32;
3627 }
3628 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3629 SkASSERT(winding != SK_MinS32);
3630 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003631 #if DEBUG_WINDING_AT_T
3632 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003633 #endif
3634 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark@google.com3586ece2012-12-27 18:46:58 +00003635 dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003636 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3637 dx = fPts[2].fX - fPts[1].fX - dx;
3638 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003639 if (dx == 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003640 #if DEBUG_WINDING_AT_T
3641 SkDebugf(" dx=0 winding=SK_MinS32\n");
3642 #endif
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003643 return SK_MinS32;
3644 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003645 if (winding * dx > 0) { // if same signs, result is negative
3646 winding += dx > 0 ? -windVal : windVal;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003647 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003648 #if DEBUG_WINDING_AT_T
3649 SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding);
3650 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003651 return winding;
3652 }
3653
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003654 int windSum(int tIndex) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003655 return fTs[tIndex].fWindSum;
3656 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003657
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003658 int windSum(const Angle* angle) const {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003659 int start = angle->start();
3660 int end = angle->end();
3661 int index = SkMin32(start, end);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003662 return windSum(index);
caryclark@google.com495f8e42012-05-31 13:13:11 +00003663 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003664
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003665 int windValue(int tIndex) const {
3666 return fTs[tIndex].fWindValue;
3667 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003668
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003669 int windValue(const Angle* angle) const {
3670 int start = angle->start();
3671 int end = angle->end();
3672 int index = SkMin32(start, end);
3673 return windValue(index);
3674 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00003675
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003676 int windValueAt(double t) const {
3677 int count = fTs.count();
3678 for (int index = 0; index < count; ++index) {
3679 if (fTs[index].fT == t) {
3680 return fTs[index].fWindValue;
3681 }
3682 }
3683 SkASSERT(0);
3684 return 0;
3685 }
3686
caryclark@google.com3586ece2012-12-27 18:46:58 +00003687 SkScalar xAtT(int index) const {
3688 return xAtT(&fTs[index]);
3689 }
3690
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003691 SkScalar xAtT(const Span* span) const {
3692 return xyAtT(span).fX;
3693 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003694
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003695 const SkPoint& xyAtT(int index) const {
3696 return xyAtT(&fTs[index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003697 }
3698
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003699 const SkPoint& xyAtT(const Span* span) const {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003700 if (SkScalarIsNaN(span->fPt.fX)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003701 if (span->fT == 0) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003702 span->fPt = fPts[0];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003703 } else if (span->fT == 1) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003704 span->fPt = fPts[fVerb];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003705 } else {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003706 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003707 }
3708 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00003709 return span->fPt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003710 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003711
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003712 // used only by right angle winding finding
caryclark@google.com10227bf2012-12-28 22:10:41 +00003713 void xyAtT(double mid, SkPoint& pt) const {
3714 (*SegmentXYAtT[fVerb])(fPts, mid, &pt);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003715 }
3716
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003717 SkScalar yAtT(int index) const {
3718 return yAtT(&fTs[index]);
3719 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003720
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003721 SkScalar yAtT(const Span* span) const {
3722 return xyAtT(span).fY;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003723 }
3724
caryclark@google.com4eeda372012-12-06 21:47:48 +00003725 void zeroCoincidentOpp(Span* oTest, int index) {
3726 Span* const test = &fTs[index];
3727 Span* end = test;
3728 do {
3729 end->fOppValue = 0;
3730 end = &fTs[++index];
3731 } while (approximately_negative(end->fT - test->fT));
3732 }
3733
3734 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
3735 Span* const oTest = &fTs[oIndex];
3736 Span* oEnd = oTest;
3737 const double startT = test->fT;
3738 const double oStartT = oTest->fT;
3739 double otherTMatch = (test->fT - startT) * tRatio + oStartT;
3740 while (!approximately_negative(oEndT - oEnd->fT)
3741 && approximately_negative(oEnd->fT - otherTMatch)) {
3742 oEnd->fOppValue = 0;
3743 oEnd = &fTs[++oIndex];
3744 }
3745 }
3746
3747 void zeroSpan(Span* span) {
3748 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
caryclark@google.com6ec15262012-11-16 20:16:50 +00003749 span->fWindValue = 0;
caryclark@google.com729e1c42012-11-21 21:36:34 +00003750 span->fOppValue = 0;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003751 SkASSERT(!span->fDone);
3752 span->fDone = true;
3753 ++fDoneSpans;
caryclark@google.com6ec15262012-11-16 20:16:50 +00003754 }
3755
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003756#if DEBUG_DUMP
3757 void dump() const {
3758 const char className[] = "Segment";
3759 const int tab = 4;
3760 for (int i = 0; i < fTs.count(); ++i) {
3761 SkPoint out;
3762 (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
3763 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003764 " otherT=%1.9g windSum=%d\n",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003765 tab + sizeof(className), className, fID,
3766 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003767 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003768 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00003769 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003770 tab + sizeof(className), className, fID,
caryclark@google.com15fa1382012-05-07 20:49:36 +00003771 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003772 }
3773#endif
3774
caryclark@google.com47580692012-07-23 12:14:49 +00003775#if DEBUG_CONCIDENT
caryclark@google.comaa358312013-01-29 20:28:49 +00003776 // SkASSERT if pair has not already been added
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003777 void debugAddTPair(double t, const Segment& other, double otherT) const {
caryclark@google.comcc905052012-07-25 20:59:42 +00003778 for (int i = 0; i < fTs.count(); ++i) {
3779 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
3780 return;
3781 }
3782 }
3783 SkASSERT(0);
3784 }
3785#endif
3786
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003787#if DEBUG_DUMP
3788 int debugID() const {
3789 return fID;
3790 }
3791#endif
3792
caryclark@google.com24bec792012-08-20 12:43:57 +00003793#if DEBUG_WINDING
3794 void debugShowSums() const {
3795 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
3796 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
3797 for (int i = 0; i < fTs.count(); ++i) {
3798 const Span& span = fTs[i];
3799 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
3800 if (span.fWindSum == SK_MinS32) {
3801 SkDebugf("?");
3802 } else {
3803 SkDebugf("%d", span.fWindSum);
3804 }
3805 SkDebugf("]");
3806 }
3807 SkDebugf("\n");
3808 }
3809#endif
3810
caryclark@google.comcc905052012-07-25 20:59:42 +00003811#if DEBUG_CONCIDENT
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003812 void debugShowTs() const {
caryclark@google.com24bec792012-08-20 12:43:57 +00003813 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003814 int lastWind = -1;
3815 int lastOpp = -1;
3816 double lastT = -1;
3817 int i;
3818 for (i = 0; i < fTs.count(); ++i) {
3819 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
3820 || lastOpp != fTs[i].fOppValue;
3821 if (change && lastWind >= 0) {
3822 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3823 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3824 }
3825 if (change) {
3826 SkDebugf(" [o=%d", fTs[i].fOther->fID);
3827 lastWind = fTs[i].fWindValue;
3828 lastOpp = fTs[i].fOppValue;
3829 lastT = fTs[i].fT;
3830 } else {
3831 SkDebugf(",%d", fTs[i].fOther->fID);
3832 }
3833 }
3834 if (i <= 0) {
3835 return;
3836 }
3837 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3838 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3839 if (fOperand) {
3840 SkDebugf(" operand");
3841 }
3842 if (done()) {
3843 SkDebugf(" done");
caryclark@google.com47580692012-07-23 12:14:49 +00003844 }
3845 SkDebugf("\n");
3846 }
3847#endif
3848
caryclark@google.com027de222012-07-12 12:52:50 +00003849#if DEBUG_ACTIVE_SPANS
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003850 void debugShowActiveSpans() const {
caryclark@google.com027de222012-07-12 12:52:50 +00003851 if (done()) {
3852 return;
3853 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003854#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3855 int lastId = -1;
3856 double lastT = -1;
3857#endif
caryclark@google.com027de222012-07-12 12:52:50 +00003858 for (int i = 0; i < fTs.count(); ++i) {
3859 if (fTs[i].fDone) {
3860 continue;
3861 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003862#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3863 if (lastId == fID && lastT == fTs[i].fT) {
3864 continue;
3865 }
3866 lastId = fID;
3867 lastT = fTs[i].fT;
3868#endif
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003869 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com027de222012-07-12 12:52:50 +00003870 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3871 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3872 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3873 }
3874 const Span* span = &fTs[i];
rmistry@google.comd6176b02012-08-23 18:14:13 +00003875 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
caryclark@google.com0c803d02012-08-06 11:15:47 +00003876 xAtT(span), yAtT(span));
caryclark@google.com027de222012-07-12 12:52:50 +00003877 const Segment* other = fTs[i].fOther;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003878 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
3879 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
3880 if (fTs[i].fWindSum == SK_MinS32) {
3881 SkDebugf("?");
3882 } else {
3883 SkDebugf("%d", fTs[i].fWindSum);
3884 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003885 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
caryclark@google.com027de222012-07-12 12:52:50 +00003886 }
3887 }
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +00003888
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003889 // This isn't useful yet -- but leaving it in for now in case i think of something
3890 // to use it for
3891 void validateActiveSpans() const {
3892 if (done()) {
3893 return;
3894 }
3895 int tCount = fTs.count();
3896 for (int index = 0; index < tCount; ++index) {
3897 if (fTs[index].fDone) {
3898 continue;
3899 }
3900 // count number of connections which are not done
3901 int first = index;
3902 double baseT = fTs[index].fT;
3903 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
3904 --first;
3905 }
3906 int last = index;
3907 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
3908 ++last;
3909 }
3910 int connections = 0;
3911 connections += first > 0 && !fTs[first - 1].fDone;
3912 for (int test = first; test <= last; ++test) {
3913 connections += !fTs[test].fDone;
3914 const Segment* other = fTs[test].fOther;
3915 int oIndex = fTs[test].fOtherIndex;
3916 connections += !other->fTs[oIndex].fDone;
3917 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
3918 }
3919 // SkASSERT(!(connections & 1));
3920 }
3921 }
caryclark@google.com027de222012-07-12 12:52:50 +00003922#endif
3923
caryclark@google.com0c803d02012-08-06 11:15:47 +00003924#if DEBUG_MARK_DONE
3925 void debugShowNewWinding(const char* fun, const Span& span, int winding) {
3926 const SkPoint& pt = xyAtT(&span);
3927 SkDebugf("%s id=%d", fun, fID);
3928 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3929 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3930 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3931 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003932 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3933 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3934 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d windSum=",
3935 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, winding);
caryclark@google.com0c803d02012-08-06 11:15:47 +00003936 if (span.fWindSum == SK_MinS32) {
3937 SkDebugf("?");
3938 } else {
3939 SkDebugf("%d", span.fWindSum);
3940 }
3941 SkDebugf(" windValue=%d\n", span.fWindValue);
3942 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003943
3944 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
3945 const SkPoint& pt = xyAtT(&span);
3946 SkDebugf("%s id=%d", fun, fID);
3947 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3948 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3949 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3950 }
3951 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3952 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3953 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=",
3954 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
3955 winding, oppWinding);
3956 if (span.fOppSum == SK_MinS32) {
3957 SkDebugf("?");
3958 } else {
3959 SkDebugf("%d", span.fOppSum);
3960 }
3961 SkDebugf(" windSum=");
3962 if (span.fWindSum == SK_MinS32) {
3963 SkDebugf("?");
3964 } else {
3965 SkDebugf("%d", span.fWindSum);
3966 }
3967 SkDebugf(" windValue=%d\n", span.fWindValue);
3968 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003969#endif
3970
caryclark@google.com47580692012-07-23 12:14:49 +00003971#if DEBUG_SORT
caryclark@google.com03f97062012-08-21 13:13:52 +00003972 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
caryclark@google.com31143cf2012-11-09 22:14:19 +00003973 const int contourWinding, const int oppContourWinding) const {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003974 SkASSERT(angles[first]->segment() == this);
caryclark@google.com200c2112012-08-03 15:05:04 +00003975 SkASSERT(angles.count() > 1);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003976 int lastSum = contourWinding;
caryclark@google.com31143cf2012-11-09 22:14:19 +00003977 int oppLastSum = oppContourWinding;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003978 const Angle* firstAngle = angles[first];
3979 int windSum = lastSum - spanSign(firstAngle);
3980 int oppoSign = oppSign(firstAngle);
3981 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.com31143cf2012-11-09 22:14:19 +00003982 SkDebugf("%s %s contourWinding=%d oppContourWinding=%d sign=%d\n", fun, __FUNCTION__,
3983 contourWinding, oppContourWinding, spanSign(angles[first]));
caryclark@google.comafe56de2012-07-24 18:11:03 +00003984 int index = first;
3985 bool firstTime = true;
caryclark@google.com47580692012-07-23 12:14:49 +00003986 do {
3987 const Angle& angle = *angles[index];
3988 const Segment& segment = *angle.segment();
3989 int start = angle.start();
3990 int end = angle.end();
3991 const Span& sSpan = segment.fTs[start];
3992 const Span& eSpan = segment.fTs[end];
3993 const Span& mSpan = segment.fTs[SkMin32(start, end)];
caryclark@google.com31143cf2012-11-09 22:14:19 +00003994 bool opp = segment.fOperand ^ fOperand;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003995 if (!firstTime) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003996 oppoSign = segment.oppSign(&angle);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003997 if (opp) {
3998 oppLastSum = oppWindSum;
3999 oppWindSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004000 if (oppoSign) {
4001 lastSum = windSum;
4002 windSum -= oppoSign;
4003 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004004 } else {
4005 lastSum = windSum;
4006 windSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004007 if (oppoSign) {
4008 oppLastSum = oppWindSum;
4009 oppWindSum -= oppoSign;
4010 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004011 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004012 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004013 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 +00004014 " sign=%d windValue=%d windSum=",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004015 __FUNCTION__, index, angle.unsortable() ? "*** UNSORTABLE *** " : "",
caryclark@google.comc91dfe42012-10-16 12:06:27 +00004016 segment.fID, kLVerbStr[segment.fVerb],
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004017 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
4018 segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(),
4019 mSpan.fWindValue);
4020 if (mSpan.fWindSum == SK_MinS32) {
4021 SkDebugf("?");
4022 } else {
4023 SkDebugf("%d", mSpan.fWindSum);
4024 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004025 int last, wind;
4026 if (opp) {
4027 last = oppLastSum;
4028 wind = oppWindSum;
4029 } else {
4030 last = lastSum;
4031 wind = windSum;
4032 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004033 if (!oppoSign) {
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00004034 SkDebugf(" %d->%d (max=%d)", last, wind,
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004035 useInnerWinding(last, wind) ? wind : last);
4036 } else {
4037 SkDebugf(" %d->%d (%d->%d)", last, wind, opp ? lastSum : oppLastSum,
4038 opp ? windSum : oppWindSum);
4039 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004040 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004041#if false && DEBUG_ANGLE
caryclark@google.comc899ad92012-08-23 15:24:42 +00004042 angle.debugShow(segment.xyAtT(&sSpan));
4043#endif
caryclark@google.com47580692012-07-23 12:14:49 +00004044 ++index;
4045 if (index == angles.count()) {
4046 index = 0;
4047 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004048 if (firstTime) {
4049 firstTime = false;
4050 }
caryclark@google.com47580692012-07-23 12:14:49 +00004051 } while (index != first);
4052 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00004053
4054 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
4055 const Angle* firstAngle = angles[first];
4056 const Segment* segment = firstAngle->segment();
4057 int winding = segment->updateWinding(firstAngle);
4058 int oppWinding = segment->updateOppWinding(firstAngle);
4059 debugShowSort(fun, angles, first, winding, oppWinding);
4060 }
4061
caryclark@google.com47580692012-07-23 12:14:49 +00004062#endif
4063
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004064#if DEBUG_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004065 static char as_digit(int value) {
4066 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
4067 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004068#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004069
caryclark@google.com729e1c42012-11-21 21:36:34 +00004070#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004071 int debugShowWindingValues(int slotCount, int ofInterest) const {
4072 if (!(1 << fID & ofInterest)) {
4073 return 0;
4074 }
4075 int sum = 0;
4076 SkTDArray<char> slots;
4077 slots.setCount(slotCount * 2);
4078 memset(slots.begin(), ' ', slotCount * 2);
4079 for (int i = 0; i < fTs.count(); ++i) {
4080 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
4081 // continue;
4082 // }
4083 sum += fTs[i].fWindValue;
4084 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
4085 sum += fTs[i].fOppValue;
4086 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
4087 }
4088 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
4089 slots.begin() + slotCount);
4090 return sum;
4091 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004092#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004093
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004094private:
4095 const SkPoint* fPts;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004096 Bounds fBounds;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004097 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
caryclark@google.com4eeda372012-12-06 21:47:48 +00004098 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
caryclark@google.com24bec792012-08-20 12:43:57 +00004099 int fDoneSpans; // quick check that segment is finished
caryclark@google.com4eeda372012-12-06 21:47:48 +00004100 // OPTIMIZATION: force the following to be byte-sized
4101 SkPath::Verb fVerb;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004102 bool fOperand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004103 bool fXor; // set if original contour had even-odd fill
4104 bool fOppXor; // set if opposite operand had even-odd fill
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004105#if DEBUG_DUMP
4106 int fID;
4107#endif
4108};
4109
caryclark@google.comb9738012012-07-03 19:53:30 +00004110class Contour;
4111
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004112struct Coincidence {
caryclark@google.comb9738012012-07-03 19:53:30 +00004113 Contour* fContours[2];
4114 int fSegments[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004115 double fTs[2][2];
4116};
4117
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004118class Contour {
4119public:
4120 Contour() {
4121 reset();
4122#if DEBUG_DUMP
4123 fID = ++gContourID;
4124#endif
4125 }
4126
4127 bool operator<(const Contour& rh) const {
4128 return fBounds.fTop == rh.fBounds.fTop
4129 ? fBounds.fLeft < rh.fBounds.fLeft
4130 : fBounds.fTop < rh.fBounds.fTop;
4131 }
4132
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004133 void addCoincident(int index, Contour* other, int otherIndex,
4134 const Intersections& ts, bool swap) {
4135 Coincidence& coincidence = *fCoincidences.append();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004136 coincidence.fContours[0] = this; // FIXME: no need to store
caryclark@google.comb9738012012-07-03 19:53:30 +00004137 coincidence.fContours[1] = other;
4138 coincidence.fSegments[0] = index;
4139 coincidence.fSegments[1] = otherIndex;
caryclark@google.com32546db2012-08-31 20:55:07 +00004140 if (fSegments[index].verb() == SkPath::kLine_Verb &&
4141 other->fSegments[otherIndex].verb() == SkPath::kLine_Verb) {
4142 // FIXME: coincident lines use legacy Ts instead of coincident Ts
4143 coincidence.fTs[swap][0] = ts.fT[0][0];
4144 coincidence.fTs[swap][1] = ts.fT[0][1];
4145 coincidence.fTs[!swap][0] = ts.fT[1][0];
4146 coincidence.fTs[!swap][1] = ts.fT[1][1];
4147 } else if (fSegments[index].verb() == SkPath::kQuad_Verb &&
4148 other->fSegments[otherIndex].verb() == SkPath::kQuad_Verb) {
4149 coincidence.fTs[swap][0] = ts.fCoincidentT[0][0];
4150 coincidence.fTs[swap][1] = ts.fCoincidentT[0][1];
4151 coincidence.fTs[!swap][0] = ts.fCoincidentT[1][0];
4152 coincidence.fTs[!swap][1] = ts.fCoincidentT[1][1];
4153 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004154 }
4155
4156 void addCross(const Contour* crosser) {
4157#ifdef DEBUG_CROSS
4158 for (int index = 0; index < fCrosses.count(); ++index) {
4159 SkASSERT(fCrosses[index] != crosser);
4160 }
4161#endif
4162 *fCrosses.append() = crosser;
4163 }
4164
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004165 void addCubic(const SkPoint pts[4]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004166 fSegments.push_back().addCubic(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004167 fContainsCurves = true;
4168 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004169
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004170 int addLine(const SkPoint pts[2]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004171 fSegments.push_back().addLine(pts, fOperand, fXor);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004172 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004173 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004174
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004175 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
4176 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
4177 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004178
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004179 int addQuad(const SkPoint pts[3]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004180 fSegments.push_back().addQuad(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004181 fContainsCurves = true;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004182 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004183 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004184
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004185 int addT(int segIndex, double newT, Contour* other, int otherIndex) {
4186 containsIntercepts();
4187 return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex]);
4188 }
4189
caryclark@google.com73ca6242013-01-17 21:02:47 +00004190 int addUnsortableT(int segIndex, double newT, Contour* other, int otherIndex, bool start) {
4191 return fSegments[segIndex].addUnsortableT(newT, &other->fSegments[otherIndex], start);
4192 }
4193
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004194 const Bounds& bounds() const {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004195 return fBounds;
4196 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004197
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004198 void complete() {
4199 setBounds();
4200 fContainsIntercepts = false;
4201 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004202
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004203 void containsIntercepts() {
4204 fContainsIntercepts = true;
4205 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004206
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004207 bool crosses(const Contour* crosser) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004208 for (int index = 0; index < fCrosses.count(); ++index) {
4209 if (fCrosses[index] == crosser) {
4210 return true;
4211 }
4212 }
4213 return false;
4214 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004215
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004216 bool done() const {
4217 return fDone;
4218 }
4219
caryclark@google.comf839c032012-10-26 21:03:50 +00004220 const SkPoint& end() const {
4221 const Segment& segment = fSegments.back();
4222 return segment.pts()[segment.verb()];
4223 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004224
caryclark@google.com4eeda372012-12-06 21:47:48 +00004225 void findTooCloseToCall() {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004226 int segmentCount = fSegments.count();
4227 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004228 fSegments[sIndex].findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004229 }
4230 }
4231
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004232 void fixOtherTIndex() {
4233 int segmentCount = fSegments.count();
4234 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4235 fSegments[sIndex].fixOtherTIndex();
4236 }
4237 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004238
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004239 Segment* nonVerticalSegment(int& start, int& end) {
4240 int segmentCount = fSortedSegments.count();
4241 SkASSERT(segmentCount > 0);
4242 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4243 Segment* testSegment = fSortedSegments[sortedIndex];
4244 if (testSegment->done()) {
4245 continue;
4246 }
4247 start = end = 0;
4248 while (testSegment->nextCandidate(start, end)) {
4249 if (!testSegment->isVertical(start, end)) {
4250 return testSegment;
4251 }
4252 }
4253 }
4254 return NULL;
4255 }
4256
caryclark@google.com31143cf2012-11-09 22:14:19 +00004257 bool operand() const {
4258 return fOperand;
4259 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004260
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004261 void reset() {
4262 fSegments.reset();
4263 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004264 fContainsCurves = fContainsIntercepts = fDone = false;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004265 }
caryclark@google.comb9738012012-07-03 19:53:30 +00004266
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004267 void resolveCoincidence(SkTDArray<Contour*>& contourList) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004268 int count = fCoincidences.count();
4269 for (int index = 0; index < count; ++index) {
4270 Coincidence& coincidence = fCoincidences[index];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004271 SkASSERT(coincidence.fContours[0] == this);
caryclark@google.comb9738012012-07-03 19:53:30 +00004272 int thisIndex = coincidence.fSegments[0];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004273 Segment& thisOne = fSegments[thisIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004274 Contour* otherContour = coincidence.fContours[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004275 int otherIndex = coincidence.fSegments[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004276 Segment& other = otherContour->fSegments[otherIndex];
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004277 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004278 continue;
4279 }
caryclark@google.com47580692012-07-23 12:14:49 +00004280 #if DEBUG_CONCIDENT
4281 thisOne.debugShowTs();
4282 other.debugShowTs();
4283 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004284 double startT = coincidence.fTs[0][0];
4285 double endT = coincidence.fTs[0][1];
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004286 bool cancelers = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004287 if (startT > endT) {
4288 SkTSwap<double>(startT, endT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004289 cancelers ^= true; // FIXME: just assign true
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004290 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004291 SkASSERT(!approximately_negative(endT - startT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004292 double oStartT = coincidence.fTs[1][0];
4293 double oEndT = coincidence.fTs[1][1];
4294 if (oStartT > oEndT) {
4295 SkTSwap<double>(oStartT, oEndT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004296 cancelers ^= true;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004297 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004298 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00004299 bool opp = fOperand ^ otherContour->fOperand;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004300 if (cancelers && !opp) {
4301 // make sure startT and endT have t entries
caryclark@google.com2ddff932012-08-07 21:25:27 +00004302 if (startT > 0 || oEndT < 1
4303 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
4304 thisOne.addTPair(startT, other, oEndT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004305 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00004306 if (oStartT > 0 || endT < 1
4307 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
4308 other.addTPair(oStartT, thisOne, endT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004309 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004310 if (!thisOne.done() && !other.done()) {
4311 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4312 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004313 } else {
caryclark@google.com200c2112012-08-03 15:05:04 +00004314 if (startT > 0 || oStartT > 0
4315 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00004316 thisOne.addTPair(startT, other, oStartT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004317 }
caryclark@google.com200c2112012-08-03 15:05:04 +00004318 if (endT < 1 || oEndT < 1
4319 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00004320 other.addTPair(oEndT, thisOne, endT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004321 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004322 if (!thisOne.done() && !other.done()) {
4323 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4324 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004325 }
caryclark@google.com47580692012-07-23 12:14:49 +00004326 #if DEBUG_CONCIDENT
4327 thisOne.debugShowTs();
4328 other.debugShowTs();
4329 #endif
caryclark@google.com729e1c42012-11-21 21:36:34 +00004330 #if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004331 debugShowWindingValues(contourList);
4332 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004333 }
4334 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004335
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004336 // first pass, add missing T values
4337 // second pass, determine winding values of overlaps
4338 void addCoincidentPoints() {
4339 int count = fCoincidences.count();
4340 for (int index = 0; index < count; ++index) {
4341 Coincidence& coincidence = fCoincidences[index];
4342 SkASSERT(coincidence.fContours[0] == this);
4343 int thisIndex = coincidence.fSegments[0];
4344 Segment& thisOne = fSegments[thisIndex];
4345 Contour* otherContour = coincidence.fContours[1];
4346 int otherIndex = coincidence.fSegments[1];
4347 Segment& other = otherContour->fSegments[otherIndex];
4348 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
4349 // OPTIMIZATION: remove from array
4350 continue;
4351 }
4352 #if DEBUG_CONCIDENT
4353 thisOne.debugShowTs();
4354 other.debugShowTs();
4355 #endif
4356 double startT = coincidence.fTs[0][0];
4357 double endT = coincidence.fTs[0][1];
4358 bool cancelers;
4359 if ((cancelers = startT > endT)) {
4360 SkTSwap<double>(startT, endT);
4361 }
4362 SkASSERT(!approximately_negative(endT - startT));
4363 double oStartT = coincidence.fTs[1][0];
4364 double oEndT = coincidence.fTs[1][1];
4365 if (oStartT > oEndT) {
4366 SkTSwap<double>(oStartT, oEndT);
4367 cancelers ^= true;
4368 }
4369 SkASSERT(!approximately_negative(oEndT - oStartT));
4370 bool opp = fOperand ^ otherContour->fOperand;
4371 if (cancelers && !opp) {
4372 // make sure startT and endT have t entries
4373 if (startT > 0 || oEndT < 1
4374 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
4375 thisOne.addTPair(startT, other, oEndT, true);
4376 }
4377 if (oStartT > 0 || endT < 1
4378 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
4379 other.addTPair(oStartT, thisOne, endT, true);
4380 }
4381 } else {
4382 if (startT > 0 || oStartT > 0
4383 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
4384 thisOne.addTPair(startT, other, oStartT, true);
4385 }
4386 if (endT < 1 || oEndT < 1
4387 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
4388 other.addTPair(oEndT, thisOne, endT, true);
4389 }
4390 }
4391 #if DEBUG_CONCIDENT
4392 thisOne.debugShowTs();
4393 other.debugShowTs();
4394 #endif
4395 }
4396 }
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00004397
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004398 void calcCoincidentWinding() {
4399 int count = fCoincidences.count();
4400 for (int index = 0; index < count; ++index) {
4401 Coincidence& coincidence = fCoincidences[index];
4402 SkASSERT(coincidence.fContours[0] == this);
4403 int thisIndex = coincidence.fSegments[0];
4404 Segment& thisOne = fSegments[thisIndex];
4405 if (thisOne.done()) {
4406 continue;
4407 }
4408 Contour* otherContour = coincidence.fContours[1];
4409 int otherIndex = coincidence.fSegments[1];
4410 Segment& other = otherContour->fSegments[otherIndex];
4411 if (other.done()) {
4412 continue;
4413 }
4414 double startT = coincidence.fTs[0][0];
4415 double endT = coincidence.fTs[0][1];
4416 bool cancelers;
4417 if ((cancelers = startT > endT)) {
4418 SkTSwap<double>(startT, endT);
4419 }
4420 SkASSERT(!approximately_negative(endT - startT));
4421 double oStartT = coincidence.fTs[1][0];
4422 double oEndT = coincidence.fTs[1][1];
4423 if (oStartT > oEndT) {
4424 SkTSwap<double>(oStartT, oEndT);
4425 cancelers ^= true;
4426 }
4427 SkASSERT(!approximately_negative(oEndT - oStartT));
4428 bool opp = fOperand ^ otherContour->fOperand;
4429 if (cancelers && !opp) {
4430 // make sure startT and endT have t entries
4431 if (!thisOne.done() && !other.done()) {
4432 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4433 }
4434 } else {
4435 if (!thisOne.done() && !other.done()) {
4436 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4437 }
4438 }
4439 #if DEBUG_CONCIDENT
4440 thisOne.debugShowTs();
4441 other.debugShowTs();
4442 #endif
4443 }
4444 }
4445
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004446 SkTArray<Segment>& segments() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004447 return fSegments;
4448 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004449
caryclark@google.com235f56a2012-09-14 14:19:30 +00004450 void setOperand(bool isOp) {
4451 fOperand = isOp;
4452 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00004453
caryclark@google.com4eeda372012-12-06 21:47:48 +00004454 void setOppXor(bool isOppXor) {
4455 fOppXor = isOppXor;
4456 int segmentCount = fSegments.count();
4457 for (int test = 0; test < segmentCount; ++test) {
4458 fSegments[test].setOppXor(isOppXor);
4459 }
4460 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004461
caryclark@google.com235f56a2012-09-14 14:19:30 +00004462 void setXor(bool isXor) {
4463 fXor = isXor;
4464 }
4465
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004466 void sortSegments() {
4467 int segmentCount = fSegments.count();
4468 fSortedSegments.setReserve(segmentCount);
4469 for (int test = 0; test < segmentCount; ++test) {
4470 *fSortedSegments.append() = &fSegments[test];
4471 }
4472 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4473 fFirstSorted = 0;
4474 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004475
caryclark@google.comf839c032012-10-26 21:03:50 +00004476 const SkPoint& start() const {
4477 return fSegments.front().pts()[0];
4478 }
4479
4480 void toPath(PathWrapper& path) const {
4481 int segmentCount = fSegments.count();
4482 const SkPoint& pt = fSegments.front().pts()[0];
4483 path.deferredMove(pt);
4484 for (int test = 0; test < segmentCount; ++test) {
4485 fSegments[test].addCurveTo(0, 1, path, true);
4486 }
4487 path.close();
4488 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004489
caryclark@google.comf839c032012-10-26 21:03:50 +00004490 void toPartialBackward(PathWrapper& path) const {
4491 int segmentCount = fSegments.count();
4492 for (int test = segmentCount - 1; test >= 0; --test) {
4493 fSegments[test].addCurveTo(1, 0, path, true);
4494 }
4495 }
4496
4497 void toPartialForward(PathWrapper& path) const {
4498 int segmentCount = fSegments.count();
4499 for (int test = 0; test < segmentCount; ++test) {
4500 fSegments[test].addCurveTo(0, 1, path, true);
4501 }
4502 }
4503
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004504 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004505 int segmentCount = fSortedSegments.count();
4506 SkASSERT(segmentCount > 0);
caryclark@google.comf839c032012-10-26 21:03:50 +00004507 int sortedIndex = fFirstSorted;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004508 fDone = true; // may be cleared below
caryclark@google.comf839c032012-10-26 21:03:50 +00004509 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4510 Segment* testSegment = fSortedSegments[sortedIndex];
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004511 if (testSegment->done()) {
caryclark@google.comf839c032012-10-26 21:03:50 +00004512 if (sortedIndex == fFirstSorted) {
4513 ++fFirstSorted;
4514 }
4515 continue;
4516 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004517 fDone = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00004518 SkPoint testXY;
4519 testSegment->activeLeftTop(testXY);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004520 if (topStart) {
4521 if (testXY.fY < topLeft.fY) {
4522 continue;
4523 }
4524 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4525 continue;
4526 }
4527 if (bestXY.fY < testXY.fY) {
4528 continue;
4529 }
4530 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4531 continue;
4532 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004533 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004534 topStart = testSegment;
caryclark@google.comf839c032012-10-26 21:03:50 +00004535 bestXY = testXY;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004536 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004537 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004538
caryclark@google.com24bec792012-08-20 12:43:57 +00004539 Segment* undoneSegment(int& start, int& end) {
4540 int segmentCount = fSegments.count();
4541 for (int test = 0; test < segmentCount; ++test) {
4542 Segment* testSegment = &fSegments[test];
4543 if (testSegment->done()) {
4544 continue;
4545 }
4546 testSegment->undoneSpan(start, end);
4547 return testSegment;
4548 }
4549 return NULL;
4550 }
4551
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004552 int updateSegment(int index, const SkPoint* pts) {
4553 Segment& segment = fSegments[index];
4554 segment.updatePts(pts);
4555 return segment.verb() + 1;
4556 }
4557
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004558#if DEBUG_TEST
4559 SkTArray<Segment>& debugSegments() {
4560 return fSegments;
4561 }
4562#endif
4563
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004564#if DEBUG_DUMP
4565 void dump() {
4566 int i;
4567 const char className[] = "Contour";
4568 const int tab = 4;
4569 SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4570 for (i = 0; i < fSegments.count(); ++i) {
4571 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4572 className, i);
4573 fSegments[i].dump();
4574 }
4575 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4576 tab + sizeof(className), className,
4577 fBounds.fLeft, fBounds.fTop,
4578 fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004579 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4580 className, fContainsIntercepts);
4581 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4582 className, fContainsCurves);
4583 }
4584#endif
4585
caryclark@google.com027de222012-07-12 12:52:50 +00004586#if DEBUG_ACTIVE_SPANS
4587 void debugShowActiveSpans() {
4588 for (int index = 0; index < fSegments.count(); ++index) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004589 fSegments[index].debugShowActiveSpans();
caryclark@google.com027de222012-07-12 12:52:50 +00004590 }
4591 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004592
4593 void validateActiveSpans() {
4594 for (int index = 0; index < fSegments.count(); ++index) {
4595 fSegments[index].validateActiveSpans();
4596 }
4597 }
caryclark@google.com027de222012-07-12 12:52:50 +00004598#endif
4599
caryclark@google.com729e1c42012-11-21 21:36:34 +00004600#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004601 int debugShowWindingValues(int totalSegments, int ofInterest) {
4602 int count = fSegments.count();
4603 int sum = 0;
4604 for (int index = 0; index < count; ++index) {
4605 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4606 }
4607 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4608 return sum;
4609 }
4610
4611 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4612 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4613 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4614 int ofInterest = 1 << 5 | 1 << 8;
4615 int total = 0;
4616 int index;
4617 for (index = 0; index < contourList.count(); ++index) {
4618 total += contourList[index]->segments().count();
4619 }
4620 int sum = 0;
4621 for (index = 0; index < contourList.count(); ++index) {
4622 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4623 }
4624 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4625 }
4626#endif
4627
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004628protected:
4629 void setBounds() {
4630 int count = fSegments.count();
4631 if (count == 0) {
4632 SkDebugf("%s empty contour\n", __FUNCTION__);
4633 SkASSERT(0);
4634 // FIXME: delete empty contour?
4635 return;
4636 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004637 fBounds = fSegments.front().bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004638 for (int index = 1; index < count; ++index) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004639 fBounds.add(fSegments[index].bounds());
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004640 }
4641 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004642
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004643private:
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004644 SkTArray<Segment> fSegments;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004645 SkTDArray<Segment*> fSortedSegments;
4646 int fFirstSorted;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004647 SkTDArray<Coincidence> fCoincidences;
4648 SkTDArray<const Contour*> fCrosses;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004649 Bounds fBounds;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004650 bool fContainsIntercepts;
4651 bool fContainsCurves;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004652 bool fDone;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004653 bool fOperand; // true for the second argument to a binary operator
4654 bool fXor;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004655 bool fOppXor;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004656#if DEBUG_DUMP
4657 int fID;
4658#endif
4659};
4660
4661class EdgeBuilder {
4662public:
4663
caryclark@google.comf839c032012-10-26 21:03:50 +00004664EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
4665 : fPath(path.nativePath())
4666 , fContours(contours)
4667{
4668 init();
4669}
4670
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004671EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
caryclark@google.com235f56a2012-09-14 14:19:30 +00004672 : fPath(&path)
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004673 , fContours(contours)
4674{
caryclark@google.comf839c032012-10-26 21:03:50 +00004675 init();
4676}
4677
4678void init() {
4679 fCurrentContour = NULL;
4680 fOperand = false;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004681 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004682#if DEBUG_DUMP
4683 gContourID = 0;
4684 gSegmentID = 0;
4685#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00004686 fSecondHalf = preFetch();
4687}
4688
4689void addOperand(const SkPath& path) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00004690 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
4691 fPathVerbs.pop();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004692 fPath = &path;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004693 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004694 preFetch();
4695}
4696
4697void finish() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004698 walk();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004699 complete();
4700 if (fCurrentContour && !fCurrentContour->segments().count()) {
4701 fContours.pop_back();
4702 }
4703 // correct pointers in contours since fReducePts may have moved as it grew
4704 int cIndex = 0;
4705 int extraCount = fExtra.count();
4706 SkASSERT(extraCount == 0 || fExtra[0] == -1);
4707 int eIndex = 0;
4708 int rIndex = 0;
4709 while (++eIndex < extraCount) {
4710 int offset = fExtra[eIndex];
4711 if (offset < 0) {
4712 ++cIndex;
4713 continue;
4714 }
4715 fCurrentContour = &fContours[cIndex];
4716 rIndex += fCurrentContour->updateSegment(offset - 1,
4717 &fReducePts[rIndex]);
4718 }
4719 fExtra.reset(); // we're done with this
4720}
4721
4722ShapeOpMask xorMask() const {
caryclark@google.com729e1c42012-11-21 21:36:34 +00004723 return fXorMask[fOperand];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004724}
4725
4726protected:
4727
4728void complete() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004729 if (fCurrentContour && fCurrentContour->segments().count()) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004730 fCurrentContour->complete();
4731 fCurrentContour = NULL;
4732 }
4733}
4734
caryclark@google.com235f56a2012-09-14 14:19:30 +00004735// FIXME:remove once we can access path pts directly
4736int preFetch() {
4737 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004738 SkPoint pts[4];
4739 SkPath::Verb verb;
4740 do {
4741 verb = iter.next(pts);
4742 *fPathVerbs.append() = verb;
4743 if (verb == SkPath::kMove_Verb) {
4744 *fPathPts.append() = pts[0];
4745 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
4746 fPathPts.append(verb, &pts[1]);
4747 }
4748 } while (verb != SkPath::kDone_Verb);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004749 return fPathVerbs.count() - 1;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004750}
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004751
caryclark@google.com235f56a2012-09-14 14:19:30 +00004752void walk() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004753 SkPath::Verb reducedVerb;
4754 uint8_t* verbPtr = fPathVerbs.begin();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004755 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004756 const SkPoint* pointsPtr = fPathPts.begin();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004757 const SkPoint* finalCurveStart = NULL;
4758 const SkPoint* finalCurveEnd = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004759 SkPath::Verb verb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004760 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
4761 switch (verb) {
4762 case SkPath::kMove_Verb:
4763 complete();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004764 if (!fCurrentContour) {
4765 fCurrentContour = fContours.push_back_n(1);
caryclark@google.com235f56a2012-09-14 14:19:30 +00004766 fCurrentContour->setOperand(fOperand);
caryclark@google.com729e1c42012-11-21 21:36:34 +00004767 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004768 *fExtra.append() = -1; // start new contour
4769 }
caryclark@google.com59823f72012-08-09 18:17:47 +00004770 finalCurveEnd = pointsPtr++;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004771 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004772 case SkPath::kLine_Verb:
4773 // skip degenerate points
4774 if (pointsPtr[-1].fX != pointsPtr[0].fX
4775 || pointsPtr[-1].fY != pointsPtr[0].fY) {
4776 fCurrentContour->addLine(&pointsPtr[-1]);
4777 }
4778 break;
4779 case SkPath::kQuad_Verb:
rmistry@google.comd6176b02012-08-23 18:14:13 +00004780
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004781 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
4782 if (reducedVerb == 0) {
4783 break; // skip degenerate points
4784 }
4785 if (reducedVerb == 1) {
rmistry@google.comd6176b02012-08-23 18:14:13 +00004786 *fExtra.append() =
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004787 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004788 break;
4789 }
4790 fCurrentContour->addQuad(&pointsPtr[-1]);
4791 break;
4792 case SkPath::kCubic_Verb:
4793 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
4794 if (reducedVerb == 0) {
4795 break; // skip degenerate points
4796 }
4797 if (reducedVerb == 1) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004798 *fExtra.append() =
4799 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004800 break;
4801 }
4802 if (reducedVerb == 2) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004803 *fExtra.append() =
4804 fCurrentContour->addQuad(fReducePts.end() - 3);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004805 break;
4806 }
4807 fCurrentContour->addCubic(&pointsPtr[-1]);
4808 break;
4809 case SkPath::kClose_Verb:
4810 SkASSERT(fCurrentContour);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004811 if (finalCurveStart && finalCurveEnd
4812 && *finalCurveStart != *finalCurveEnd) {
4813 *fReducePts.append() = *finalCurveStart;
4814 *fReducePts.append() = *finalCurveEnd;
4815 *fExtra.append() =
4816 fCurrentContour->addLine(fReducePts.end() - 2);
4817 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004818 complete();
caryclark@google.com31143cf2012-11-09 22:14:19 +00004819 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004820 default:
4821 SkDEBUGFAIL("bad verb");
4822 return;
4823 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004824 finalCurveStart = &pointsPtr[verb - 1];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004825 pointsPtr += verb;
4826 SkASSERT(fCurrentContour);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004827 nextVerb:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004828 if (verbPtr == endOfFirstHalf) {
4829 fOperand = true;
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004830 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004831 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004832}
4833
4834private:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004835 const SkPath* fPath;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004836 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004837 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004838 Contour* fCurrentContour;
4839 SkTArray<Contour>& fContours;
4840 SkTDArray<SkPoint> fReducePts; // segments created on the fly
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004841 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
caryclark@google.com729e1c42012-11-21 21:36:34 +00004842 ShapeOpMask fXorMask[2];
caryclark@google.com235f56a2012-09-14 14:19:30 +00004843 int fSecondHalf;
4844 bool fOperand;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004845};
4846
4847class Work {
4848public:
4849 enum SegmentType {
4850 kHorizontalLine_Segment = -1,
4851 kVerticalLine_Segment = 0,
4852 kLine_Segment = SkPath::kLine_Verb,
4853 kQuad_Segment = SkPath::kQuad_Verb,
4854 kCubic_Segment = SkPath::kCubic_Verb,
4855 };
rmistry@google.comd6176b02012-08-23 18:14:13 +00004856
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004857 void addCoincident(Work& other, const Intersections& ts, bool swap) {
4858 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
4859 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004860
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004861 // FIXME: does it make sense to write otherIndex now if we're going to
4862 // fix it up later?
4863 void addOtherT(int index, double otherT, int otherIndex) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004864 fContour->addOtherT(fIndex, index, otherT, otherIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004865 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004866
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004867 // Avoid collapsing t values that are close to the same since
4868 // we walk ts to describe consecutive intersections. Since a pair of ts can
4869 // be nearly equal, any problems caused by this should be taken care
4870 // of later.
4871 // On the edge or out of range values are negative; add 2 to get end
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004872 int addT(double newT, const Work& other) {
4873 return fContour->addT(fIndex, newT, other.fContour, other.fIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004874 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004875
caryclark@google.com73ca6242013-01-17 21:02:47 +00004876 int addUnsortableT(double newT, const Work& other, bool start) {
4877 return fContour->addUnsortableT(fIndex, newT, other.fContour, other.fIndex, start);
4878 }
4879
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004880 bool advance() {
4881 return ++fIndex < fLast;
4882 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004883
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004884 SkScalar bottom() const {
4885 return bounds().fBottom;
4886 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004887
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004888 const Bounds& bounds() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004889 return fContour->segments()[fIndex].bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004890 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004891
caryclark@google.com73ca6242013-01-17 21:02:47 +00004892#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004893 const SkPoint* cubic() const {
4894 return fCubic;
4895 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00004896#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004897
4898 void init(Contour* contour) {
4899 fContour = contour;
4900 fIndex = 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004901 fLast = contour->segments().count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004902 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004903
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00004904 bool isAdjacent(const Work& next) {
4905 return fContour == next.fContour && fIndex + 1 == next.fIndex;
4906 }
4907
4908 bool isFirstLast(const Work& next) {
4909 return fContour == next.fContour && fIndex == 0
4910 && next.fIndex == fLast - 1;
4911 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004912
4913 SkScalar left() const {
4914 return bounds().fLeft;
4915 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004916
caryclark@google.com73ca6242013-01-17 21:02:47 +00004917#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004918 void promoteToCubic() {
4919 fCubic[0] = pts()[0];
4920 fCubic[2] = pts()[1];
4921 fCubic[3] = pts()[2];
4922 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
4923 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
4924 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
4925 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
4926 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00004927#endif
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004928
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004929 const SkPoint* pts() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004930 return fContour->segments()[fIndex].pts();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004931 }
4932
4933 SkScalar right() const {
4934 return bounds().fRight;
4935 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004936
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004937 ptrdiff_t segmentIndex() const {
4938 return fIndex;
4939 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004940
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004941 SegmentType segmentType() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004942 const Segment& segment = fContour->segments()[fIndex];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004943 SegmentType type = (SegmentType) segment.verb();
4944 if (type != kLine_Segment) {
4945 return type;
4946 }
4947 if (segment.isHorizontal()) {
4948 return kHorizontalLine_Segment;
4949 }
4950 if (segment.isVertical()) {
4951 return kVerticalLine_Segment;
4952 }
4953 return kLine_Segment;
4954 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004955
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004956 bool startAfter(const Work& after) {
4957 fIndex = after.fIndex;
4958 return advance();
4959 }
4960
4961 SkScalar top() const {
4962 return bounds().fTop;
4963 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004964
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004965 SkPath::Verb verb() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004966 return fContour->segments()[fIndex].verb();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004967 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004968
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004969 SkScalar x() const {
4970 return bounds().fLeft;
4971 }
4972
4973 bool xFlipped() const {
4974 return x() != pts()[0].fX;
4975 }
4976
4977 SkScalar y() const {
4978 return bounds().fTop;
4979 }
4980
4981 bool yFlipped() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004982 return y() != pts()[0].fY;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004983 }
4984
4985protected:
4986 Contour* fContour;
caryclark@google.com73ca6242013-01-17 21:02:47 +00004987#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004988 SkPoint fCubic[4];
caryclark@google.com73ca6242013-01-17 21:02:47 +00004989#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004990 int fIndex;
4991 int fLast;
4992};
4993
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00004994#if DEBUG_ADD_INTERSECTING_TS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004995static void debugShowLineIntersection(int pts, const Work& wt,
4996 const Work& wn, const double wtTs[2], const double wnTs[2]) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004997 return;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004998 if (!pts) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004999 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n",
5000 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
5001 wt.pts()[1].fX, wt.pts()[1].fY, wn.pts()[0].fX, wn.pts()[0].fY,
5002 wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005003 return;
5004 }
5005 SkPoint wtOutPt, wnOutPt;
5006 LineXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5007 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005008 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 +00005009 __FUNCTION__,
5010 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5011 wt.pts()[1].fX, wt.pts()[1].fY, wtOutPt.fX, wtOutPt.fY);
5012 if (pts == 2) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005013 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005014 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00005015 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005016 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5017 wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
5018 if (pts == 2) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005019 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
5020 }
5021 SkDebugf("\n");
5022}
5023
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005024static void debugShowQuadLineIntersection(int pts, const Work& wt,
5025 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5026 if (!pts) {
5027 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
caryclark@google.com0b7da432012-10-31 19:00:20 +00005028 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005029 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
5030 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005031 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005032 return;
5033 }
5034 SkPoint wtOutPt, wnOutPt;
5035 QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5036 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5037 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5038 __FUNCTION__,
5039 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5040 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
5041 wtOutPt.fX, wtOutPt.fY);
5042 if (pts == 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005043 QuadXYAtT(wt.pts(), wtTs[1], &wtOutPt);
5044 SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", wtTs[1], wtOutPt.fX, wtOutPt.fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005045 }
5046 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5047 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5048 wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
5049 if (pts == 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005050 LineXYAtT(wn.pts(), wnTs[1], &wnOutPt);
5051 SkDebugf(" wnTs[1]=%1.9g (%1.9g,%1.9g)", wnTs[1], wnOutPt.fX, wnOutPt.fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005052 }
5053 SkDebugf("\n");
5054}
5055
caryclark@google.com73ca6242013-01-17 21:02:47 +00005056// FIXME: show more than two intersection points
caryclark@google.coma461ff02012-10-11 12:54:23 +00005057static void debugShowQuadIntersection(int pts, const Work& wt,
5058 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5059 if (!pts) {
5060 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5061 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5062 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
skia.committer@gmail.com5b6f9162012-10-12 02:01:15 +00005063 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.coma461ff02012-10-11 12:54:23 +00005064 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005065 wn.pts()[2].fX, wn.pts()[2].fY );
caryclark@google.coma461ff02012-10-11 12:54:23 +00005066 return;
5067 }
5068 SkPoint wtOutPt, wnOutPt;
5069 QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5070 QuadXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5071 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5072 __FUNCTION__,
5073 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5074 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
5075 wtOutPt.fX, wtOutPt.fY);
5076 if (pts == 2) {
5077 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
5078 }
5079 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5080 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5081 wn.pts()[1].fX, wn.pts()[1].fY, wn.pts()[2].fX, wn.pts()[2].fY,
5082 wnOutPt.fX, wnOutPt.fY);
5083 if (pts == 2) {
5084 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005085 }
caryclark@google.comb9738012012-07-03 19:53:30 +00005086 SkDebugf("\n");
5087}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005088
5089static void debugShowCubicLineIntersection(int pts, const Work& wt,
5090 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5091 if (!pts) {
5092 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5093 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
5094 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5095 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5096 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
5097 return;
5098 }
5099 SkPoint wtOutPt, wnOutPt;
5100 CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5101 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5102 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5103 __FUNCTION__,
5104 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5105 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5106 wtOutPt.fX, wtOutPt.fY);
5107 if (pts == 2) {
5108 CubicXYAtT(wt.pts(), wtTs[1], &wtOutPt);
5109 SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", wtTs[1], wtOutPt.fX, wtOutPt.fY);
5110 }
5111 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5112 wtTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5113 wnOutPt.fX, wnOutPt.fY);
5114 if (pts == 2) {
5115 LineXYAtT(wn.pts(), wnTs[1], &wnOutPt);
5116 SkDebugf(" wnTs[1]=%1.9g (%1.9g,%1.9g)", wnTs[1], wnOutPt.fX, wnOutPt.fY);
5117 }
5118 SkDebugf("\n");
5119}
5120
caryclark@google.com73ca6242013-01-17 21:02:47 +00005121// FIXME: show more than two intersection points
5122static void debugShowCubicQuadIntersection(int pts, const Work& wt,
5123 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5124 if (!pts) {
5125 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5126 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5127 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5128 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5129 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5130 wn.pts()[2].fX, wn.pts()[2].fY );
5131 return;
5132 }
5133 SkPoint wtOutPt, wnOutPt;
5134 CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005135 QuadXYAtT(wn.pts(), wnTs[0], &wnOutPt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005136 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)",
5137 __FUNCTION__,
5138 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5139 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5140 wtOutPt.fX, wtOutPt.fY);
5141 if (pts == 2) {
5142 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
5143 }
5144 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5145 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5146 wn.pts()[2].fX, wn.pts()[2].fY,
5147 wnOutPt.fX, wnOutPt.fY);
5148 if (pts == 2) {
5149 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
5150 }
5151 SkDebugf("\n");
5152}
5153
5154// FIXME: show more than two intersection points
5155static void debugShowCubicIntersection(int pts, const Work& wt,
5156 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5157 if (!pts) {
5158 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5159 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5160 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5161 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5162 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5163 wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY );
5164 return;
5165 }
5166 SkPoint wtOutPt, wnOutPt;
5167 CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5168 CubicXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5169 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)",
5170 __FUNCTION__,
5171 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5172 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5173 wtOutPt.fX, wtOutPt.fY);
5174 if (pts == 2) {
5175 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
5176 }
5177 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5178 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5179 wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY,
5180 wnOutPt.fX, wnOutPt.fY);
5181 if (pts == 2) {
5182 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
5183 }
5184 SkDebugf("\n");
5185}
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005186
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005187#else
5188static void debugShowLineIntersection(int , const Work& ,
5189 const Work& , const double [2], const double [2]) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005190}
caryclark@google.coma461ff02012-10-11 12:54:23 +00005191
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005192static void debugShowQuadLineIntersection(int , const Work& ,
5193 const Work& , const double [2], const double [2]) {
5194}
5195
caryclark@google.coma461ff02012-10-11 12:54:23 +00005196static void debugShowQuadIntersection(int , const Work& ,
5197 const Work& , const double [2], const double [2]) {
5198}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005199
5200static void debugShowCubicLineIntersection(int , const Work& ,
5201 const Work& , const double [2], const double [2]) {
5202}
5203
caryclark@google.com73ca6242013-01-17 21:02:47 +00005204static void debugShowCubicQuadIntersection(int , const Work& ,
5205 const Work& , const double [2], const double [2]) {
5206}
5207
5208static void debugShowCubicIntersection(int , const Work& ,
5209 const Work& , const double [2], const double [2]) {
5210}
5211#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005212
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005213static bool addIntersectTs(Contour* test, Contour* next) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005214
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005215 if (test != next) {
5216 if (test->bounds().fBottom < next->bounds().fTop) {
5217 return false;
5218 }
5219 if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5220 return true;
5221 }
5222 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005223 Work wt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005224 wt.init(test);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005225 bool foundCommonContour = test == next;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005226 do {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005227 Work wn;
5228 wn.init(next);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005229 if (test == next && !wn.startAfter(wt)) {
5230 continue;
5231 }
5232 do {
5233 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5234 continue;
5235 }
5236 int pts;
5237 Intersections ts;
5238 bool swap = false;
5239 switch (wt.segmentType()) {
5240 case Work::kHorizontalLine_Segment:
5241 swap = true;
5242 switch (wn.segmentType()) {
5243 case Work::kHorizontalLine_Segment:
5244 case Work::kVerticalLine_Segment:
5245 case Work::kLine_Segment: {
5246 pts = HLineIntersect(wn.pts(), wt.left(),
5247 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005248 debugShowLineIntersection(pts, wt, wn,
5249 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005250 break;
5251 }
5252 case Work::kQuad_Segment: {
5253 pts = HQuadIntersect(wn.pts(), wt.left(),
5254 wt.right(), wt.y(), wt.xFlipped(), ts);
5255 break;
5256 }
5257 case Work::kCubic_Segment: {
5258 pts = HCubicIntersect(wn.pts(), wt.left(),
5259 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005260 debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005261 break;
5262 }
5263 default:
5264 SkASSERT(0);
5265 }
5266 break;
5267 case Work::kVerticalLine_Segment:
5268 swap = true;
5269 switch (wn.segmentType()) {
5270 case Work::kHorizontalLine_Segment:
5271 case Work::kVerticalLine_Segment:
5272 case Work::kLine_Segment: {
5273 pts = VLineIntersect(wn.pts(), wt.top(),
5274 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005275 debugShowLineIntersection(pts, wt, wn,
5276 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005277 break;
5278 }
5279 case Work::kQuad_Segment: {
5280 pts = VQuadIntersect(wn.pts(), wt.top(),
5281 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5282 break;
5283 }
5284 case Work::kCubic_Segment: {
5285 pts = VCubicIntersect(wn.pts(), wt.top(),
5286 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005287 debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005288 break;
5289 }
5290 default:
5291 SkASSERT(0);
5292 }
5293 break;
5294 case Work::kLine_Segment:
5295 switch (wn.segmentType()) {
5296 case Work::kHorizontalLine_Segment:
5297 pts = HLineIntersect(wt.pts(), wn.left(),
5298 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005299 debugShowLineIntersection(pts, wt, wn,
5300 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005301 break;
5302 case Work::kVerticalLine_Segment:
5303 pts = VLineIntersect(wt.pts(), wn.top(),
5304 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005305 debugShowLineIntersection(pts, wt, wn,
5306 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005307 break;
5308 case Work::kLine_Segment: {
5309 pts = LineIntersect(wt.pts(), wn.pts(), ts);
5310 debugShowLineIntersection(pts, wt, wn,
5311 ts.fT[1], ts.fT[0]);
5312 break;
5313 }
5314 case Work::kQuad_Segment: {
5315 swap = true;
5316 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005317 debugShowQuadLineIntersection(pts, wn, wt,
5318 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005319 break;
5320 }
5321 case Work::kCubic_Segment: {
5322 swap = true;
5323 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005324 debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005325 break;
5326 }
5327 default:
5328 SkASSERT(0);
5329 }
5330 break;
5331 case Work::kQuad_Segment:
5332 switch (wn.segmentType()) {
5333 case Work::kHorizontalLine_Segment:
5334 pts = HQuadIntersect(wt.pts(), wn.left(),
5335 wn.right(), wn.y(), wn.xFlipped(), ts);
5336 break;
5337 case Work::kVerticalLine_Segment:
5338 pts = VQuadIntersect(wt.pts(), wn.top(),
5339 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5340 break;
5341 case Work::kLine_Segment: {
5342 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005343 debugShowQuadLineIntersection(pts, wt, wn,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005344 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005345 break;
5346 }
5347 case Work::kQuad_Segment: {
5348 pts = QuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005349 debugShowQuadIntersection(pts, wt, wn,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005350 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005351 break;
5352 }
5353 case Work::kCubic_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005354 #if APPROXIMATE_CUBICS
5355 swap = true;
5356 pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts);
5357 debugShowCubicQuadIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
5358 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005359 wt.promoteToCubic();
5360 pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005361 debugShowCubicIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005362 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005363 break;
5364 }
5365 default:
5366 SkASSERT(0);
5367 }
5368 break;
5369 case Work::kCubic_Segment:
5370 switch (wn.segmentType()) {
5371 case Work::kHorizontalLine_Segment:
5372 pts = HCubicIntersect(wt.pts(), wn.left(),
5373 wn.right(), wn.y(), wn.xFlipped(), ts);
5374 break;
5375 case Work::kVerticalLine_Segment:
5376 pts = VCubicIntersect(wt.pts(), wn.top(),
5377 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005378 debugShowCubicLineIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005379 break;
5380 case Work::kLine_Segment: {
5381 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005382 debugShowCubicLineIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005383 break;
5384 }
5385 case Work::kQuad_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005386 #if APPROXIMATE_CUBICS
5387 pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts);
5388 debugShowCubicQuadIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
5389 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005390 wn.promoteToCubic();
5391 pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005392 debugShowCubicIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005393 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005394 break;
5395 }
5396 case Work::kCubic_Segment: {
5397 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005398 debugShowCubicIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005399 break;
5400 }
5401 default:
5402 SkASSERT(0);
5403 }
5404 break;
5405 default:
5406 SkASSERT(0);
5407 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005408 if (!foundCommonContour && pts > 0) {
5409 test->addCross(next);
5410 next->addCross(test);
5411 foundCommonContour = true;
5412 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005413 // in addition to recording T values, record matching segment
caryclark@google.com73ca6242013-01-17 21:02:47 +00005414 if (ts.unsortable()) {
5415 bool start = true;
5416 for (int pt = 0; pt < ts.used(); ++pt) {
5417 // FIXME: if unsortable, the other points to the original. This logic is
5418 // untested downstream.
5419 int testTAt = wt.addUnsortableT(ts.fT[swap][pt], wt, start);
5420 wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt);
5421 testTAt = wn.addUnsortableT(ts.fT[!swap][pt], wn, start ^ ts.fFlip);
5422 wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt);
5423 start ^= true;
5424 }
5425 continue;
5426 }
caryclark@google.com32546db2012-08-31 20:55:07 +00005427 if (pts == 2) {
5428 if (wn.segmentType() <= Work::kLine_Segment
5429 && wt.segmentType() <= Work::kLine_Segment) {
5430 wt.addCoincident(wn, ts, swap);
5431 continue;
5432 }
5433 if (wn.segmentType() == Work::kQuad_Segment
5434 && wt.segmentType() == Work::kQuad_Segment
5435 && ts.coincidentUsed() == 2) {
5436 wt.addCoincident(wn, ts, swap);
5437 continue;
5438 }
5439
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00005440 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00005441 for (int pt = 0; pt < pts; ++pt) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005442 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5443 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005444 int testTAt = wt.addT(ts.fT[swap][pt], wn);
5445 int nextTAt = wn.addT(ts.fT[!swap][pt], wt);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005446 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
5447 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005448 }
5449 } while (wn.advance());
5450 } while (wt.advance());
5451 return true;
5452}
5453
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005454// resolve any coincident pairs found while intersecting, and
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005455// see if coincidence is formed by clipping non-concident segments
caryclark@google.com4eeda372012-12-06 21:47:48 +00005456static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005457 int contourCount = contourList.count();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005458#if ONE_PASS_COINCIDENCE_CHECK
caryclark@google.comf25edfe2012-06-01 18:20:10 +00005459 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005460 Contour* contour = contourList[cIndex];
caryclark@google.com7ba591e2012-11-20 14:21:54 +00005461 contour->resolveCoincidence(contourList);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005462 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005463#else
5464 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5465 Contour* contour = contourList[cIndex];
5466 contour->addCoincidentPoints();
5467 }
5468 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5469 Contour* contour = contourList[cIndex];
5470 contour->calcCoincidentWinding();
5471 }
5472#endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005473 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5474 Contour* contour = contourList[cIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00005475 contour->findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005476 }
5477}
5478
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005479static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005480 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005481 SkPoint basePt;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005482 double tAtMid = current->tAtMid(index, endIndex, mid);
5483 current->xyAtT(tAtMid, basePt);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005484 int contourCount = contourList.count();
5485 SkScalar bestY = SK_ScalarMin;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005486 Segment* bestSeg = NULL;
5487 int bestTIndex;
5488 bool bestOpp;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005489 bool hitSomething = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005490 for (int cTest = 0; cTest < contourCount; ++cTest) {
5491 Contour* contour = contourList[cTest];
5492 bool testOpp = contour->operand() ^ current->operand() ^ opp;
5493 if (basePt.fY < contour->bounds().fTop) {
5494 continue;
5495 }
5496 if (bestY > contour->bounds().fBottom) {
5497 continue;
5498 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005499 int segmentCount = contour->segments().count();
5500 for (int test = 0; test < segmentCount; ++test) {
5501 Segment* testSeg = &contour->segments()[test];
5502 SkScalar testY = bestY;
5503 double testHit;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005504 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
5505 testOpp, testSeg == current);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005506 if (testTIndex < 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005507 if (testTIndex == SK_MinS32) {
5508 hitSomething = true;
5509 bestSeg = NULL;
5510 goto abortContours; // vertical encountered, return and try different point
5511 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005512 continue;
5513 }
5514 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005515 double baseT = current->t(index);
5516 double endT = current->t(endIndex);
5517 double newMid = (testHit - baseT) / (endT - baseT);
5518#if DEBUG_WINDING
5519 SkPoint midXY, newXY;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005520 double midT = current->tAtMid(index, endIndex, mid);
5521 current->xyAtT(midT, midXY);
5522 double newMidT = current->tAtMid(index, endIndex, newMid);
5523 current->xyAtT(newMidT, newXY);
caryclark@google.com3586ece2012-12-27 18:46:58 +00005524 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
5525 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
5526 current->debugID(), mid, newMid,
5527 baseT, current->xAtT(index), current->yAtT(index),
5528 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
5529 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
5530 endT, current->xAtT(endIndex), current->yAtT(endIndex));
5531#endif
5532 mid = newMid * 2; // calling loop with divide by 2 before continuing
5533 return SK_MinS32;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005534 }
5535 bestSeg = testSeg;
5536 bestHit = testHit;
5537 bestOpp = testOpp;
5538 bestTIndex = testTIndex;
5539 bestY = testY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005540 }
5541 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005542abortContours:
caryclark@google.com10227bf2012-12-28 22:10:41 +00005543 int result;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005544 if (!bestSeg) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00005545 result = hitSomething ? SK_MinS32 : 0;
5546 } else {
5547 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
5548 current = bestSeg;
5549 index = bestTIndex;
5550 endIndex = bestSeg->nextSpan(bestTIndex, 1);
5551 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
5552 tryAgain = true;
5553 return 0;
5554 }
5555 result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
5556 SkASSERT(bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005557 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005558 double baseT = current->t(index);
5559 double endT = current->t(endIndex);
5560 bestHit = baseT + mid * (endT - baseT);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005561 return result;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005562}
5563
caryclark@google.com24bec792012-08-20 12:43:57 +00005564static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
5565 int contourCount = contourList.count();
5566 Segment* result;
5567 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5568 Contour* contour = contourList[cIndex];
5569 result = contour->undoneSegment(start, end);
5570 if (result) {
5571 return result;
5572 }
5573 }
5574 return NULL;
5575}
5576
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005577#define OLD_FIND_CHASE 1
caryclark@google.com24bec792012-08-20 12:43:57 +00005578
caryclark@google.com31143cf2012-11-09 22:14:19 +00005579static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005580 while (chase.count()) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005581 Span* span;
5582 chase.pop(&span);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005583 const Span& backPtr = span->fOther->span(span->fOtherIndex);
5584 Segment* segment = backPtr.fOther;
5585 tIndex = backPtr.fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005586 SkTDArray<Angle> angles;
5587 int done = 0;
5588 if (segment->activeAngle(tIndex, done, angles)) {
5589 Angle* last = angles.end() - 1;
5590 tIndex = last->start();
5591 endIndex = last->end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005592 #if TRY_ROTATE
5593 *chase.insert(0) = span;
5594 #else
5595 *chase.append() = span;
5596 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005597 return last->segment();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005598 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005599 if (done == angles.count()) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00005600 continue;
5601 }
5602 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005603 bool sortable = Segment::SortAngles(angles, sorted);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005604 int angleCount = sorted.count();
caryclark@google.com03f97062012-08-21 13:13:52 +00005605#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005606 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00005607#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005608 if (!sortable) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005609 continue;
5610 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005611 // find first angle, initialize winding to computed fWindSum
5612 int firstIndex = -1;
5613 const Angle* angle;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005614#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005615 int winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005616 do {
5617 angle = sorted[++firstIndex];
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005618 segment = angle->segment();
5619 winding = segment->windSum(angle);
5620 } while (winding == SK_MinS32);
5621 int spanWinding = segment->spanSign(angle->start(), angle->end());
5622 #if DEBUG_WINDING
caryclark@google.com31143cf2012-11-09 22:14:19 +00005623 SkDebugf("%s winding=%d spanWinding=%d\n",
5624 __FUNCTION__, winding, spanWinding);
caryclark@google.com47580692012-07-23 12:14:49 +00005625 #endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005626 // turn span winding into contour winding
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005627 if (spanWinding * winding < 0) {
5628 winding += spanWinding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005629 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005630 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005631 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005632 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005633 // we care about first sign and whether wind sum indicates this
5634 // edge is inside or outside. Maybe need to pass span winding
5635 // or first winding or something into this function?
5636 // advance to first undone angle, then return it and winding
5637 // (to set whether edges are active or not)
5638 int nextIndex = firstIndex + 1;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005639 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005640 angle = sorted[firstIndex];
caryclark@google.com2ddff932012-08-07 21:25:27 +00005641 winding -= angle->segment()->spanSign(angle);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005642#else
5643 do {
5644 angle = sorted[++firstIndex];
5645 segment = angle->segment();
5646 } while (segment->windSum(angle) == SK_MinS32);
5647 #if DEBUG_SORT
5648 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5649 #endif
5650 int sumWinding = segment->updateWindingReverse(angle);
5651 int nextIndex = firstIndex + 1;
5652 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5653 Segment* first = NULL;
5654#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005655 do {
5656 SkASSERT(nextIndex != firstIndex);
5657 if (nextIndex == angleCount) {
5658 nextIndex = 0;
5659 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005660 angle = sorted[nextIndex];
caryclark@google.com9764cc62012-07-12 19:29:45 +00005661 segment = angle->segment();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005662#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005663 int maxWinding = winding;
caryclark@google.com2ddff932012-08-07 21:25:27 +00005664 winding -= segment->spanSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005665 #if DEBUG_SORT
caryclark@google.com2ddff932012-08-07 21:25:27 +00005666 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
5667 segment->debugID(), maxWinding, winding, angle->sign());
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005668 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005669 tIndex = angle->start();
5670 endIndex = angle->end();
5671 int lesser = SkMin32(tIndex, endIndex);
5672 const Span& nextSpan = segment->span(lesser);
5673 if (!nextSpan.fDone) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005674#if 1
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005675 // FIXME: this be wrong? assign startWinding if edge is in
caryclark@google.com9764cc62012-07-12 19:29:45 +00005676 // same direction. If the direction is opposite, winding to
5677 // assign is flipped sign or +/- 1?
caryclark@google.com59823f72012-08-09 18:17:47 +00005678 if (useInnerWinding(maxWinding, winding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005679 maxWinding = winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005680 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005681 segment->markAndChaseWinding(angle, maxWinding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005682#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005683 break;
5684 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005685#else
5686 int start = angle->start();
5687 int end = angle->end();
5688 int maxWinding;
5689 segment->setUpWinding(start, end, maxWinding, sumWinding);
5690 if (!segment->done(angle)) {
5691 if (!first) {
5692 first = segment;
5693 tIndex = start;
5694 endIndex = end;
5695 }
5696 (void) segment->markAngle(maxWinding, sumWinding, true, angle);
5697 }
5698#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005699 } while (++nextIndex != lastIndex);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005700 #if TRY_ROTATE
5701 *chase.insert(0) = span;
5702 #else
5703 *chase.append() = span;
5704 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005705 return segment;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005706 }
5707 return NULL;
5708}
5709
caryclark@google.com027de222012-07-12 12:52:50 +00005710#if DEBUG_ACTIVE_SPANS
5711static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005712 int index;
5713 for (index = 0; index < contourList.count(); ++ index) {
caryclark@google.com027de222012-07-12 12:52:50 +00005714 contourList[index]->debugShowActiveSpans();
5715 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005716 for (index = 0; index < contourList.count(); ++ index) {
5717 contourList[index]->validateActiveSpans();
5718 }
caryclark@google.com027de222012-07-12 12:52:50 +00005719}
5720#endif
5721
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005722static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005723 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005724 Segment* result;
5725 do {
caryclark@google.comf839c032012-10-26 21:03:50 +00005726 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005727 int contourCount = contourList.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00005728 Segment* topStart = NULL;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005729 done = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00005730 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5731 Contour* contour = contourList[cIndex];
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005732 if (contour->done()) {
5733 continue;
5734 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005735 const Bounds& bounds = contour->bounds();
5736 if (bounds.fBottom < topLeft.fY) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005737 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005738 continue;
5739 }
5740 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005741 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005742 continue;
5743 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005744 contour->topSortableSegment(topLeft, bestXY, topStart);
5745 if (!contour->done()) {
5746 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005747 }
5748 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005749 if (!topStart) {
5750 return NULL;
5751 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005752 topLeft = bestXY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005753 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005754 } while (!result);
5755 return result;
5756}
caryclark@google.com31143cf2012-11-09 22:14:19 +00005757
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005758static int rightAngleWinding(SkTDArray<Contour*>& contourList,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005759 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005760 bool opp) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005761 double test = 0.9;
5762 int contourWinding;
5763 do {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005764 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
5765 tryAgain, test, opp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005766 if (contourWinding != SK_MinS32 || tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005767 return contourWinding;
5768 }
5769 test /= 2;
5770 } while (!approximately_negative(test));
5771 SkASSERT(0); // should be OK to comment out, but interested when this hits
5772 return contourWinding;
5773}
5774
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005775static void skipVertical(SkTDArray<Contour*>& contourList,
5776 Segment*& current, int& index, int& endIndex) {
5777 if (!current->isVertical(index, endIndex)) {
5778 return;
5779 }
5780 int contourCount = contourList.count();
5781 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5782 Contour* contour = contourList[cIndex];
5783 if (contour->done()) {
5784 continue;
5785 }
5786 current = contour->nonVerticalSegment(index, endIndex);
5787 if (current) {
5788 return;
5789 }
5790 }
5791}
5792
caryclark@google.com3586ece2012-12-27 18:46:58 +00005793static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005794 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
5795 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
5796 true);
5797 if (!current) {
5798 return NULL;
5799 }
5800 if (firstContour) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005801 current->initWinding(index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005802 firstContour = false;
5803 return current;
5804 }
5805 int minIndex = SkMin32(index, endIndex);
5806 int sumWinding = current->windSum(minIndex);
5807 if (sumWinding != SK_MinS32) {
5808 return current;
5809 }
5810 sumWinding = current->computeSum(index, endIndex, binary);
5811 if (sumWinding != SK_MinS32) {
5812 return current;
5813 }
5814 int contourWinding;
5815 int oppContourWinding = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005816 // the simple upward projection of the unresolved points hit unsortable angles
5817 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005818 bool tryAgain;
5819 double tHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005820 SkScalar hitDx = 0;
5821 SkScalar hitOppDx = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005822 do {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005823 // if current is vertical, find another candidate which is not
5824 // if only remaining candidates are vertical, then they can be marked done
caryclark@google.com10227bf2012-12-28 22:10:41 +00005825 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005826 skipVertical(contourList, current, index, endIndex);
caryclark@google.com10227bf2012-12-28 22:10:41 +00005827 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005828 tryAgain = false;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005829 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005830 tryAgain, false);
5831 if (tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005832 continue;
5833 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005834 if (!binary) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005835 break;
5836 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005837 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005838 tryAgain, true);
5839 } while (tryAgain);
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00005840
caryclark@google.com3586ece2012-12-27 18:46:58 +00005841 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005842 return current;
5843}
5844
5845// rewrite that abandons keeping local track of winding
caryclark@google.com3586ece2012-12-27 18:46:58 +00005846static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005847 bool firstContour = true;
5848 bool unsortable = false;
5849 bool topUnsortable = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005850 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
5851 do {
5852 int index, endIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005853 bool topDone;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005854 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005855 topUnsortable, topDone, false);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005856 if (!current) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005857 if (topUnsortable || !topDone) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005858 topUnsortable = false;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005859 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005860 topLeft.fX = topLeft.fY = SK_ScalarMin;
5861 continue;
5862 }
5863 break;
5864 }
5865 SkTDArray<Span*> chaseArray;
5866 do {
5867 if (current->activeWinding(index, endIndex)) {
5868 do {
5869 #if DEBUG_ACTIVE_SPANS
5870 if (!unsortable && current->done()) {
5871 debugShowActiveSpans(contourList);
5872 }
5873 #endif
5874 SkASSERT(unsortable || !current->done());
5875 int nextStart = index;
5876 int nextEnd = endIndex;
5877 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
5878 unsortable);
5879 if (!next) {
5880 if (!unsortable && simple.hasMove()
5881 && current->verb() != SkPath::kLine_Verb
5882 && !simple.isClosed()) {
5883 current->addCurveTo(index, endIndex, simple, true);
5884 SkASSERT(simple.isClosed());
5885 }
5886 break;
5887 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005888 #if DEBUG_FLOW
5889 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
5890 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
5891 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
5892 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005893 current->addCurveTo(index, endIndex, simple, true);
5894 current = next;
5895 index = nextStart;
5896 endIndex = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005897 } while (!simple.isClosed() && (!unsortable
caryclark@google.com10227bf2012-12-28 22:10:41 +00005898 || !current->done(SkMin32(index, endIndex))));
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005899 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
5900 SkASSERT(unsortable);
5901 int min = SkMin32(index, endIndex);
5902 if (!current->done(min)) {
5903 current->addCurveTo(index, endIndex, simple, true);
5904 current->markDoneUnary(min);
5905 }
5906 }
5907 simple.close();
5908 } else {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005909 Span* last = current->markAndChaseDoneUnary(index, endIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005910 if (last) {
5911 *chaseArray.append() = last;
5912 }
5913 }
5914 current = findChase(chaseArray, index, endIndex);
5915 #if DEBUG_ACTIVE_SPANS
5916 debugShowActiveSpans(contourList);
5917 #endif
5918 if (!current) {
5919 break;
5920 }
5921 } while (true);
5922 } while (true);
5923 return simple.someAssemblyRequired();
5924}
5925
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005926// returns true if all edges were processed
caryclark@google.comf839c032012-10-26 21:03:50 +00005927static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.com24bec792012-08-20 12:43:57 +00005928 Segment* current;
5929 int start, end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005930 bool unsortable = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005931 bool closable = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00005932 while ((current = findUndone(contourList, start, end))) {
caryclark@google.com24bec792012-08-20 12:43:57 +00005933 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005934 #if DEBUG_ACTIVE_SPANS
5935 if (!unsortable && current->done()) {
5936 debugShowActiveSpans(contourList);
5937 }
5938 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005939 SkASSERT(unsortable || !current->done());
caryclark@google.com24bec792012-08-20 12:43:57 +00005940 int nextStart = start;
5941 int nextEnd = end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005942 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
caryclark@google.com24bec792012-08-20 12:43:57 +00005943 if (!next) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005944 if (!unsortable && simple.hasMove()
caryclark@google.comf839c032012-10-26 21:03:50 +00005945 && current->verb() != SkPath::kLine_Verb
5946 && !simple.isClosed()) {
5947 current->addCurveTo(start, end, simple, true);
5948 SkASSERT(simple.isClosed());
caryclark@google.comc899ad92012-08-23 15:24:42 +00005949 }
caryclark@google.com24bec792012-08-20 12:43:57 +00005950 break;
5951 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005952 #if DEBUG_FLOW
5953 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
5954 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
5955 current->xyAtT(end).fX, current->xyAtT(end).fY);
5956 #endif
caryclark@google.comf839c032012-10-26 21:03:50 +00005957 current->addCurveTo(start, end, simple, true);
caryclark@google.com24bec792012-08-20 12:43:57 +00005958 current = next;
5959 start = nextStart;
5960 end = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005961 } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005962 if (!simple.isClosed()) {
5963 SkASSERT(unsortable);
5964 int min = SkMin32(start, end);
5965 if (!current->done(min)) {
5966 current->addCurveTo(start, end, simple, true);
5967 current->markDone(min, 1);
5968 }
5969 closable = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00005970 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005971 simple.close();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005972 #if DEBUG_ACTIVE_SPANS
5973 debugShowActiveSpans(contourList);
5974 #endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00005975 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005976 return closable;
caryclark@google.com24bec792012-08-20 12:43:57 +00005977}
5978
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005979static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
5980 int contourCount = contourList.count();
5981 for (int cTest = 0; cTest < contourCount; ++cTest) {
5982 Contour* contour = contourList[cTest];
5983 contour->fixOtherTIndex();
5984 }
5985}
5986
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005987static void sortSegments(SkTDArray<Contour*>& contourList) {
5988 int contourCount = contourList.count();
5989 for (int cTest = 0; cTest < contourCount; ++cTest) {
5990 Contour* contour = contourList[cTest];
5991 contour->sortSegments();
5992 }
5993}
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005994
caryclark@google.com4eeda372012-12-06 21:47:48 +00005995static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
5996 bool evenOdd, bool oppEvenOdd) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005997 int count = contours.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005998 if (count == 0) {
5999 return;
6000 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006001 for (int index = 0; index < count; ++index) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00006002 Contour& contour = contours[index];
6003 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
6004 *list.append() = &contour;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006005 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006006 QSort<Contour>(list.begin(), list.end() - 1);
6007}
6008
caryclark@google.comf839c032012-10-26 21:03:50 +00006009static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006010 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006011}
6012
caryclark@google.com10227bf2012-12-28 22:10:41 +00006013static bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
6014 return distances[one] < distances[two];
6015}
caryclark@google.comf839c032012-10-26 21:03:50 +00006016 /*
6017 check start and end of each contour
6018 if not the same, record them
6019 match them up
6020 connect closest
6021 reassemble contour pieces into new path
6022 */
6023static void assemble(const PathWrapper& path, PathWrapper& simple) {
6024#if DEBUG_PATH_CONSTRUCTION
6025 SkDebugf("%s\n", __FUNCTION__);
6026#endif
6027 SkTArray<Contour> contours;
6028 EdgeBuilder builder(path, contours);
6029 builder.finish();
6030 int count = contours.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006031 int outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006032 SkTDArray<int> runs; // indices of partial contours
caryclark@google.com0b7da432012-10-31 19:00:20 +00006033 for (outer = 0; outer < count; ++outer) {
6034 const Contour& eContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006035 const SkPoint& eStart = eContour.start();
6036 const SkPoint& eEnd = eContour.end();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006037#if DEBUG_ASSEMBLE
6038 SkDebugf("%s contour", __FUNCTION__);
6039 if (!approximatelyEqual(eStart, eEnd)) {
6040 SkDebugf("[%d]", runs.count());
6041 } else {
6042 SkDebugf(" ");
6043 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006044 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006045 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
6046#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006047 if (approximatelyEqual(eStart, eEnd)) {
6048 eContour.toPath(simple);
6049 continue;
6050 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006051 *runs.append() = outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006052 }
6053 count = runs.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006054 if (count == 0) {
6055 return;
6056 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006057 SkTDArray<int> sLink, eLink;
6058 sLink.setCount(count);
6059 eLink.setCount(count);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006060 int rIndex, iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006061 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006062 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006063 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006064 SkTDArray<double> distances;
6065 const int ends = count * 2; // all starts and ends
6066 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
6067 distances.setCount(entries);
6068 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
6069 outer = runs[rIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006070 const Contour& oContour = contours[outer];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006071 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
6072 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
6073 * ends - rIndex - 1;
6074 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
6075 int inner = runs[iIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006076 const Contour& iContour = contours[inner];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006077 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
6078 double dx = iPt.fX - oPt.fX;
6079 double dy = iPt.fY - oPt.fY;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006080 double dist = dx * dx + dy * dy;
caryclark@google.com10227bf2012-12-28 22:10:41 +00006081 distances[row + iIndex] = dist; // oStart distance from iStart
6082 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006083 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006084 SkTDArray<int> sortedDist;
6085 sortedDist.setCount(entries);
6086 for (rIndex = 0; rIndex < entries; ++rIndex) {
6087 sortedDist[rIndex] = rIndex;
6088 }
6089 QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
6090 int remaining = count; // number of start/end pairs
6091 for (rIndex = 0; rIndex < entries; ++rIndex) {
6092 int pair = sortedDist[rIndex];
6093 int row = pair / ends;
6094 int col = pair - row * ends;
6095 int thingOne = row < col ? row : ends - row - 2;
6096 int ndxOne = thingOne >> 1;
6097 bool endOne = thingOne & 1;
6098 int* linkOne = endOne ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006099 if (linkOne[ndxOne] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006100 continue;
6101 }
6102 int thingTwo = row < col ? col : ends - row + col - 1;
6103 int ndxTwo = thingTwo >> 1;
6104 bool endTwo = thingTwo & 1;
6105 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006106 if (linkTwo[ndxTwo] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006107 continue;
6108 }
6109 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
6110 bool flip = endOne == endTwo;
6111 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
6112 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
6113 if (!--remaining) {
6114 break;
6115 }
6116 }
6117 SkASSERT(!remaining);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006118#if DEBUG_ASSEMBLE
6119 for (rIndex = 0; rIndex < count; ++rIndex) {
6120 int s = sLink[rIndex];
6121 int e = eLink[rIndex];
6122 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
6123 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
caryclark@google.comf839c032012-10-26 21:03:50 +00006124 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006125#endif
6126 rIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00006127 do {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006128 bool forward = true;
6129 bool first = true;
6130 int sIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006131 SkASSERT(sIndex != SK_MaxS32);
6132 sLink[rIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006133 int eIndex;
6134 if (sIndex < 0) {
6135 eIndex = sLink[~sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006136 sLink[~sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006137 } else {
6138 eIndex = eLink[sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006139 eLink[sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006140 }
caryclark@google.comaa358312013-01-29 20:28:49 +00006141 SkASSERT(eIndex != SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006142#if DEBUG_ASSEMBLE
6143 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006144 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
6145 eIndex < 0 ? ~eIndex : eIndex);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006146#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006147 do {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006148 outer = runs[rIndex];
6149 const Contour& contour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006150 if (first) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006151 first = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006152 const SkPoint* startPtr = &contour.start();
caryclark@google.comf839c032012-10-26 21:03:50 +00006153 simple.deferredMove(startPtr[0]);
6154 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006155 if (forward) {
6156 contour.toPartialForward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006157 } else {
6158 contour.toPartialBackward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006159 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006160#if DEBUG_ASSEMBLE
6161 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006162 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006163 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
6164#endif
6165 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006166 simple.close();
caryclark@google.comf839c032012-10-26 21:03:50 +00006167 break;
6168 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006169 if (forward) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006170 eIndex = eLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006171 SkASSERT(eIndex != SK_MaxS32);
6172 eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006173 if (eIndex >= 0) {
6174 SkASSERT(sLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006175 sLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006176 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006177 SkASSERT(eLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006178 eLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006179 }
6180 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006181 eIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006182 SkASSERT(eIndex != SK_MaxS32);
6183 sLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006184 if (eIndex >= 0) {
6185 SkASSERT(eLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006186 eLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006187 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006188 SkASSERT(sLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006189 sLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006190 }
6191 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006192 rIndex = eIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006193 if (rIndex < 0) {
6194 forward ^= 1;
6195 rIndex = ~rIndex;
6196 }
6197 } while (true);
6198 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006199 if (sLink[rIndex] != SK_MaxS32) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006200 break;
6201 }
6202 }
6203 } while (rIndex < count);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006204#if DEBUG_ASSEMBLE
6205 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006206 SkASSERT(sLink[rIndex] == SK_MaxS32);
6207 SkASSERT(eLink[rIndex] == SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006208 }
6209#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006210}
6211
6212void simplifyx(const SkPath& path, SkPath& result) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006213 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
caryclark@google.comf839c032012-10-26 21:03:50 +00006214 result.reset();
6215 result.setFillType(SkPath::kEvenOdd_FillType);
6216 PathWrapper simple(result);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006217
6218 // turn path into list of segments
6219 SkTArray<Contour> contours;
6220 // FIXME: add self-intersecting cubics' T values to segment
6221 EdgeBuilder builder(path, contours);
caryclark@google.com235f56a2012-09-14 14:19:30 +00006222 builder.finish();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006223 SkTDArray<Contour*> contourList;
caryclark@google.com4eeda372012-12-06 21:47:48 +00006224 makeContourList(contours, contourList, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006225 Contour** currentPtr = contourList.begin();
6226 if (!currentPtr) {
6227 return;
6228 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006229 Contour** listEnd = contourList.end();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006230 // find all intersections between segments
6231 do {
6232 Contour** nextPtr = currentPtr;
6233 Contour* current = *currentPtr++;
6234 Contour* next;
6235 do {
6236 next = *nextPtr++;
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00006237 } while (addIntersectTs(current, next) && nextPtr != listEnd);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006238 } while (currentPtr != listEnd);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006239 // eat through coincident edges
caryclark@google.com4eeda372012-12-06 21:47:48 +00006240 coincidenceCheck(contourList, 0);
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00006241 fixOtherTIndex(contourList);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006242 sortSegments(contourList);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006243#if DEBUG_ACTIVE_SPANS
6244 debugShowActiveSpans(contourList);
6245#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006246 // construct closed contours
caryclark@google.com3586ece2012-12-27 18:46:58 +00006247 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00006248 : !bridgeXor(contourList, simple))
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006249 { // if some edges could not be resolved, assemble remaining fragments
caryclark@google.comf839c032012-10-26 21:03:50 +00006250 SkPath temp;
6251 temp.setFillType(SkPath::kEvenOdd_FillType);
6252 PathWrapper assembled(temp);
6253 assemble(simple, assembled);
6254 result = *assembled.nativePath();
caryclark@google.com24bec792012-08-20 12:43:57 +00006255 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006256}