blob: 28766792f3616580056a4b2391558e832b42eb42 [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.coma461ff02012-10-11 12:54:23 +000030
caryclark@google.com47580692012-07-23 12:14:49 +000031#define DEBUG_UNUSED 0 // set to expose unused functions
caryclark@google.come7bd5f42012-12-13 19:47:53 +000032#define FORCE_RELEASE 0 // set force release to 1 for multiple thread -- no debugging
caryclark@google.comfa0588f2012-04-26 21:01:06 +000033
caryclark@google.com31143cf2012-11-09 22:14:19 +000034#if FORCE_RELEASE || defined SK_RELEASE
caryclark@google.com47580692012-07-23 12:14:49 +000035
36const bool gRunTestsInOneThread = false;
37
38#define DEBUG_ACTIVE_SPANS 0
caryclark@google.com4eeda372012-12-06 21:47:48 +000039#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000040#define DEBUG_ADD_INTERSECTING_TS 0
caryclark@google.com47580692012-07-23 12:14:49 +000041#define DEBUG_ADD_T_PAIR 0
caryclark@google.comc899ad92012-08-23 15:24:42 +000042#define DEBUG_ANGLE 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000043#define DEBUG_ASSEMBLE 0
caryclark@google.com47580692012-07-23 12:14:49 +000044#define DEBUG_CONCIDENT 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000045#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000046#define DEBUG_FLOW 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000047#define DEBUG_MARK_DONE 0
caryclark@google.comf839c032012-10-26 21:03:50 +000048#define DEBUG_PATH_CONSTRUCTION 0
caryclark@google.com729e1c42012-11-21 21:36:34 +000049#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000050#define DEBUG_SORT 0
caryclark@google.comafe56de2012-07-24 18:11:03 +000051#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000052#define DEBUG_WINDING 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000053
54#else
55
caryclark@google.com47580692012-07-23 12:14:49 +000056const bool gRunTestsInOneThread = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +000057
caryclark@google.comc91dfe42012-10-16 12:06:27 +000058#define DEBUG_ACTIVE_SPANS 1
caryclark@google.com4eeda372012-12-06 21:47:48 +000059#define DEBUG_ACTIVE_SPANS_SHORT_FORM 1
caryclark@google.com6aea33f2012-10-09 14:11:58 +000060#define DEBUG_ADD_INTERSECTING_TS 1
61#define DEBUG_ADD_T_PAIR 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000062#define DEBUG_ANGLE 1
caryclark@google.come7bd5f42012-12-13 19:47:53 +000063#define DEBUG_ASSEMBLE 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000064#define DEBUG_CONCIDENT 1
caryclark@google.com534aa5b2012-08-02 20:08:21 +000065#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000066#define DEBUG_FLOW 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000067#define DEBUG_MARK_DONE 1
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000068#define DEBUG_PATH_CONSTRUCTION 1
caryclark@google.com729e1c42012-11-21 21:36:34 +000069#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000070#define DEBUG_SORT 1
caryclark@google.comafe56de2012-07-24 18:11:03 +000071#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000072#define DEBUG_WINDING 1
caryclark@google.comfa0588f2012-04-26 21:01:06 +000073
74#endif
75
caryclark@google.com6aea33f2012-10-09 14:11:58 +000076#define DEBUG_DUMP (DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | DEBUG_PATH_CONSTRUCTION)
caryclark@google.com027de222012-07-12 12:52:50 +000077
caryclark@google.comfa0588f2012-04-26 21:01:06 +000078#if DEBUG_DUMP
79static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000080// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
caryclark@google.comfa0588f2012-04-26 21:01:06 +000081static int gContourID;
82static int gSegmentID;
83#endif
84
caryclark@google.com8dcf1142012-07-02 20:27:02 +000085#ifndef DEBUG_TEST
86#define DEBUG_TEST 0
87#endif
88
caryclark@google.com32546db2012-08-31 20:55:07 +000089#define MAKE_CONST_LINE(line, pts) \
90 const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}
91#define MAKE_CONST_QUAD(quad, pts) \
92 const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
93 {pts[2].fX, pts[2].fY}}
94#define MAKE_CONST_CUBIC(cubic, pts) \
95 const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
96 {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}}
97
caryclark@google.comfa0588f2012-04-26 21:01:06 +000098static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
99 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000100 MAKE_CONST_LINE(aLine, a);
101 MAKE_CONST_LINE(bLine, b);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000102 return intersect(aLine, bLine, intersections.fT[0], intersections.fT[1]);
103}
104
105static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
106 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000107 MAKE_CONST_QUAD(aQuad, a);
108 MAKE_CONST_LINE(bLine, b);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000109 return intersect(aQuad, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000110}
111
caryclark@google.com32546db2012-08-31 20:55:07 +0000112static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000113 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000114 MAKE_CONST_CUBIC(aCubic, a);
115 MAKE_CONST_LINE(bLine, b);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000116 return intersect(aCubic, bLine, intersections.fT[0], intersections.fT[1]);
117}
118
119static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
120 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000121 MAKE_CONST_QUAD(aQuad, a);
122 MAKE_CONST_QUAD(bQuad, b);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000123#define TRY_QUARTIC_SOLUTION 1
124#if TRY_QUARTIC_SOLUTION
125 intersect2(aQuad, bQuad, intersections);
126#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000127 intersect(aQuad, bQuad, intersections);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000128#endif
caryclark@google.com32546db2012-08-31 20:55:07 +0000129 return intersections.fUsed ? intersections.fUsed : intersections.fCoincidentUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000130}
131
132static int CubicIntersect(const SkPoint a[4], const SkPoint b[4],
133 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000134 MAKE_CONST_CUBIC(aCubic, a);
135 MAKE_CONST_CUBIC(bCubic, b);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000136 intersect(aCubic, bCubic, intersections);
137 return intersections.fUsed;
138}
139
140static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
141 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000142 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000143 return horizontalIntersect(aLine, left, right, y, flipped, intersections);
144}
145
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000146static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
147 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000148 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000149 return horizontalIntersect(aQuad, left, right, y, flipped, intersections);
150}
151
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000152static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
153 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000154 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000155 return horizontalIntersect(aCubic, left, right, y, flipped, intersections);
156}
157
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000158static int (* const HSegmentIntersect[])(const SkPoint [], SkScalar ,
159 SkScalar , SkScalar , bool , Intersections& ) = {
160 NULL,
161 HLineIntersect,
162 HQuadIntersect,
163 HCubicIntersect
164};
165
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000166static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom,
167 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000168 MAKE_CONST_LINE(aLine, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000169 return verticalIntersect(aLine, top, bottom, x, flipped, intersections);
170}
171
172static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom,
173 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000174 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000175 return verticalIntersect(aQuad, top, bottom, x, flipped, intersections);
176}
177
178static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom,
179 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000180 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000181 return verticalIntersect(aCubic, top, bottom, x, flipped, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000182}
183
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000184static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar ,
185 SkScalar , SkScalar , bool , Intersections& ) = {
186 NULL,
187 VLineIntersect,
188 VQuadIntersect,
189 VCubicIntersect
190};
191
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000192static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000193 MAKE_CONST_LINE(line, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000194 double x, y;
195 xy_at_t(line, t, x, y);
196 out->fX = SkDoubleToScalar(x);
197 out->fY = SkDoubleToScalar(y);
198}
199
200static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000201 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000202 double x, y;
203 xy_at_t(quad, t, x, y);
204 out->fX = SkDoubleToScalar(x);
205 out->fY = SkDoubleToScalar(y);
206}
207
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000208static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
209 MAKE_CONST_QUAD(quad, a);
210 xy_at_t(quad, t, out->x, out->y);
211}
212
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000213static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000214 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000215 double x, y;
216 xy_at_t(cubic, t, x, y);
217 out->fX = SkDoubleToScalar(x);
218 out->fY = SkDoubleToScalar(y);
219}
220
221static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
222 NULL,
223 LineXYAtT,
224 QuadXYAtT,
225 CubicXYAtT
226};
227
228static SkScalar LineXAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000229 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000230 double x;
231 xy_at_t(aLine, t, x, *(double*) 0);
232 return SkDoubleToScalar(x);
233}
234
235static SkScalar QuadXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000236 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000237 double x;
238 xy_at_t(quad, t, x, *(double*) 0);
239 return SkDoubleToScalar(x);
240}
241
242static SkScalar CubicXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000243 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000244 double x;
245 xy_at_t(cubic, t, x, *(double*) 0);
246 return SkDoubleToScalar(x);
247}
248
249static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
250 NULL,
251 LineXAtT,
252 QuadXAtT,
253 CubicXAtT
254};
255
256static SkScalar LineYAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000257 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000258 double y;
259 xy_at_t(aLine, t, *(double*) 0, y);
260 return SkDoubleToScalar(y);
261}
262
263static SkScalar QuadYAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000264 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000265 double y;
266 xy_at_t(quad, t, *(double*) 0, y);
267 return SkDoubleToScalar(y);
268}
269
270static SkScalar CubicYAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000271 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000272 double y;
273 xy_at_t(cubic, t, *(double*) 0, y);
274 return SkDoubleToScalar(y);
275}
276
277static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
278 NULL,
279 LineYAtT,
280 QuadYAtT,
281 CubicYAtT
282};
283
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000284static SkScalar LineDXAtT(const SkPoint a[2], double ) {
285 return a[1].fX - a[0].fX;
286}
287
288static SkScalar QuadDXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000289 MAKE_CONST_QUAD(quad, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000290 double x;
291 dxdy_at_t(quad, t, x, *(double*) 0);
292 return SkDoubleToScalar(x);
293}
294
295static SkScalar CubicDXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000296 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000297 double x;
298 dxdy_at_t(cubic, t, x, *(double*) 0);
299 return SkDoubleToScalar(x);
300}
301
302static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
303 NULL,
304 LineDXAtT,
305 QuadDXAtT,
306 CubicDXAtT
307};
308
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000309static SkScalar LineDYAtT(const SkPoint a[2], double ) {
310 return a[1].fY - a[0].fY;
311}
312
313static SkScalar QuadDYAtT(const SkPoint a[3], double t) {
314 MAKE_CONST_QUAD(quad, a);
315 double y;
316 dxdy_at_t(quad, t, *(double*) 0, y);
317 return SkDoubleToScalar(y);
318}
319
320static SkScalar CubicDYAtT(const SkPoint a[4], double t) {
321 MAKE_CONST_CUBIC(cubic, a);
322 double y;
323 dxdy_at_t(cubic, t, *(double*) 0, y);
324 return SkDoubleToScalar(y);
325}
326
327static SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = {
328 NULL,
329 LineDYAtT,
330 QuadDYAtT,
331 CubicDYAtT
332};
333
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000334static void LineSubDivide(const SkPoint a[2], double startT, double endT,
335 SkPoint sub[2]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000336 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000337 _Line dst;
338 sub_divide(aLine, startT, endT, dst);
339 sub[0].fX = SkDoubleToScalar(dst[0].x);
340 sub[0].fY = SkDoubleToScalar(dst[0].y);
341 sub[1].fX = SkDoubleToScalar(dst[1].x);
342 sub[1].fY = SkDoubleToScalar(dst[1].y);
343}
344
345static void QuadSubDivide(const SkPoint a[3], double startT, double endT,
346 SkPoint sub[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000347 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000348 Quadratic dst;
349 sub_divide(aQuad, startT, endT, dst);
350 sub[0].fX = SkDoubleToScalar(dst[0].x);
351 sub[0].fY = SkDoubleToScalar(dst[0].y);
352 sub[1].fX = SkDoubleToScalar(dst[1].x);
353 sub[1].fY = SkDoubleToScalar(dst[1].y);
354 sub[2].fX = SkDoubleToScalar(dst[2].x);
355 sub[2].fY = SkDoubleToScalar(dst[2].y);
356}
357
358static void CubicSubDivide(const SkPoint a[4], double startT, double endT,
359 SkPoint sub[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000360 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000361 Cubic dst;
362 sub_divide(aCubic, startT, endT, dst);
363 sub[0].fX = SkDoubleToScalar(dst[0].x);
364 sub[0].fY = SkDoubleToScalar(dst[0].y);
365 sub[1].fX = SkDoubleToScalar(dst[1].x);
366 sub[1].fY = SkDoubleToScalar(dst[1].y);
367 sub[2].fX = SkDoubleToScalar(dst[2].x);
368 sub[2].fY = SkDoubleToScalar(dst[2].y);
369 sub[3].fX = SkDoubleToScalar(dst[3].x);
370 sub[3].fY = SkDoubleToScalar(dst[3].y);
371}
372
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000373static void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
374 SkPoint []) = {
375 NULL,
376 LineSubDivide,
377 QuadSubDivide,
378 CubicSubDivide
379};
380
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000381static void LineSubDivideHD(const SkPoint a[2], double startT, double endT,
caryclark@google.com32546db2012-08-31 20:55:07 +0000382 _Line sub) {
383 MAKE_CONST_LINE(aLine, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000384 _Line dst;
385 sub_divide(aLine, startT, endT, dst);
386 sub[0] = dst[0];
387 sub[1] = dst[1];
388}
389
390static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT,
caryclark@google.com32546db2012-08-31 20:55:07 +0000391 Quadratic sub) {
392 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000393 Quadratic dst;
394 sub_divide(aQuad, startT, endT, dst);
395 sub[0] = dst[0];
396 sub[1] = dst[1];
397 sub[2] = dst[2];
398}
399
400static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT,
caryclark@google.com32546db2012-08-31 20:55:07 +0000401 Cubic sub) {
402 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000403 Cubic dst;
404 sub_divide(aCubic, startT, endT, dst);
405 sub[0] = dst[0];
406 sub[1] = dst[1];
407 sub[2] = dst[2];
408 sub[3] = dst[3];
409}
410
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000411#if DEBUG_UNUSED
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000412static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
413 SkRect& bounds) {
414 SkPoint dst[3];
415 QuadSubDivide(a, startT, endT, dst);
416 bounds.fLeft = bounds.fRight = dst[0].fX;
417 bounds.fTop = bounds.fBottom = dst[0].fY;
418 for (int index = 1; index < 3; ++index) {
419 bounds.growToInclude(dst[index].fX, dst[index].fY);
420 }
421}
422
423static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
424 SkRect& bounds) {
425 SkPoint dst[4];
426 CubicSubDivide(a, startT, endT, dst);
427 bounds.fLeft = bounds.fRight = dst[0].fX;
428 bounds.fTop = bounds.fBottom = dst[0].fY;
429 for (int index = 1; index < 4; ++index) {
430 bounds.growToInclude(dst[index].fX, dst[index].fY);
431 }
432}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000433#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000434
caryclark@google.com15fa1382012-05-07 20:49:36 +0000435static SkPath::Verb QuadReduceOrder(const SkPoint a[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000436 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000437 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000438 Quadratic dst;
439 int order = reduceOrder(aQuad, dst);
caryclark@google.com24bec792012-08-20 12:43:57 +0000440 if (order == 2) { // quad became line
441 for (int index = 0; index < order; ++index) {
442 SkPoint* pt = reducePts.append();
443 pt->fX = SkDoubleToScalar(dst[index].x);
444 pt->fY = SkDoubleToScalar(dst[index].y);
445 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000446 }
447 return (SkPath::Verb) (order - 1);
448}
449
450static SkPath::Verb CubicReduceOrder(const SkPoint a[4],
451 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000452 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000453 Cubic dst;
454 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed);
caryclark@google.com24bec792012-08-20 12:43:57 +0000455 if (order == 2 || order == 3) { // cubic became line or quad
456 for (int index = 0; index < order; ++index) {
457 SkPoint* pt = reducePts.append();
458 pt->fX = SkDoubleToScalar(dst[index].x);
459 pt->fY = SkDoubleToScalar(dst[index].y);
460 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000461 }
462 return (SkPath::Verb) (order - 1);
463}
464
caryclark@google.com15fa1382012-05-07 20:49:36 +0000465static bool QuadIsLinear(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000466 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000467 return isLinear(aQuad, 0, 2);
468}
469
470static bool CubicIsLinear(const SkPoint a[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000471 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000472 return isLinear(aCubic, 0, 3);
473}
474
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000475static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000476 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000477 double x[2];
478 xy_at_t(aLine, startT, x[0], *(double*) 0);
caryclark@google.com495f8e42012-05-31 13:13:11 +0000479 xy_at_t(aLine, endT, x[1], *(double*) 0);
480 return SkMinScalar((float) x[0], (float) x[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000481}
482
483static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000484 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000485 return (float) leftMostT(aQuad, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000486}
487
488static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000489 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000490 return (float) leftMostT(aCubic, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000491}
492
493static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
494 NULL,
495 LineLeftMost,
496 QuadLeftMost,
497 CubicLeftMost
498};
499
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000500#if 0 // currently unused
caryclark@google.com235f56a2012-09-14 14:19:30 +0000501static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
502 Intersections& intersections) {
503 MAKE_CONST_QUAD(aQuad, a);
504 MAKE_CONST_LINE(bLine, b);
505 return intersectRay(aQuad, bLine, intersections);
506}
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000507#endif
508
509static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine,
510 Intersections& intersections) {
511 MAKE_CONST_QUAD(aQuad, a);
512 return intersectRay(aQuad, bLine, intersections);
513}
caryclark@google.com235f56a2012-09-14 14:19:30 +0000514
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000515static bool LineVertical(const SkPoint a[2], double startT, double endT) {
516 MAKE_CONST_LINE(aLine, a);
517 double x[2];
518 xy_at_t(aLine, startT, x[0], *(double*) 0);
519 xy_at_t(aLine, endT, x[1], *(double*) 0);
520 return approximately_equal((float) x[0], (float) x[1]);
521}
522
523static bool QuadVertical(const SkPoint a[3], double startT, double endT) {
524 SkPoint dst[3];
525 QuadSubDivide(a, startT, endT, dst);
526 return approximately_equal(dst[0].fX, dst[1].fX) && approximately_equal(dst[1].fX, dst[2].fX);
527}
528
529static bool CubicVertical(const SkPoint a[4], double startT, double endT) {
530 SkPoint dst[4];
531 CubicSubDivide(a, startT, endT, dst);
532 return approximately_equal(dst[0].fX, dst[1].fX) && approximately_equal(dst[1].fX, dst[2].fX)
533 && approximately_equal(dst[2].fX, dst[3].fX);
534}
535
536static bool (* const SegmentVertical[])(const SkPoint [], double , double) = {
537 NULL,
538 LineVertical,
539 QuadVertical,
540 CubicVertical
541};
542
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000543class Segment;
544
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000545struct Span {
546 Segment* fOther;
547 mutable SkPoint fPt; // lazily computed as needed
548 double fT;
549 double fOtherT; // value at fOther[fOtherIndex].fT
550 int fOtherIndex; // can't be used during intersection
caryclark@google.com31143cf2012-11-09 22:14:19 +0000551 int fWindSum; // accumulated from contours surrounding this one.
552 int fOppSum; // for binary operators: the opposite winding sum
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000553 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
caryclark@google.com57cff8d2012-11-14 21:14:56 +0000554 int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000555 bool fDone; // if set, this span to next higher T has been processed
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000556 bool fUnsortableStart; // set when start is part of an unsortable pair
557 bool fUnsortableEnd; // set when end is part of an unsortable pair
caryclark@google.comf839c032012-10-26 21:03:50 +0000558 bool fTiny; // if set, span may still be considered once for edge following
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000559};
560
caryclark@google.com15fa1382012-05-07 20:49:36 +0000561// sorting angles
562// given angles of {dx dy ddx ddy dddx dddy} sort them
563class Angle {
564public:
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000565 // FIXME: this is bogus for quads and cubics
566 // if the quads and cubics' line from end pt to ctrl pt are coincident,
567 // there's no obvious way to determine the curve ordering from the
568 // derivatives alone. In particular, if one quadratic's coincident tangent
569 // is longer than the other curve, the final control point can place the
570 // longer curve on either side of the shorter one.
571 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
572 // may provide some help, but nothing has been figured out yet.
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000573
caryclark@google.com32546db2012-08-31 20:55:07 +0000574 /*(
575 for quads and cubics, set up a parameterized line (e.g. LineParameters )
576 for points [0] to [1]. See if point [2] is on that line, or on one side
577 or the other. If it both quads' end points are on the same side, choose
578 the shorter tangent. If the tangents are equal, choose the better second
579 tangent angle
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000580
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000581 maybe I could set up LineParameters lazily
caryclark@google.com32546db2012-08-31 20:55:07 +0000582 */
caryclark@google.com15fa1382012-05-07 20:49:36 +0000583 bool operator<(const Angle& rh) const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000584 double y = dy();
585 double ry = rh.dy();
586 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
587 return y < 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000588 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000589 double x = dx();
590 double rx = rh.dx();
591 if (y == 0 && ry == 0 && x * rx < 0) {
592 return x < rx;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000593 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000594 double x_ry = x * ry;
595 double rx_y = rx * y;
596 double cmp = x_ry - rx_y;
caryclark@google.comc899ad92012-08-23 15:24:42 +0000597 if (!approximately_zero(cmp)) {
caryclark@google.com15fa1382012-05-07 20:49:36 +0000598 return cmp < 0;
599 }
caryclark@google.comd1688742012-09-18 20:08:37 +0000600 if (approximately_zero(x_ry) && approximately_zero(rx_y)
601 && !approximately_zero_squared(cmp)) {
602 return cmp < 0;
603 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000604 // at this point, the initial tangent line is coincident
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.coma461ff02012-10-11 12:54:23 +0000621 // what if we extend in the other direction?
622 longer = *this;
623 rhLonger = rh;
624 if (longer.reverseLengthen() | rhLonger.reverseLengthen()) {
625 return longer < rhLonger;
626 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000627 }
caryclark@google.com185c7c42012-10-19 18:26:24 +0000628 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
caryclark@google.com31143cf2012-11-09 22:14:19 +0000629 || (rh.fVerb == SkPath::kLine_Verb
630 && approximately_zero(rx) && approximately_zero(ry))) {
caryclark@google.com185c7c42012-10-19 18:26:24 +0000631 // See general unsortable comment below. This case can happen when
632 // one line has a non-zero change in t but no change in x and y.
633 fUnsortable = true;
634 rh.fUnsortable = true;
635 return this < &rh; // even with no solution, return a stable sort
636 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000637 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
638 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
639 fUnsortable = true;
640 rh.fUnsortable = true;
641 return this < &rh; // even with no solution, return a stable sort
642 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000643 SkASSERT(fVerb == SkPath::kQuad_Verb); // worry about cubics later
644 SkASSERT(rh.fVerb == SkPath::kQuad_Verb);
skia.committer@gmail.comc1ad0222012-09-19 02:01:47 +0000645 // FIXME: until I can think of something better, project a ray from the
caryclark@google.comd1688742012-09-18 20:08:37 +0000646 // end of the shorter tangent to midway between the end points
647 // through both curves and use the resulting angle to sort
caryclark@google.com235f56a2012-09-14 14:19:30 +0000648 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
649 double len = fTangent1.normalSquared();
650 double rlen = rh.fTangent1.normalSquared();
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000651 _Line ray;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000652 Intersections i, ri;
caryclark@google.comd1688742012-09-18 20:08:37 +0000653 int roots, rroots;
654 bool flip = false;
655 do {
656 const Quadratic& q = (len < rlen) ^ flip ? fQ : rh.fQ;
657 double midX = (q[0].x + q[2].x) / 2;
658 double midY = (q[0].y + q[2].y) / 2;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000659 ray[0] = q[1];
660 ray[1].x = midX;
661 ray[1].y = midY;
caryclark@google.comd1688742012-09-18 20:08:37 +0000662 SkASSERT(ray[0] != ray[1]);
663 roots = QuadRayIntersect(fPts, ray, i);
664 rroots = QuadRayIntersect(rh.fPts, ray, ri);
665 } while ((roots == 0 || rroots == 0) && (flip ^= true));
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000666 if (roots == 0 || rroots == 0) {
667 // FIXME: we don't have a solution in this case. The interim solution
668 // is to mark the edges as unsortable, exclude them from this and
669 // future computations, and allow the returned path to be fragmented
670 fUnsortable = true;
671 rh.fUnsortable = true;
672 return this < &rh; // even with no solution, return a stable sort
673 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000674 _Point loc;
675 double best = SK_ScalarInfinity;
676 double dx, dy, dist;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000677 int index;
678 for (index = 0; index < roots; ++index) {
679 QuadXYAtT(fPts, i.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000680 dx = loc.x - ray[0].x;
681 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000682 dist = dx * dx + dy * dy;
683 if (best > dist) {
684 best = dist;
685 }
686 }
687 for (index = 0; index < rroots; ++index) {
688 QuadXYAtT(rh.fPts, ri.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000689 dx = loc.x - ray[0].x;
690 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000691 dist = dx * dx + dy * dy;
692 if (best > dist) {
693 return fSide < 0;
694 }
695 }
696 return fSide > 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000697 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000698
caryclark@google.com47580692012-07-23 12:14:49 +0000699 double dx() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000700 return fTangent1.dx();
caryclark@google.com47580692012-07-23 12:14:49 +0000701 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000702
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000703 double dy() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000704 return fTangent1.dy();
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000705 }
706
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000707 int end() const {
708 return fEnd;
709 }
710
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000711 bool isHorizontal() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000712 return dy() == 0 && fVerb == SkPath::kLine_Verb;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000713 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000714
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000715 bool lengthen() {
716 int newEnd = fEnd;
717 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
718 fEnd = newEnd;
719 setSpans();
720 return true;
721 }
722 return false;
723 }
724
caryclark@google.coma461ff02012-10-11 12:54:23 +0000725 bool reverseLengthen() {
726 if (fReversed) {
727 return false;
728 }
729 int newEnd = fStart;
730 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
731 fEnd = newEnd;
732 fReversed = true;
733 setSpans();
734 return true;
735 }
736 return false;
737 }
738
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000739 void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000740 int start, int end, const SkTDArray<Span>& spans) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000741 fSegment = segment;
742 fStart = start;
743 fEnd = end;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000744 fPts = orig;
745 fVerb = verb;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000746 fSpans = &spans;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000747 fReversed = false;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000748 fUnsortable = false;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000749 setSpans();
750 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000751
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000752 void setSpans() {
753 double startT = (*fSpans)[fStart].fT;
754 double endT = (*fSpans)[fEnd].fT;
755 switch (fVerb) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000756 case SkPath::kLine_Verb:
757 _Line l;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000758 LineSubDivideHD(fPts, startT, endT, l);
caryclark@google.com32546db2012-08-31 20:55:07 +0000759 // OPTIMIZATION: for pure line compares, we never need fTangent1.c
760 fTangent1.lineEndPoints(l);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000761 fSide = 0;
caryclark@google.com32546db2012-08-31 20:55:07 +0000762 break;
763 case SkPath::kQuad_Verb:
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000764 QuadSubDivideHD(fPts, startT, endT, fQ);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000765 fTangent1.quadEndPoints(fQ, 0, 1);
766 fSide = -fTangent1.pointDistance(fQ[2]); // not normalized -- compare sign only
caryclark@google.com32546db2012-08-31 20:55:07 +0000767 break;
768 case SkPath::kCubic_Verb:
769 Cubic c;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000770 CubicSubDivideHD(fPts, startT, endT, c);
caryclark@google.com32546db2012-08-31 20:55:07 +0000771 fTangent1.cubicEndPoints(c, 0, 1);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000772 fSide = -fTangent1.pointDistance(c[2]); // not normalized -- compare sign only
caryclark@google.com32546db2012-08-31 20:55:07 +0000773 break;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000774 default:
775 SkASSERT(0);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000776 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000777 fUnsortable = dx() == 0 && dy() == 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000778 if (fUnsortable) {
779 return;
780 }
781 SkASSERT(fStart != fEnd);
782 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
783 for (int index = fStart; index != fEnd; index += step) {
784 if ((*fSpans)[index].fUnsortableStart) {
785 fUnsortable = true;
786 return;
787 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000788#if 0
caryclark@google.comf839c032012-10-26 21:03:50 +0000789 if (index != fStart && (*fSpans)[index].fUnsortableEnd) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000790 SkASSERT(0);
caryclark@google.comf839c032012-10-26 21:03:50 +0000791 fUnsortable = true;
792 return;
793 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000794#endif
caryclark@google.comf839c032012-10-26 21:03:50 +0000795 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000796 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000797
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000798 Segment* segment() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000799 return const_cast<Segment*>(fSegment);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000800 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000801
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000802 int sign() const {
caryclark@google.com495f8e42012-05-31 13:13:11 +0000803 return SkSign32(fStart - fEnd);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000804 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000805
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000806 const SkTDArray<Span>* spans() const {
807 return fSpans;
808 }
809
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000810 int start() const {
811 return fStart;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000812 }
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +0000813
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000814 bool unsortable() const {
815 return fUnsortable;
816 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000817
caryclark@google.comc899ad92012-08-23 15:24:42 +0000818#if DEBUG_ANGLE
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000819 const SkPoint* pts() const {
820 return fPts;
821 }
822
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000823 SkPath::Verb verb() const {
824 return fVerb;
825 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000826
caryclark@google.comc899ad92012-08-23 15:24:42 +0000827 void debugShow(const SkPoint& a) const {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000828 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
caryclark@google.comc899ad92012-08-23 15:24:42 +0000829 }
830#endif
831
caryclark@google.com15fa1382012-05-07 20:49:36 +0000832private:
caryclark@google.com235f56a2012-09-14 14:19:30 +0000833 const SkPoint* fPts;
834 Quadratic fQ;
835 SkPath::Verb fVerb;
836 double fSide;
837 LineParameters fTangent1;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000838 const SkTDArray<Span>* fSpans;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000839 const Segment* fSegment;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000840 int fStart;
841 int fEnd;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000842 bool fReversed;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000843 mutable bool fUnsortable; // this alone is editable by the less than operator
caryclark@google.com15fa1382012-05-07 20:49:36 +0000844};
845
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000846// Bounds, unlike Rect, does not consider a line to be empty.
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000847struct Bounds : public SkRect {
848 static bool Intersects(const Bounds& a, const Bounds& b) {
849 return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
850 a.fTop <= b.fBottom && b.fTop <= a.fBottom;
851 }
852
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000853 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
854 if (left < fLeft) {
855 fLeft = left;
856 }
857 if (top < fTop) {
858 fTop = top;
859 }
860 if (right > fRight) {
861 fRight = right;
862 }
863 if (bottom > fBottom) {
864 fBottom = bottom;
865 }
866 }
867
868 void add(const Bounds& toAdd) {
869 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
870 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000871
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000872 void add(const SkPoint& pt) {
873 if (pt.fX < fLeft) fLeft = pt.fX;
874 if (pt.fY < fTop) fTop = pt.fY;
875 if (pt.fX > fRight) fRight = pt.fX;
876 if (pt.fY > fBottom) fBottom = pt.fY;
877 }
878
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000879 bool isEmpty() {
880 return fLeft > fRight || fTop > fBottom
caryclark@google.com235f56a2012-09-14 14:19:30 +0000881 || (fLeft == fRight && fTop == fBottom)
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000882 || isnan(fLeft) || isnan(fRight)
883 || isnan(fTop) || isnan(fBottom);
884 }
885
886 void setCubicBounds(const SkPoint a[4]) {
887 _Rect dRect;
caryclark@google.com32546db2012-08-31 20:55:07 +0000888 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000889 dRect.setBounds(cubic);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000890 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
891 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000892 }
893
894 void setQuadBounds(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000895 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000896 _Rect dRect;
897 dRect.setBounds(quad);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000898 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
899 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000900 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000901
902 void setPoint(const SkPoint& pt) {
903 fLeft = fRight = pt.fX;
904 fTop = fBottom = pt.fY;
905 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000906};
907
caryclark@google.com7ba591e2012-11-20 14:21:54 +0000908// OPTIMIZATION: does the following also work, and is it any faster?
909// return outerWinding * innerWinding > 0
910// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
caryclark@google.com2ddff932012-08-07 21:25:27 +0000911static bool useInnerWinding(int outerWinding, int innerWinding) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000912 // SkASSERT(outerWinding != innerWinding);
caryclark@google.com2ddff932012-08-07 21:25:27 +0000913 int absOut = abs(outerWinding);
914 int absIn = abs(innerWinding);
915 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
916 if (outerWinding * innerWinding < 0) {
917#if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +0000918 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
caryclark@google.com2ddff932012-08-07 21:25:27 +0000919 outerWinding, innerWinding, result ? "true" : "false");
920#endif
921 }
922 return result;
923}
924
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000925#define F (false) // discard the edge
926#define T (true) // keep the edge
927
caryclark@google.comd0deb4f2012-12-17 13:58:08 +0000928static const bool gUnaryActiveEdge[2][2] = {
929// from=0 from=1
930// to=0,1 to=0,1
931 {F, T}, {T, F},
932};
933
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000934static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
935// miFrom=0 miFrom=1
936// miTo=0 miTo=1 miTo=0 miTo=1
937// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
938// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
939 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
940 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
941 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
942 {{{{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 +0000943};
944
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000945#undef F
946#undef T
caryclark@google.com235f56a2012-09-14 14:19:30 +0000947
caryclark@google.comf839c032012-10-26 21:03:50 +0000948// wrap path to keep track of whether the contour is initialized and non-empty
949class PathWrapper {
950public:
951 PathWrapper(SkPath& path)
952 : fPathPtr(&path)
caryclark@google.comd0deb4f2012-12-17 13:58:08 +0000953 , fCloses(0)
954 , fMoves(0)
caryclark@google.comf839c032012-10-26 21:03:50 +0000955 {
956 init();
957 }
958
959 void close() {
960 if (!fHasMove) {
961 return;
962 }
963 bool callClose = isClosed();
964 lineTo();
965 if (fEmpty) {
966 return;
967 }
968 if (callClose) {
969 #if DEBUG_PATH_CONSTRUCTION
970 SkDebugf("path.close();\n");
971 #endif
972 fPathPtr->close();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +0000973 fCloses++;
caryclark@google.comf839c032012-10-26 21:03:50 +0000974 }
975 init();
976 }
977
978 void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
979 lineTo();
980 moveTo();
981#if DEBUG_PATH_CONSTRUCTION
982 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
983 pt1.fX, pt1.fY, pt2.fX, pt2.fY, pt3.fX, pt3.fY);
984#endif
985 fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, pt3.fX, pt3.fY);
986 fDefer[0] = fDefer[1] = pt3;
987 fEmpty = false;
988 }
989
990 void deferredLine(const SkPoint& pt) {
991 if (pt == fDefer[1]) {
992 return;
993 }
994 if (changedSlopes(pt)) {
995 lineTo();
996 fDefer[0] = fDefer[1];
997 }
998 fDefer[1] = pt;
999 }
1000
1001 void deferredMove(const SkPoint& pt) {
1002 fMoved = true;
1003 fHasMove = true;
1004 fEmpty = true;
1005 fDefer[0] = fDefer[1] = pt;
1006 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001007
caryclark@google.comf839c032012-10-26 21:03:50 +00001008 void deferredMoveLine(const SkPoint& pt) {
1009 if (!fHasMove) {
1010 deferredMove(pt);
1011 }
1012 deferredLine(pt);
1013 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001014
caryclark@google.comf839c032012-10-26 21:03:50 +00001015 bool hasMove() const {
1016 return fHasMove;
1017 }
1018
1019 void init() {
1020 fEmpty = true;
1021 fHasMove = false;
1022 fMoved = false;
1023 }
1024
1025 bool isClosed() const {
1026 return !fEmpty && fFirstPt == fDefer[1];
1027 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001028
caryclark@google.comf839c032012-10-26 21:03:50 +00001029 void lineTo() {
1030 if (fDefer[0] == fDefer[1]) {
1031 return;
1032 }
1033 moveTo();
1034 fEmpty = false;
1035#if DEBUG_PATH_CONSTRUCTION
1036 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
1037#endif
1038 fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
1039 fDefer[0] = fDefer[1];
1040 }
1041
1042 const SkPath* nativePath() const {
1043 return fPathPtr;
1044 }
1045
1046 void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
1047 lineTo();
1048 moveTo();
1049#if DEBUG_PATH_CONSTRUCTION
1050 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
1051 pt1.fX, pt1.fY, pt2.fX, pt2.fY);
1052#endif
1053 fPathPtr->quadTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY);
1054 fDefer[0] = fDefer[1] = pt2;
1055 fEmpty = false;
1056 }
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00001057
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001058 bool someAssemblyRequired() const {
1059 return fCloses < fMoves;
1060 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001061
1062protected:
1063 bool changedSlopes(const SkPoint& pt) const {
1064 if (fDefer[0] == fDefer[1]) {
1065 return false;
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001066 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001067 SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
1068 SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
1069 SkScalar lineDx = pt.fX - fDefer[1].fX;
1070 SkScalar lineDy = pt.fY - fDefer[1].fY;
1071 return deferDx * lineDy != deferDy * lineDx;
1072 }
1073
1074 void moveTo() {
1075 if (!fMoved) {
1076 return;
1077 }
1078 fFirstPt = fDefer[0];
1079#if DEBUG_PATH_CONSTRUCTION
1080 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
1081#endif
1082 fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
1083 fMoved = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001084 fMoves++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001085 }
1086
1087private:
1088 SkPath* fPathPtr;
1089 SkPoint fDefer[2];
1090 SkPoint fFirstPt;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001091 int fCloses;
1092 int fMoves;
caryclark@google.comf839c032012-10-26 21:03:50 +00001093 bool fEmpty;
1094 bool fHasMove;
1095 bool fMoved;
1096};
1097
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001098class Segment {
1099public:
1100 Segment() {
1101#if DEBUG_DUMP
1102 fID = ++gSegmentID;
1103#endif
1104 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00001105
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001106 bool operator<(const Segment& rh) const {
1107 return fBounds.fTop < rh.fBounds.fTop;
1108 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001109
caryclark@google.com4eeda372012-12-06 21:47:48 +00001110 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001111 if (activeAngleInner(index, done, angles)) {
1112 return true;
1113 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001114 int lesser = index;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001115 while (--lesser >= 0 && equalPoints(index, lesser)) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001116 if (activeAngleOther(lesser, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001117 return true;
1118 }
1119 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001120 lesser = index;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001121 do {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001122 if (activeAngleOther(index, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001123 return true;
1124 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001125 } while (++index < fTs.count() && equalPoints(index, lesser));
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001126 return false;
1127 }
1128
caryclark@google.com4eeda372012-12-06 21:47:48 +00001129 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001130 Span* span = &fTs[index];
1131 Segment* other = span->fOther;
1132 int oIndex = span->fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001133 return other->activeAngleInner(oIndex, done, angles);
1134 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001135
caryclark@google.com4eeda372012-12-06 21:47:48 +00001136 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001137 int next = nextExactSpan(index, 1);
caryclark@google.com9764cc62012-07-12 19:29:45 +00001138 if (next > 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001139 Span& upSpan = fTs[index];
1140 if (upSpan.fWindValue || upSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001141 addAngle(angles, index, next);
caryclark@google.comf839c032012-10-26 21:03:50 +00001142 if (upSpan.fDone || upSpan.fUnsortableEnd) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001143 done++;
1144 } else if (upSpan.fWindSum != SK_MinS32) {
1145 return true;
1146 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001147 } else if (!upSpan.fDone) {
1148 upSpan.fDone = true;
1149 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001150 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001151 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001152 int prev = nextExactSpan(index, -1);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001153 // edge leading into junction
caryclark@google.com9764cc62012-07-12 19:29:45 +00001154 if (prev >= 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001155 Span& downSpan = fTs[prev];
1156 if (downSpan.fWindValue || downSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001157 addAngle(angles, index, prev);
1158 if (downSpan.fDone) {
1159 done++;
1160 } else if (downSpan.fWindSum != SK_MinS32) {
1161 return true;
1162 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001163 } else if (!downSpan.fDone) {
1164 downSpan.fDone = true;
1165 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001166 }
1167 }
1168 return false;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001169 }
1170
caryclark@google.comf839c032012-10-26 21:03:50 +00001171 void activeLeftTop(SkPoint& result) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001172 SkASSERT(!done());
1173 int count = fTs.count();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001174 result.fX = result.fY = SK_ScalarMax;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001175 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00001176 bool lastUnsortable = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001177 for (int index = 0; index < count; ++index) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001178 const Span& span = fTs[index];
1179 if (span.fUnsortableStart | lastUnsortable) {
1180 goto next;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001181 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001182 if (!span.fDone | !lastDone) {
1183 const SkPoint& xy = xyAtT(index);
1184 if (result.fY < xy.fY) {
1185 goto next;
1186 }
1187 if (result.fY == xy.fY && result.fX < xy.fX) {
1188 goto next;
1189 }
1190 result = xy;
1191 }
1192 next:
1193 lastDone = span.fDone;
1194 lastUnsortable = span.fUnsortableEnd;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001195 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001196 }
1197
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001198 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
1199 int sumMiWinding = updateWinding(endIndex, index);
1200 int sumSuWinding = updateOppWinding(endIndex, index);
1201 if (fOperand) {
1202 SkTSwap<int>(sumMiWinding, sumSuWinding);
1203 }
1204 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1205 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001206 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001207 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001208
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001209 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00001210 int& sumMiWinding, int& sumSuWinding,
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001211 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
1212 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1213 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001214 bool miFrom;
1215 bool miTo;
1216 bool suFrom;
1217 bool suTo;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001218 if (operand()) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001219 miFrom = (oppMaxWinding & xorMiMask) != 0;
1220 miTo = (oppSumWinding & xorMiMask) != 0;
1221 suFrom = (maxWinding & xorSuMask) != 0;
1222 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001223 } else {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001224 miFrom = (maxWinding & xorMiMask) != 0;
1225 miTo = (sumWinding & xorMiMask) != 0;
1226 suFrom = (oppMaxWinding & xorSuMask) != 0;
1227 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001228 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001229 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
1230 SkASSERT(result != -1);
1231 return result;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001232 }
1233
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001234 bool activeWinding(int index, int endIndex) {
1235 int sumWinding = updateWinding(endIndex, index);
1236 int maxWinding;
1237 return activeWinding(index, endIndex, maxWinding, sumWinding);
1238 }
1239
1240 bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
1241 setUpWinding(index, endIndex, maxWinding, sumWinding);
1242 bool from = maxWinding != 0;
1243 bool to = sumWinding != 0;
1244 bool result = gUnaryActiveEdge[from][to];
1245 SkASSERT(result != -1);
1246 return result;
1247 }
1248
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001249 void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001250 SkASSERT(start != end);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001251 Angle* angle = angles.append();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001252#if DEBUG_ANGLE
caryclark@google.com31143cf2012-11-09 22:14:19 +00001253 if (angles.count() > 1 && !fTs[start].fTiny) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001254 SkPoint angle0Pt, newPt;
1255 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
1256 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
1257 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
1258 SkASSERT(approximately_equal(angle0Pt.fX, newPt.fX));
1259 SkASSERT(approximately_equal(angle0Pt.fY, newPt.fY));
1260 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001261#endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001262 angle->set(fPts, fVerb, this, start, end, fTs);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001263 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001264
caryclark@google.com2ddff932012-08-07 21:25:27 +00001265 void addCancelOutsides(double tStart, double oStart, Segment& other,
caryclark@google.comcc905052012-07-25 20:59:42 +00001266 double oEnd) {
1267 int tIndex = -1;
1268 int tCount = fTs.count();
1269 int oIndex = -1;
1270 int oCount = other.fTs.count();
caryclark@google.comcc905052012-07-25 20:59:42 +00001271 do {
1272 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001273 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001274 int tIndexStart = tIndex;
1275 do {
1276 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001277 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001278 int oIndexStart = oIndex;
1279 double nextT;
1280 do {
1281 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001282 } while (nextT < 1 && approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001283 double oNextT;
1284 do {
1285 oNextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001286 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001287 // at this point, spans before and after are at:
1288 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1289 // if tIndexStart == 0, no prior span
1290 // if nextT == 1, no following span
rmistry@google.comd6176b02012-08-23 18:14:13 +00001291
caryclark@google.comcc905052012-07-25 20:59:42 +00001292 // advance the span with zero winding
1293 // if the following span exists (not past the end, non-zero winding)
1294 // connect the two edges
1295 if (!fTs[tIndexStart].fWindValue) {
1296 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1297 #if DEBUG_CONCIDENT
1298 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1299 __FUNCTION__, fID, other.fID, tIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001300 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
1301 xyAtT(tIndexStart).fY);
caryclark@google.comcc905052012-07-25 20:59:42 +00001302 #endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001303 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001304 }
1305 if (nextT < 1 && fTs[tIndex].fWindValue) {
1306 #if DEBUG_CONCIDENT
1307 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1308 __FUNCTION__, fID, other.fID, tIndex,
1309 fTs[tIndex].fT, xyAtT(tIndex).fX,
1310 xyAtT(tIndex).fY);
1311 #endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001312 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001313 }
1314 } else {
1315 SkASSERT(!other.fTs[oIndexStart].fWindValue);
1316 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1317 #if DEBUG_CONCIDENT
1318 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1319 __FUNCTION__, fID, other.fID, oIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001320 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
1321 other.xyAtT(oIndexStart).fY);
1322 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
caryclark@google.comcc905052012-07-25 20:59:42 +00001323 #endif
caryclark@google.comcc905052012-07-25 20:59:42 +00001324 }
1325 if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1326 #if DEBUG_CONCIDENT
1327 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1328 __FUNCTION__, fID, other.fID, oIndex,
1329 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1330 other.xyAtT(oIndex).fY);
1331 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1332 #endif
1333 }
1334 }
1335 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001336
caryclark@google.comcc905052012-07-25 20:59:42 +00001337 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1338 double oEnd) {
1339 // walk this to outsideTs[0]
1340 // walk other to outsideTs[1]
1341 // if either is > 0, add a pointer to the other, copying adjacent winding
1342 int tIndex = -1;
1343 int oIndex = -1;
1344 double tStart = outsideTs[0];
1345 double oStart = outsideTs[1];
1346 do {
1347 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001348 } while (!approximately_negative(tStart - fTs[tIndex].fT));
caryclark@google.comcc905052012-07-25 20:59:42 +00001349 do {
1350 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001351 } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001352 if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001353 addTPair(tStart, other, oStart, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001354 }
1355 tStart = fTs[tIndex].fT;
1356 oStart = other.fTs[oIndex].fT;
1357 do {
1358 double nextT;
1359 do {
1360 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001361 } while (approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001362 tStart = nextT;
1363 do {
1364 nextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001365 } while (approximately_negative(nextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001366 oStart = nextT;
caryclark@google.com4eeda372012-12-06 21:47:48 +00001367 if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001368 break;
1369 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00001370 addTPair(tStart, other, oStart, false);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001371 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001372 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001373
caryclark@google.com4eeda372012-12-06 21:47:48 +00001374 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
1375 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001376 fBounds.setCubicBounds(pts);
1377 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001378
caryclark@google.comf839c032012-10-26 21:03:50 +00001379 /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001380 SkPoint edge[4];
caryclark@google.comf839c032012-10-26 21:03:50 +00001381 const SkPoint* ePtr;
1382 int lastT = fTs.count() - 1;
1383 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1384 ePtr = fPts;
1385 } else {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001386 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
caryclark@google.comf839c032012-10-26 21:03:50 +00001387 (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
1388 ePtr = edge;
1389 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001390 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001391 bool reverse = ePtr == fPts && start != 0;
1392 if (reverse) {
1393 path.deferredMoveLine(ePtr[fVerb]);
1394 switch (fVerb) {
1395 case SkPath::kLine_Verb:
1396 path.deferredLine(ePtr[0]);
1397 break;
1398 case SkPath::kQuad_Verb:
1399 path.quadTo(ePtr[1], ePtr[0]);
1400 break;
1401 case SkPath::kCubic_Verb:
1402 path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1403 break;
1404 default:
1405 SkASSERT(0);
1406 }
1407 // return ePtr[0];
1408 } else {
1409 path.deferredMoveLine(ePtr[0]);
1410 switch (fVerb) {
1411 case SkPath::kLine_Verb:
1412 path.deferredLine(ePtr[1]);
1413 break;
1414 case SkPath::kQuad_Verb:
1415 path.quadTo(ePtr[1], ePtr[2]);
1416 break;
1417 case SkPath::kCubic_Verb:
1418 path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1419 break;
1420 default:
1421 SkASSERT(0);
1422 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001423 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001424 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001425 // return ePtr[fVerb];
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001426 }
1427
caryclark@google.com4eeda372012-12-06 21:47:48 +00001428 void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
1429 init(pts, SkPath::kLine_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001430 fBounds.set(pts, 2);
1431 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001432
caryclark@google.comf839c032012-10-26 21:03:50 +00001433#if 0
1434 const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001435 const SkPoint& pt = xyAtT(tIndex);
1436 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001437 path.deferredMove(pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001438 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00001439 return pt;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001440 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001441#endif
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001442
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001443 // add 2 to edge or out of range values to get T extremes
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001444 void addOtherT(int index, double otherT, int otherIndex) {
1445 Span& span = fTs[index];
caryclark@google.comf839c032012-10-26 21:03:50 +00001446 #if PIN_ADD_T
caryclark@google.com185c7c42012-10-19 18:26:24 +00001447 if (precisely_less_than_zero(otherT)) {
1448 otherT = 0;
1449 } else if (precisely_greater_than_one(otherT)) {
1450 otherT = 1;
1451 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001452 #endif
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001453 span.fOtherT = otherT;
1454 span.fOtherIndex = otherIndex;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001455 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001456
caryclark@google.com4eeda372012-12-06 21:47:48 +00001457 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
1458 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001459 fBounds.setQuadBounds(pts);
1460 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001461
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001462 // Defer all coincident edge processing until
1463 // after normal intersections have been computed
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001464
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001465// no need to be tricky; insert in normal T order
1466// resolve overlapping ts when considering coincidence later
1467
1468 // add non-coincident intersection. Resulting edges are sorted in T.
1469 int addT(double newT, Segment* other) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001470 // FIXME: in the pathological case where there is a ton of intercepts,
1471 // binary search?
1472 int insertedAt = -1;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001473 size_t tCount = fTs.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00001474 #if PIN_ADD_T
caryclark@google.comc899ad92012-08-23 15:24:42 +00001475 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
caryclark@google.com185c7c42012-10-19 18:26:24 +00001476 if (precisely_less_than_zero(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001477 newT = 0;
caryclark@google.com185c7c42012-10-19 18:26:24 +00001478 } else if (precisely_greater_than_one(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001479 newT = 1;
1480 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001481 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001482 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001483 // OPTIMIZATION: if there are three or more identical Ts, then
1484 // the fourth and following could be further insertion-sorted so
1485 // that all the edges are clockwise or counterclockwise.
1486 // This could later limit segment tests to the two adjacent
1487 // neighbors, although it doesn't help with determining which
1488 // circular direction to go in.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001489 if (newT < fTs[index].fT) {
1490 insertedAt = index;
1491 break;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001492 }
1493 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001494 Span* span;
1495 if (insertedAt >= 0) {
1496 span = fTs.insert(insertedAt);
1497 } else {
1498 insertedAt = tCount;
1499 span = fTs.append();
1500 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001501 span->fT = newT;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001502 span->fOther = other;
caryclark@google.com27c449a2012-07-27 18:26:38 +00001503 span->fPt.fX = SK_ScalarNaN;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001504 span->fWindSum = SK_MinS32;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001505 span->fOppSum = SK_MinS32;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001506 span->fWindValue = 1;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001507 span->fOppValue = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00001508 span->fTiny = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001509 if ((span->fDone = newT == 1)) {
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00001510 ++fDoneSpans;
rmistry@google.comd6176b02012-08-23 18:14:13 +00001511 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001512 span->fUnsortableStart = false;
1513 span->fUnsortableEnd = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00001514 if (span - fTs.begin() > 0 && !span[-1].fDone
1515 && !precisely_negative(newT - span[-1].fT)
1516 // && approximately_negative(newT - span[-1].fT)
1517 && xyAtT(&span[-1]) == xyAtT(span)) {
1518 span[-1].fTiny = true;
1519 span[-1].fDone = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001520 if (approximately_negative(newT - span[-1].fT)) {
1521 if (approximately_greater_than_one(newT)) {
1522 span[-1].fUnsortableStart = true;
1523 span[-2].fUnsortableEnd = true;
1524 }
1525 if (approximately_less_than_zero(span[-1].fT)) {
1526 span->fUnsortableStart = true;
1527 span[-1].fUnsortableEnd = true;
1528 }
1529 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001530 ++fDoneSpans;
1531 }
1532 if (fTs.end() - span > 1 && !span->fDone
1533 && !precisely_negative(span[1].fT - newT)
1534 // && approximately_negative(span[1].fT - newT)
1535 && xyAtT(&span[1]) == xyAtT(span)) {
1536 span->fTiny = true;
1537 span->fDone = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001538 if (approximately_negative(span[1].fT - newT)) {
1539 if (approximately_greater_than_one(span[1].fT)) {
1540 span->fUnsortableStart = true;
1541 span[-1].fUnsortableEnd = true;
1542 }
1543 if (approximately_less_than_zero(newT)) {
1544 span[1].fUnsortableStart = true;
1545 span->fUnsortableEnd = true;
1546 }
1547 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001548 ++fDoneSpans;
1549 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001550 return insertedAt;
1551 }
1552
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001553 // set spans from start to end to decrement by one
1554 // note this walks other backwards
1555 // FIMXE: there's probably an edge case that can be constructed where
1556 // two span in one segment are separated by float epsilon on one span but
1557 // not the other, if one segment is very small. For this
1558 // case the counts asserted below may or may not be enough to separate the
caryclark@google.com2ddff932012-08-07 21:25:27 +00001559 // spans. Even if the counts work out, what if the spans aren't correctly
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001560 // sorted? It feels better in such a case to match the span's other span
1561 // pointer since both coincident segments must contain the same spans.
1562 void addTCancel(double startT, double endT, Segment& other,
1563 double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001564 SkASSERT(!approximately_negative(endT - startT));
1565 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00001566 bool binary = fOperand != other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001567 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001568 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001569 ++index;
1570 }
caryclark@google.comb9738012012-07-03 19:53:30 +00001571 int oIndex = other.fTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001572 while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001573 ;
caryclark@google.com59823f72012-08-09 18:17:47 +00001574 double tRatio = (oEndT - oStartT) / (endT - startT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001575 Span* test = &fTs[index];
1576 Span* oTest = &other.fTs[oIndex];
caryclark@google.com18063442012-07-25 12:05:18 +00001577 SkTDArray<double> outsideTs;
1578 SkTDArray<double> oOutsideTs;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001579 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001580 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
caryclark@google.comcc905052012-07-25 20:59:42 +00001581 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.com200c2112012-08-03 15:05:04 +00001582 double testT = test->fT;
1583 double oTestT = oTest->fT;
1584 Span* span = test;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001585 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001586 if (decrement) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001587 decrementSpan(span);
caryclark@google.com200c2112012-08-03 15:05:04 +00001588 } else if (track && span->fT < 1 && oTestT < 1) {
1589 TrackOutside(outsideTs, span->fT, oTestT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001590 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001591 span = &fTs[++index];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001592 } while (approximately_negative(span->fT - testT));
caryclark@google.com200c2112012-08-03 15:05:04 +00001593 Span* oSpan = oTest;
caryclark@google.com59823f72012-08-09 18:17:47 +00001594 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1595 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1596 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001597 while (approximately_negative(otherTMatchStart - oSpan->fT)
1598 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
caryclark@google.com03f97062012-08-21 13:13:52 +00001599 #ifdef SK_DEBUG
caryclark@google.com59823f72012-08-09 18:17:47 +00001600 SkASSERT(originalWindValue == oSpan->fWindValue);
caryclark@google.com03f97062012-08-21 13:13:52 +00001601 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001602 if (decrement) {
caryclark@google.com200c2112012-08-03 15:05:04 +00001603 other.decrementSpan(oSpan);
1604 } else if (track && oSpan->fT < 1 && testT < 1) {
1605 TrackOutside(oOutsideTs, oSpan->fT, testT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001606 }
1607 if (!oIndex) {
1608 break;
1609 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001610 oSpan = &other.fTs[--oIndex];
rmistry@google.comd6176b02012-08-23 18:14:13 +00001611 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001612 test = span;
1613 oTest = oSpan;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001614 } while (!approximately_negative(endT - test->fT));
1615 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
caryclark@google.com18063442012-07-25 12:05:18 +00001616 // FIXME: determine if canceled edges need outside ts added
caryclark@google.comcc905052012-07-25 20:59:42 +00001617 if (!done() && outsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001618 double tStart = outsideTs[0];
1619 double oStart = outsideTs[1];
1620 addCancelOutsides(tStart, oStart, other, oEndT);
1621 int count = outsideTs.count();
1622 if (count > 2) {
1623 double tStart = outsideTs[count - 2];
1624 double oStart = outsideTs[count - 1];
1625 addCancelOutsides(tStart, oStart, other, oEndT);
1626 }
caryclark@google.com18063442012-07-25 12:05:18 +00001627 }
caryclark@google.comcc905052012-07-25 20:59:42 +00001628 if (!other.done() && oOutsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001629 double tStart = oOutsideTs[0];
1630 double oStart = oOutsideTs[1];
1631 other.addCancelOutsides(tStart, oStart, *this, endT);
caryclark@google.com18063442012-07-25 12:05:18 +00001632 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001633 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00001634
caryclark@google.com4eeda372012-12-06 21:47:48 +00001635 int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1636 SkTDArray<double>& outsideTs) {
1637 int oWindValue = oTest->fWindValue;
1638 int oOppValue = oTest->fOppValue;
1639 if (opp) {
1640 SkTSwap<int>(oWindValue, oOppValue);
1641 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001642 Span* const test = &fTs[index];
1643 Span* end = test;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001644 const double oStartT = oTest->fT;
1645 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001646 if (bumpSpan(end, oWindValue, oOppValue)) {
1647 TrackOutside(outsideTs, end->fT, oStartT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001648 }
1649 end = &fTs[++index];
1650 } while (approximately_negative(end->fT - test->fT));
1651 return index;
1652 }
1653
1654 // because of the order in which coincidences are resolved, this and other
1655 // may not have the same intermediate points. Compute the corresponding
1656 // intermediate T values (using this as the master, other as the follower)
1657 // and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com4eeda372012-12-06 21:47:48 +00001658 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1659 SkTDArray<double>& oOutsideTs) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001660 Span* const oTest = &fTs[oIndex];
1661 Span* oEnd = oTest;
1662 const double startT = test->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001663 const double oStartT = oTest->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001664 while (!approximately_negative(oEndT - oEnd->fT)
caryclark@google.com4eeda372012-12-06 21:47:48 +00001665 && approximately_negative(oEnd->fT - oStartT)) {
1666 zeroSpan(oEnd);
1667 TrackOutside(oOutsideTs, oEnd->fT, startT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001668 oEnd = &fTs[++oIndex];
1669 }
1670 return oIndex;
1671 }
1672
1673 // FIXME: need to test this case:
1674 // contourA has two segments that are coincident
1675 // contourB has two segments that are coincident in the same place
1676 // each ends up with +2/0 pairs for winding count
1677 // since logic below doesn't transfer count (only increments/decrements) can this be
1678 // resolved to +4/0 ?
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001679
1680 // set spans from start to end to increment the greater by one and decrement
1681 // the lesser
caryclark@google.com4eeda372012-12-06 21:47:48 +00001682 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001683 SkASSERT(!approximately_negative(endT - startT));
1684 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001685 bool opp = fOperand ^ other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001686 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001687 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001688 ++index;
1689 }
1690 int oIndex = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001691 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001692 ++oIndex;
1693 }
1694 Span* test = &fTs[index];
1695 Span* oTest = &other.fTs[oIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001696 SkTDArray<double> outsideTs;
1697 SkTDArray<double> oOutsideTs;
1698 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001699 // if either span has an opposite value and the operands don't match, resolve first
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001700 // SkASSERT(!test->fDone || !oTest->fDone);
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001701 if (test->fDone || oTest->fDone) {
1702 index = advanceCoincidentThis(oTest, opp, index);
1703 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
1704 } else {
1705 index = bumpCoincidentThis(oTest, opp, index, outsideTs);
1706 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
1707 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001708 test = &fTs[index];
1709 oTest = &other.fTs[oIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001710 } while (!approximately_negative(endT - test->fT));
1711 SkASSERT(approximately_negative(oTest->fT - oEndT));
1712 SkASSERT(approximately_negative(oEndT - oTest->fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001713 if (!done() && outsideTs.count()) {
1714 addCoinOutsides(outsideTs, other, oEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001715 }
1716 if (!other.done() && oOutsideTs.count()) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001717 other.addCoinOutsides(oOutsideTs, *this, endT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001718 }
1719 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001720
caryclark@google.comcc905052012-07-25 20:59:42 +00001721 // FIXME: this doesn't prevent the same span from being added twice
1722 // fix in caller, assert here?
caryclark@google.com2ddff932012-08-07 21:25:27 +00001723 void addTPair(double t, Segment& other, double otherT, bool borrowWind) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001724 int tCount = fTs.count();
1725 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1726 const Span& span = fTs[tIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001727 if (!approximately_negative(span.fT - t)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001728 break;
1729 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001730 if (approximately_negative(span.fT - t) && span.fOther == &other
1731 && approximately_equal(span.fOtherT, otherT)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001732#if DEBUG_ADD_T_PAIR
1733 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1734 __FUNCTION__, fID, t, other.fID, otherT);
1735#endif
1736 return;
1737 }
1738 }
caryclark@google.com47580692012-07-23 12:14:49 +00001739#if DEBUG_ADD_T_PAIR
1740 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1741 __FUNCTION__, fID, t, other.fID, otherT);
1742#endif
caryclark@google.comb9738012012-07-03 19:53:30 +00001743 int insertedAt = addT(t, &other);
1744 int otherInsertedAt = other.addT(otherT, this);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001745 addOtherT(insertedAt, otherT, otherInsertedAt);
caryclark@google.comb9738012012-07-03 19:53:30 +00001746 other.addOtherT(otherInsertedAt, t, insertedAt);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001747 matchWindingValue(insertedAt, t, borrowWind);
1748 other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001749 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001750
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001751 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001752 // add edge leading into junction
caryclark@google.com4eeda372012-12-06 21:47:48 +00001753 int min = SkMin32(end, start);
1754 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001755 addAngle(angles, end, start);
1756 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001757 // add edge leading away from junction
caryclark@google.com495f8e42012-05-31 13:13:11 +00001758 int step = SkSign32(end - start);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001759 int tIndex = nextExactSpan(end, step);
caryclark@google.com4eeda372012-12-06 21:47:48 +00001760 min = SkMin32(end, tIndex);
1761 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001762 addAngle(angles, end, tIndex);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001763 }
1764 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001765
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001766 int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
1767 Span* const test = &fTs[index];
1768 Span* end = test;
1769 do {
1770 end = &fTs[++index];
1771 } while (approximately_negative(end->fT - test->fT));
1772 return index;
1773 }
1774
1775 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
1776 Span* const oTest = &fTs[oIndex];
1777 Span* oEnd = oTest;
1778 const double oStartT = oTest->fT;
1779 while (!approximately_negative(oEndT - oEnd->fT)
1780 && approximately_negative(oEnd->fT - oStartT)) {
1781 oEnd = &fTs[++oIndex];
1782 }
1783 return oIndex;
1784 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00001785
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001786 bool betweenTs(int lesser, double testT, int greater) {
1787 if (lesser > greater) {
1788 SkTSwap<int>(lesser, greater);
1789 }
1790 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
1791 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001792
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001793 const Bounds& bounds() const {
1794 return fBounds;
1795 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001796
caryclark@google.com31143cf2012-11-09 22:14:19 +00001797 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001798 double referenceT = fTs[index].fT;
1799 int lesser = index;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001800 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
1801 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00001802 buildAnglesInner(lesser, angles);
1803 }
1804 do {
1805 buildAnglesInner(index, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001806 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
1807 && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001808 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001809
1810 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
1811 Span* span = &fTs[index];
1812 Segment* other = span->fOther;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001813 // if there is only one live crossing, and no coincidence, continue
1814 // in the same direction
1815 // if there is coincidence, the only choice may be to reverse direction
1816 // find edge on either side of intersection
1817 int oIndex = span->fOtherIndex;
1818 // if done == -1, prior span has already been processed
1819 int step = 1;
caryclark@google.coma461ff02012-10-11 12:54:23 +00001820 int next = other->nextExactSpan(oIndex, step);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001821 if (next < 0) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001822 step = -step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00001823 next = other->nextExactSpan(oIndex, step);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001824 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001825 // add candidate into and away from junction
1826 other->addTwoAngles(next, oIndex, angles);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001827 }
1828
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001829 int computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001830 SkTDArray<Angle> angles;
1831 addTwoAngles(startIndex, endIndex, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001832 buildAngles(endIndex, angles, false);
caryclark@google.comd1688742012-09-18 20:08:37 +00001833 // OPTIMIZATION: check all angles to see if any have computed wind sum
1834 // before sorting (early exit if none)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001835 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001836 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00001837#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00001838 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00001839#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001840 if (!sortable) {
1841 return SK_MinS32;
1842 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001843 int angleCount = angles.count();
1844 const Angle* angle;
1845 const Segment* base;
1846 int winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001847 int oWinding;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001848 int firstIndex = 0;
1849 do {
1850 angle = sorted[firstIndex];
1851 base = angle->segment();
1852 winding = base->windSum(angle);
1853 if (winding != SK_MinS32) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001854 oWinding = base->oppSum(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001855 break;
1856 }
1857 if (++firstIndex == angleCount) {
1858 return SK_MinS32;
1859 }
1860 } while (true);
1861 // turn winding into contourWinding
caryclark@google.com2ddff932012-08-07 21:25:27 +00001862 int spanWinding = base->spanSign(angle);
1863 bool inner = useInnerWinding(winding + spanWinding, winding);
1864 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00001865 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
caryclark@google.com59823f72012-08-09 18:17:47 +00001866 spanWinding, winding, angle->sign(), inner,
caryclark@google.com2ddff932012-08-07 21:25:27 +00001867 inner ? winding + spanWinding : winding);
1868 #endif
1869 if (inner) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001870 winding += spanWinding;
1871 }
1872 #if DEBUG_SORT
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001873 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001874 #endif
1875 int nextIndex = firstIndex + 1;
1876 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com2ddff932012-08-07 21:25:27 +00001877 winding -= base->spanSign(angle);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001878 oWinding -= base->oppSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001879 do {
1880 if (nextIndex == angleCount) {
1881 nextIndex = 0;
1882 }
1883 angle = sorted[nextIndex];
1884 Segment* segment = angle->segment();
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001885 bool opp = base->fOperand ^ segment->fOperand;
1886 int maxWinding, oMaxWinding;
1887 int spanSign = segment->spanSign(angle);
1888 int oppoSign = segment->oppSign(angle);
1889 if (opp) {
1890 oMaxWinding = oWinding;
1891 oWinding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00001892 maxWinding = winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001893 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001894 winding -= oppoSign;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001895 }
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001896 } else {
1897 maxWinding = winding;
1898 winding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00001899 oMaxWinding = oWinding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001900 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001901 oWinding -= oppoSign;
1902 }
1903 }
1904 if (segment->windSum(angle) == SK_MinS32) {
1905 if (opp) {
1906 if (useInnerWinding(oMaxWinding, oWinding)) {
1907 oMaxWinding = oWinding;
1908 }
1909 if (oppoSign && useInnerWinding(maxWinding, winding)) {
1910 maxWinding = winding;
1911 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001912 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001913 } else {
1914 if (useInnerWinding(maxWinding, winding)) {
1915 maxWinding = winding;
1916 }
1917 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
1918 oMaxWinding = oWinding;
1919 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001920 (void) segment->markAndChaseWinding(angle, maxWinding,
1921 binary ? oMaxWinding : 0);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001922 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001923 }
1924 } while (++nextIndex != lastIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00001925 int minIndex = SkMin32(startIndex, endIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00001926 return windSum(minIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001927 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001928
caryclark@google.com3586ece2012-12-27 18:46:58 +00001929 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001930 bool opp) const {
1931 SkScalar bottom = fBounds.fBottom;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001932 int bestT = -1;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001933 if (bottom <= bestY) {
1934 return bestT;
1935 }
1936 SkScalar top = fBounds.fTop;
1937 if (top >= basePt.fY) {
1938 return bestT;
1939 }
1940 if (fBounds.fLeft > basePt.fX) {
1941 return bestT;
1942 }
1943 if (fBounds.fRight < basePt.fX) {
1944 return bestT;
1945 }
1946 if (fBounds.fLeft == fBounds.fRight) {
1947 return bestT;
1948 }
caryclark@google.com210acaf2012-07-12 21:05:13 +00001949 int end = 0;
caryclark@google.com3586ece2012-12-27 18:46:58 +00001950 int xbestT = -1;
1951 double xhitT;
1952 bool xhitSomething = false;
1953 SkScalar xbestY = bestY;
1954 bool expectNoDx = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001955 do {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001956 int start = end;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001957 end = nextSpan(start, 1);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001958 if ((opp ? fTs[start].fOppValue : fTs[start].fWindValue) == 0) {
caryclark@google.com47580692012-07-23 12:14:49 +00001959 continue;
1960 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001961 SkPoint edge[4];
caryclark@google.com24bec792012-08-20 12:43:57 +00001962 double startT = fTs[start].fT;
1963 double endT = fTs[end].fT;
1964 (*SegmentSubDivide[fVerb])(fPts, startT, endT, edge);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001965 // intersect ray starting at basePt with edge
caryclark@google.com3586ece2012-12-27 18:46:58 +00001966 Intersections intersections, intersectionsX;
caryclark@google.comd1688742012-09-18 20:08:37 +00001967 // FIXME: always use original and limit results to T values within
1968 // start t and end t.
1969 // OPTIMIZE: use specialty function that intersects ray with curve,
1970 // returning t values only for curve (we don't care about t on ray)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001971 int pts = (*VSegmentIntersect[fVerb])(edge, top, bottom, basePt.fX,
1972 false, intersections);
caryclark@google.com3586ece2012-12-27 18:46:58 +00001973 int ptsX = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX,
1974 false, intersectionsX);
1975 int index;
1976 for (index = 0; index < ptsX; ++index) {
1977 double xfoundT = intersectionsX.fT[0][index];
1978 SkScalar xtestY = (*SegmentYAtT[fVerb])(fPts, xfoundT);
1979 if (approximately_negative(xtestY - bestY)
1980 || approximately_negative(basePt.fY - xtestY)) {
1981 continue;
1982 }
1983 xhitSomething = true;
1984 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
1985 // if the intersection is edge on, wait for another one
1986 expectNoDx = true;
1987 break;
1988 }
1989 if (fVerb > SkPath::kLine_Verb
1990 && !approximately_negative(xfoundT - startT)
1991 && !approximately_negative(endT - xfoundT)) {
1992 SkScalar xdx = (*SegmentDXAtT[fVerb])(fPts, xfoundT);
1993 if (approximately_zero(xdx)) {
1994 continue;
1995 }
1996 }
1997 xbestY = xtestY;
1998 while (start + 1 < end && fTs[start].fDone) {
1999 ++start;
2000 }
2001 xbestT = xfoundT < 1 ? start : end;
2002 xhitT = xfoundT;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002003 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00002004 for (index = 0; index < pts; ++index) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002005 double foundT = intersections.fT[0][index];
caryclark@google.com3586ece2012-12-27 18:46:58 +00002006 SkScalar testY = (*SegmentYAtT[fVerb])(edge, foundT);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002007 if (bestY < testY && testY < basePt.fY) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00002008 hitSomething = true;
2009 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
2010 // if the intersection is edge on, wait for another one
2011 SkASSERT(expectNoDx);
2012 return -1;
2013 }
caryclark@google.comd1688742012-09-18 20:08:37 +00002014 if (fVerb > SkPath::kLine_Verb
2015 && !approximately_less_than_zero(foundT)
2016 && !approximately_greater_than_one(foundT)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00002017 SkScalar dx = (*SegmentDXAtT[fVerb])(edge, foundT);
caryclark@google.comd1688742012-09-18 20:08:37 +00002018 if (approximately_zero(dx)) {
2019 continue;
2020 }
2021 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002022 bestY = testY;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002023 while (start + 1 < end && fTs[start].fDone) {
2024 ++start;
2025 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002026 bestT = foundT < 1 ? start : end;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002027 hitT = startT + (endT - startT) * foundT;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002028 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002029 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002030 } while (fTs[end].fT != 1);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002031 SkASSERT(!expectNoDx);
2032 if (bestT != xbestT) {
2033 SkDebugf("%s mismatch bestT=%d xbestT=%d\n", __FUNCTION__, bestT, xbestT);
2034 bestT = xbestT;
2035 }
2036 if (bestY != xbestY) {
2037 SkDebugf("%s mismatch bestY=%1.9g xbestY=%1.9g\n", __FUNCTION__, bestY, xbestY);
2038 bestY = xbestY;
2039 }
2040 if (hitT != xhitT) {
2041 SkDebugf("%s mismatch hitT=%1.9g xhitT=%1.9g\n", __FUNCTION__, hitT, xhitT);
2042 hitT = xhitT;
2043 }
2044 if (hitSomething != xhitSomething) {
2045 SkDebugf("%s mismatch hitSomething=%d xhitSomething=%d\n", __FUNCTION__, hitSomething,
2046 xhitSomething);
2047 hitSomething = xhitSomething;
2048 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00002049
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002050 return bestT;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002051 }
caryclark@google.com18063442012-07-25 12:05:18 +00002052
caryclark@google.com4eeda372012-12-06 21:47:48 +00002053 void decrementSpan(Span* span) {
caryclark@google.com18063442012-07-25 12:05:18 +00002054 SkASSERT(span->fWindValue > 0);
2055 if (--(span->fWindValue) == 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002056 if (!span->fOppValue && !span->fDone) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002057 span->fDone = true;
2058 ++fDoneSpans;
2059 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002060 }
2061 }
2062
2063 bool bumpSpan(Span* span, int windDelta, int oppDelta) {
2064 SkASSERT(!span->fDone);
2065 span->fWindValue += windDelta;
2066 SkASSERT(span->fWindValue >= 0);
2067 span->fOppValue += oppDelta;
2068 SkASSERT(span->fOppValue >= 0);
2069 if (fXor) {
2070 span->fWindValue &= 1;
2071 }
2072 if (fOppXor) {
2073 span->fOppValue &= 1;
2074 }
2075 if (!span->fWindValue && !span->fOppValue) {
2076 span->fDone = true;
2077 ++fDoneSpans;
caryclark@google.com18063442012-07-25 12:05:18 +00002078 return true;
2079 }
2080 return false;
2081 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002082
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002083 // OPTIMIZE
2084 // when the edges are initially walked, they don't automatically get the prior and next
2085 // 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 +00002086 // and would additionally remove the need for similar checks in condition edges. It would
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002087 // also allow intersection code to assume end of segment intersections (maybe?)
2088 bool complete() const {
2089 int count = fTs.count();
2090 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
2091 }
caryclark@google.com18063442012-07-25 12:05:18 +00002092
caryclark@google.com15fa1382012-05-07 20:49:36 +00002093 bool done() const {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002094 SkASSERT(fDoneSpans <= fTs.count());
2095 return fDoneSpans == fTs.count();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002096 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002097
caryclark@google.comf839c032012-10-26 21:03:50 +00002098 bool done(int min) const {
2099 return fTs[min].fDone;
2100 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002101
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002102 bool done(const Angle* angle) const {
2103 return done(SkMin32(angle->start(), angle->end()));
caryclark@google.com47580692012-07-23 12:14:49 +00002104 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00002105
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002106 bool equalPoints(int greaterTIndex, int lesserTIndex) {
2107 SkASSERT(greaterTIndex >= lesserTIndex);
2108 double greaterT = fTs[greaterTIndex].fT;
2109 double lesserT = fTs[lesserTIndex].fT;
2110 if (greaterT == lesserT) {
2111 return true;
2112 }
2113 if (!approximately_negative(greaterT - lesserT)) {
2114 return false;
2115 }
2116 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2117 }
2118
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002119 /*
2120 The M and S variable name parts stand for the operators.
2121 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2122 Su stands for Subtrahend
2123 The Opp variable name part designates that the value is for the Opposite operator.
2124 Opposite values result from combining coincident spans.
2125 */
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002126
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002127 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2128 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002129 const int startIndex = nextStart;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002130 const int endIndex = nextEnd;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002131 SkASSERT(startIndex != endIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002132 const int count = fTs.count();
2133 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2134 const int step = SkSign32(endIndex - startIndex);
2135 const int end = nextExactSpan(startIndex, step);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002136 SkASSERT(end >= 0);
2137 Span* endSpan = &fTs[end];
2138 Segment* other;
2139 if (isSimple(end)) {
2140 // mark the smaller of startIndex, endIndex done, and all adjacent
2141 // spans with the same T value (but not 'other' spans)
2142 #if DEBUG_WINDING
2143 SkDebugf("%s simple\n", __FUNCTION__);
2144 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002145 int min = SkMin32(startIndex, endIndex);
2146 if (fTs[min].fDone) {
2147 return NULL;
2148 }
2149 markDoneBinary(min);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002150 other = endSpan->fOther;
2151 nextStart = endSpan->fOtherIndex;
2152 double startT = other->fTs[nextStart].fT;
2153 nextEnd = nextStart;
2154 do {
2155 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002156 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002157 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002158 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2159 return other;
2160 }
2161 // more than one viable candidate -- measure angles to find best
2162 SkTDArray<Angle> angles;
2163 SkASSERT(startIndex - endIndex != 0);
2164 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2165 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002166 buildAngles(end, angles, true);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002167 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002168 bool sortable = SortAngles(angles, sorted);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002169 int angleCount = angles.count();
2170 int firstIndex = findStartingEdge(sorted, startIndex, end);
2171 SkASSERT(firstIndex >= 0);
2172 #if DEBUG_SORT
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002173 debugShowSort(__FUNCTION__, sorted, firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002174 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002175 if (!sortable) {
2176 unsortable = true;
2177 return NULL;
2178 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002179 SkASSERT(sorted[firstIndex]->segment() == this);
2180 #if DEBUG_WINDING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002181 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2182 sorted[firstIndex]->sign());
caryclark@google.com235f56a2012-09-14 14:19:30 +00002183 #endif
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002184 int sumMiWinding = updateWinding(endIndex, startIndex);
2185 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2186 if (operand()) {
2187 SkTSwap<int>(sumMiWinding, sumSuWinding);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002188 }
2189 int nextIndex = firstIndex + 1;
2190 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2191 const Angle* foundAngle = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002192 bool foundDone = false;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002193 // iterate through the angle, and compute everyone's winding
caryclark@google.com235f56a2012-09-14 14:19:30 +00002194 Segment* nextSegment;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002195 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002196 SkASSERT(nextIndex != firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002197 if (nextIndex == angleCount) {
2198 nextIndex = 0;
2199 }
2200 const Angle* nextAngle = sorted[nextIndex];
2201 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002202 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2203 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2204 nextAngle->end(), op, sumMiWinding, sumSuWinding,
2205 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
2206 if (activeAngle && (!foundAngle || foundDone)) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002207 foundAngle = nextAngle;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002208 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002209 }
2210 if (nextSegment->done()) {
2211 continue;
2212 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002213 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2214 continue;
2215 }
2216 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2217 oppSumWinding, activeAngle, nextAngle);
2218 if (last) {
2219 *chase.append() = last;
2220#if DEBUG_WINDING
2221 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2222 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2223#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002224 }
2225 } while (++nextIndex != lastIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002226 markDoneBinary(SkMin32(startIndex, endIndex));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002227 if (!foundAngle) {
2228 return NULL;
2229 }
2230 nextStart = foundAngle->start();
2231 nextEnd = foundAngle->end();
2232 nextSegment = foundAngle->segment();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002233
caryclark@google.com235f56a2012-09-14 14:19:30 +00002234 #if DEBUG_WINDING
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002235 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2236 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002237 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002238 return nextSegment;
2239 }
caryclark@google.com47580692012-07-23 12:14:49 +00002240
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002241 // so the span needs to contain the pairing info found here
2242 // this should include the winding computed for the edge, and
2243 // what edge it connects to, and whether it is discarded
2244 // (maybe discarded == abs(winding) > 1) ?
2245 // only need derivatives for duration of sorting, add a new struct
2246 // for pairings, remove extra spans that have zero length and
2247 // reference an unused other
2248 // for coincident, the last span on the other may be marked done
2249 // (always?)
rmistry@google.comd6176b02012-08-23 18:14:13 +00002250
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002251 // if loop is exhausted, contour may be closed.
2252 // FIXME: pass in close point so we can check for closure
2253
2254 // given a segment, and a sense of where 'inside' is, return the next
2255 // segment. If this segment has an intersection, or ends in multiple
2256 // segments, find the mate that continues the outside.
2257 // note that if there are multiples, but no coincidence, we can limit
2258 // choices to connections in the correct direction
rmistry@google.comd6176b02012-08-23 18:14:13 +00002259
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002260 // mark found segments as done
2261
caryclark@google.com15fa1382012-05-07 20:49:36 +00002262 // start is the index of the beginning T of this edge
2263 // it is guaranteed to have an end which describes a non-zero length (?)
2264 // winding -1 means ccw, 1 means cw
caryclark@google.com24bec792012-08-20 12:43:57 +00002265 Segment* findNextWinding(SkTDArray<Span*>& chase, bool active,
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002266 int& nextStart, int& nextEnd, int& winding, int& spanWinding,
2267 bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002268 const int startIndex = nextStart;
2269 const int endIndex = nextEnd;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002270 int outerWinding = winding;
2271 int innerWinding = winding + spanWinding;
caryclark@google.come21cb182012-07-23 21:26:31 +00002272 #if DEBUG_WINDING
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002273 SkDebugf("%s winding=%d spanWinding=%d outerWinding=%d innerWinding=%d\n",
2274 __FUNCTION__, winding, spanWinding, outerWinding, innerWinding);
caryclark@google.come21cb182012-07-23 21:26:31 +00002275 #endif
caryclark@google.com59823f72012-08-09 18:17:47 +00002276 if (useInnerWinding(outerWinding, innerWinding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002277 outerWinding = innerWinding;
2278 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002279 SkASSERT(startIndex != endIndex);
caryclark@google.com15fa1382012-05-07 20:49:36 +00002280 int count = fTs.count();
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002281 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2282 : startIndex > 0);
caryclark@google.com495f8e42012-05-31 13:13:11 +00002283 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002284 int end = nextExactSpan(startIndex, step);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002285 SkASSERT(end >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002286 Span* endSpan = &fTs[end];
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002287 Segment* other;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002288 if (isSimple(end)) {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002289 // mark the smaller of startIndex, endIndex done, and all adjacent
2290 // spans with the same T value (but not 'other' spans)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002291 #if DEBUG_WINDING
2292 SkDebugf("%s simple\n", __FUNCTION__);
2293 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002294 int min = SkMin32(startIndex, endIndex);
2295 if (fTs[min].fDone) {
2296 return NULL;
2297 }
2298 markDone(min, outerWinding);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002299 other = endSpan->fOther;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002300 nextStart = endSpan->fOtherIndex;
caryclark@google.com18063442012-07-25 12:05:18 +00002301 double startT = other->fTs[nextStart].fT;
2302 nextEnd = nextStart;
2303 do {
2304 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002305 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002306 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com495f8e42012-05-31 13:13:11 +00002307 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
caryclark@google.com15fa1382012-05-07 20:49:36 +00002308 return other;
2309 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002310 // more than one viable candidate -- measure angles to find best
caryclark@google.com15fa1382012-05-07 20:49:36 +00002311 SkTDArray<Angle> angles;
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002312 SkASSERT(startIndex - endIndex != 0);
2313 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002314 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002315 buildAngles(end, angles, false);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002316 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002317 bool sortable = SortAngles(angles, sorted);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002318 int angleCount = angles.count();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002319 int firstIndex = findStartingEdge(sorted, startIndex, end);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002320 SkASSERT(firstIndex >= 0);
caryclark@google.com47580692012-07-23 12:14:49 +00002321 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002322 debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com47580692012-07-23 12:14:49 +00002323 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002324 if (!sortable) {
2325 unsortable = true;
2326 return NULL;
2327 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002328 SkASSERT(sorted[firstIndex]->segment() == this);
caryclark@google.com0e08a192012-07-13 21:07:52 +00002329 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00002330 SkDebugf("%s [%d] sign=%d\n", __FUNCTION__, firstIndex, sorted[firstIndex]->sign());
caryclark@google.com0e08a192012-07-13 21:07:52 +00002331 #endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00002332 int sumWinding = winding - spanSign(sorted[firstIndex]);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002333 int nextIndex = firstIndex + 1;
2334 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2335 const Angle* foundAngle = NULL;
caryclark@google.com24bec792012-08-20 12:43:57 +00002336 // FIXME: found done logic probably fails if there are more than 4
2337 // sorted angles. It should bias towards the first and last undone
2338 // edges -- but not sure that it won't choose a middle (incorrect)
rmistry@google.comd6176b02012-08-23 18:14:13 +00002339 // edge if one is undone
caryclark@google.com47580692012-07-23 12:14:49 +00002340 bool foundDone = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002341 bool foundDone2 = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002342 // iterate through the angle, and compute everyone's winding
caryclark@google.com24bec792012-08-20 12:43:57 +00002343 bool altFlipped = false;
2344 bool foundFlipped = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002345 int foundSum = SK_MinS32;
caryclark@google.comafe56de2012-07-24 18:11:03 +00002346 Segment* nextSegment;
caryclark@google.com24bec792012-08-20 12:43:57 +00002347 int lastNonZeroSum = winding;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002348 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002349 if (nextIndex == angleCount) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002350 nextIndex = 0;
2351 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002352 const Angle* nextAngle = sorted[nextIndex];
caryclark@google.come21cb182012-07-23 21:26:31 +00002353 int maxWinding = sumWinding;
caryclark@google.com24bec792012-08-20 12:43:57 +00002354 if (sumWinding) {
2355 lastNonZeroSum = sumWinding;
2356 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00002357 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002358 bool nextDone = nextSegment->done(nextAngle);
2359 bool nextTiny = nextSegment->tiny(nextAngle);
caryclark@google.com2ddff932012-08-07 21:25:27 +00002360 sumWinding -= nextSegment->spanSign(nextAngle);
caryclark@google.com24bec792012-08-20 12:43:57 +00002361 altFlipped ^= lastNonZeroSum * sumWinding < 0; // flip if different signs
caryclark@google.comd1688742012-09-18 20:08:37 +00002362 #if 0 && DEBUG_WINDING
caryclark@google.com03f97062012-08-21 13:13:52 +00002363 SkASSERT(abs(sumWinding) <= gDebugMaxWindSum);
caryclark@google.com24bec792012-08-20 12:43:57 +00002364 SkDebugf("%s [%d] maxWinding=%d sumWinding=%d sign=%d altFlipped=%d\n", __FUNCTION__,
2365 nextIndex, maxWinding, sumWinding, nextAngle->sign(), altFlipped);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002366 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002367 if (!sumWinding) {
caryclark@google.com5c286d32012-07-13 11:57:28 +00002368 if (!active) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00002369 // FIXME: shouldn't this call mark and chase done ?
caryclark@google.com59823f72012-08-09 18:17:47 +00002370 markDone(SkMin32(startIndex, endIndex), outerWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002371 // FIXME: shouldn't this call mark and chase winding ?
caryclark@google.com47580692012-07-23 12:14:49 +00002372 nextSegment->markWinding(SkMin32(nextAngle->start(),
caryclark@google.com59823f72012-08-09 18:17:47 +00002373 nextAngle->end()), maxWinding);
caryclark@google.com0e08a192012-07-13 21:07:52 +00002374 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00002375 SkDebugf("%s [%d] inactive\n", __FUNCTION__, nextIndex);
caryclark@google.com0e08a192012-07-13 21:07:52 +00002376 #endif
caryclark@google.com5c286d32012-07-13 11:57:28 +00002377 return NULL;
2378 }
caryclark@google.com47580692012-07-23 12:14:49 +00002379 if (!foundAngle || foundDone) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002380 foundAngle = nextAngle;
caryclark@google.comf839c032012-10-26 21:03:50 +00002381 foundDone = nextDone && !nextTiny;
caryclark@google.com24bec792012-08-20 12:43:57 +00002382 foundFlipped = altFlipped;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002383 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002384 continue;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002385 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002386
caryclark@google.com24bec792012-08-20 12:43:57 +00002387 if (!maxWinding && (!foundAngle || foundDone2)) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00002388 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00002389 if (foundAngle && foundDone2) {
2390 SkDebugf("%s [%d] !foundAngle && foundDone2\n", __FUNCTION__, nextIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002391 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00002392 #endif
caryclark@google.com0e08a192012-07-13 21:07:52 +00002393 foundAngle = nextAngle;
caryclark@google.comf839c032012-10-26 21:03:50 +00002394 foundDone2 = nextDone && !nextTiny;
caryclark@google.com24bec792012-08-20 12:43:57 +00002395 foundFlipped = altFlipped;
2396 foundSum = sumWinding;
caryclark@google.com0e08a192012-07-13 21:07:52 +00002397 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002398 if (nextSegment->done()) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002399 continue;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002400 }
2401 // if the winding is non-zero, nextAngle does not connect to
2402 // current chain. If we haven't done so already, mark the angle
2403 // as done, record the winding value, and mark connected unambiguous
2404 // segments as well.
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002405 if (nextSegment->windSum(nextAngle) == SK_MinS32) {
caryclark@google.com59823f72012-08-09 18:17:47 +00002406 if (useInnerWinding(maxWinding, sumWinding)) {
caryclark@google.come21cb182012-07-23 21:26:31 +00002407 maxWinding = sumWinding;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002408 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002409 Span* last;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002410 if (foundAngle) {
caryclark@google.com59823f72012-08-09 18:17:47 +00002411 last = nextSegment->markAndChaseWinding(nextAngle, maxWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002412 } else {
caryclark@google.com59823f72012-08-09 18:17:47 +00002413 last = nextSegment->markAndChaseDone(nextAngle, maxWinding);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002414 }
2415 if (last) {
2416 *chase.append() = last;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002417 #if DEBUG_WINDING
2418 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2419 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2420 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002421 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00002422 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002423 } while (++nextIndex != lastIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00002424 markDone(SkMin32(startIndex, endIndex), outerWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002425 if (!foundAngle) {
2426 return NULL;
2427 }
2428 nextStart = foundAngle->start();
2429 nextEnd = foundAngle->end();
caryclark@google.comafe56de2012-07-24 18:11:03 +00002430 nextSegment = foundAngle->segment();
caryclark@google.com24bec792012-08-20 12:43:57 +00002431 int flipped = foundFlipped ? -1 : 1;
caryclark@google.comafe56de2012-07-24 18:11:03 +00002432 spanWinding = SkSign32(spanWinding) * flipped * nextSegment->windValue(
2433 SkMin32(nextStart, nextEnd));
caryclark@google.com24bec792012-08-20 12:43:57 +00002434 if (winding) {
2435 #if DEBUG_WINDING
2436 SkDebugf("%s ---6 winding=%d foundSum=", __FUNCTION__, winding);
2437 if (foundSum == SK_MinS32) {
2438 SkDebugf("?");
2439 } else {
2440 SkDebugf("%d", foundSum);
2441 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002442 SkDebugf("\n");
2443 #endif
2444 winding = foundSum;
caryclark@google.com27c449a2012-07-27 18:26:38 +00002445 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00002446 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00002447 SkDebugf("%s spanWinding=%d flipped=%d\n", __FUNCTION__, spanWinding, flipped);
caryclark@google.com27c449a2012-07-27 18:26:38 +00002448 #endif
caryclark@google.comafe56de2012-07-24 18:11:03 +00002449 return nextSegment;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002450 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002451
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002452 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2453 bool& unsortable) {
2454 const int startIndex = nextStart;
2455 const int endIndex = nextEnd;
2456 SkASSERT(startIndex != endIndex);
2457 const int count = fTs.count();
2458 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2459 const int step = SkSign32(endIndex - startIndex);
2460 const int end = nextExactSpan(startIndex, step);
2461 SkASSERT(end >= 0);
2462 Span* endSpan = &fTs[end];
2463 Segment* other;
2464 if (isSimple(end)) {
2465 // mark the smaller of startIndex, endIndex done, and all adjacent
2466 // spans with the same T value (but not 'other' spans)
2467 #if DEBUG_WINDING
2468 SkDebugf("%s simple\n", __FUNCTION__);
2469 #endif
2470 int min = SkMin32(startIndex, endIndex);
2471 if (fTs[min].fDone) {
2472 return NULL;
2473 }
2474 markDoneUnary(min);
2475 other = endSpan->fOther;
2476 nextStart = endSpan->fOtherIndex;
2477 double startT = other->fTs[nextStart].fT;
2478 nextEnd = nextStart;
2479 do {
2480 nextEnd += step;
2481 }
2482 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2483 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2484 return other;
2485 }
2486 // more than one viable candidate -- measure angles to find best
2487 SkTDArray<Angle> angles;
2488 SkASSERT(startIndex - endIndex != 0);
2489 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2490 addTwoAngles(startIndex, end, angles);
2491 buildAngles(end, angles, true);
2492 SkTDArray<Angle*> sorted;
2493 bool sortable = SortAngles(angles, sorted);
2494 int angleCount = angles.count();
2495 int firstIndex = findStartingEdge(sorted, startIndex, end);
2496 SkASSERT(firstIndex >= 0);
2497 #if DEBUG_SORT
2498 debugShowSort(__FUNCTION__, sorted, firstIndex);
2499 #endif
2500 if (!sortable) {
2501 unsortable = true;
2502 return NULL;
2503 }
2504 SkASSERT(sorted[firstIndex]->segment() == this);
2505 #if DEBUG_WINDING
2506 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2507 sorted[firstIndex]->sign());
2508 #endif
2509 int sumWinding = updateWinding(endIndex, startIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002510 int nextIndex = firstIndex + 1;
2511 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2512 const Angle* foundAngle = NULL;
2513 bool foundDone = false;
2514 // iterate through the angle, and compute everyone's winding
2515 Segment* nextSegment;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002516 int activeCount = 0;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002517 do {
2518 SkASSERT(nextIndex != firstIndex);
2519 if (nextIndex == angleCount) {
2520 nextIndex = 0;
2521 }
2522 const Angle* nextAngle = sorted[nextIndex];
2523 nextSegment = nextAngle->segment();
2524 int maxWinding;
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00002525 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002526 maxWinding, sumWinding);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002527 if (activeAngle) {
2528 ++activeCount;
2529 if (!foundAngle || (foundDone && activeCount & 1)) {
2530 if (nextSegment->tiny(nextAngle)) {
2531 unsortable = true;
2532 return NULL;
2533 }
2534 foundAngle = nextAngle;
2535 foundDone = nextSegment->done(nextAngle);
2536 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002537 }
2538 if (nextSegment->done()) {
2539 continue;
2540 }
2541 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2542 continue;
2543 }
2544 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2545 if (last) {
2546 *chase.append() = last;
2547#if DEBUG_WINDING
2548 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2549 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2550#endif
2551 }
2552 } while (++nextIndex != lastIndex);
2553 markDoneUnary(SkMin32(startIndex, endIndex));
2554 if (!foundAngle) {
2555 return NULL;
2556 }
2557 nextStart = foundAngle->start();
2558 nextEnd = foundAngle->end();
2559 nextSegment = foundAngle->segment();
2560
2561 #if DEBUG_WINDING
2562 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2563 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2564 #endif
2565 return nextSegment;
2566 }
2567
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002568 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002569 const int startIndex = nextStart;
2570 const int endIndex = nextEnd;
2571 SkASSERT(startIndex != endIndex);
2572 int count = fTs.count();
2573 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2574 : startIndex > 0);
2575 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002576 int end = nextExactSpan(startIndex, step);
caryclark@google.com24bec792012-08-20 12:43:57 +00002577 SkASSERT(end >= 0);
2578 Span* endSpan = &fTs[end];
2579 Segment* other;
caryclark@google.com24bec792012-08-20 12:43:57 +00002580 if (isSimple(end)) {
2581 #if DEBUG_WINDING
2582 SkDebugf("%s simple\n", __FUNCTION__);
2583 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002584 int min = SkMin32(startIndex, endIndex);
2585 if (fTs[min].fDone) {
2586 return NULL;
2587 }
2588 markDone(min, 1);
caryclark@google.com24bec792012-08-20 12:43:57 +00002589 other = endSpan->fOther;
2590 nextStart = endSpan->fOtherIndex;
2591 double startT = other->fTs[nextStart].fT;
2592 SkDEBUGCODE(bool firstLoop = true;)
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002593 if ((approximately_less_than_zero(startT) && step < 0)
2594 || (approximately_greater_than_one(startT) && step > 0)) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002595 step = -step;
2596 SkDEBUGCODE(firstLoop = false;)
2597 }
2598 do {
2599 nextEnd = nextStart;
2600 do {
2601 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002602 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002603 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com24bec792012-08-20 12:43:57 +00002604 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2605 break;
2606 }
caryclark@google.com03f97062012-08-21 13:13:52 +00002607 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00002608 SkASSERT(firstLoop);
caryclark@google.com03f97062012-08-21 13:13:52 +00002609 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002610 SkDEBUGCODE(firstLoop = false;)
2611 step = -step;
2612 } while (true);
2613 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2614 return other;
2615 }
2616 SkTDArray<Angle> angles;
2617 SkASSERT(startIndex - endIndex != 0);
2618 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2619 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002620 buildAngles(end, angles, false);
caryclark@google.com24bec792012-08-20 12:43:57 +00002621 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002622 bool sortable = SortAngles(angles, sorted);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002623 if (!sortable) {
2624 unsortable = true;
2625 return NULL;
2626 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002627 int angleCount = angles.count();
2628 int firstIndex = findStartingEdge(sorted, startIndex, end);
2629 SkASSERT(firstIndex >= 0);
2630 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002631 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
caryclark@google.com24bec792012-08-20 12:43:57 +00002632 #endif
2633 SkASSERT(sorted[firstIndex]->segment() == this);
2634 int nextIndex = firstIndex + 1;
2635 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2636 const Angle* nextAngle;
2637 Segment* nextSegment;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002638 bool foundAngle = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002639 do {
2640 if (nextIndex == angleCount) {
2641 nextIndex = 0;
2642 }
2643 nextAngle = sorted[nextIndex];
2644 nextSegment = nextAngle->segment();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002645 if (!nextSegment->done(nextAngle) || nextSegment->tiny(nextAngle)) {
2646 foundAngle = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00002647 break;
2648 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002649 } while (++nextIndex != lastIndex);
2650 markDone(SkMin32(startIndex, endIndex), 1);
2651 if (!foundAngle) {
2652 nextIndex = firstIndex + 1 == angleCount ? 0 : firstIndex + 1;
2653 nextAngle = sorted[nextIndex];
2654 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002655 nextStart = nextAngle->start();
2656 nextEnd = nextAngle->end();
2657 return nextSegment;
2658 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002659
2660 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2661 int angleCount = sorted.count();
2662 int firstIndex = -1;
2663 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2664 const Angle* angle = sorted[angleIndex];
2665 if (angle->segment() == this && angle->start() == end &&
2666 angle->end() == start) {
2667 firstIndex = angleIndex;
2668 break;
2669 }
2670 }
2671 return firstIndex;
2672 }
2673
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002674 // FIXME: this is tricky code; needs its own unit test
caryclark@google.com4eeda372012-12-06 21:47:48 +00002675 void findTooCloseToCall() {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002676 int count = fTs.count();
2677 if (count < 3) { // require t=0, x, 1 at minimum
2678 return;
2679 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002680 int matchIndex = 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002681 int moCount;
2682 Span* match;
2683 Segment* mOther;
2684 do {
2685 match = &fTs[matchIndex];
2686 mOther = match->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002687 // FIXME: allow quads, cubics to be near coincident?
2688 if (mOther->fVerb == SkPath::kLine_Verb) {
2689 moCount = mOther->fTs.count();
2690 if (moCount >= 3) {
2691 break;
2692 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002693 }
2694 if (++matchIndex >= count) {
2695 return;
2696 }
2697 } while (true); // require t=0, x, 1 at minimum
caryclark@google.com15fa1382012-05-07 20:49:36 +00002698 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002699 const SkPoint* matchPt = &xyAtT(match);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002700 // look for a pair of nearby T values that map to the same (x,y) value
2701 // if found, see if the pair of other segments share a common point. If
2702 // so, the span from here to there is coincident.
caryclark@google.com15fa1382012-05-07 20:49:36 +00002703 for (int index = matchIndex + 1; index < count; ++index) {
2704 Span* test = &fTs[index];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002705 if (test->fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002706 continue;
2707 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002708 Segment* tOther = test->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002709 if (tOther->fVerb != SkPath::kLine_Verb) {
2710 continue; // FIXME: allow quads, cubics to be near coincident?
2711 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002712 int toCount = tOther->fTs.count();
2713 if (toCount < 3) { // require t=0, x, 1 at minimum
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002714 continue;
2715 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002716 const SkPoint* testPt = &xyAtT(test);
2717 if (*matchPt != *testPt) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002718 matchIndex = index;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002719 moCount = toCount;
2720 match = test;
2721 mOther = tOther;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002722 matchPt = testPt;
2723 continue;
2724 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002725 int moStart = -1;
2726 int moEnd = -1;
2727 double moStartT, moEndT;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002728 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002729 Span& moSpan = mOther->fTs[moIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002730 if (moSpan.fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002731 continue;
2732 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002733 if (moSpan.fOther == this) {
2734 if (moSpan.fOtherT == match->fT) {
2735 moStart = moIndex;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002736 moStartT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002737 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002738 continue;
2739 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002740 if (moSpan.fOther == tOther) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002741 if (tOther->fTs[moSpan.fOtherIndex].fWindValue == 0) {
2742 moStart = -1;
2743 break;
2744 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002745 SkASSERT(moEnd == -1);
2746 moEnd = moIndex;
2747 moEndT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002748 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002749 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002750 if (moStart < 0 || moEnd < 0) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002751 continue;
2752 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002753 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002754 if (approximately_equal(moStartT, moEndT)) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002755 continue;
2756 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002757 int toStart = -1;
2758 int toEnd = -1;
2759 double toStartT, toEndT;
2760 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2761 Span& toSpan = tOther->fTs[toIndex];
caryclark@google.comc899ad92012-08-23 15:24:42 +00002762 if (toSpan.fDone) {
2763 continue;
2764 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002765 if (toSpan.fOther == this) {
2766 if (toSpan.fOtherT == test->fT) {
2767 toStart = toIndex;
2768 toStartT = toSpan.fT;
2769 }
2770 continue;
2771 }
2772 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002773 if (mOther->fTs[toSpan.fOtherIndex].fWindValue == 0) {
2774 moStart = -1;
2775 break;
2776 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002777 SkASSERT(toEnd == -1);
2778 toEnd = toIndex;
2779 toEndT = toSpan.fT;
2780 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002781 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002782 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2783 if (toStart <= 0 || toEnd <= 0) {
2784 continue;
2785 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002786 if (approximately_equal(toStartT, toEndT)) {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002787 continue;
2788 }
2789 // test to see if the segment between there and here is linear
2790 if (!mOther->isLinear(moStart, moEnd)
2791 || !tOther->isLinear(toStart, toEnd)) {
2792 continue;
2793 }
caryclark@google.comc899ad92012-08-23 15:24:42 +00002794 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002795 if (flipped) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002796 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002797 } else {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002798 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002799 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002800 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002801 }
2802
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002803 // start here;
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00002804 // either:
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002805 // a) mark spans with either end unsortable as done, or
2806 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2807 // when encountering an unsortable span
2808
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002809 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2810 // and use more concise logic like the old edge walker code?
2811 // FIXME: this needs to deal with coincident edges
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002812 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002813 // iterate through T intersections and return topmost
2814 // topmost tangent from y-min to first pt is closer to horizontal
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002815 SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002816 int firstT = -1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002817 SkPoint topPt;
2818 topPt.fY = SK_ScalarMax;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002819 int count = fTs.count();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002820 // see if either end is not done since we want smaller Y of the pair
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002821 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002822 bool lastUnsortable = false;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002823 for (int index = 0; index < count; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002824 const Span& span = fTs[index];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002825 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002826 goto next;
2827 }
2828 if (!span.fDone | !lastDone) {
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002829 const SkPoint& intercept = xyAtT(&span);
2830 if (topPt.fY > intercept.fY || (topPt.fY == intercept.fY
2831 && topPt.fX > intercept.fX)) {
2832 topPt = intercept;
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002833 firstT = index;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002834 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002835 }
caryclark@google.comf839c032012-10-26 21:03:50 +00002836 next:
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002837 lastDone = span.fDone;
caryclark@google.comf839c032012-10-26 21:03:50 +00002838 lastUnsortable = span.fUnsortableEnd;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002839 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002840 SkASSERT(firstT >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002841 // sort the edges to find the leftmost
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002842 int step = 1;
2843 int end = nextSpan(firstT, step);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002844 if (end == -1) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002845 step = -1;
2846 end = nextSpan(firstT, step);
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00002847 SkASSERT(end != -1);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002848 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002849 // if the topmost T is not on end, or is three-way or more, find left
2850 // look for left-ness from tLeft to firstT (matching y of other)
2851 SkTDArray<Angle> angles;
2852 SkASSERT(firstT - end != 0);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002853 addTwoAngles(end, firstT, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002854 buildAngles(firstT, angles, true);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002855 SkTDArray<Angle*> sorted;
caryclark@google.comf839c032012-10-26 21:03:50 +00002856 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002857 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002858 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002859 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002860 if (onlySortable && !sortable) {
2861 unsortable = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002862 return NULL;
2863 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002864 // skip edges that have already been processed
2865 firstT = -1;
2866 Segment* leftSegment;
2867 do {
2868 const Angle* angle = sorted[++firstT];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002869 SkASSERT(!onlySortable || !angle->unsortable());
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002870 leftSegment = angle->segment();
2871 tIndex = angle->end();
2872 endIndex = angle->start();
2873 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002874 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002875 return leftSegment;
2876 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002877
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002878 // FIXME: not crazy about this
2879 // when the intersections are performed, the other index is into an
2880 // incomplete array. as the array grows, the indices become incorrect
2881 // while the following fixes the indices up again, it isn't smart about
2882 // skipping segments whose indices are already correct
2883 // assuming we leave the code that wrote the index in the first place
2884 void fixOtherTIndex() {
2885 int iCount = fTs.count();
2886 for (int i = 0; i < iCount; ++i) {
2887 Span& iSpan = fTs[i];
2888 double oT = iSpan.fOtherT;
2889 Segment* other = iSpan.fOther;
2890 int oCount = other->fTs.count();
2891 for (int o = 0; o < oCount; ++o) {
2892 Span& oSpan = other->fTs[o];
2893 if (oT == oSpan.fT && this == oSpan.fOther) {
2894 iSpan.fOtherIndex = o;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002895 break;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002896 }
2897 }
2898 }
2899 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002900
caryclark@google.com4eeda372012-12-06 21:47:48 +00002901 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002902 fDoneSpans = 0;
2903 fOperand = operand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00002904 fXor = evenOdd;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002905 fPts = pts;
2906 fVerb = verb;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002907 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00002908
caryclark@google.com3586ece2012-12-27 18:46:58 +00002909 void initWinding(int start, int end) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002910 int local = spanSign(start, end);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002911 int oppLocal = oppSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002912 (void) markAndChaseWinding(start, end, local, oppLocal);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002913 }
2914
caryclark@google.com3586ece2012-12-27 18:46:58 +00002915 void initWinding(int start, int end, int winding, int oppWinding) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002916 int local = spanSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002917 if (local * winding >= 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002918 winding += local;
2919 }
2920 int oppLocal = oppSign(start, end);
2921 if (oppLocal * oppWinding >= 0) {
2922 oppWinding += oppLocal;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002923 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002924 (void) markAndChaseWinding(start, end, winding, oppWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002925 }
2926
caryclark@google.com3586ece2012-12-27 18:46:58 +00002927/*
2928when we start with a vertical intersect, we try to use the dx to determine if the edge is to
2929the 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 +00002930sign or not. However, this isn't enough.
2931If 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 +00002932If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
2933from 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 +00002934the same winding is shared by both.
caryclark@google.com3586ece2012-12-27 18:46:58 +00002935*/
2936 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
2937 SkScalar hitOppDx) {
2938 SkASSERT(hitDx || !winding);
2939 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
2940 SkASSERT(dx);
2941 int windVal = windValue(SkMin32(start, end));
2942 if (!winding) {
2943 winding = dx < 0 ? windVal : -windVal;
2944 } else if (hitDx * dx >= 0) {
2945 int sideWind = winding + (dx < 0 ? windVal : -windVal);
2946 if (abs(winding) < abs(sideWind)) {
2947 winding = sideWind;
2948 }
2949 }
2950 int oppLocal = oppSign(start, end);
2951 SkASSERT(hitOppDx || !oppWind || !oppLocal);
2952 int oppWindVal = oppValue(SkMin32(start, end));
2953 if (!oppWind) {
2954 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
2955 } else if (hitOppDx * dx >= 0) {
2956 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
2957 if (abs(oppWind) < abs(oppSideWind)) {
2958 oppWind = oppSideWind;
2959 }
2960 }
2961 (void) markAndChaseWinding(start, end, winding, oppWind);
2962 }
2963
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002964 bool intersected() const {
2965 return fTs.count() > 0;
2966 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002967
2968 bool isConnected(int startIndex, int endIndex) const {
2969 return fTs[startIndex].fWindSum != SK_MinS32
2970 || fTs[endIndex].fWindSum != SK_MinS32;
2971 }
2972
caryclark@google.com235f56a2012-09-14 14:19:30 +00002973 bool isHorizontal() const {
2974 return fBounds.fTop == fBounds.fBottom;
2975 }
2976
caryclark@google.com15fa1382012-05-07 20:49:36 +00002977 bool isLinear(int start, int end) const {
2978 if (fVerb == SkPath::kLine_Verb) {
2979 return true;
2980 }
2981 if (fVerb == SkPath::kQuad_Verb) {
2982 SkPoint qPart[3];
2983 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
2984 return QuadIsLinear(qPart);
2985 } else {
2986 SkASSERT(fVerb == SkPath::kCubic_Verb);
2987 SkPoint cPart[4];
2988 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
2989 return CubicIsLinear(cPart);
2990 }
2991 }
caryclark@google.comb9738012012-07-03 19:53:30 +00002992
2993 // OPTIMIZE: successive calls could start were the last leaves off
2994 // or calls could specialize to walk forwards or backwards
2995 bool isMissing(double startT) const {
2996 size_t tCount = fTs.count();
2997 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002998 if (approximately_zero(startT - fTs[index].fT)) {
caryclark@google.comb9738012012-07-03 19:53:30 +00002999 return false;
3000 }
3001 }
3002 return true;
3003 }
3004
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003005 bool isSimple(int end) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003006 int count = fTs.count();
3007 if (count == 2) {
3008 return true;
3009 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003010 double t = fTs[end].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003011 if (approximately_less_than_zero(t)) {
3012 return !approximately_less_than_zero(fTs[1].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003013 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003014 if (approximately_greater_than_one(t)) {
3015 return !approximately_greater_than_one(fTs[count - 2].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003016 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003017 return false;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003018 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003019
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003020 bool isVertical() const {
3021 return fBounds.fLeft == fBounds.fRight;
3022 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003023
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003024 bool isVertical(int start, int end) const {
3025 return (*SegmentVertical[fVerb])(fPts, start, end);
3026 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003027
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003028 SkScalar leftMost(int start, int end) const {
3029 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
3030 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003031
caryclark@google.com495f8e42012-05-31 13:13:11 +00003032 // this span is excluded by the winding rule -- chase the ends
3033 // as long as they are unambiguous to mark connections as done
3034 // and give them the same winding value
caryclark@google.com59823f72012-08-09 18:17:47 +00003035 Span* markAndChaseDone(const Angle* angle, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003036 int index = angle->start();
3037 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003038 return markAndChaseDone(index, endIndex, winding);
3039 }
3040
caryclark@google.com31143cf2012-11-09 22:14:19 +00003041 Span* markAndChaseDone(int index, int endIndex, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003042 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003043 int min = SkMin32(index, endIndex);
3044 markDone(min, winding);
3045 Span* last;
3046 Segment* other = this;
3047 while ((other = other->nextChase(index, step, min, last))) {
3048 other->markDone(min, winding);
3049 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003050 return last;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003051 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003052
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003053 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
3054 int index = angle->start();
3055 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003056 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003057 int min = SkMin32(index, endIndex);
3058 markDoneBinary(min, winding, oppWinding);
3059 Span* last;
3060 Segment* other = this;
3061 while ((other = other->nextChase(index, step, min, last))) {
3062 other->markDoneBinary(min, winding, oppWinding);
3063 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003064 return last;
3065 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003066
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003067 Span* markAndChaseDoneBinary(int index, int endIndex) {
3068 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003069 int min = SkMin32(index, endIndex);
3070 markDoneBinary(min);
3071 Span* last;
3072 Segment* other = this;
3073 while ((other = other->nextChase(index, step, min, last))) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003074 if (other->done()) {
3075 return NULL;
3076 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003077 other->markDoneBinary(min);
3078 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003079 return last;
3080 }
3081
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003082 Span* markAndChaseDoneUnary(int index, int endIndex) {
3083 int step = SkSign32(endIndex - index);
3084 int min = SkMin32(index, endIndex);
3085 markDoneUnary(min);
3086 Span* last;
3087 Segment* other = this;
3088 while ((other = other->nextChase(index, step, min, last))) {
3089 if (other->done()) {
3090 return NULL;
3091 }
3092 other->markDoneUnary(min);
3093 }
3094 return last;
3095 }
3096
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003097 Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
3098 int index = angle->start();
3099 int endIndex = angle->end();
3100 return markAndChaseDone(index, endIndex, winding);
3101 }
3102
caryclark@google.com4eeda372012-12-06 21:47:48 +00003103 Span* markAndChaseWinding(const Angle* angle, const int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003104 int index = angle->start();
3105 int endIndex = angle->end();
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003106 int step = SkSign32(endIndex - index);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003107 int min = SkMin32(index, endIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00003108 markWinding(min, winding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003109 Span* last;
3110 Segment* other = this;
3111 while ((other = other->nextChase(index, step, min, last))) {
3112 if (other->fTs[min].fWindSum != SK_MinS32) {
3113 SkASSERT(other->fTs[min].fWindSum == winding);
3114 return NULL;
3115 }
3116 other->markWinding(min, winding);
3117 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003118 return last;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003119 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003120
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003121 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003122 int min = SkMin32(index, endIndex);
3123 int step = SkSign32(endIndex - index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003124 markWinding(min, winding, oppWinding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003125 Span* last;
3126 Segment* other = this;
3127 while ((other = other->nextChase(index, step, min, last))) {
3128 if (other->fTs[min].fWindSum != SK_MinS32) {
3129 SkASSERT(other->fTs[min].fWindSum == winding);
3130 return NULL;
3131 }
3132 other->markWinding(min, winding, oppWinding);
3133 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003134 return last;
3135 }
3136
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003137 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
3138 int start = angle->start();
3139 int end = angle->end();
3140 return markAndChaseWinding(start, end, winding, oppWinding);
3141 }
3142
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003143 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
3144 SkASSERT(angle->segment() == this);
3145 if (useInnerWinding(maxWinding, sumWinding)) {
3146 maxWinding = sumWinding;
3147 }
3148 Span* last;
3149 if (activeAngle) {
3150 last = markAndChaseWinding(angle, maxWinding);
3151 } else {
3152 last = markAndChaseDoneUnary(angle, maxWinding);
3153 }
3154 return last;
3155 }
3156
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003157 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
3158 bool activeAngle, const Angle* angle) {
3159 SkASSERT(angle->segment() == this);
3160 if (useInnerWinding(maxWinding, sumWinding)) {
3161 maxWinding = sumWinding;
3162 }
3163 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
3164 oppMaxWinding = oppSumWinding;
3165 }
3166 Span* last;
3167 if (activeAngle) {
3168 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3169 } else {
3170 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
3171 }
3172 return last;
3173 }
3174
caryclark@google.com495f8e42012-05-31 13:13:11 +00003175 // FIXME: this should also mark spans with equal (x,y)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003176 // This may be called when the segment is already marked done. While this
3177 // wastes time, it shouldn't do any more than spin through the T spans.
rmistry@google.comd6176b02012-08-23 18:14:13 +00003178 // OPTIMIZATION: abort on first done found (assuming that this code is
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003179 // always called to mark segments done).
caryclark@google.com59823f72012-08-09 18:17:47 +00003180 void markDone(int index, int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003181 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003182 SkASSERT(winding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003183 double referenceT = fTs[index].fT;
3184 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003185 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3186 markOneDone(__FUNCTION__, lesser, winding);
3187 }
3188 do {
3189 markOneDone(__FUNCTION__, index, winding);
3190 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003191 }
3192
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003193 void markDoneBinary(int index, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003194 // SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003195 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003196 double referenceT = fTs[index].fT;
3197 int lesser = index;
3198 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003199 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003200 }
3201 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003202 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
3203 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3204 }
3205
3206 void markDoneBinary(int index) {
3207 double referenceT = fTs[index].fT;
3208 int lesser = index;
3209 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3210 markOneDoneBinary(__FUNCTION__, lesser);
3211 }
3212 do {
3213 markOneDoneBinary(__FUNCTION__, index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003214 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003215 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00003216
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003217 void markDoneUnary(int index, int winding) {
3218 // SkASSERT(!done());
3219 SkASSERT(winding);
3220 double referenceT = fTs[index].fT;
3221 int lesser = index;
3222 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3223 markOneDoneUnary(__FUNCTION__, lesser, winding);
3224 }
3225 do {
3226 markOneDoneUnary(__FUNCTION__, index, winding);
3227 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3228 }
3229
3230 void markDoneUnary(int index) {
3231 double referenceT = fTs[index].fT;
3232 int lesser = index;
3233 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3234 markOneDoneUnary(__FUNCTION__, lesser);
3235 }
3236 do {
3237 markOneDoneUnary(__FUNCTION__, index);
3238 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3239 }
3240
caryclark@google.com24bec792012-08-20 12:43:57 +00003241 void markOneDone(const char* funName, int tIndex, int winding) {
3242 Span* span = markOneWinding(funName, tIndex, winding);
3243 if (!span) {
3244 return;
3245 }
3246 span->fDone = true;
3247 fDoneSpans++;
3248 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003249
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003250 void markOneDoneBinary(const char* funName, int tIndex) {
3251 Span* span = verifyOneWinding(funName, tIndex);
3252 if (!span) {
3253 return;
3254 }
3255 span->fDone = true;
3256 fDoneSpans++;
3257 }
3258
3259 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003260 Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
3261 if (!span) {
3262 return;
3263 }
3264 span->fDone = true;
3265 fDoneSpans++;
3266 }
3267
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003268 void markOneDoneUnary(const char* funName, int tIndex) {
3269 Span* span = verifyOneWindingU(funName, tIndex);
3270 if (!span) {
3271 return;
3272 }
3273 span->fDone = true;
3274 fDoneSpans++;
3275 }
3276
3277 void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3278 Span* span = markOneWinding(funName, tIndex, winding);
3279 if (!span) {
3280 return;
3281 }
3282 span->fDone = true;
3283 fDoneSpans++;
3284 }
3285
caryclark@google.com24bec792012-08-20 12:43:57 +00003286 Span* markOneWinding(const char* funName, int tIndex, int winding) {
3287 Span& span = fTs[tIndex];
3288 if (span.fDone) {
3289 return NULL;
3290 }
3291 #if DEBUG_MARK_DONE
3292 debugShowNewWinding(funName, span, winding);
3293 #endif
3294 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com03f97062012-08-21 13:13:52 +00003295 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00003296 SkASSERT(abs(winding) <= gDebugMaxWindSum);
caryclark@google.com03f97062012-08-21 13:13:52 +00003297 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00003298 span.fWindSum = winding;
3299 return &span;
3300 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003301
caryclark@google.com31143cf2012-11-09 22:14:19 +00003302 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
3303 Span& span = fTs[tIndex];
3304 if (span.fDone) {
3305 return NULL;
3306 }
3307 #if DEBUG_MARK_DONE
3308 debugShowNewWinding(funName, span, winding, oppWinding);
3309 #endif
3310 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3311 #ifdef SK_DEBUG
3312 SkASSERT(abs(winding) <= gDebugMaxWindSum);
3313 #endif
3314 span.fWindSum = winding;
3315 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3316 #ifdef SK_DEBUG
3317 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
3318 #endif
3319 span.fOppSum = oppWinding;
3320 return &span;
3321 }
3322
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003323 Span* verifyOneWinding(const char* funName, int tIndex) {
3324 Span& span = fTs[tIndex];
3325 if (span.fDone) {
3326 return NULL;
3327 }
3328 #if DEBUG_MARK_DONE
3329 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3330 #endif
3331 SkASSERT(span.fWindSum != SK_MinS32);
3332 SkASSERT(span.fOppSum != SK_MinS32);
3333 return &span;
3334 }
3335
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003336 Span* verifyOneWindingU(const char* funName, int tIndex) {
3337 Span& span = fTs[tIndex];
3338 if (span.fDone) {
3339 return NULL;
3340 }
3341 #if DEBUG_MARK_DONE
3342 debugShowNewWinding(funName, span, span.fWindSum);
3343 #endif
3344 SkASSERT(span.fWindSum != SK_MinS32);
3345 return &span;
3346 }
3347
caryclark@google.comf839c032012-10-26 21:03:50 +00003348 // note that just because a span has one end that is unsortable, that's
3349 // not enough to mark it done. The other end may be sortable, allowing the
3350 // span to be added.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003351 void markUnsortable(int start, int end) {
3352 Span* span = &fTs[start];
3353 if (start < end) {
3354 span->fUnsortableStart = true;
3355 } else {
3356 --span;
3357 span->fUnsortableEnd = true;
3358 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003359 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003360 return;
3361 }
3362 span->fDone = true;
3363 fDoneSpans++;
3364 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003365
caryclark@google.com59823f72012-08-09 18:17:47 +00003366 void markWinding(int index, int winding) {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003367 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003368 SkASSERT(winding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003369 double referenceT = fTs[index].fT;
3370 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003371 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3372 markOneWinding(__FUNCTION__, lesser, winding);
3373 }
3374 do {
3375 markOneWinding(__FUNCTION__, index, winding);
3376 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003377 }
3378
3379 void markWinding(int index, int winding, int oppWinding) {
3380 // SkASSERT(!done());
caryclark@google.com4eeda372012-12-06 21:47:48 +00003381 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003382 double referenceT = fTs[index].fT;
3383 int lesser = index;
3384 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3385 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003386 }
3387 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003388 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3389 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003390 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003391
caryclark@google.com2ddff932012-08-07 21:25:27 +00003392 void matchWindingValue(int tIndex, double t, bool borrowWind) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003393 int nextDoorWind = SK_MaxS32;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003394 int nextOppWind = SK_MaxS32;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003395 if (tIndex > 0) {
3396 const Span& below = fTs[tIndex - 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003397 if (approximately_negative(t - below.fT)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003398 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003399 nextOppWind = below.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003400 }
3401 }
3402 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3403 const Span& above = fTs[tIndex + 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003404 if (approximately_negative(above.fT - t)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003405 nextDoorWind = above.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003406 nextOppWind = above.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003407 }
3408 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003409 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3410 const Span& below = fTs[tIndex - 1];
3411 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003412 nextOppWind = below.fOppValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003413 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003414 if (nextDoorWind != SK_MaxS32) {
3415 Span& newSpan = fTs[tIndex];
3416 newSpan.fWindValue = nextDoorWind;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003417 newSpan.fOppValue = nextOppWind;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003418 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003419 newSpan.fDone = true;
3420 ++fDoneSpans;
3421 }
3422 }
3423 }
3424
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003425 bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3426 // find bounds
3427 Bounds bounds;
3428 bounds.setPoint(xyAtT(index));
3429 bounds.add(xyAtT(endIndex));
3430 SkScalar width = bounds.width();
3431 SkScalar height = bounds.height();
3432 if (width > height) {
3433 if (approximately_negative(width)) {
3434 unsortable = true; // edge is too small to resolve meaningfully
3435 }
3436 return false;
3437 } else {
3438 if (approximately_negative(height)) {
3439 unsortable = true; // edge is too small to resolve meaningfully
3440 }
3441 return true;
3442 }
3443 }
3444
caryclark@google.com9764cc62012-07-12 19:29:45 +00003445 // return span if when chasing, two or more radiating spans are not done
3446 // OPTIMIZATION: ? multiple spans is detected when there is only one valid
3447 // candidate and the remaining spans have windValue == 0 (canceled by
3448 // coincidence). The coincident edges could either be removed altogether,
3449 // or this code could be more complicated in detecting this case. Worth it?
3450 bool multipleSpans(int end) const {
3451 return end > 0 && end < fTs.count() - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00003452 }
3453
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003454 bool nextCandidate(int& start, int& end) const {
3455 do {
3456 start = end;
3457 if (fTs[start].fT == 1) {
3458 return false;
3459 }
3460 end = nextExactSpan(start, 1);
3461 } while (fTs[start].fDone);
3462 return true;
3463 }
3464
caryclark@google.com4eeda372012-12-06 21:47:48 +00003465 Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
3466 int end = nextExactSpan(index, step);
3467 SkASSERT(end >= 0);
3468 if (multipleSpans(end)) {
3469 last = &fTs[end];
3470 return NULL;
3471 }
3472 const Span& endSpan = fTs[end];
3473 Segment* other = endSpan.fOther;
3474 index = endSpan.fOtherIndex;
3475 int otherEnd = other->nextExactSpan(index, step);
3476 min = SkMin32(index, otherEnd);
3477 return other;
3478 }
3479
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003480 // This has callers for two different situations: one establishes the end
3481 // of the current span, and one establishes the beginning of the next span
3482 // (thus the name). When this is looking for the end of the current span,
3483 // coincidence is found when the beginning Ts contain -step and the end
3484 // contains step. When it is looking for the beginning of the next, the
3485 // first Ts found can be ignored and the last Ts should contain -step.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003486 // OPTIMIZATION: probably should split into two functions
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003487 int nextSpan(int from, int step) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003488 const Span& fromSpan = fTs[from];
caryclark@google.com495f8e42012-05-31 13:13:11 +00003489 int count = fTs.count();
3490 int to = from;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003491 while (step > 0 ? ++to < count : --to >= 0) {
3492 const Span& span = fTs[to];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003493 if (approximately_zero(span.fT - fromSpan.fT)) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003494 continue;
3495 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003496 return to;
3497 }
3498 return -1;
3499 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +00003500
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003501 // FIXME
3502 // this returns at any difference in T, vs. a preset minimum. It may be
3503 // that all callers to nextSpan should use this instead.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003504 // OPTIMIZATION splitting this into separate loops for up/down steps
3505 // would allow using precisely_negative instead of precisely_zero
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003506 int nextExactSpan(int from, int step) const {
3507 const Span& fromSpan = fTs[from];
3508 int count = fTs.count();
3509 int to = from;
3510 while (step > 0 ? ++to < count : --to >= 0) {
3511 const Span& span = fTs[to];
caryclark@google.coma461ff02012-10-11 12:54:23 +00003512 if (precisely_zero(span.fT - fromSpan.fT)) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003513 continue;
3514 }
3515 return to;
3516 }
3517 return -1;
3518 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003519
caryclark@google.com235f56a2012-09-14 14:19:30 +00003520 bool operand() const {
3521 return fOperand;
3522 }
3523
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003524 int oppSign(const Angle* angle) const {
3525 SkASSERT(angle->segment() == this);
3526 return oppSign(angle->start(), angle->end());
3527 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003528
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003529 int oppSign(int startIndex, int endIndex) const {
3530 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3531 : fTs[endIndex].fOppValue;
3532#if DEBUG_WIND_BUMP
3533 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3534#endif
3535 return result;
3536 }
3537
caryclark@google.com31143cf2012-11-09 22:14:19 +00003538 int oppSum(int tIndex) const {
3539 return fTs[tIndex].fOppSum;
3540 }
3541
3542 int oppSum(const Angle* angle) const {
3543 int lesser = SkMin32(angle->start(), angle->end());
3544 return fTs[lesser].fOppSum;
caryclark@google.com235f56a2012-09-14 14:19:30 +00003545 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003546
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003547 int oppValue(int tIndex) const {
3548 return fTs[tIndex].fOppValue;
3549 }
3550
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003551 int oppValue(const Angle* angle) const {
3552 int lesser = SkMin32(angle->start(), angle->end());
3553 return fTs[lesser].fOppValue;
3554 }
3555
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003556 const SkPoint* pts() const {
3557 return fPts;
3558 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003559
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003560 void reset() {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003561 init(NULL, (SkPath::Verb) -1, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003562 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3563 fTs.reset();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003564 }
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +00003565
caryclark@google.com4eeda372012-12-06 21:47:48 +00003566 void setOppXor(bool isOppXor) {
3567 fOppXor = isOppXor;
3568 }
3569
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003570 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3571 int deltaSum = spanSign(index, endIndex);
3572 maxWinding = sumWinding;
3573 sumWinding = sumWinding -= deltaSum;
3574 }
3575
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003576 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3577 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3578 int deltaSum = spanSign(index, endIndex);
3579 int oppDeltaSum = oppSign(index, endIndex);
3580 if (operand()) {
3581 maxWinding = sumSuWinding;
3582 sumWinding = sumSuWinding -= deltaSum;
3583 oppMaxWinding = sumMiWinding;
3584 oppSumWinding = sumMiWinding -= oppDeltaSum;
3585 } else {
3586 maxWinding = sumMiWinding;
3587 sumWinding = sumMiWinding -= deltaSum;
3588 oppMaxWinding = sumSuWinding;
3589 oppSumWinding = sumSuWinding -= oppDeltaSum;
3590 }
3591 }
3592
caryclark@google.comf839c032012-10-26 21:03:50 +00003593 // This marks all spans unsortable so that this info is available for early
3594 // exclusion in find top and others. This could be optimized to only mark
3595 // adjacent spans that unsortable. However, this makes it difficult to later
3596 // determine starting points for edge detection in find top and the like.
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003597 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
caryclark@google.comf839c032012-10-26 21:03:50 +00003598 bool sortable = true;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003599 int angleCount = angles.count();
3600 int angleIndex;
3601 angleList.setReserve(angleCount);
3602 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003603 Angle& angle = angles[angleIndex];
caryclark@google.comf839c032012-10-26 21:03:50 +00003604 *angleList.append() = &angle;
3605 sortable &= !angle.unsortable();
3606 }
3607 if (sortable) {
3608 QSort<Angle>(angleList.begin(), angleList.end() - 1);
3609 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3610 if (angles[angleIndex].unsortable()) {
3611 sortable = false;
3612 break;
3613 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003614 }
3615 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003616 if (!sortable) {
3617 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3618 Angle& angle = angles[angleIndex];
3619 angle.segment()->markUnsortable(angle.start(), angle.end());
3620 }
3621 }
3622 return sortable;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003623 }
3624
caryclark@google.com1577e8f2012-05-22 17:01:14 +00003625 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003626 const Span& span(int tIndex) const {
3627 return fTs[tIndex];
3628 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003629
caryclark@google.com235f56a2012-09-14 14:19:30 +00003630 int spanSign(const Angle* angle) const {
3631 SkASSERT(angle->segment() == this);
3632 return spanSign(angle->start(), angle->end());
3633 }
3634
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003635 int spanSign(int startIndex, int endIndex) const {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003636 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3637 : fTs[endIndex].fWindValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003638#if DEBUG_WIND_BUMP
3639 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3640#endif
3641 return result;
3642 }
3643
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003644 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003645 double t(int tIndex) const {
3646 return fTs[tIndex].fT;
3647 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003648
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003649 bool tiny(const Angle* angle) const {
3650 int start = angle->start();
3651 int end = angle->end();
caryclark@google.comf839c032012-10-26 21:03:50 +00003652 const Span& mSpan = fTs[SkMin32(start, end)];
3653 return mSpan.fTiny;
3654 }
3655
caryclark@google.com18063442012-07-25 12:05:18 +00003656 static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3657 double start) {
3658 int outCount = outsideTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003659 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
caryclark@google.com18063442012-07-25 12:05:18 +00003660 *outsideTs.append() = end;
3661 *outsideTs.append() = start;
3662 }
3663 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003664
caryclark@google.com24bec792012-08-20 12:43:57 +00003665 void undoneSpan(int& start, int& end) {
3666 size_t tCount = fTs.count();
3667 size_t index;
3668 for (index = 0; index < tCount; ++index) {
3669 if (!fTs[index].fDone) {
3670 break;
3671 }
3672 }
3673 SkASSERT(index < tCount - 1);
3674 start = index;
3675 double startT = fTs[index].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003676 while (approximately_negative(fTs[++index].fT - startT))
caryclark@google.com24bec792012-08-20 12:43:57 +00003677 SkASSERT(index < tCount);
3678 SkASSERT(index < tCount);
3679 end = index;
3680 }
caryclark@google.com18063442012-07-25 12:05:18 +00003681
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003682 bool unsortable(int index) const {
3683 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3684 }
3685
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003686 void updatePts(const SkPoint pts[]) {
3687 fPts = pts;
3688 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003689
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003690 int updateOppWinding(int index, int endIndex) const {
3691 int lesser = SkMin32(index, endIndex);
3692 int oppWinding = oppSum(lesser);
3693 int oppSpanWinding = oppSign(index, endIndex);
3694 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)) {
3695 oppWinding -= oppSpanWinding;
3696 }
3697 return oppWinding;
3698 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003699
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003700 int updateOppWinding(const Angle* angle) const {
3701 int startIndex = angle->start();
3702 int endIndex = angle->end();
3703 return updateOppWinding(endIndex, startIndex);
3704 }
3705
3706 int updateOppWindingReverse(const Angle* angle) const {
3707 int startIndex = angle->start();
3708 int endIndex = angle->end();
3709 return updateOppWinding(startIndex, endIndex);
3710 }
3711
3712 int updateWinding(int index, int endIndex) const {
3713 int lesser = SkMin32(index, endIndex);
3714 int winding = windSum(lesser);
3715 int spanWinding = spanSign(index, endIndex);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003716 if (winding && useInnerWinding(winding - spanWinding, winding)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003717 winding -= spanWinding;
3718 }
3719 return winding;
3720 }
3721
3722 int updateWinding(const Angle* angle) const {
3723 int startIndex = angle->start();
3724 int endIndex = angle->end();
3725 return updateWinding(endIndex, startIndex);
3726 }
3727
3728 int updateWindingReverse(const Angle* angle) const {
3729 int startIndex = angle->start();
3730 int endIndex = angle->end();
3731 return updateWinding(startIndex, endIndex);
3732 }
3733
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003734 SkPath::Verb verb() const {
3735 return fVerb;
3736 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003737
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003738 int windingAtTX(double tHit, int tIndex, bool crossOpp) const {
3739 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3740 return SK_MinS32;
3741 }
3742 int endIndex = nextSpan(tIndex, 1);
3743 if (crossOpp) {
3744 return updateOppWinding(tIndex, endIndex);
3745 }
3746 return updateWinding(tIndex, endIndex);
3747 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00003748
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003749 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003750 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3751 return SK_MinS32;
3752 }
3753 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3754 SkASSERT(winding != SK_MinS32);
3755 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
3756 #if DEBUG_WINDING
3757 SkDebugf("%s single winding=%d windValue=%d\n", __FUNCTION__, winding,
3758 windVal);
3759 #endif
3760 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark@google.com3586ece2012-12-27 18:46:58 +00003761 dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003762 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3763 dx = fPts[2].fX - fPts[1].fX - dx;
3764 }
3765 #if DEBUG_WINDING
3766 SkDebugf("%s dx=%1.9g\n", __FUNCTION__, dx);
3767 #endif
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003768 if (dx == 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003769 return SK_MinS32;
3770 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003771 if (winding * dx > 0) { // if same signs, result is negative
3772 winding += dx > 0 ? -windVal : windVal;
3773 #if DEBUG_WINDING
3774 SkDebugf("%s final winding=%d\n", __FUNCTION__, winding);
3775 #endif
3776 }
3777 return winding;
3778 }
3779
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003780 int windSum(int tIndex) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003781 return fTs[tIndex].fWindSum;
3782 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003783
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003784 int windSum(const Angle* angle) const {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003785 int start = angle->start();
3786 int end = angle->end();
3787 int index = SkMin32(start, end);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003788 return windSum(index);
caryclark@google.com495f8e42012-05-31 13:13:11 +00003789 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003790
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003791 int windValue(int tIndex) const {
3792 return fTs[tIndex].fWindValue;
3793 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003794
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003795 int windValue(const Angle* angle) const {
3796 int start = angle->start();
3797 int end = angle->end();
3798 int index = SkMin32(start, end);
3799 return windValue(index);
3800 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00003801
caryclark@google.com3586ece2012-12-27 18:46:58 +00003802 SkScalar xAtT(int index) const {
3803 return xAtT(&fTs[index]);
3804 }
3805
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003806 SkScalar xAtT(const Span* span) const {
3807 return xyAtT(span).fX;
3808 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003809
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003810 const SkPoint& xyAtT(int index) const {
3811 return xyAtT(&fTs[index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003812 }
3813
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003814 const SkPoint& xyAtT(const Span* span) const {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003815 if (SkScalarIsNaN(span->fPt.fX)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003816 if (span->fT == 0) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003817 span->fPt = fPts[0];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003818 } else if (span->fT == 1) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003819 span->fPt = fPts[fVerb];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003820 } else {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003821 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003822 }
3823 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00003824 return span->fPt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003825 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003826
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003827 // used only by right angle winding finding
3828 void xyAtT(int start, int end, double mid, SkPoint& pt) const {
3829 double t = fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
3830 (*SegmentXYAtT[fVerb])(fPts, t, &pt);
3831 }
3832
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003833 SkScalar yAtT(int index) const {
3834 return yAtT(&fTs[index]);
3835 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003836
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003837 SkScalar yAtT(const Span* span) const {
3838 return xyAtT(span).fY;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003839 }
3840
caryclark@google.com4eeda372012-12-06 21:47:48 +00003841 void zeroCoincidentOpp(Span* oTest, int index) {
3842 Span* const test = &fTs[index];
3843 Span* end = test;
3844 do {
3845 end->fOppValue = 0;
3846 end = &fTs[++index];
3847 } while (approximately_negative(end->fT - test->fT));
3848 }
3849
3850 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
3851 Span* const oTest = &fTs[oIndex];
3852 Span* oEnd = oTest;
3853 const double startT = test->fT;
3854 const double oStartT = oTest->fT;
3855 double otherTMatch = (test->fT - startT) * tRatio + oStartT;
3856 while (!approximately_negative(oEndT - oEnd->fT)
3857 && approximately_negative(oEnd->fT - otherTMatch)) {
3858 oEnd->fOppValue = 0;
3859 oEnd = &fTs[++oIndex];
3860 }
3861 }
3862
3863 void zeroSpan(Span* span) {
3864 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
caryclark@google.com6ec15262012-11-16 20:16:50 +00003865 span->fWindValue = 0;
caryclark@google.com729e1c42012-11-21 21:36:34 +00003866 span->fOppValue = 0;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003867 SkASSERT(!span->fDone);
3868 span->fDone = true;
3869 ++fDoneSpans;
caryclark@google.com6ec15262012-11-16 20:16:50 +00003870 }
3871
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003872#if DEBUG_DUMP
3873 void dump() const {
3874 const char className[] = "Segment";
3875 const int tab = 4;
3876 for (int i = 0; i < fTs.count(); ++i) {
3877 SkPoint out;
3878 (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
3879 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003880 " otherT=%1.9g windSum=%d\n",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003881 tab + sizeof(className), className, fID,
3882 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003883 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003884 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00003885 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003886 tab + sizeof(className), className, fID,
caryclark@google.com15fa1382012-05-07 20:49:36 +00003887 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003888 }
3889#endif
3890
caryclark@google.com47580692012-07-23 12:14:49 +00003891#if DEBUG_CONCIDENT
caryclark@google.comcc905052012-07-25 20:59:42 +00003892 // assert if pair has not already been added
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003893 void debugAddTPair(double t, const Segment& other, double otherT) const {
caryclark@google.comcc905052012-07-25 20:59:42 +00003894 for (int i = 0; i < fTs.count(); ++i) {
3895 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
3896 return;
3897 }
3898 }
3899 SkASSERT(0);
3900 }
3901#endif
3902
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003903#if DEBUG_DUMP
3904 int debugID() const {
3905 return fID;
3906 }
3907#endif
3908
caryclark@google.com24bec792012-08-20 12:43:57 +00003909#if DEBUG_WINDING
3910 void debugShowSums() const {
3911 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
3912 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
3913 for (int i = 0; i < fTs.count(); ++i) {
3914 const Span& span = fTs[i];
3915 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
3916 if (span.fWindSum == SK_MinS32) {
3917 SkDebugf("?");
3918 } else {
3919 SkDebugf("%d", span.fWindSum);
3920 }
3921 SkDebugf("]");
3922 }
3923 SkDebugf("\n");
3924 }
3925#endif
3926
caryclark@google.comcc905052012-07-25 20:59:42 +00003927#if DEBUG_CONCIDENT
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003928 void debugShowTs() const {
caryclark@google.com24bec792012-08-20 12:43:57 +00003929 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003930 int lastWind = -1;
3931 int lastOpp = -1;
3932 double lastT = -1;
3933 int i;
3934 for (i = 0; i < fTs.count(); ++i) {
3935 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
3936 || lastOpp != fTs[i].fOppValue;
3937 if (change && lastWind >= 0) {
3938 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3939 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3940 }
3941 if (change) {
3942 SkDebugf(" [o=%d", fTs[i].fOther->fID);
3943 lastWind = fTs[i].fWindValue;
3944 lastOpp = fTs[i].fOppValue;
3945 lastT = fTs[i].fT;
3946 } else {
3947 SkDebugf(",%d", fTs[i].fOther->fID);
3948 }
3949 }
3950 if (i <= 0) {
3951 return;
3952 }
3953 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3954 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3955 if (fOperand) {
3956 SkDebugf(" operand");
3957 }
3958 if (done()) {
3959 SkDebugf(" done");
caryclark@google.com47580692012-07-23 12:14:49 +00003960 }
3961 SkDebugf("\n");
3962 }
3963#endif
3964
caryclark@google.com027de222012-07-12 12:52:50 +00003965#if DEBUG_ACTIVE_SPANS
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003966 void debugShowActiveSpans() const {
caryclark@google.com027de222012-07-12 12:52:50 +00003967 if (done()) {
3968 return;
3969 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003970#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3971 int lastId = -1;
3972 double lastT = -1;
3973#endif
caryclark@google.com027de222012-07-12 12:52:50 +00003974 for (int i = 0; i < fTs.count(); ++i) {
3975 if (fTs[i].fDone) {
3976 continue;
3977 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003978#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3979 if (lastId == fID && lastT == fTs[i].fT) {
3980 continue;
3981 }
3982 lastId = fID;
3983 lastT = fTs[i].fT;
3984#endif
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003985 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com027de222012-07-12 12:52:50 +00003986 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3987 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3988 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3989 }
3990 const Span* span = &fTs[i];
rmistry@google.comd6176b02012-08-23 18:14:13 +00003991 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
caryclark@google.com0c803d02012-08-06 11:15:47 +00003992 xAtT(span), yAtT(span));
caryclark@google.com027de222012-07-12 12:52:50 +00003993 const Segment* other = fTs[i].fOther;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003994 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
3995 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
3996 if (fTs[i].fWindSum == SK_MinS32) {
3997 SkDebugf("?");
3998 } else {
3999 SkDebugf("%d", fTs[i].fWindSum);
4000 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004001 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
caryclark@google.com027de222012-07-12 12:52:50 +00004002 }
4003 }
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +00004004
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004005 // This isn't useful yet -- but leaving it in for now in case i think of something
4006 // to use it for
4007 void validateActiveSpans() const {
4008 if (done()) {
4009 return;
4010 }
4011 int tCount = fTs.count();
4012 for (int index = 0; index < tCount; ++index) {
4013 if (fTs[index].fDone) {
4014 continue;
4015 }
4016 // count number of connections which are not done
4017 int first = index;
4018 double baseT = fTs[index].fT;
4019 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
4020 --first;
4021 }
4022 int last = index;
4023 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
4024 ++last;
4025 }
4026 int connections = 0;
4027 connections += first > 0 && !fTs[first - 1].fDone;
4028 for (int test = first; test <= last; ++test) {
4029 connections += !fTs[test].fDone;
4030 const Segment* other = fTs[test].fOther;
4031 int oIndex = fTs[test].fOtherIndex;
4032 connections += !other->fTs[oIndex].fDone;
4033 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
4034 }
4035 // SkASSERT(!(connections & 1));
4036 }
4037 }
caryclark@google.com027de222012-07-12 12:52:50 +00004038#endif
4039
caryclark@google.com0c803d02012-08-06 11:15:47 +00004040#if DEBUG_MARK_DONE
4041 void debugShowNewWinding(const char* fun, const Span& span, int winding) {
4042 const SkPoint& pt = xyAtT(&span);
4043 SkDebugf("%s id=%d", fun, fID);
4044 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4045 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4046 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4047 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004048 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4049 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4050 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d windSum=",
4051 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, winding);
caryclark@google.com0c803d02012-08-06 11:15:47 +00004052 if (span.fWindSum == SK_MinS32) {
4053 SkDebugf("?");
4054 } else {
4055 SkDebugf("%d", span.fWindSum);
4056 }
4057 SkDebugf(" windValue=%d\n", span.fWindValue);
4058 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004059
4060 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
4061 const SkPoint& pt = xyAtT(&span);
4062 SkDebugf("%s id=%d", fun, fID);
4063 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4064 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4065 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4066 }
4067 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4068 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4069 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=",
4070 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
4071 winding, oppWinding);
4072 if (span.fOppSum == SK_MinS32) {
4073 SkDebugf("?");
4074 } else {
4075 SkDebugf("%d", span.fOppSum);
4076 }
4077 SkDebugf(" windSum=");
4078 if (span.fWindSum == SK_MinS32) {
4079 SkDebugf("?");
4080 } else {
4081 SkDebugf("%d", span.fWindSum);
4082 }
4083 SkDebugf(" windValue=%d\n", span.fWindValue);
4084 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00004085#endif
4086
caryclark@google.com47580692012-07-23 12:14:49 +00004087#if DEBUG_SORT
caryclark@google.com03f97062012-08-21 13:13:52 +00004088 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
caryclark@google.com31143cf2012-11-09 22:14:19 +00004089 const int contourWinding, const int oppContourWinding) const {
caryclark@google.comafe56de2012-07-24 18:11:03 +00004090 SkASSERT(angles[first]->segment() == this);
caryclark@google.com200c2112012-08-03 15:05:04 +00004091 SkASSERT(angles.count() > 1);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004092 int lastSum = contourWinding;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004093 int oppLastSum = oppContourWinding;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004094 const Angle* firstAngle = angles[first];
4095 int windSum = lastSum - spanSign(firstAngle);
4096 int oppoSign = oppSign(firstAngle);
4097 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004098 SkDebugf("%s %s contourWinding=%d oppContourWinding=%d sign=%d\n", fun, __FUNCTION__,
4099 contourWinding, oppContourWinding, spanSign(angles[first]));
caryclark@google.comafe56de2012-07-24 18:11:03 +00004100 int index = first;
4101 bool firstTime = true;
caryclark@google.com47580692012-07-23 12:14:49 +00004102 do {
4103 const Angle& angle = *angles[index];
4104 const Segment& segment = *angle.segment();
4105 int start = angle.start();
4106 int end = angle.end();
4107 const Span& sSpan = segment.fTs[start];
4108 const Span& eSpan = segment.fTs[end];
4109 const Span& mSpan = segment.fTs[SkMin32(start, end)];
caryclark@google.com31143cf2012-11-09 22:14:19 +00004110 bool opp = segment.fOperand ^ fOperand;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004111 if (!firstTime) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004112 oppoSign = segment.oppSign(&angle);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004113 if (opp) {
4114 oppLastSum = oppWindSum;
4115 oppWindSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004116 if (oppoSign) {
4117 lastSum = windSum;
4118 windSum -= oppoSign;
4119 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004120 } else {
4121 lastSum = windSum;
4122 windSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004123 if (oppoSign) {
4124 oppLastSum = oppWindSum;
4125 oppWindSum -= oppoSign;
4126 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004127 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004128 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004129 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 +00004130 " sign=%d windValue=%d windSum=",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004131 __FUNCTION__, index, angle.unsortable() ? "*** UNSORTABLE *** " : "",
caryclark@google.comc91dfe42012-10-16 12:06:27 +00004132 segment.fID, kLVerbStr[segment.fVerb],
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004133 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
4134 segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(),
4135 mSpan.fWindValue);
4136 if (mSpan.fWindSum == SK_MinS32) {
4137 SkDebugf("?");
4138 } else {
4139 SkDebugf("%d", mSpan.fWindSum);
4140 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004141 int last, wind;
4142 if (opp) {
4143 last = oppLastSum;
4144 wind = oppWindSum;
4145 } else {
4146 last = lastSum;
4147 wind = windSum;
4148 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004149 if (!oppoSign) {
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00004150 SkDebugf(" %d->%d (max=%d)", last, wind,
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004151 useInnerWinding(last, wind) ? wind : last);
4152 } else {
4153 SkDebugf(" %d->%d (%d->%d)", last, wind, opp ? lastSum : oppLastSum,
4154 opp ? windSum : oppWindSum);
4155 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004156 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004157#if false && DEBUG_ANGLE
caryclark@google.comc899ad92012-08-23 15:24:42 +00004158 angle.debugShow(segment.xyAtT(&sSpan));
4159#endif
caryclark@google.com47580692012-07-23 12:14:49 +00004160 ++index;
4161 if (index == angles.count()) {
4162 index = 0;
4163 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004164 if (firstTime) {
4165 firstTime = false;
4166 }
caryclark@google.com47580692012-07-23 12:14:49 +00004167 } while (index != first);
4168 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00004169
4170 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
4171 const Angle* firstAngle = angles[first];
4172 const Segment* segment = firstAngle->segment();
4173 int winding = segment->updateWinding(firstAngle);
4174 int oppWinding = segment->updateOppWinding(firstAngle);
4175 debugShowSort(fun, angles, first, winding, oppWinding);
4176 }
4177
caryclark@google.com47580692012-07-23 12:14:49 +00004178#endif
4179
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004180#if DEBUG_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004181 static char as_digit(int value) {
4182 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
4183 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004184#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004185
caryclark@google.com729e1c42012-11-21 21:36:34 +00004186#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004187 int debugShowWindingValues(int slotCount, int ofInterest) const {
4188 if (!(1 << fID & ofInterest)) {
4189 return 0;
4190 }
4191 int sum = 0;
4192 SkTDArray<char> slots;
4193 slots.setCount(slotCount * 2);
4194 memset(slots.begin(), ' ', slotCount * 2);
4195 for (int i = 0; i < fTs.count(); ++i) {
4196 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
4197 // continue;
4198 // }
4199 sum += fTs[i].fWindValue;
4200 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
4201 sum += fTs[i].fOppValue;
4202 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
4203 }
4204 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
4205 slots.begin() + slotCount);
4206 return sum;
4207 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004208#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004209
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004210private:
4211 const SkPoint* fPts;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004212 Bounds fBounds;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004213 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
caryclark@google.com4eeda372012-12-06 21:47:48 +00004214 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
caryclark@google.com24bec792012-08-20 12:43:57 +00004215 int fDoneSpans; // quick check that segment is finished
caryclark@google.com4eeda372012-12-06 21:47:48 +00004216 // OPTIMIZATION: force the following to be byte-sized
4217 SkPath::Verb fVerb;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004218 bool fOperand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004219 bool fXor; // set if original contour had even-odd fill
4220 bool fOppXor; // set if opposite operand had even-odd fill
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004221#if DEBUG_DUMP
4222 int fID;
4223#endif
4224};
4225
caryclark@google.comb9738012012-07-03 19:53:30 +00004226class Contour;
4227
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004228struct Coincidence {
caryclark@google.comb9738012012-07-03 19:53:30 +00004229 Contour* fContours[2];
4230 int fSegments[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004231 double fTs[2][2];
4232};
4233
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004234class Contour {
4235public:
4236 Contour() {
4237 reset();
4238#if DEBUG_DUMP
4239 fID = ++gContourID;
4240#endif
4241 }
4242
4243 bool operator<(const Contour& rh) const {
4244 return fBounds.fTop == rh.fBounds.fTop
4245 ? fBounds.fLeft < rh.fBounds.fLeft
4246 : fBounds.fTop < rh.fBounds.fTop;
4247 }
4248
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004249 void addCoincident(int index, Contour* other, int otherIndex,
4250 const Intersections& ts, bool swap) {
4251 Coincidence& coincidence = *fCoincidences.append();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004252 coincidence.fContours[0] = this; // FIXME: no need to store
caryclark@google.comb9738012012-07-03 19:53:30 +00004253 coincidence.fContours[1] = other;
4254 coincidence.fSegments[0] = index;
4255 coincidence.fSegments[1] = otherIndex;
caryclark@google.com32546db2012-08-31 20:55:07 +00004256 if (fSegments[index].verb() == SkPath::kLine_Verb &&
4257 other->fSegments[otherIndex].verb() == SkPath::kLine_Verb) {
4258 // FIXME: coincident lines use legacy Ts instead of coincident Ts
4259 coincidence.fTs[swap][0] = ts.fT[0][0];
4260 coincidence.fTs[swap][1] = ts.fT[0][1];
4261 coincidence.fTs[!swap][0] = ts.fT[1][0];
4262 coincidence.fTs[!swap][1] = ts.fT[1][1];
4263 } else if (fSegments[index].verb() == SkPath::kQuad_Verb &&
4264 other->fSegments[otherIndex].verb() == SkPath::kQuad_Verb) {
4265 coincidence.fTs[swap][0] = ts.fCoincidentT[0][0];
4266 coincidence.fTs[swap][1] = ts.fCoincidentT[0][1];
4267 coincidence.fTs[!swap][0] = ts.fCoincidentT[1][0];
4268 coincidence.fTs[!swap][1] = ts.fCoincidentT[1][1];
4269 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004270 }
4271
4272 void addCross(const Contour* crosser) {
4273#ifdef DEBUG_CROSS
4274 for (int index = 0; index < fCrosses.count(); ++index) {
4275 SkASSERT(fCrosses[index] != crosser);
4276 }
4277#endif
4278 *fCrosses.append() = crosser;
4279 }
4280
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004281 void addCubic(const SkPoint pts[4]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004282 fSegments.push_back().addCubic(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004283 fContainsCurves = true;
4284 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004285
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004286 int addLine(const SkPoint pts[2]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004287 fSegments.push_back().addLine(pts, fOperand, fXor);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004288 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004289 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004290
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004291 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
4292 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
4293 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004294
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004295 int addQuad(const SkPoint pts[3]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004296 fSegments.push_back().addQuad(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004297 fContainsCurves = true;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004298 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004299 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004300
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004301 int addT(int segIndex, double newT, Contour* other, int otherIndex) {
4302 containsIntercepts();
4303 return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex]);
4304 }
4305
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004306 const Bounds& bounds() const {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004307 return fBounds;
4308 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004309
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004310 void complete() {
4311 setBounds();
4312 fContainsIntercepts = false;
4313 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004314
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004315 void containsIntercepts() {
4316 fContainsIntercepts = true;
4317 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004318
caryclark@google.com3586ece2012-12-27 18:46:58 +00004319#if 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +00004320 const Segment* crossedSegmentY(const SkPoint& basePt, SkScalar& bestY,
4321 int &tIndex, double& hitT, bool opp) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004322 int segmentCount = fSegments.count();
4323 const Segment* bestSegment = NULL;
4324 for (int test = 0; test < segmentCount; ++test) {
4325 Segment* testSegment = &fSegments[test];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004326 double testHitT;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00004327 int testT = testSegment->crossedSpanY(basePt, bestY, testHitT, opp);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004328 if (testT >= 0) {
4329 bestSegment = testSegment;
4330 tIndex = testT;
4331 hitT = testHitT;
4332 }
4333 }
4334 return bestSegment;
4335 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00004336#endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00004337
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004338 bool crosses(const Contour* crosser) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004339 for (int index = 0; index < fCrosses.count(); ++index) {
4340 if (fCrosses[index] == crosser) {
4341 return true;
4342 }
4343 }
4344 return false;
4345 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004346
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004347 bool done() const {
4348 return fDone;
4349 }
4350
caryclark@google.comf839c032012-10-26 21:03:50 +00004351 const SkPoint& end() const {
4352 const Segment& segment = fSegments.back();
4353 return segment.pts()[segment.verb()];
4354 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004355
caryclark@google.com4eeda372012-12-06 21:47:48 +00004356 void findTooCloseToCall() {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004357 int segmentCount = fSegments.count();
4358 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004359 fSegments[sIndex].findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004360 }
4361 }
4362
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004363 void fixOtherTIndex() {
4364 int segmentCount = fSegments.count();
4365 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4366 fSegments[sIndex].fixOtherTIndex();
4367 }
4368 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004369
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004370 Segment* nonVerticalSegment(int& start, int& end) {
4371 int segmentCount = fSortedSegments.count();
4372 SkASSERT(segmentCount > 0);
4373 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4374 Segment* testSegment = fSortedSegments[sortedIndex];
4375 if (testSegment->done()) {
4376 continue;
4377 }
4378 start = end = 0;
4379 while (testSegment->nextCandidate(start, end)) {
4380 if (!testSegment->isVertical(start, end)) {
4381 return testSegment;
4382 }
4383 }
4384 }
4385 return NULL;
4386 }
4387
caryclark@google.com31143cf2012-11-09 22:14:19 +00004388 bool operand() const {
4389 return fOperand;
4390 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004391
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004392 void reset() {
4393 fSegments.reset();
4394 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004395 fContainsCurves = fContainsIntercepts = fDone = false;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004396 }
caryclark@google.comb9738012012-07-03 19:53:30 +00004397
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004398 void resolveCoincidence(SkTDArray<Contour*>& contourList) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004399 int count = fCoincidences.count();
4400 for (int index = 0; index < count; ++index) {
4401 Coincidence& coincidence = fCoincidences[index];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004402 SkASSERT(coincidence.fContours[0] == this);
caryclark@google.comb9738012012-07-03 19:53:30 +00004403 int thisIndex = coincidence.fSegments[0];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004404 Segment& thisOne = fSegments[thisIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004405 Contour* otherContour = coincidence.fContours[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004406 int otherIndex = coincidence.fSegments[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004407 Segment& other = otherContour->fSegments[otherIndex];
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004408 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004409 continue;
4410 }
caryclark@google.com47580692012-07-23 12:14:49 +00004411 #if DEBUG_CONCIDENT
4412 thisOne.debugShowTs();
4413 other.debugShowTs();
4414 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004415 double startT = coincidence.fTs[0][0];
4416 double endT = coincidence.fTs[0][1];
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004417 bool cancelers = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004418 if (startT > endT) {
4419 SkTSwap<double>(startT, endT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004420 cancelers ^= true; // FIXME: just assign true
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004421 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004422 SkASSERT(!approximately_negative(endT - startT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004423 double oStartT = coincidence.fTs[1][0];
4424 double oEndT = coincidence.fTs[1][1];
4425 if (oStartT > oEndT) {
4426 SkTSwap<double>(oStartT, oEndT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004427 cancelers ^= true;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004428 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004429 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00004430 bool opp = fOperand ^ otherContour->fOperand;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004431 if (cancelers && !opp) {
4432 // make sure startT and endT have t entries
caryclark@google.com2ddff932012-08-07 21:25:27 +00004433 if (startT > 0 || oEndT < 1
4434 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
4435 thisOne.addTPair(startT, other, oEndT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004436 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00004437 if (oStartT > 0 || endT < 1
4438 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
4439 other.addTPair(oStartT, thisOne, endT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004440 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004441 if (!thisOne.done() && !other.done()) {
4442 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4443 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004444 } else {
caryclark@google.com200c2112012-08-03 15:05:04 +00004445 if (startT > 0 || oStartT > 0
4446 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00004447 thisOne.addTPair(startT, other, oStartT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004448 }
caryclark@google.com200c2112012-08-03 15:05:04 +00004449 if (endT < 1 || oEndT < 1
4450 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00004451 other.addTPair(oEndT, thisOne, endT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004452 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004453 if (!thisOne.done() && !other.done()) {
4454 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4455 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004456 }
caryclark@google.com47580692012-07-23 12:14:49 +00004457 #if DEBUG_CONCIDENT
4458 thisOne.debugShowTs();
4459 other.debugShowTs();
4460 #endif
caryclark@google.com729e1c42012-11-21 21:36:34 +00004461 #if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004462 debugShowWindingValues(contourList);
4463 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004464 }
4465 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004466
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004467 SkTArray<Segment>& segments() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004468 return fSegments;
4469 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004470
caryclark@google.com235f56a2012-09-14 14:19:30 +00004471 void setOperand(bool isOp) {
4472 fOperand = isOp;
4473 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00004474
caryclark@google.com4eeda372012-12-06 21:47:48 +00004475 void setOppXor(bool isOppXor) {
4476 fOppXor = isOppXor;
4477 int segmentCount = fSegments.count();
4478 for (int test = 0; test < segmentCount; ++test) {
4479 fSegments[test].setOppXor(isOppXor);
4480 }
4481 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004482
caryclark@google.com235f56a2012-09-14 14:19:30 +00004483 void setXor(bool isXor) {
4484 fXor = isXor;
4485 }
4486
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004487 void sortSegments() {
4488 int segmentCount = fSegments.count();
4489 fSortedSegments.setReserve(segmentCount);
4490 for (int test = 0; test < segmentCount; ++test) {
4491 *fSortedSegments.append() = &fSegments[test];
4492 }
4493 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4494 fFirstSorted = 0;
4495 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004496
caryclark@google.comf839c032012-10-26 21:03:50 +00004497 const SkPoint& start() const {
4498 return fSegments.front().pts()[0];
4499 }
4500
4501 void toPath(PathWrapper& path) const {
4502 int segmentCount = fSegments.count();
4503 const SkPoint& pt = fSegments.front().pts()[0];
4504 path.deferredMove(pt);
4505 for (int test = 0; test < segmentCount; ++test) {
4506 fSegments[test].addCurveTo(0, 1, path, true);
4507 }
4508 path.close();
4509 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004510
caryclark@google.comf839c032012-10-26 21:03:50 +00004511 void toPartialBackward(PathWrapper& path) const {
4512 int segmentCount = fSegments.count();
4513 for (int test = segmentCount - 1; test >= 0; --test) {
4514 fSegments[test].addCurveTo(1, 0, path, true);
4515 }
4516 }
4517
4518 void toPartialForward(PathWrapper& path) const {
4519 int segmentCount = fSegments.count();
4520 for (int test = 0; test < segmentCount; ++test) {
4521 fSegments[test].addCurveTo(0, 1, path, true);
4522 }
4523 }
4524
4525#if 0 // FIXME: obsolete, remove
caryclark@google.com15fa1382012-05-07 20:49:36 +00004526 // OPTIMIZATION: feel pretty uneasy about this. It seems like once again
4527 // we need to sort and walk edges in y, but that on the surface opens the
rmistry@google.comd6176b02012-08-23 18:14:13 +00004528 // same can of worms as before. But then, this is a rough sort based on
caryclark@google.com15fa1382012-05-07 20:49:36 +00004529 // segments' top, and not a true sort, so it could be ameniable to regular
4530 // sorting instead of linear searching. Still feel like I'm missing something
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004531 Segment* topSegment(SkScalar& bestY) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00004532 int segmentCount = fSegments.count();
4533 SkASSERT(segmentCount > 0);
4534 int best = -1;
4535 Segment* bestSegment = NULL;
4536 while (++best < segmentCount) {
4537 Segment* testSegment = &fSegments[best];
4538 if (testSegment->done()) {
4539 continue;
4540 }
4541 bestSegment = testSegment;
4542 break;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004543 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00004544 if (!bestSegment) {
4545 return NULL;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004546 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004547 SkScalar bestTop = bestSegment->activeTop();
caryclark@google.com15fa1382012-05-07 20:49:36 +00004548 for (int test = best + 1; test < segmentCount; ++test) {
4549 Segment* testSegment = &fSegments[test];
4550 if (testSegment->done()) {
4551 continue;
4552 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004553 if (testSegment->bounds().fTop > bestTop) {
4554 continue;
4555 }
4556 SkScalar testTop = testSegment->activeTop();
caryclark@google.com15fa1382012-05-07 20:49:36 +00004557 if (bestTop > testTop) {
4558 bestTop = testTop;
4559 bestSegment = testSegment;
4560 }
4561 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004562 bestY = bestTop;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004563 return bestSegment;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004564 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004565#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004566
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004567 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004568 int segmentCount = fSortedSegments.count();
4569 SkASSERT(segmentCount > 0);
caryclark@google.comf839c032012-10-26 21:03:50 +00004570 int sortedIndex = fFirstSorted;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004571 fDone = true; // may be cleared below
caryclark@google.comf839c032012-10-26 21:03:50 +00004572 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4573 Segment* testSegment = fSortedSegments[sortedIndex];
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004574 if (testSegment->done()) {
caryclark@google.comf839c032012-10-26 21:03:50 +00004575 if (sortedIndex == fFirstSorted) {
4576 ++fFirstSorted;
4577 }
4578 continue;
4579 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004580 fDone = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00004581 SkPoint testXY;
4582 testSegment->activeLeftTop(testXY);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004583 if (topStart) {
4584 if (testXY.fY < topLeft.fY) {
4585 continue;
4586 }
4587 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4588 continue;
4589 }
4590 if (bestXY.fY < testXY.fY) {
4591 continue;
4592 }
4593 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4594 continue;
4595 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004596 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004597 topStart = testSegment;
caryclark@google.comf839c032012-10-26 21:03:50 +00004598 bestXY = testXY;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004599 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004600 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004601
caryclark@google.com24bec792012-08-20 12:43:57 +00004602 Segment* undoneSegment(int& start, int& end) {
4603 int segmentCount = fSegments.count();
4604 for (int test = 0; test < segmentCount; ++test) {
4605 Segment* testSegment = &fSegments[test];
4606 if (testSegment->done()) {
4607 continue;
4608 }
4609 testSegment->undoneSpan(start, end);
4610 return testSegment;
4611 }
4612 return NULL;
4613 }
4614
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004615 int updateSegment(int index, const SkPoint* pts) {
4616 Segment& segment = fSegments[index];
4617 segment.updatePts(pts);
4618 return segment.verb() + 1;
4619 }
4620
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004621#if DEBUG_TEST
4622 SkTArray<Segment>& debugSegments() {
4623 return fSegments;
4624 }
4625#endif
4626
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004627#if DEBUG_DUMP
4628 void dump() {
4629 int i;
4630 const char className[] = "Contour";
4631 const int tab = 4;
4632 SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4633 for (i = 0; i < fSegments.count(); ++i) {
4634 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4635 className, i);
4636 fSegments[i].dump();
4637 }
4638 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4639 tab + sizeof(className), className,
4640 fBounds.fLeft, fBounds.fTop,
4641 fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004642 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4643 className, fContainsIntercepts);
4644 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4645 className, fContainsCurves);
4646 }
4647#endif
4648
caryclark@google.com027de222012-07-12 12:52:50 +00004649#if DEBUG_ACTIVE_SPANS
4650 void debugShowActiveSpans() {
4651 for (int index = 0; index < fSegments.count(); ++index) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004652 fSegments[index].debugShowActiveSpans();
caryclark@google.com027de222012-07-12 12:52:50 +00004653 }
4654 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004655
4656 void validateActiveSpans() {
4657 for (int index = 0; index < fSegments.count(); ++index) {
4658 fSegments[index].validateActiveSpans();
4659 }
4660 }
caryclark@google.com027de222012-07-12 12:52:50 +00004661#endif
4662
caryclark@google.com729e1c42012-11-21 21:36:34 +00004663#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004664 int debugShowWindingValues(int totalSegments, int ofInterest) {
4665 int count = fSegments.count();
4666 int sum = 0;
4667 for (int index = 0; index < count; ++index) {
4668 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4669 }
4670 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4671 return sum;
4672 }
4673
4674 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4675 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4676 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4677 int ofInterest = 1 << 5 | 1 << 8;
4678 int total = 0;
4679 int index;
4680 for (index = 0; index < contourList.count(); ++index) {
4681 total += contourList[index]->segments().count();
4682 }
4683 int sum = 0;
4684 for (index = 0; index < contourList.count(); ++index) {
4685 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4686 }
4687 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4688 }
4689#endif
4690
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004691protected:
4692 void setBounds() {
4693 int count = fSegments.count();
4694 if (count == 0) {
4695 SkDebugf("%s empty contour\n", __FUNCTION__);
4696 SkASSERT(0);
4697 // FIXME: delete empty contour?
4698 return;
4699 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004700 fBounds = fSegments.front().bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004701 for (int index = 1; index < count; ++index) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004702 fBounds.add(fSegments[index].bounds());
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004703 }
4704 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004705
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004706private:
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004707 SkTArray<Segment> fSegments;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004708 SkTDArray<Segment*> fSortedSegments;
4709 int fFirstSorted;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004710 SkTDArray<Coincidence> fCoincidences;
4711 SkTDArray<const Contour*> fCrosses;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004712 Bounds fBounds;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004713 bool fContainsIntercepts;
4714 bool fContainsCurves;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004715 bool fDone;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004716 bool fOperand; // true for the second argument to a binary operator
4717 bool fXor;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004718 bool fOppXor;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004719#if DEBUG_DUMP
4720 int fID;
4721#endif
4722};
4723
4724class EdgeBuilder {
4725public:
4726
caryclark@google.comf839c032012-10-26 21:03:50 +00004727EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
4728 : fPath(path.nativePath())
4729 , fContours(contours)
4730{
4731 init();
4732}
4733
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004734EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
caryclark@google.com235f56a2012-09-14 14:19:30 +00004735 : fPath(&path)
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004736 , fContours(contours)
4737{
caryclark@google.comf839c032012-10-26 21:03:50 +00004738 init();
4739}
4740
4741void init() {
4742 fCurrentContour = NULL;
4743 fOperand = false;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004744 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004745#if DEBUG_DUMP
4746 gContourID = 0;
4747 gSegmentID = 0;
4748#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00004749 fSecondHalf = preFetch();
4750}
4751
4752void addOperand(const SkPath& path) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00004753 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
4754 fPathVerbs.pop();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004755 fPath = &path;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004756 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004757 preFetch();
4758}
4759
4760void finish() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004761 walk();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004762 complete();
4763 if (fCurrentContour && !fCurrentContour->segments().count()) {
4764 fContours.pop_back();
4765 }
4766 // correct pointers in contours since fReducePts may have moved as it grew
4767 int cIndex = 0;
4768 int extraCount = fExtra.count();
4769 SkASSERT(extraCount == 0 || fExtra[0] == -1);
4770 int eIndex = 0;
4771 int rIndex = 0;
4772 while (++eIndex < extraCount) {
4773 int offset = fExtra[eIndex];
4774 if (offset < 0) {
4775 ++cIndex;
4776 continue;
4777 }
4778 fCurrentContour = &fContours[cIndex];
4779 rIndex += fCurrentContour->updateSegment(offset - 1,
4780 &fReducePts[rIndex]);
4781 }
4782 fExtra.reset(); // we're done with this
4783}
4784
4785ShapeOpMask xorMask() const {
caryclark@google.com729e1c42012-11-21 21:36:34 +00004786 return fXorMask[fOperand];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004787}
4788
4789protected:
4790
4791void complete() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004792 if (fCurrentContour && fCurrentContour->segments().count()) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004793 fCurrentContour->complete();
4794 fCurrentContour = NULL;
4795 }
4796}
4797
caryclark@google.com235f56a2012-09-14 14:19:30 +00004798// FIXME:remove once we can access path pts directly
4799int preFetch() {
4800 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004801 SkPoint pts[4];
4802 SkPath::Verb verb;
4803 do {
4804 verb = iter.next(pts);
4805 *fPathVerbs.append() = verb;
4806 if (verb == SkPath::kMove_Verb) {
4807 *fPathPts.append() = pts[0];
4808 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
4809 fPathPts.append(verb, &pts[1]);
4810 }
4811 } while (verb != SkPath::kDone_Verb);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004812 return fPathVerbs.count() - 1;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004813}
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004814
caryclark@google.com235f56a2012-09-14 14:19:30 +00004815void walk() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004816 SkPath::Verb reducedVerb;
4817 uint8_t* verbPtr = fPathVerbs.begin();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004818 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004819 const SkPoint* pointsPtr = fPathPts.begin();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004820 const SkPoint* finalCurveStart = NULL;
4821 const SkPoint* finalCurveEnd = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004822 SkPath::Verb verb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004823 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
4824 switch (verb) {
4825 case SkPath::kMove_Verb:
4826 complete();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004827 if (!fCurrentContour) {
4828 fCurrentContour = fContours.push_back_n(1);
caryclark@google.com235f56a2012-09-14 14:19:30 +00004829 fCurrentContour->setOperand(fOperand);
caryclark@google.com729e1c42012-11-21 21:36:34 +00004830 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004831 *fExtra.append() = -1; // start new contour
4832 }
caryclark@google.com59823f72012-08-09 18:17:47 +00004833 finalCurveEnd = pointsPtr++;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004834 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004835 case SkPath::kLine_Verb:
4836 // skip degenerate points
4837 if (pointsPtr[-1].fX != pointsPtr[0].fX
4838 || pointsPtr[-1].fY != pointsPtr[0].fY) {
4839 fCurrentContour->addLine(&pointsPtr[-1]);
4840 }
4841 break;
4842 case SkPath::kQuad_Verb:
rmistry@google.comd6176b02012-08-23 18:14:13 +00004843
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004844 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
4845 if (reducedVerb == 0) {
4846 break; // skip degenerate points
4847 }
4848 if (reducedVerb == 1) {
rmistry@google.comd6176b02012-08-23 18:14:13 +00004849 *fExtra.append() =
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004850 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004851 break;
4852 }
4853 fCurrentContour->addQuad(&pointsPtr[-1]);
4854 break;
4855 case SkPath::kCubic_Verb:
4856 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
4857 if (reducedVerb == 0) {
4858 break; // skip degenerate points
4859 }
4860 if (reducedVerb == 1) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004861 *fExtra.append() =
4862 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004863 break;
4864 }
4865 if (reducedVerb == 2) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004866 *fExtra.append() =
4867 fCurrentContour->addQuad(fReducePts.end() - 3);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004868 break;
4869 }
4870 fCurrentContour->addCubic(&pointsPtr[-1]);
4871 break;
4872 case SkPath::kClose_Verb:
4873 SkASSERT(fCurrentContour);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004874 if (finalCurveStart && finalCurveEnd
4875 && *finalCurveStart != *finalCurveEnd) {
4876 *fReducePts.append() = *finalCurveStart;
4877 *fReducePts.append() = *finalCurveEnd;
4878 *fExtra.append() =
4879 fCurrentContour->addLine(fReducePts.end() - 2);
4880 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004881 complete();
caryclark@google.com31143cf2012-11-09 22:14:19 +00004882 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004883 default:
4884 SkDEBUGFAIL("bad verb");
4885 return;
4886 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004887 finalCurveStart = &pointsPtr[verb - 1];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004888 pointsPtr += verb;
4889 SkASSERT(fCurrentContour);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004890 nextVerb:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004891 if (verbPtr == endOfFirstHalf) {
4892 fOperand = true;
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004893 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004894 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004895}
4896
4897private:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004898 const SkPath* fPath;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004899 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004900 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004901 Contour* fCurrentContour;
4902 SkTArray<Contour>& fContours;
4903 SkTDArray<SkPoint> fReducePts; // segments created on the fly
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004904 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
caryclark@google.com729e1c42012-11-21 21:36:34 +00004905 ShapeOpMask fXorMask[2];
caryclark@google.com235f56a2012-09-14 14:19:30 +00004906 int fSecondHalf;
4907 bool fOperand;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004908};
4909
4910class Work {
4911public:
4912 enum SegmentType {
4913 kHorizontalLine_Segment = -1,
4914 kVerticalLine_Segment = 0,
4915 kLine_Segment = SkPath::kLine_Verb,
4916 kQuad_Segment = SkPath::kQuad_Verb,
4917 kCubic_Segment = SkPath::kCubic_Verb,
4918 };
rmistry@google.comd6176b02012-08-23 18:14:13 +00004919
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004920 void addCoincident(Work& other, const Intersections& ts, bool swap) {
4921 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
4922 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004923
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004924 // FIXME: does it make sense to write otherIndex now if we're going to
4925 // fix it up later?
4926 void addOtherT(int index, double otherT, int otherIndex) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004927 fContour->addOtherT(fIndex, index, otherT, otherIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004928 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004929
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004930 // Avoid collapsing t values that are close to the same since
4931 // we walk ts to describe consecutive intersections. Since a pair of ts can
4932 // be nearly equal, any problems caused by this should be taken care
4933 // of later.
4934 // On the edge or out of range values are negative; add 2 to get end
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004935 int addT(double newT, const Work& other) {
4936 return fContour->addT(fIndex, newT, other.fContour, other.fIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004937 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004938
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004939 bool advance() {
4940 return ++fIndex < fLast;
4941 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004942
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004943 SkScalar bottom() const {
4944 return bounds().fBottom;
4945 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004946
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004947 const Bounds& bounds() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004948 return fContour->segments()[fIndex].bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004949 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004950
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004951 const SkPoint* cubic() const {
4952 return fCubic;
4953 }
4954
4955 void init(Contour* contour) {
4956 fContour = contour;
4957 fIndex = 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004958 fLast = contour->segments().count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004959 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004960
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00004961 bool isAdjacent(const Work& next) {
4962 return fContour == next.fContour && fIndex + 1 == next.fIndex;
4963 }
4964
4965 bool isFirstLast(const Work& next) {
4966 return fContour == next.fContour && fIndex == 0
4967 && next.fIndex == fLast - 1;
4968 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004969
4970 SkScalar left() const {
4971 return bounds().fLeft;
4972 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004973
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004974 void promoteToCubic() {
4975 fCubic[0] = pts()[0];
4976 fCubic[2] = pts()[1];
4977 fCubic[3] = pts()[2];
4978 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
4979 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
4980 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
4981 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
4982 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004983
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004984 const SkPoint* pts() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004985 return fContour->segments()[fIndex].pts();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004986 }
4987
4988 SkScalar right() const {
4989 return bounds().fRight;
4990 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004991
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004992 ptrdiff_t segmentIndex() const {
4993 return fIndex;
4994 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004995
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004996 SegmentType segmentType() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004997 const Segment& segment = fContour->segments()[fIndex];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004998 SegmentType type = (SegmentType) segment.verb();
4999 if (type != kLine_Segment) {
5000 return type;
5001 }
5002 if (segment.isHorizontal()) {
5003 return kHorizontalLine_Segment;
5004 }
5005 if (segment.isVertical()) {
5006 return kVerticalLine_Segment;
5007 }
5008 return kLine_Segment;
5009 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005010
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005011 bool startAfter(const Work& after) {
5012 fIndex = after.fIndex;
5013 return advance();
5014 }
5015
5016 SkScalar top() const {
5017 return bounds().fTop;
5018 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005019
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005020 SkPath::Verb verb() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005021 return fContour->segments()[fIndex].verb();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005022 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005023
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005024 SkScalar x() const {
5025 return bounds().fLeft;
5026 }
5027
5028 bool xFlipped() const {
5029 return x() != pts()[0].fX;
5030 }
5031
5032 SkScalar y() const {
5033 return bounds().fTop;
5034 }
5035
5036 bool yFlipped() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005037 return y() != pts()[0].fY;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005038 }
5039
5040protected:
5041 Contour* fContour;
5042 SkPoint fCubic[4];
5043 int fIndex;
5044 int fLast;
5045};
5046
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005047#if DEBUG_ADD_INTERSECTING_TS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005048static void debugShowLineIntersection(int pts, const Work& wt,
5049 const Work& wn, const double wtTs[2], const double wnTs[2]) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005050 return;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005051 if (!pts) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005052 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n",
5053 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
5054 wt.pts()[1].fX, wt.pts()[1].fY, wn.pts()[0].fX, wn.pts()[0].fY,
5055 wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005056 return;
5057 }
5058 SkPoint wtOutPt, wnOutPt;
5059 LineXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5060 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005061 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 +00005062 __FUNCTION__,
5063 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5064 wt.pts()[1].fX, wt.pts()[1].fY, wtOutPt.fX, wtOutPt.fY);
5065 if (pts == 2) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005066 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005067 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00005068 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005069 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5070 wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
5071 if (pts == 2) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005072 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
5073 }
5074 SkDebugf("\n");
5075}
5076
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005077static void debugShowQuadLineIntersection(int pts, const Work& wt,
5078 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5079 if (!pts) {
5080 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
caryclark@google.com0b7da432012-10-31 19:00:20 +00005081 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005082 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
5083 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005084 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005085 return;
5086 }
5087 SkPoint wtOutPt, wnOutPt;
5088 QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5089 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5090 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5091 __FUNCTION__,
5092 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5093 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
5094 wtOutPt.fX, wtOutPt.fY);
5095 if (pts == 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005096 QuadXYAtT(wt.pts(), wtTs[1], &wtOutPt);
5097 SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", wtTs[1], wtOutPt.fX, wtOutPt.fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005098 }
5099 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5100 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5101 wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
5102 if (pts == 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005103 LineXYAtT(wn.pts(), wnTs[1], &wnOutPt);
5104 SkDebugf(" wnTs[1]=%1.9g (%1.9g,%1.9g)", wnTs[1], wnOutPt.fX, wnOutPt.fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005105 }
5106 SkDebugf("\n");
5107}
5108
caryclark@google.coma461ff02012-10-11 12:54:23 +00005109static void debugShowQuadIntersection(int pts, const Work& wt,
5110 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5111 if (!pts) {
5112 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5113 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5114 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
skia.committer@gmail.com5b6f9162012-10-12 02:01:15 +00005115 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.coma461ff02012-10-11 12:54:23 +00005116 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005117 wn.pts()[2].fX, wn.pts()[2].fY );
caryclark@google.coma461ff02012-10-11 12:54:23 +00005118 return;
5119 }
5120 SkPoint wtOutPt, wnOutPt;
5121 QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5122 QuadXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5123 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5124 __FUNCTION__,
5125 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5126 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
5127 wtOutPt.fX, wtOutPt.fY);
5128 if (pts == 2) {
5129 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
5130 }
5131 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5132 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5133 wn.pts()[1].fX, wn.pts()[1].fY, wn.pts()[2].fX, wn.pts()[2].fY,
5134 wnOutPt.fX, wnOutPt.fY);
5135 if (pts == 2) {
5136 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005137 }
caryclark@google.comb9738012012-07-03 19:53:30 +00005138 SkDebugf("\n");
5139}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005140#else
5141static void debugShowLineIntersection(int , const Work& ,
5142 const Work& , const double [2], const double [2]) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005143}
caryclark@google.coma461ff02012-10-11 12:54:23 +00005144
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005145static void debugShowQuadLineIntersection(int , const Work& ,
5146 const Work& , const double [2], const double [2]) {
5147}
5148
caryclark@google.coma461ff02012-10-11 12:54:23 +00005149static void debugShowQuadIntersection(int , const Work& ,
5150 const Work& , const double [2], const double [2]) {
5151}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005152#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005153
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005154static bool addIntersectTs(Contour* test, Contour* next) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005155
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005156 if (test != next) {
5157 if (test->bounds().fBottom < next->bounds().fTop) {
5158 return false;
5159 }
5160 if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5161 return true;
5162 }
5163 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005164 Work wt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005165 wt.init(test);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005166 bool foundCommonContour = test == next;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005167 do {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005168 Work wn;
5169 wn.init(next);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005170 if (test == next && !wn.startAfter(wt)) {
5171 continue;
5172 }
5173 do {
5174 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5175 continue;
5176 }
5177 int pts;
5178 Intersections ts;
5179 bool swap = false;
5180 switch (wt.segmentType()) {
5181 case Work::kHorizontalLine_Segment:
5182 swap = true;
5183 switch (wn.segmentType()) {
5184 case Work::kHorizontalLine_Segment:
5185 case Work::kVerticalLine_Segment:
5186 case Work::kLine_Segment: {
5187 pts = HLineIntersect(wn.pts(), wt.left(),
5188 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005189 debugShowLineIntersection(pts, wt, wn,
5190 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005191 break;
5192 }
5193 case Work::kQuad_Segment: {
5194 pts = HQuadIntersect(wn.pts(), wt.left(),
5195 wt.right(), wt.y(), wt.xFlipped(), ts);
5196 break;
5197 }
5198 case Work::kCubic_Segment: {
5199 pts = HCubicIntersect(wn.pts(), wt.left(),
5200 wt.right(), wt.y(), wt.xFlipped(), ts);
5201 break;
5202 }
5203 default:
5204 SkASSERT(0);
5205 }
5206 break;
5207 case Work::kVerticalLine_Segment:
5208 swap = true;
5209 switch (wn.segmentType()) {
5210 case Work::kHorizontalLine_Segment:
5211 case Work::kVerticalLine_Segment:
5212 case Work::kLine_Segment: {
5213 pts = VLineIntersect(wn.pts(), wt.top(),
5214 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005215 debugShowLineIntersection(pts, wt, wn,
5216 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005217 break;
5218 }
5219 case Work::kQuad_Segment: {
5220 pts = VQuadIntersect(wn.pts(), wt.top(),
5221 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5222 break;
5223 }
5224 case Work::kCubic_Segment: {
5225 pts = VCubicIntersect(wn.pts(), wt.top(),
5226 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5227 break;
5228 }
5229 default:
5230 SkASSERT(0);
5231 }
5232 break;
5233 case Work::kLine_Segment:
5234 switch (wn.segmentType()) {
5235 case Work::kHorizontalLine_Segment:
5236 pts = HLineIntersect(wt.pts(), wn.left(),
5237 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005238 debugShowLineIntersection(pts, wt, wn,
5239 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005240 break;
5241 case Work::kVerticalLine_Segment:
5242 pts = VLineIntersect(wt.pts(), wn.top(),
5243 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005244 debugShowLineIntersection(pts, wt, wn,
5245 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005246 break;
5247 case Work::kLine_Segment: {
5248 pts = LineIntersect(wt.pts(), wn.pts(), ts);
5249 debugShowLineIntersection(pts, wt, wn,
5250 ts.fT[1], ts.fT[0]);
5251 break;
5252 }
5253 case Work::kQuad_Segment: {
5254 swap = true;
5255 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005256 debugShowQuadLineIntersection(pts, wn, wt,
5257 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005258 break;
5259 }
5260 case Work::kCubic_Segment: {
5261 swap = true;
5262 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
5263 break;
5264 }
5265 default:
5266 SkASSERT(0);
5267 }
5268 break;
5269 case Work::kQuad_Segment:
5270 switch (wn.segmentType()) {
5271 case Work::kHorizontalLine_Segment:
5272 pts = HQuadIntersect(wt.pts(), wn.left(),
5273 wn.right(), wn.y(), wn.xFlipped(), ts);
5274 break;
5275 case Work::kVerticalLine_Segment:
5276 pts = VQuadIntersect(wt.pts(), wn.top(),
5277 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5278 break;
5279 case Work::kLine_Segment: {
5280 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005281 debugShowQuadLineIntersection(pts, wt, wn,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005282 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005283 break;
5284 }
5285 case Work::kQuad_Segment: {
5286 pts = QuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005287 debugShowQuadIntersection(pts, wt, wn,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005288 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005289 break;
5290 }
5291 case Work::kCubic_Segment: {
5292 wt.promoteToCubic();
5293 pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
5294 break;
5295 }
5296 default:
5297 SkASSERT(0);
5298 }
5299 break;
5300 case Work::kCubic_Segment:
5301 switch (wn.segmentType()) {
5302 case Work::kHorizontalLine_Segment:
5303 pts = HCubicIntersect(wt.pts(), wn.left(),
5304 wn.right(), wn.y(), wn.xFlipped(), ts);
5305 break;
5306 case Work::kVerticalLine_Segment:
5307 pts = VCubicIntersect(wt.pts(), wn.top(),
5308 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5309 break;
5310 case Work::kLine_Segment: {
5311 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
5312 break;
5313 }
5314 case Work::kQuad_Segment: {
5315 wn.promoteToCubic();
5316 pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
5317 break;
5318 }
5319 case Work::kCubic_Segment: {
5320 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
5321 break;
5322 }
5323 default:
5324 SkASSERT(0);
5325 }
5326 break;
5327 default:
5328 SkASSERT(0);
5329 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005330 if (!foundCommonContour && pts > 0) {
5331 test->addCross(next);
5332 next->addCross(test);
5333 foundCommonContour = true;
5334 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005335 // in addition to recording T values, record matching segment
caryclark@google.com32546db2012-08-31 20:55:07 +00005336 if (pts == 2) {
5337 if (wn.segmentType() <= Work::kLine_Segment
5338 && wt.segmentType() <= Work::kLine_Segment) {
5339 wt.addCoincident(wn, ts, swap);
5340 continue;
5341 }
5342 if (wn.segmentType() == Work::kQuad_Segment
5343 && wt.segmentType() == Work::kQuad_Segment
5344 && ts.coincidentUsed() == 2) {
5345 wt.addCoincident(wn, ts, swap);
5346 continue;
5347 }
5348
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00005349 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00005350 for (int pt = 0; pt < pts; ++pt) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005351 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5352 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005353 int testTAt = wt.addT(ts.fT[swap][pt], wn);
5354 int nextTAt = wn.addT(ts.fT[!swap][pt], wt);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005355 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
5356 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005357 }
5358 } while (wn.advance());
5359 } while (wt.advance());
5360 return true;
5361}
5362
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005363// resolve any coincident pairs found while intersecting, and
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005364// see if coincidence is formed by clipping non-concident segments
caryclark@google.com4eeda372012-12-06 21:47:48 +00005365static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005366 int contourCount = contourList.count();
caryclark@google.comf25edfe2012-06-01 18:20:10 +00005367 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005368 Contour* contour = contourList[cIndex];
caryclark@google.com7ba591e2012-11-20 14:21:54 +00005369 contour->resolveCoincidence(contourList);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005370 }
5371 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5372 Contour* contour = contourList[cIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00005373 contour->findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005374 }
5375}
5376
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005377static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005378 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005379 SkPoint basePt;
5380 current->xyAtT(index, endIndex, mid, basePt);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005381 int contourCount = contourList.count();
5382 SkScalar bestY = SK_ScalarMin;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005383 Segment* bestSeg = NULL;
5384 int bestTIndex;
5385 bool bestOpp;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005386 bool hitSomething = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005387 for (int cTest = 0; cTest < contourCount; ++cTest) {
5388 Contour* contour = contourList[cTest];
5389 bool testOpp = contour->operand() ^ current->operand() ^ opp;
5390 if (basePt.fY < contour->bounds().fTop) {
5391 continue;
5392 }
5393 if (bestY > contour->bounds().fBottom) {
5394 continue;
5395 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005396 int segmentCount = contour->segments().count();
5397 for (int test = 0; test < segmentCount; ++test) {
5398 Segment* testSeg = &contour->segments()[test];
5399 SkScalar testY = bestY;
5400 double testHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005401 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, testOpp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005402 if (testTIndex < 0) {
5403 continue;
5404 }
5405 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005406 double baseT = current->t(index);
5407 double endT = current->t(endIndex);
5408 double newMid = (testHit - baseT) / (endT - baseT);
5409#if DEBUG_WINDING
5410 SkPoint midXY, newXY;
5411 current->xyAtT(index, endIndex, mid, midXY);
5412 current->xyAtT(index, endIndex, newMid, newXY);
5413 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
5414 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
5415 current->debugID(), mid, newMid,
5416 baseT, current->xAtT(index), current->yAtT(index),
5417 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
5418 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
5419 endT, current->xAtT(endIndex), current->yAtT(endIndex));
5420#endif
5421 mid = newMid * 2; // calling loop with divide by 2 before continuing
5422 return SK_MinS32;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005423 }
5424 bestSeg = testSeg;
5425 bestHit = testHit;
5426 bestOpp = testOpp;
5427 bestTIndex = testTIndex;
5428 bestY = testY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005429 }
5430 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005431 if (!bestSeg) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005432 return hitSomething ? SK_MinS32 : 0;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005433 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005434 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
5435 current = bestSeg;
5436 index = bestTIndex;
5437 endIndex = bestSeg->nextSpan(bestTIndex, 1);
5438 tryAgain = true;
5439 return 0;
5440 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005441 int tryAnother = bestSeg->windingAtTX(bestHit, bestTIndex, bestOpp);
caryclark@google.com3586ece2012-12-27 18:46:58 +00005442 int result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005443 if (result != tryAnother) {
5444 SkDebugf("%s result=%d tryAnother=%d\n", __FUNCTION__, result,
5445 tryAnother);
5446 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005447 double baseT = current->t(index);
5448 double endT = current->t(endIndex);
5449 bestHit = baseT + mid * (endT - baseT);
5450 SkASSERT(bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005451 return result;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005452}
5453
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005454// project a ray from the top of the contour up and see if it hits anything
5455// note: when we compute line intersections, we keep track of whether
5456// two contours touch, so we need only look at contours not touching this one.
5457// OPTIMIZATION: sort contourList vertically to avoid linear walk
caryclark@google.com3586ece2012-12-27 18:46:58 +00005458#if 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005459static int innerContourCheck(SkTDArray<Contour*>& contourList,
caryclark@google.com31143cf2012-11-09 22:14:19 +00005460 const Segment* current, int index, int endIndex, bool opp) {
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00005461 const SkPoint& basePt = current->xyAtT(endIndex);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005462 int contourCount = contourList.count();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005463 SkScalar bestY = SK_ScalarMin;
caryclark@google.com47580692012-07-23 12:14:49 +00005464 const Segment* test = NULL;
5465 int tIndex;
5466 double tHit;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005467 bool crossOpp;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005468 for (int cTest = 0; cTest < contourCount; ++cTest) {
5469 Contour* contour = contourList[cTest];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005470 bool testOpp = contour->operand() ^ current->operand() ^ opp;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005471 if (basePt.fY < contour->bounds().fTop) {
5472 continue;
5473 }
5474 if (bestY > contour->bounds().fBottom) {
5475 continue;
5476 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005477 const Segment* next = contour->crossedSegmentY(basePt, bestY, tIndex, tHit, testOpp);
caryclark@google.com47580692012-07-23 12:14:49 +00005478 if (next) {
5479 test = next;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005480 crossOpp = testOpp;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005481 }
caryclark@google.com47580692012-07-23 12:14:49 +00005482 }
5483 if (!test) {
caryclark@google.com47580692012-07-23 12:14:49 +00005484 return 0;
5485 }
5486 int winding, windValue;
5487 // If the ray hit the end of a span, we need to construct the wheel of
5488 // angles to find the span closest to the ray -- even if there are just
5489 // two spokes on the wheel.
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005490 const Angle* angle = NULL;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00005491 if (approximately_zero(tHit - test->t(tIndex))) {
caryclark@google.com47580692012-07-23 12:14:49 +00005492 SkTDArray<Angle> angles;
5493 int end = test->nextSpan(tIndex, 1);
5494 if (end < 0) {
5495 end = test->nextSpan(tIndex, -1);
5496 }
5497 test->addTwoAngles(end, tIndex, angles);
caryclark@google.com59823f72012-08-09 18:17:47 +00005498 SkASSERT(angles.count() > 0);
5499 if (angles[0].segment()->yAtT(angles[0].start()) >= basePt.fY) {
5500#if DEBUG_SORT
caryclark@google.com24bec792012-08-20 12:43:57 +00005501 SkDebugf("%s early return\n", __FUNCTION__);
caryclark@google.com59823f72012-08-09 18:17:47 +00005502#endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005503 return SK_MinS32;
caryclark@google.com59823f72012-08-09 18:17:47 +00005504 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00005505 test->buildAngles(tIndex, angles, false);
caryclark@google.com47580692012-07-23 12:14:49 +00005506 SkTDArray<Angle*> sorted;
rmistry@google.comd6176b02012-08-23 18:14:13 +00005507 // OPTIMIZATION: call a sort that, if base point is the leftmost,
caryclark@google.com47580692012-07-23 12:14:49 +00005508 // returns the first counterclockwise hour before 6 o'clock,
rmistry@google.comd6176b02012-08-23 18:14:13 +00005509 // or if the base point is rightmost, returns the first clockwise
caryclark@google.com47580692012-07-23 12:14:49 +00005510 // hour after 6 o'clock
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005511 bool sortable = Segment::SortAngles(angles, sorted);
5512 if (!sortable) {
5513 return SK_MinS32;
5514 }
caryclark@google.com47580692012-07-23 12:14:49 +00005515#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005516 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com47580692012-07-23 12:14:49 +00005517#endif
5518 // walk the sorted angle fan to find the lowest angle
5519 // above the base point. Currently, the first angle in the sorted array
5520 // is 12 noon or an earlier hour (the next counterclockwise)
5521 int count = sorted.count();
5522 int left = -1;
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00005523 int mid = -1;
caryclark@google.com47580692012-07-23 12:14:49 +00005524 int right = -1;
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00005525 bool baseMatches = test->yAtT(tIndex) == basePt.fY;
caryclark@google.com47580692012-07-23 12:14:49 +00005526 for (int index = 0; index < count; ++index) {
caryclark@google.com59823f72012-08-09 18:17:47 +00005527 angle = sorted[index];
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005528 if (angle->unsortable()) {
5529 continue;
5530 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00005531 if (baseMatches && angle->isHorizontal()) {
5532 continue;
5533 }
5534 double indexDx = angle->dx();
caryclark@google.comd1688742012-09-18 20:08:37 +00005535 test = angle->segment();
5536 if (test->verb() > SkPath::kLine_Verb && approximately_zero(indexDx)) {
5537 const SkPoint* pts = test->pts();
5538 indexDx = pts[2].fX - pts[1].fX - indexDx;
5539 }
caryclark@google.com47580692012-07-23 12:14:49 +00005540 if (indexDx < 0) {
5541 left = index;
5542 } else if (indexDx > 0) {
5543 right = index;
caryclark@google.com59823f72012-08-09 18:17:47 +00005544 int previous = index - 1;
5545 if (previous < 0) {
5546 previous = count - 1;
5547 }
5548 const Angle* prev = sorted[previous];
5549 if (prev->dy() >= 0 && prev->dx() > 0 && angle->dy() < 0) {
5550#if DEBUG_SORT
5551 SkDebugf("%s use prev\n", __FUNCTION__);
5552#endif
5553 right = previous;
5554 }
caryclark@google.com47580692012-07-23 12:14:49 +00005555 break;
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00005556 } else {
5557 mid = index;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005558 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005559 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005560 if ((left < 0 || right < 0) && mid >= 0) {
5561 angle = sorted[mid];
5562 Segment* midSeg = angle->segment();
5563 int end = angle->end();
5564 if (midSeg->unsortable(end)) {
5565 return SK_MinS32;
5566 }
5567 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00005568 if (left < 0 && right < 0) {
5569 left = mid;
5570 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005571 if (left < 0 && right < 0) {
5572 SkASSERT(0);
5573 return SK_MinS32; // unsortable
5574 }
caryclark@google.com47580692012-07-23 12:14:49 +00005575 if (left < 0) {
5576 left = right;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005577 } else if (left >= 0 && mid >= 0 && right >= 0
5578 && sorted[mid]->sign() == sorted[right]->sign()) {
5579 left = right;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005580 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005581 angle = sorted[left];
caryclark@google.com47580692012-07-23 12:14:49 +00005582 test = angle->segment();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005583 winding = crossOpp ? test->oppSum(angle) : test->windSum(angle);
caryclark@google.come21cb182012-07-23 21:26:31 +00005584 SkASSERT(winding != SK_MinS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005585 windValue = crossOpp ? test->oppValue(angle) : test->windValue(angle);
caryclark@google.com47580692012-07-23 12:14:49 +00005586#if DEBUG_WINDING
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005587 SkDebugf("%s angle winding=%d windValue=%d sign=%d\n", __FUNCTION__, winding,
5588 windValue, angle->sign());
caryclark@google.com47580692012-07-23 12:14:49 +00005589#endif
5590 } else {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005591 // start here;
5592 /*
5593 FIXME: fails because the span found by findTop is not the span closest to vertical
5594 intersecting the found point. Because the most vertical span could be done, and the
5595 span found undone, findTop should not be changed. Instead, the spans at the found
5596 point need to be sorted again, and the winding found below needs to be adjusted by
5597 the span signs of the spans walking from vertical to the findTop span
5598 findTop could but probably shouldn't compute this adjustment, since if the found span
5599 already has computed winding, we won't get to innerContourCheck --
5600 best solution -- findTop could check to see if found span already has computed winding
5601 before returning adjustment
5602 */
5603 #if 0
5604 int windingTx = test->windingAtTX(tHit, tIndex, crossOpp);
5605 SkScalar dx;
5606 int windingT = test->windingAtT(tHit, tIndex, crossOpp, dx);
5607 SkDebugf("%s windingTx=%d windingT=%d\n", __FUNCTION__, windingTx, windingT);
5608 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005609 winding = crossOpp ? test->oppSum(tIndex) : test->windSum(tIndex);
5610 if (winding == SK_MinS32) {
5611 return SK_MinS32; // unsortable
5612 }
5613 windValue = crossOpp ? test->oppValue(tIndex) : test->windValue(tIndex);
caryclark@google.com47580692012-07-23 12:14:49 +00005614#if DEBUG_WINDING
5615 SkDebugf("%s single winding=%d windValue=%d\n", __FUNCTION__, winding,
5616 windValue);
5617#endif
5618 }
5619 // see if a + change in T results in a +/- change in X (compute x'(T))
5620 SkScalar dx = (*SegmentDXAtT[test->verb()])(test->pts(), tHit);
caryclark@google.comd1688742012-09-18 20:08:37 +00005621 if (test->verb() > SkPath::kLine_Verb && approximately_zero(dx)) {
5622 const SkPoint* pts = test->pts();
5623 dx = pts[2].fX - pts[1].fX - dx;
5624 }
caryclark@google.com47580692012-07-23 12:14:49 +00005625#if DEBUG_WINDING
caryclark@google.com3586ece2012-12-27 18:46:58 +00005626 SkDebugf("%s dx=%1.9g winding=%d\n", __FUNCTION__, dx, winding);
caryclark@google.com47580692012-07-23 12:14:49 +00005627#endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00005628 SkASSERT(dx != 0);
5629 if (winding * dx > 0) { // if same signs, result is negative
caryclark@google.com47580692012-07-23 12:14:49 +00005630 winding += dx > 0 ? -windValue : windValue;
5631#if DEBUG_WINDING
5632 SkDebugf("%s final winding=%d\n", __FUNCTION__, winding);
5633#endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005634 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005635 return winding;
5636}
caryclark@google.com3586ece2012-12-27 18:46:58 +00005637#endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00005638
caryclark@google.com24bec792012-08-20 12:43:57 +00005639static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
5640 int contourCount = contourList.count();
5641 Segment* result;
5642 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5643 Contour* contour = contourList[cIndex];
5644 result = contour->undoneSegment(start, end);
5645 if (result) {
5646 return result;
5647 }
5648 }
5649 return NULL;
5650}
5651
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005652#define OLD_FIND_CHASE 1
caryclark@google.com24bec792012-08-20 12:43:57 +00005653
caryclark@google.com31143cf2012-11-09 22:14:19 +00005654static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005655 while (chase.count()) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005656 Span* span;
5657 chase.pop(&span);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005658 const Span& backPtr = span->fOther->span(span->fOtherIndex);
5659 Segment* segment = backPtr.fOther;
5660 tIndex = backPtr.fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005661 SkTDArray<Angle> angles;
5662 int done = 0;
5663 if (segment->activeAngle(tIndex, done, angles)) {
5664 Angle* last = angles.end() - 1;
5665 tIndex = last->start();
5666 endIndex = last->end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005667 #if TRY_ROTATE
5668 *chase.insert(0) = span;
5669 #else
5670 *chase.append() = span;
5671 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005672 return last->segment();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005673 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005674 if (done == angles.count()) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00005675 continue;
5676 }
5677 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005678 bool sortable = Segment::SortAngles(angles, sorted);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005679 int angleCount = sorted.count();
caryclark@google.com03f97062012-08-21 13:13:52 +00005680#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005681 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00005682#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005683 if (!sortable) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005684 continue;
5685 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005686 // find first angle, initialize winding to computed fWindSum
5687 int firstIndex = -1;
5688 const Angle* angle;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005689#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005690 int winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005691 do {
5692 angle = sorted[++firstIndex];
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005693 segment = angle->segment();
5694 winding = segment->windSum(angle);
5695 } while (winding == SK_MinS32);
5696 int spanWinding = segment->spanSign(angle->start(), angle->end());
5697 #if DEBUG_WINDING
caryclark@google.com31143cf2012-11-09 22:14:19 +00005698 SkDebugf("%s winding=%d spanWinding=%d\n",
5699 __FUNCTION__, winding, spanWinding);
caryclark@google.com47580692012-07-23 12:14:49 +00005700 #endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005701 // turn span winding into contour winding
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005702 if (spanWinding * winding < 0) {
5703 winding += spanWinding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005704 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005705 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005706 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005707 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005708 // we care about first sign and whether wind sum indicates this
5709 // edge is inside or outside. Maybe need to pass span winding
5710 // or first winding or something into this function?
5711 // advance to first undone angle, then return it and winding
5712 // (to set whether edges are active or not)
5713 int nextIndex = firstIndex + 1;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005714 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005715 angle = sorted[firstIndex];
caryclark@google.com2ddff932012-08-07 21:25:27 +00005716 winding -= angle->segment()->spanSign(angle);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005717#else
5718 do {
5719 angle = sorted[++firstIndex];
5720 segment = angle->segment();
5721 } while (segment->windSum(angle) == SK_MinS32);
5722 #if DEBUG_SORT
5723 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5724 #endif
5725 int sumWinding = segment->updateWindingReverse(angle);
5726 int nextIndex = firstIndex + 1;
5727 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5728 Segment* first = NULL;
5729#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005730 do {
5731 SkASSERT(nextIndex != firstIndex);
5732 if (nextIndex == angleCount) {
5733 nextIndex = 0;
5734 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005735 angle = sorted[nextIndex];
caryclark@google.com9764cc62012-07-12 19:29:45 +00005736 segment = angle->segment();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005737#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005738 int maxWinding = winding;
caryclark@google.com2ddff932012-08-07 21:25:27 +00005739 winding -= segment->spanSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005740 #if DEBUG_SORT
caryclark@google.com2ddff932012-08-07 21:25:27 +00005741 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
5742 segment->debugID(), maxWinding, winding, angle->sign());
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005743 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005744 tIndex = angle->start();
5745 endIndex = angle->end();
5746 int lesser = SkMin32(tIndex, endIndex);
5747 const Span& nextSpan = segment->span(lesser);
5748 if (!nextSpan.fDone) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005749#if 1
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005750 // FIXME: this be wrong? assign startWinding if edge is in
caryclark@google.com9764cc62012-07-12 19:29:45 +00005751 // same direction. If the direction is opposite, winding to
5752 // assign is flipped sign or +/- 1?
caryclark@google.com59823f72012-08-09 18:17:47 +00005753 if (useInnerWinding(maxWinding, winding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005754 maxWinding = winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005755 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005756 segment->markAndChaseWinding(angle, maxWinding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005757#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005758 break;
5759 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005760#else
5761 int start = angle->start();
5762 int end = angle->end();
5763 int maxWinding;
5764 segment->setUpWinding(start, end, maxWinding, sumWinding);
5765 if (!segment->done(angle)) {
5766 if (!first) {
5767 first = segment;
5768 tIndex = start;
5769 endIndex = end;
5770 }
5771 (void) segment->markAngle(maxWinding, sumWinding, true, angle);
5772 }
5773#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005774 } while (++nextIndex != lastIndex);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005775 #if TRY_ROTATE
5776 *chase.insert(0) = span;
5777 #else
5778 *chase.append() = span;
5779 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005780 return segment;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005781 }
5782 return NULL;
5783}
5784
caryclark@google.com027de222012-07-12 12:52:50 +00005785#if DEBUG_ACTIVE_SPANS
5786static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005787 int index;
5788 for (index = 0; index < contourList.count(); ++ index) {
caryclark@google.com027de222012-07-12 12:52:50 +00005789 contourList[index]->debugShowActiveSpans();
5790 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005791 for (index = 0; index < contourList.count(); ++ index) {
5792 contourList[index]->validateActiveSpans();
5793 }
caryclark@google.com027de222012-07-12 12:52:50 +00005794}
5795#endif
5796
caryclark@google.com3586ece2012-12-27 18:46:58 +00005797#if 0
caryclark@google.com27c449a2012-07-27 18:26:38 +00005798static bool windingIsActive(int winding, int spanWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00005799 // FIXME: !spanWinding test must be superflorous, true?
caryclark@google.com27c449a2012-07-27 18:26:38 +00005800 return winding * spanWinding <= 0 && abs(winding) <= abs(spanWinding)
5801 && (!winding || !spanWinding || winding == -spanWinding);
5802}
caryclark@google.com3586ece2012-12-27 18:46:58 +00005803#endif
caryclark@google.com27c449a2012-07-27 18:26:38 +00005804
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005805static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005806 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005807 Segment* result;
5808 do {
caryclark@google.comf839c032012-10-26 21:03:50 +00005809 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005810 int contourCount = contourList.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00005811 Segment* topStart = NULL;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005812 done = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00005813 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5814 Contour* contour = contourList[cIndex];
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005815 if (contour->done()) {
5816 continue;
5817 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005818 const Bounds& bounds = contour->bounds();
5819 if (bounds.fBottom < topLeft.fY) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005820 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005821 continue;
5822 }
5823 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005824 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005825 continue;
5826 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005827 contour->topSortableSegment(topLeft, bestXY, topStart);
5828 if (!contour->done()) {
5829 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005830 }
5831 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005832 if (!topStart) {
5833 return NULL;
5834 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005835 topLeft = bestXY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005836 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005837 } while (!result);
5838 return result;
5839}
caryclark@google.com31143cf2012-11-09 22:14:19 +00005840
caryclark@google.com3586ece2012-12-27 18:46:58 +00005841#if 0
caryclark@google.com57cff8d2012-11-14 21:14:56 +00005842static int updateWindings(const Segment* current, int index, int endIndex, int& spanWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00005843 int lesser = SkMin32(index, endIndex);
5844 spanWinding = current->spanSign(index, endIndex);
5845 int winding = current->windSum(lesser);
5846 bool inner = useInnerWinding(winding - spanWinding, winding);
5847#if DEBUG_WINDING
5848 SkDebugf("%s id=%d t=%1.9g spanWinding=%d winding=%d sign=%d"
5849 " inner=%d result=%d\n",
5850 __FUNCTION__, current->debugID(), current->t(lesser),
5851 spanWinding, winding, SkSign32(index - endIndex),
5852 useInnerWinding(winding - spanWinding, winding),
5853 inner ? winding - spanWinding : winding);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005854#endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005855 if (inner) {
5856 winding -= spanWinding;
5857 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00005858 return winding;
5859}
caryclark@google.com3586ece2012-12-27 18:46:58 +00005860#endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005861
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005862static int rightAngleWinding(SkTDArray<Contour*>& contourList,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005863 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005864 bool opp) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005865 double test = 0.9;
5866 int contourWinding;
5867 do {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005868 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
5869 tryAgain, test, opp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005870 if (contourWinding != SK_MinS32 || tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005871 return contourWinding;
5872 }
5873 test /= 2;
5874 } while (!approximately_negative(test));
5875 SkASSERT(0); // should be OK to comment out, but interested when this hits
5876 return contourWinding;
5877}
5878
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005879static void skipVertical(SkTDArray<Contour*>& contourList,
5880 Segment*& current, int& index, int& endIndex) {
5881 if (!current->isVertical(index, endIndex)) {
5882 return;
5883 }
5884 int contourCount = contourList.count();
5885 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5886 Contour* contour = contourList[cIndex];
5887 if (contour->done()) {
5888 continue;
5889 }
5890 current = contour->nonVerticalSegment(index, endIndex);
5891 if (current) {
5892 return;
5893 }
5894 }
5895}
5896
caryclark@google.com3586ece2012-12-27 18:46:58 +00005897static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005898 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
5899 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
5900 true);
5901 if (!current) {
5902 return NULL;
5903 }
5904 if (firstContour) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005905 current->initWinding(index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005906 firstContour = false;
5907 return current;
5908 }
5909 int minIndex = SkMin32(index, endIndex);
5910 int sumWinding = current->windSum(minIndex);
5911 if (sumWinding != SK_MinS32) {
5912 return current;
5913 }
5914 sumWinding = current->computeSum(index, endIndex, binary);
5915 if (sumWinding != SK_MinS32) {
5916 return current;
5917 }
5918 int contourWinding;
5919 int oppContourWinding = 0;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005920#if 0
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005921 contourWinding = innerContourCheck(contourList, current, index, endIndex, false);
5922 if (contourWinding != SK_MinS32) {
5923 if (binary) {
5924 oppContourWinding = innerContourCheck(contourList, current, index, endIndex, true);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005925 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005926 if (!binary || oppContourWinding != SK_MinS32) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005927 current->initWinding(index, endIndex, contourWinding, oppContourWinding);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005928 return current;
5929 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005930 }
5931#endif
5932 // the simple upward projection of the unresolved points hit unsortable angles
5933 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005934 bool tryAgain;
5935 double tHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005936 SkScalar hitDx = 0;
5937 SkScalar hitOppDx = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005938 do {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005939 // if current is vertical, find another candidate which is not
5940 // if only remaining candidates are vertical, then they can be marked done
5941 skipVertical(contourList, current, index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005942 tryAgain = false;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005943 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005944 tryAgain, false);
5945 if (tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005946 continue;
5947 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005948 if (!binary) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005949 break;
5950 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005951 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005952 tryAgain, true);
5953 } while (tryAgain);
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00005954
caryclark@google.com3586ece2012-12-27 18:46:58 +00005955 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005956 return current;
5957}
5958
5959// rewrite that abandons keeping local track of winding
caryclark@google.com3586ece2012-12-27 18:46:58 +00005960static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005961 bool firstContour = true;
5962 bool unsortable = false;
5963 bool topUnsortable = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005964 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
5965 do {
5966 int index, endIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005967 bool topDone;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005968 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005969 topUnsortable, topDone, false);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005970 if (!current) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005971 if (topUnsortable || !topDone) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005972 topUnsortable = false;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005973 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005974 topLeft.fX = topLeft.fY = SK_ScalarMin;
5975 continue;
5976 }
5977 break;
5978 }
5979 SkTDArray<Span*> chaseArray;
5980 do {
5981 if (current->activeWinding(index, endIndex)) {
5982 do {
5983 #if DEBUG_ACTIVE_SPANS
5984 if (!unsortable && current->done()) {
5985 debugShowActiveSpans(contourList);
5986 }
5987 #endif
5988 SkASSERT(unsortable || !current->done());
5989 int nextStart = index;
5990 int nextEnd = endIndex;
5991 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
5992 unsortable);
5993 if (!next) {
5994 if (!unsortable && simple.hasMove()
5995 && current->verb() != SkPath::kLine_Verb
5996 && !simple.isClosed()) {
5997 current->addCurveTo(index, endIndex, simple, true);
5998 SkASSERT(simple.isClosed());
5999 }
6000 break;
6001 }
6002 current->addCurveTo(index, endIndex, simple, true);
6003 current = next;
6004 index = nextStart;
6005 endIndex = nextEnd;
6006 } while (!simple.isClosed() && ((!unsortable) || !current->done()));
6007 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
6008 SkASSERT(unsortable);
6009 int min = SkMin32(index, endIndex);
6010 if (!current->done(min)) {
6011 current->addCurveTo(index, endIndex, simple, true);
6012 current->markDoneUnary(min);
6013 }
6014 }
6015 simple.close();
6016 } else {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006017 Span* last = current->markAndChaseDoneUnary(index, endIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006018 if (last) {
6019 *chaseArray.append() = last;
6020 }
6021 }
6022 current = findChase(chaseArray, index, endIndex);
6023 #if DEBUG_ACTIVE_SPANS
6024 debugShowActiveSpans(contourList);
6025 #endif
6026 if (!current) {
6027 break;
6028 }
6029 } while (true);
6030 } while (true);
6031 return simple.someAssemblyRequired();
6032}
6033
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006034// returns true if all edges were processed
caryclark@google.comf839c032012-10-26 21:03:50 +00006035static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006036 Segment* current;
6037 int start, end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006038 bool unsortable = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006039 bool closable = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00006040 while ((current = findUndone(contourList, start, end))) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006041 do {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006042 SkASSERT(unsortable || !current->done());
caryclark@google.com24bec792012-08-20 12:43:57 +00006043 int nextStart = start;
6044 int nextEnd = end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006045 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
caryclark@google.com24bec792012-08-20 12:43:57 +00006046 if (!next) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006047 if (!unsortable && simple.hasMove()
caryclark@google.comf839c032012-10-26 21:03:50 +00006048 && current->verb() != SkPath::kLine_Verb
6049 && !simple.isClosed()) {
6050 current->addCurveTo(start, end, simple, true);
6051 SkASSERT(simple.isClosed());
caryclark@google.comc899ad92012-08-23 15:24:42 +00006052 }
caryclark@google.com24bec792012-08-20 12:43:57 +00006053 break;
6054 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006055 #if DEBUG_FLOW
6056 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6057 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
6058 current->xyAtT(end).fX, current->xyAtT(end).fY);
6059 #endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006060 current->addCurveTo(start, end, simple, true);
caryclark@google.com24bec792012-08-20 12:43:57 +00006061 current = next;
6062 start = nextStart;
6063 end = nextEnd;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006064 } while (!simple.isClosed() && (!unsortable || !current->done()));
6065 if (!simple.isClosed()) {
6066 SkASSERT(unsortable);
6067 int min = SkMin32(start, end);
6068 if (!current->done(min)) {
6069 current->addCurveTo(start, end, simple, true);
6070 current->markDone(min, 1);
6071 }
6072 closable = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00006073 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006074 simple.close();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00006075 #if DEBUG_ACTIVE_SPANS
6076 debugShowActiveSpans(contourList);
6077 #endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00006078 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006079 return closable;
caryclark@google.com24bec792012-08-20 12:43:57 +00006080}
6081
caryclark@google.comb45a1b42012-05-18 20:50:33 +00006082static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
6083 int contourCount = contourList.count();
6084 for (int cTest = 0; cTest < contourCount; ++cTest) {
6085 Contour* contour = contourList[cTest];
6086 contour->fixOtherTIndex();
6087 }
6088}
6089
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006090static void sortSegments(SkTDArray<Contour*>& contourList) {
6091 int contourCount = contourList.count();
6092 for (int cTest = 0; cTest < contourCount; ++cTest) {
6093 Contour* contour = contourList[cTest];
6094 contour->sortSegments();
6095 }
6096}
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006097
caryclark@google.com4eeda372012-12-06 21:47:48 +00006098static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
6099 bool evenOdd, bool oppEvenOdd) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006100 int count = contours.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006101 if (count == 0) {
6102 return;
6103 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006104 for (int index = 0; index < count; ++index) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00006105 Contour& contour = contours[index];
6106 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
6107 *list.append() = &contour;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006108 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006109 QSort<Contour>(list.begin(), list.end() - 1);
6110}
6111
caryclark@google.comf839c032012-10-26 21:03:50 +00006112static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006113 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006114}
6115
caryclark@google.comf839c032012-10-26 21:03:50 +00006116 /*
6117 check start and end of each contour
6118 if not the same, record them
6119 match them up
6120 connect closest
6121 reassemble contour pieces into new path
6122 */
6123static void assemble(const PathWrapper& path, PathWrapper& simple) {
6124#if DEBUG_PATH_CONSTRUCTION
6125 SkDebugf("%s\n", __FUNCTION__);
6126#endif
6127 SkTArray<Contour> contours;
6128 EdgeBuilder builder(path, contours);
6129 builder.finish();
6130 int count = contours.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006131 int outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006132 SkTDArray<int> runs; // indices of partial contours
caryclark@google.com0b7da432012-10-31 19:00:20 +00006133 for (outer = 0; outer < count; ++outer) {
6134 const Contour& eContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006135 const SkPoint& eStart = eContour.start();
6136 const SkPoint& eEnd = eContour.end();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006137#if DEBUG_ASSEMBLE
6138 SkDebugf("%s contour", __FUNCTION__);
6139 if (!approximatelyEqual(eStart, eEnd)) {
6140 SkDebugf("[%d]", runs.count());
6141 } else {
6142 SkDebugf(" ");
6143 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006144 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006145 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
6146#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006147 if (approximatelyEqual(eStart, eEnd)) {
6148 eContour.toPath(simple);
6149 continue;
6150 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006151 *runs.append() = outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006152 }
6153 count = runs.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006154 if (count == 0) {
6155 return;
6156 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006157 SkTDArray<int> sLink, eLink;
6158 sLink.setCount(count);
6159 eLink.setCount(count);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006160 SkTDArray<double> sBest, eBest;
6161 sBest.setCount(count);
6162 eBest.setCount(count);
caryclark@google.comf839c032012-10-26 21:03:50 +00006163 int rIndex;
6164 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006165 outer = runs[rIndex];
6166 const Contour& oContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006167 const SkPoint& oStart = oContour.start();
6168 const SkPoint& oEnd = oContour.end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006169 double dx = oEnd.fX - oStart.fX;
6170 double dy = oEnd.fY - oStart.fY;
6171 double dist = dx * dx + dy * dy;
6172 sBest[rIndex] = eBest[rIndex] = dist;
6173 sLink[rIndex] = eLink[rIndex] = rIndex;
6174 }
6175 for (rIndex = 0; rIndex < count - 1; ++rIndex) {
6176 outer = runs[rIndex];
6177 const Contour& oContour = contours[outer];
6178 const SkPoint& oStart = oContour.start();
6179 const SkPoint& oEnd = oContour.end();
6180 double bestStartDist = sBest[rIndex];
6181 double bestEndDist = eBest[rIndex];
6182 for (int iIndex = rIndex + 1; iIndex < count; ++iIndex) {
6183 int inner = runs[iIndex];
6184 const Contour& iContour = contours[inner];
caryclark@google.comf839c032012-10-26 21:03:50 +00006185 const SkPoint& iStart = iContour.start();
6186 const SkPoint& iEnd = iContour.end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006187 double dx = iStart.fX - oStart.fX;
6188 double dy = iStart.fY - oStart.fY;
6189 double dist = dx * dx + dy * dy;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006190 if (bestStartDist > dist && sBest[iIndex] > dist) {
6191 sBest[iIndex] = bestStartDist = dist;
caryclark@google.comf839c032012-10-26 21:03:50 +00006192 sLink[rIndex] = ~iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006193 sLink[iIndex] = ~rIndex;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006194 }
6195 dx = iEnd.fX - oStart.fX;
6196 dy = iEnd.fY - oStart.fY;
6197 dist = dx * dx + dy * dy;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006198 if (bestStartDist > dist && eBest[iIndex] > dist) {
6199 eBest[iIndex] = bestStartDist = dist;
caryclark@google.comf839c032012-10-26 21:03:50 +00006200 sLink[rIndex] = iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006201 eLink[iIndex] = rIndex;
6202 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006203 dx = iStart.fX - oEnd.fX;
6204 dy = iStart.fY - oEnd.fY;
6205 dist = dx * dx + dy * dy;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006206 if (bestEndDist > dist && sBest[iIndex] > dist) {
6207 sBest[iIndex] = bestEndDist = dist;
caryclark@google.comf839c032012-10-26 21:03:50 +00006208 sLink[iIndex] = rIndex;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006209 eLink[rIndex] = iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006210 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006211 dx = iEnd.fX - oEnd.fX;
6212 dy = iEnd.fY - oEnd.fY;
6213 dist = dx * dx + dy * dy;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006214 if (bestEndDist > dist && eBest[iIndex] > dist) {
6215 eBest[iIndex] = bestEndDist = dist;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006216 eLink[iIndex] = ~rIndex;
6217 eLink[rIndex] = ~iIndex;
6218 }
6219 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006220 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006221#if DEBUG_ASSEMBLE
6222 for (rIndex = 0; rIndex < count; ++rIndex) {
6223 int s = sLink[rIndex];
6224 int e = eLink[rIndex];
6225 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
6226 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
caryclark@google.comf839c032012-10-26 21:03:50 +00006227 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006228#endif
6229 rIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00006230 do {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006231 bool forward = true;
6232 bool first = true;
6233 int sIndex = sLink[rIndex];
6234 SkASSERT(sIndex != INT_MAX);
6235 sLink[rIndex] = INT_MAX;
6236 int eIndex;
6237 if (sIndex < 0) {
6238 eIndex = sLink[~sIndex];
6239 sLink[~sIndex] = INT_MAX;
6240 } else {
6241 eIndex = eLink[sIndex];
6242 eLink[sIndex] = INT_MAX;
6243 }
6244 SkASSERT(eIndex != INT_MAX);
6245#if DEBUG_ASSEMBLE
6246 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006247 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
6248 eIndex < 0 ? ~eIndex : eIndex);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006249#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006250 do {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006251 outer = runs[rIndex];
6252 const Contour& contour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006253 if (first) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006254 first = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006255 const SkPoint* startPtr = &contour.start();
caryclark@google.comf839c032012-10-26 21:03:50 +00006256 simple.deferredMove(startPtr[0]);
6257 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006258 if (forward) {
6259 contour.toPartialForward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006260 } else {
6261 contour.toPartialBackward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006262 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006263#if DEBUG_ASSEMBLE
6264 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006265 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006266 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
6267#endif
6268 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006269 simple.close();
caryclark@google.comf839c032012-10-26 21:03:50 +00006270 break;
6271 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006272 if (forward) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006273 eIndex = eLink[rIndex];
6274 SkASSERT(eIndex != INT_MAX);
caryclark@google.comf839c032012-10-26 21:03:50 +00006275 eLink[rIndex] = INT_MAX;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006276 if (eIndex >= 0) {
6277 SkASSERT(sLink[eIndex] == rIndex);
6278 sLink[eIndex] = INT_MAX;
caryclark@google.comf839c032012-10-26 21:03:50 +00006279 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006280 SkASSERT(eLink[~eIndex] == ~rIndex);
6281 eLink[~eIndex] = INT_MAX;
caryclark@google.comf839c032012-10-26 21:03:50 +00006282 }
6283 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006284 eIndex = sLink[rIndex];
6285 SkASSERT(eIndex != INT_MAX);
caryclark@google.comf839c032012-10-26 21:03:50 +00006286 sLink[rIndex] = INT_MAX;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006287 if (eIndex >= 0) {
6288 SkASSERT(eLink[eIndex] == rIndex);
6289 eLink[eIndex] = INT_MAX;
caryclark@google.comf839c032012-10-26 21:03:50 +00006290 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006291 SkASSERT(sLink[~eIndex] == ~rIndex);
6292 sLink[~eIndex] = INT_MAX;
caryclark@google.comf839c032012-10-26 21:03:50 +00006293 }
6294 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006295 rIndex = eIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006296 if (rIndex < 0) {
6297 forward ^= 1;
6298 rIndex = ~rIndex;
6299 }
6300 } while (true);
6301 for (rIndex = 0; rIndex < count; ++rIndex) {
6302 if (sLink[rIndex] != INT_MAX) {
6303 break;
6304 }
6305 }
6306 } while (rIndex < count);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006307#if DEBUG_ASSEMBLE
6308 for (rIndex = 0; rIndex < count; ++rIndex) {
6309 SkASSERT(sLink[rIndex] == INT_MAX);
6310 SkASSERT(eLink[rIndex] == INT_MAX);
6311 }
6312#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006313}
6314
6315void simplifyx(const SkPath& path, SkPath& result) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006316 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
caryclark@google.comf839c032012-10-26 21:03:50 +00006317 result.reset();
6318 result.setFillType(SkPath::kEvenOdd_FillType);
6319 PathWrapper simple(result);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006320
6321 // turn path into list of segments
6322 SkTArray<Contour> contours;
6323 // FIXME: add self-intersecting cubics' T values to segment
6324 EdgeBuilder builder(path, contours);
caryclark@google.com235f56a2012-09-14 14:19:30 +00006325 builder.finish();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006326 SkTDArray<Contour*> contourList;
caryclark@google.com4eeda372012-12-06 21:47:48 +00006327 makeContourList(contours, contourList, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006328 Contour** currentPtr = contourList.begin();
6329 if (!currentPtr) {
6330 return;
6331 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006332 Contour** listEnd = contourList.end();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006333 // find all intersections between segments
6334 do {
6335 Contour** nextPtr = currentPtr;
6336 Contour* current = *currentPtr++;
6337 Contour* next;
6338 do {
6339 next = *nextPtr++;
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00006340 } while (addIntersectTs(current, next) && nextPtr != listEnd);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006341 } while (currentPtr != listEnd);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006342 // eat through coincident edges
caryclark@google.com4eeda372012-12-06 21:47:48 +00006343 coincidenceCheck(contourList, 0);
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00006344 fixOtherTIndex(contourList);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006345 sortSegments(contourList);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006346#if DEBUG_ACTIVE_SPANS
6347 debugShowActiveSpans(contourList);
6348#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006349 // construct closed contours
caryclark@google.com3586ece2012-12-27 18:46:58 +00006350 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00006351 : !bridgeXor(contourList, simple))
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006352 { // if some edges could not be resolved, assemble remaining fragments
caryclark@google.comf839c032012-10-26 21:03:50 +00006353 SkPath temp;
6354 temp.setFillType(SkPath::kEvenOdd_FillType);
6355 PathWrapper assembled(temp);
6356 assemble(simple, assembled);
6357 result = *assembled.nativePath();
caryclark@google.com24bec792012-08-20 12:43:57 +00006358 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006359}
6360