blob: 0a75f2a1e4e8387023f9f80ea2695778de06f578 [file] [log] [blame]
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
caryclark@google.comb45a1b42012-05-18 20:50:33 +00007#include "Simplify.h"
caryclark@google.comfa0588f2012-04-26 21:01:06 +00008
9#undef SkASSERT
10#define SkASSERT(cond) while (!(cond)) { sk_throw(); }
11
caryclark@google.com15fa1382012-05-07 20:49:36 +000012// Terminology:
13// A Path contains one of more Contours
14// A Contour is made up of Segment array
caryclark@google.comb45a1b42012-05-18 20:50:33 +000015// A Segment is described by a Verb and a Point array with 2, 3, or 4 points
16// A Verb is one of Line, Quad(ratic), or Cubic
caryclark@google.com15fa1382012-05-07 20:49:36 +000017// A Segment contains a Span array
18// A Span is describes a portion of a Segment using starting and ending T
19// T values range from 0 to 1, where 0 is the first Point in the Segment
caryclark@google.com47580692012-07-23 12:14:49 +000020// An Edge is a Segment generated from a Span
caryclark@google.com15fa1382012-05-07 20:49:36 +000021
caryclark@google.comfa0588f2012-04-26 21:01:06 +000022// FIXME: remove once debugging is complete
caryclark@google.com47580692012-07-23 12:14:49 +000023#ifdef SK_DEBUG
24int gDebugMaxWindSum = SK_MaxS32;
25int gDebugMaxWindValue = SK_MaxS32;
26#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +000027
caryclark@google.comf839c032012-10-26 21:03:50 +000028#define PIN_ADD_T 0
caryclark@google.com0b7da432012-10-31 19:00:20 +000029#define TRY_ROTATE 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000030#define ONE_PASS_COINCIDENCE_CHECK 0
caryclark@google.com73ca6242013-01-17 21:02:47 +000031#define APPROXIMATE_CUBICS 1
caryclark@google.coma461ff02012-10-11 12:54:23 +000032
caryclark@google.com47580692012-07-23 12:14:49 +000033#define DEBUG_UNUSED 0 // set to expose unused functions
caryclark@google.com45a8fc62013-02-14 15:29:11 +000034
caryclark@google.combeda3892013-02-07 13:13:41 +000035#define FORCE_RELEASE 1 // set force release to 1 for multiple thread -- no debugging
caryclark@google.comfa0588f2012-04-26 21:01:06 +000036
caryclark@google.com31143cf2012-11-09 22:14:19 +000037#if FORCE_RELEASE || defined SK_RELEASE
caryclark@google.com47580692012-07-23 12:14:49 +000038
39const bool gRunTestsInOneThread = false;
40
caryclark@google.combeda3892013-02-07 13:13:41 +000041#define DEBUG_ACTIVE_OP 0
caryclark@google.com47580692012-07-23 12:14:49 +000042#define DEBUG_ACTIVE_SPANS 0
caryclark@google.com4eeda372012-12-06 21:47:48 +000043#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000044#define DEBUG_ADD_INTERSECTING_TS 0
caryclark@google.com47580692012-07-23 12:14:49 +000045#define DEBUG_ADD_T_PAIR 0
caryclark@google.comc899ad92012-08-23 15:24:42 +000046#define DEBUG_ANGLE 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000047#define DEBUG_ASSEMBLE 0
caryclark@google.com47580692012-07-23 12:14:49 +000048#define DEBUG_CONCIDENT 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000049#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000050#define DEBUG_FLOW 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000051#define DEBUG_MARK_DONE 0
caryclark@google.comf839c032012-10-26 21:03:50 +000052#define DEBUG_PATH_CONSTRUCTION 0
caryclark@google.com729e1c42012-11-21 21:36:34 +000053#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000054#define DEBUG_SORT 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000055#define DEBUG_UNSORTABLE 0
caryclark@google.comafe56de2012-07-24 18:11:03 +000056#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000057#define DEBUG_WINDING 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000058#define DEBUG_WINDING_AT_T 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000059
60#else
61
caryclark@google.com47580692012-07-23 12:14:49 +000062const bool gRunTestsInOneThread = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +000063
caryclark@google.combeda3892013-02-07 13:13:41 +000064#define DEBUG_ACTIVE_OP 1
caryclark@google.comc91dfe42012-10-16 12:06:27 +000065#define DEBUG_ACTIVE_SPANS 1
caryclark@google.com4eeda372012-12-06 21:47:48 +000066#define DEBUG_ACTIVE_SPANS_SHORT_FORM 1
caryclark@google.com6aea33f2012-10-09 14:11:58 +000067#define DEBUG_ADD_INTERSECTING_TS 1
68#define DEBUG_ADD_T_PAIR 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000069#define DEBUG_ANGLE 1
caryclark@google.come7bd5f42012-12-13 19:47:53 +000070#define DEBUG_ASSEMBLE 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000071#define DEBUG_CONCIDENT 1
caryclark@google.com534aa5b2012-08-02 20:08:21 +000072#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000073#define DEBUG_FLOW 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000074#define DEBUG_MARK_DONE 1
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000075#define DEBUG_PATH_CONSTRUCTION 1
caryclark@google.com729e1c42012-11-21 21:36:34 +000076#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000077#define DEBUG_SORT 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000078#define DEBUG_UNSORTABLE 1
caryclark@google.comafe56de2012-07-24 18:11:03 +000079#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000080#define DEBUG_WINDING 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000081#define DEBUG_WINDING_AT_T 1
caryclark@google.comfa0588f2012-04-26 21:01:06 +000082
83#endif
84
caryclark@google.combeda3892013-02-07 13:13:41 +000085#define DEBUG_DUMP (DEBUG_ACTIVE_OP | DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | \
86 DEBUG_PATH_CONSTRUCTION)
caryclark@google.com027de222012-07-12 12:52:50 +000087
caryclark@google.comfa0588f2012-04-26 21:01:06 +000088#if DEBUG_DUMP
caryclark@google.combeda3892013-02-07 13:13:41 +000089static const char* kShapeOpStr[] = {"diff", "sect", "union", "xor"};
caryclark@google.comfa0588f2012-04-26 21:01:06 +000090static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000091// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
caryclark@google.comfa0588f2012-04-26 21:01:06 +000092static int gContourID;
93static int gSegmentID;
94#endif
95
caryclark@google.com8dcf1142012-07-02 20:27:02 +000096#ifndef DEBUG_TEST
97#define DEBUG_TEST 0
98#endif
99
caryclark@google.com32546db2012-08-31 20:55:07 +0000100#define MAKE_CONST_LINE(line, pts) \
101 const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}
102#define MAKE_CONST_QUAD(quad, pts) \
103 const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
104 {pts[2].fX, pts[2].fY}}
105#define MAKE_CONST_CUBIC(cubic, pts) \
106 const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
107 {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}}
108
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000109static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
110 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000111 MAKE_CONST_LINE(aLine, a);
112 MAKE_CONST_LINE(bLine, b);
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000113 return intersect(aLine, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000114}
115
116static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
117 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000118 MAKE_CONST_QUAD(aQuad, a);
119 MAKE_CONST_LINE(bLine, b);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000120 return intersect(aQuad, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000121}
122
caryclark@google.com32546db2012-08-31 20:55:07 +0000123static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000124 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000125 MAKE_CONST_CUBIC(aCubic, a);
126 MAKE_CONST_LINE(bLine, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000127 return intersect(aCubic, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000128}
129
130static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
131 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000132 MAKE_CONST_QUAD(aQuad, a);
133 MAKE_CONST_QUAD(bQuad, b);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000134#define TRY_QUARTIC_SOLUTION 1
135#if TRY_QUARTIC_SOLUTION
136 intersect2(aQuad, bQuad, intersections);
137#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000138 intersect(aQuad, bQuad, intersections);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000139#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000140 return intersections.fUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000141}
142
caryclark@google.com73ca6242013-01-17 21:02:47 +0000143#if APPROXIMATE_CUBICS
144static int CubicQuadIntersect(const SkPoint a[4], const SkPoint b[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000145 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000146 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000147 MAKE_CONST_QUAD(bQuad, b);
148 return intersect(aCubic, bQuad, intersections);
149}
150#endif
151
152static int CubicIntersect(const SkPoint a[4], const SkPoint b[4], Intersections& intersections) {
153 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com32546db2012-08-31 20:55:07 +0000154 MAKE_CONST_CUBIC(bCubic, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000155#if APPROXIMATE_CUBICS
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000156 intersect3(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000157#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000158 intersect(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000159#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000160 return intersections.fUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000161}
162
163static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
164 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000165 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000166 return horizontalIntersect(aLine, left, right, y, flipped, intersections);
167}
168
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000169static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
170 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000171 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000172 return horizontalIntersect(aQuad, left, right, y, flipped, intersections);
173}
174
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000175static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
176 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000177 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000178 return horizontalIntersect(aCubic, left, right, y, flipped, intersections);
179}
180
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000181static int (* const HSegmentIntersect[])(const SkPoint [], SkScalar ,
182 SkScalar , SkScalar , bool , Intersections& ) = {
183 NULL,
184 HLineIntersect,
185 HQuadIntersect,
186 HCubicIntersect
187};
188
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000189static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom,
190 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000191 MAKE_CONST_LINE(aLine, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000192 return verticalIntersect(aLine, top, bottom, x, flipped, intersections);
193}
194
195static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom,
196 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000197 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000198 return verticalIntersect(aQuad, top, bottom, x, flipped, intersections);
199}
200
201static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom,
202 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000203 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000204 return verticalIntersect(aCubic, top, bottom, x, flipped, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000205}
206
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000207static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar ,
208 SkScalar , SkScalar , bool , Intersections& ) = {
209 NULL,
210 VLineIntersect,
211 VQuadIntersect,
212 VCubicIntersect
213};
214
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000215static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000216 MAKE_CONST_LINE(line, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000217 double x, y;
218 xy_at_t(line, t, x, y);
219 out->fX = SkDoubleToScalar(x);
220 out->fY = SkDoubleToScalar(y);
221}
222
caryclark@google.comf9502d72013-02-04 14:06:49 +0000223static void LineXYAtT(const SkPoint a[2], double t, _Point* out) {
224 MAKE_CONST_LINE(line, a);
225 xy_at_t(line, t, out->x, out->y);
226}
227
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000228static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000229 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000230 double x, y;
231 xy_at_t(quad, t, x, y);
232 out->fX = SkDoubleToScalar(x);
233 out->fY = SkDoubleToScalar(y);
234}
235
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000236static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
237 MAKE_CONST_QUAD(quad, a);
238 xy_at_t(quad, t, out->x, out->y);
239}
240
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000241static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000242 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000243 double x, y;
244 xy_at_t(cubic, t, x, y);
245 out->fX = SkDoubleToScalar(x);
246 out->fY = SkDoubleToScalar(y);
247}
248
caryclark@google.comf9502d72013-02-04 14:06:49 +0000249static void CubicXYAtT(const SkPoint a[4], double t, _Point* out) {
250 MAKE_CONST_CUBIC(cubic, a);
251 xy_at_t(cubic, t, out->x, out->y);
252}
253
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000254static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
255 NULL,
256 LineXYAtT,
257 QuadXYAtT,
258 CubicXYAtT
259};
260
caryclark@google.comf9502d72013-02-04 14:06:49 +0000261static void (* const SegmentXYAtT2[])(const SkPoint [], double , _Point* ) = {
262 NULL,
263 LineXYAtT,
264 QuadXYAtT,
265 CubicXYAtT
266};
267
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000268static SkScalar LineXAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000269 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000270 double x;
271 xy_at_t(aLine, t, x, *(double*) 0);
272 return SkDoubleToScalar(x);
273}
274
275static SkScalar QuadXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000276 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000277 double x;
278 xy_at_t(quad, t, x, *(double*) 0);
279 return SkDoubleToScalar(x);
280}
281
282static SkScalar CubicXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000283 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000284 double x;
285 xy_at_t(cubic, t, x, *(double*) 0);
286 return SkDoubleToScalar(x);
287}
288
289static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
290 NULL,
291 LineXAtT,
292 QuadXAtT,
293 CubicXAtT
294};
295
296static SkScalar LineYAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000297 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000298 double y;
299 xy_at_t(aLine, t, *(double*) 0, y);
300 return SkDoubleToScalar(y);
301}
302
303static SkScalar QuadYAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000304 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000305 double y;
306 xy_at_t(quad, t, *(double*) 0, y);
307 return SkDoubleToScalar(y);
308}
309
310static SkScalar CubicYAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000311 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000312 double y;
313 xy_at_t(cubic, t, *(double*) 0, y);
314 return SkDoubleToScalar(y);
315}
316
317static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
318 NULL,
319 LineYAtT,
320 QuadYAtT,
321 CubicYAtT
322};
323
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000324static SkScalar LineDXAtT(const SkPoint a[2], double ) {
325 return a[1].fX - a[0].fX;
326}
327
328static SkScalar QuadDXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000329 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000330 double x = dx_at_t(quad, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000331 return SkDoubleToScalar(x);
332}
333
334static SkScalar CubicDXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000335 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000336 double x = dx_at_t(cubic, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000337 return SkDoubleToScalar(x);
338}
339
340static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
341 NULL,
342 LineDXAtT,
343 QuadDXAtT,
344 CubicDXAtT
345};
346
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000347static SkScalar LineDYAtT(const SkPoint a[2], double ) {
348 return a[1].fY - a[0].fY;
349}
350
351static SkScalar QuadDYAtT(const SkPoint a[3], double t) {
352 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000353 double y = dy_at_t(quad, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000354 return SkDoubleToScalar(y);
355}
356
357static SkScalar CubicDYAtT(const SkPoint a[4], double t) {
358 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000359 double y = dy_at_t(cubic, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000360 return SkDoubleToScalar(y);
361}
362
363static SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = {
364 NULL,
365 LineDYAtT,
366 QuadDYAtT,
367 CubicDYAtT
368};
369
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000370static SkPoint LineDXDYAtT(const SkPoint a[2], double ) {
371 return a[1] - a[0];
372}
373
374static SkPoint QuadDXDYAtT(const SkPoint a[3], double t) {
375 MAKE_CONST_QUAD(quad, a);
376 _Point pt;
377 dxdy_at_t(quad, t, pt);
378 return pt.asSkPoint();
379}
380
381static SkPoint CubicDXDYAtT(const SkPoint a[4], double t) {
382 MAKE_CONST_CUBIC(cubic, a);
383 _Point pt;
384 dxdy_at_t(cubic, t, pt);
385 return pt.asSkPoint();
386}
387
388static SkPoint (* const SegmentDXDYAtT[])(const SkPoint [], double ) = {
389 NULL,
390 LineDXDYAtT,
391 QuadDXDYAtT,
392 CubicDXDYAtT
393};
394
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000395static void LineSubDivide(const SkPoint a[2], double startT, double endT,
396 SkPoint sub[2]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000397 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000398 _Line dst;
399 sub_divide(aLine, startT, endT, dst);
400 sub[0].fX = SkDoubleToScalar(dst[0].x);
401 sub[0].fY = SkDoubleToScalar(dst[0].y);
402 sub[1].fX = SkDoubleToScalar(dst[1].x);
403 sub[1].fY = SkDoubleToScalar(dst[1].y);
404}
405
406static void QuadSubDivide(const SkPoint a[3], double startT, double endT,
407 SkPoint sub[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000408 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000409 Quadratic dst;
410 sub_divide(aQuad, startT, endT, dst);
411 sub[0].fX = SkDoubleToScalar(dst[0].x);
412 sub[0].fY = SkDoubleToScalar(dst[0].y);
413 sub[1].fX = SkDoubleToScalar(dst[1].x);
414 sub[1].fY = SkDoubleToScalar(dst[1].y);
415 sub[2].fX = SkDoubleToScalar(dst[2].x);
416 sub[2].fY = SkDoubleToScalar(dst[2].y);
417}
418
419static void CubicSubDivide(const SkPoint a[4], double startT, double endT,
420 SkPoint sub[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000421 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000422 Cubic dst;
423 sub_divide(aCubic, startT, endT, dst);
424 sub[0].fX = SkDoubleToScalar(dst[0].x);
425 sub[0].fY = SkDoubleToScalar(dst[0].y);
426 sub[1].fX = SkDoubleToScalar(dst[1].x);
427 sub[1].fY = SkDoubleToScalar(dst[1].y);
428 sub[2].fX = SkDoubleToScalar(dst[2].x);
429 sub[2].fY = SkDoubleToScalar(dst[2].y);
430 sub[3].fX = SkDoubleToScalar(dst[3].x);
431 sub[3].fY = SkDoubleToScalar(dst[3].y);
432}
433
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000434static void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
435 SkPoint []) = {
436 NULL,
437 LineSubDivide,
438 QuadSubDivide,
439 CubicSubDivide
440};
441
caryclark@google.comaa358312013-01-29 20:28:49 +0000442static void LineSubDivideHD(const SkPoint a[2], double startT, double endT, _Line& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000443 MAKE_CONST_LINE(aLine, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000444 sub_divide(aLine, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000445}
446
caryclark@google.comaa358312013-01-29 20:28:49 +0000447static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT, Quadratic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000448 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000449 sub_divide(aQuad, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000450}
451
caryclark@google.comaa358312013-01-29 20:28:49 +0000452static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT, Cubic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000453 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000454 sub_divide(aCubic, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000455}
456
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000457static SkPoint QuadTop(const SkPoint a[3], double startT, double endT) {
458 MAKE_CONST_QUAD(quad, a);
459 _Point topPt = top(quad, startT, endT);
460 return topPt.asSkPoint();
461}
462
463static SkPoint CubicTop(const SkPoint a[3], double startT, double endT) {
464 MAKE_CONST_CUBIC(cubic, a);
465 _Point topPt = top(cubic, startT, endT);
466 return topPt.asSkPoint();
467}
468
469static SkPoint (* SegmentTop[])(const SkPoint[], double , double ) = {
470 NULL,
471 NULL,
472 QuadTop,
473 CubicTop
474};
475
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000476#if DEBUG_UNUSED
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000477static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
478 SkRect& bounds) {
479 SkPoint dst[3];
480 QuadSubDivide(a, startT, endT, dst);
481 bounds.fLeft = bounds.fRight = dst[0].fX;
482 bounds.fTop = bounds.fBottom = dst[0].fY;
483 for (int index = 1; index < 3; ++index) {
484 bounds.growToInclude(dst[index].fX, dst[index].fY);
485 }
486}
487
488static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
489 SkRect& bounds) {
490 SkPoint dst[4];
491 CubicSubDivide(a, startT, endT, dst);
492 bounds.fLeft = bounds.fRight = dst[0].fX;
493 bounds.fTop = bounds.fBottom = dst[0].fY;
494 for (int index = 1; index < 4; ++index) {
495 bounds.growToInclude(dst[index].fX, dst[index].fY);
496 }
497}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000498#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000499
caryclark@google.com15fa1382012-05-07 20:49:36 +0000500static SkPath::Verb QuadReduceOrder(const SkPoint a[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000501 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000502 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000503 Quadratic dst;
504 int order = reduceOrder(aQuad, dst);
caryclark@google.com24bec792012-08-20 12:43:57 +0000505 if (order == 2) { // quad became line
506 for (int index = 0; index < order; ++index) {
507 SkPoint* pt = reducePts.append();
508 pt->fX = SkDoubleToScalar(dst[index].x);
509 pt->fY = SkDoubleToScalar(dst[index].y);
510 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000511 }
512 return (SkPath::Verb) (order - 1);
513}
514
515static SkPath::Verb CubicReduceOrder(const SkPoint a[4],
516 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000517 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000518 Cubic dst;
519 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed);
caryclark@google.com24bec792012-08-20 12:43:57 +0000520 if (order == 2 || order == 3) { // cubic became line or quad
521 for (int index = 0; index < order; ++index) {
522 SkPoint* pt = reducePts.append();
523 pt->fX = SkDoubleToScalar(dst[index].x);
524 pt->fY = SkDoubleToScalar(dst[index].y);
525 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000526 }
527 return (SkPath::Verb) (order - 1);
528}
529
caryclark@google.com15fa1382012-05-07 20:49:36 +0000530static bool QuadIsLinear(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000531 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000532 return isLinear(aQuad, 0, 2);
533}
534
535static bool CubicIsLinear(const SkPoint a[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000536 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000537 return isLinear(aCubic, 0, 3);
538}
539
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000540static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000541 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000542 double x[2];
543 xy_at_t(aLine, startT, x[0], *(double*) 0);
caryclark@google.com495f8e42012-05-31 13:13:11 +0000544 xy_at_t(aLine, endT, x[1], *(double*) 0);
545 return SkMinScalar((float) x[0], (float) x[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000546}
547
548static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000549 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000550 return (float) leftMostT(aQuad, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000551}
552
553static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000554 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000555 return (float) leftMostT(aCubic, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000556}
557
558static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
559 NULL,
560 LineLeftMost,
561 QuadLeftMost,
562 CubicLeftMost
563};
564
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000565#if 0 // currently unused
caryclark@google.com235f56a2012-09-14 14:19:30 +0000566static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
567 Intersections& intersections) {
568 MAKE_CONST_QUAD(aQuad, a);
569 MAKE_CONST_LINE(bLine, b);
570 return intersectRay(aQuad, bLine, intersections);
571}
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000572#endif
573
caryclark@google.comf9502d72013-02-04 14:06:49 +0000574static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000575 MAKE_CONST_QUAD(aQuad, a);
576 return intersectRay(aQuad, bLine, intersections);
577}
caryclark@google.com235f56a2012-09-14 14:19:30 +0000578
caryclark@google.comf9502d72013-02-04 14:06:49 +0000579static int CubicRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
580 MAKE_CONST_CUBIC(aCubic, a);
581 return intersectRay(aCubic, bLine, intersections);
582}
583
584static int (* const SegmentRayIntersect[])(const SkPoint [], const _Line& , Intersections&) = {
585 NULL,
586 NULL,
587 QuadRayIntersect,
588 CubicRayIntersect
589};
590
591
592
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000593static bool LineVertical(const SkPoint a[2], double startT, double endT) {
594 MAKE_CONST_LINE(aLine, a);
595 double x[2];
596 xy_at_t(aLine, startT, x[0], *(double*) 0);
597 xy_at_t(aLine, endT, x[1], *(double*) 0);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000598 return AlmostEqualUlps((float) x[0], (float) x[1]);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000599}
600
601static bool QuadVertical(const SkPoint a[3], double startT, double endT) {
602 SkPoint dst[3];
603 QuadSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000604 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000605}
606
607static bool CubicVertical(const SkPoint a[4], double startT, double endT) {
608 SkPoint dst[4];
609 CubicSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000610 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX)
611 && AlmostEqualUlps(dst[2].fX, dst[3].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000612}
613
614static bool (* const SegmentVertical[])(const SkPoint [], double , double) = {
615 NULL,
616 LineVertical,
617 QuadVertical,
618 CubicVertical
619};
620
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000621class Segment;
622
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000623struct Span {
624 Segment* fOther;
625 mutable SkPoint fPt; // lazily computed as needed
626 double fT;
627 double fOtherT; // value at fOther[fOtherIndex].fT
628 int fOtherIndex; // can't be used during intersection
caryclark@google.com31143cf2012-11-09 22:14:19 +0000629 int fWindSum; // accumulated from contours surrounding this one.
630 int fOppSum; // for binary operators: the opposite winding sum
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000631 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
caryclark@google.com57cff8d2012-11-14 21:14:56 +0000632 int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000633 bool fDone; // if set, this span to next higher T has been processed
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000634 bool fUnsortableStart; // set when start is part of an unsortable pair
635 bool fUnsortableEnd; // set when end is part of an unsortable pair
caryclark@google.comf839c032012-10-26 21:03:50 +0000636 bool fTiny; // if set, span may still be considered once for edge following
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000637};
638
caryclark@google.com15fa1382012-05-07 20:49:36 +0000639// sorting angles
640// given angles of {dx dy ddx ddy dddx dddy} sort them
641class Angle {
642public:
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000643 // FIXME: this is bogus for quads and cubics
644 // if the quads and cubics' line from end pt to ctrl pt are coincident,
645 // there's no obvious way to determine the curve ordering from the
646 // derivatives alone. In particular, if one quadratic's coincident tangent
647 // is longer than the other curve, the final control point can place the
648 // longer curve on either side of the shorter one.
649 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
650 // may provide some help, but nothing has been figured out yet.
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000651
caryclark@google.com32546db2012-08-31 20:55:07 +0000652 /*(
653 for quads and cubics, set up a parameterized line (e.g. LineParameters )
654 for points [0] to [1]. See if point [2] is on that line, or on one side
655 or the other. If it both quads' end points are on the same side, choose
656 the shorter tangent. If the tangents are equal, choose the better second
657 tangent angle
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000658
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000659 maybe I could set up LineParameters lazily
caryclark@google.com32546db2012-08-31 20:55:07 +0000660 */
caryclark@google.com15fa1382012-05-07 20:49:36 +0000661 bool operator<(const Angle& rh) const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000662 double y = dy();
663 double ry = rh.dy();
664 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
665 return y < 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000666 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000667 double x = dx();
668 double rx = rh.dx();
669 if (y == 0 && ry == 0 && x * rx < 0) {
670 return x < rx;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000671 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000672 double x_ry = x * ry;
673 double rx_y = rx * y;
674 double cmp = x_ry - rx_y;
caryclark@google.comc899ad92012-08-23 15:24:42 +0000675 if (!approximately_zero(cmp)) {
caryclark@google.com15fa1382012-05-07 20:49:36 +0000676 return cmp < 0;
677 }
caryclark@google.comd1688742012-09-18 20:08:37 +0000678 if (approximately_zero(x_ry) && approximately_zero(rx_y)
679 && !approximately_zero_squared(cmp)) {
680 return cmp < 0;
681 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000682 // at this point, the initial tangent line is coincident
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000683 // see if edges curl away from each other
caryclark@google.com31143cf2012-11-09 22:14:19 +0000684 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
685 || !approximately_zero(rh.fSide))) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000686 // FIXME: running demo will trigger this assertion
687 // (don't know if commenting out will trigger further assertion or not)
688 // commenting it out allows demo to run in release, though
689 // SkASSERT(fSide != rh.fSide);
690 return fSide < rh.fSide;
691 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000692 // see if either curve can be lengthened and try the tangent compare again
693 if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
694 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
695 Angle longer = *this;
696 Angle rhLonger = rh;
697 if (longer.lengthen() | rhLonger.lengthen()) {
698 return longer < rhLonger;
699 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000700 #if 0
caryclark@google.coma461ff02012-10-11 12:54:23 +0000701 // what if we extend in the other direction?
702 longer = *this;
703 rhLonger = rh;
704 if (longer.reverseLengthen() | rhLonger.reverseLengthen()) {
705 return longer < rhLonger;
706 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000707 #endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000708 }
caryclark@google.com185c7c42012-10-19 18:26:24 +0000709 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
caryclark@google.com31143cf2012-11-09 22:14:19 +0000710 || (rh.fVerb == SkPath::kLine_Verb
711 && approximately_zero(rx) && approximately_zero(ry))) {
caryclark@google.com185c7c42012-10-19 18:26:24 +0000712 // See general unsortable comment below. This case can happen when
713 // one line has a non-zero change in t but no change in x and y.
714 fUnsortable = true;
715 rh.fUnsortable = true;
716 return this < &rh; // even with no solution, return a stable sort
717 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000718 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
719 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
720 fUnsortable = true;
721 rh.fUnsortable = true;
722 return this < &rh; // even with no solution, return a stable sort
723 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000724 SkASSERT(fVerb >= SkPath::kQuad_Verb);
725 SkASSERT(rh.fVerb >= SkPath::kQuad_Verb);
skia.committer@gmail.comc1ad0222012-09-19 02:01:47 +0000726 // FIXME: until I can think of something better, project a ray from the
caryclark@google.comd1688742012-09-18 20:08:37 +0000727 // end of the shorter tangent to midway between the end points
728 // through both curves and use the resulting angle to sort
caryclark@google.com235f56a2012-09-14 14:19:30 +0000729 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
730 double len = fTangent1.normalSquared();
731 double rlen = rh.fTangent1.normalSquared();
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000732 _Line ray;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000733 Intersections i, ri;
caryclark@google.comd1688742012-09-18 20:08:37 +0000734 int roots, rroots;
735 bool flip = false;
736 do {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000737 bool useThis = (len < rlen) ^ flip;
738 const Cubic& part = useThis ? fCurvePart : rh.fCurvePart;
739 SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb;
740 ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ?
741 part[2] : part[1];
742 ray[1].x = (part[0].x + part[partVerb].x) / 2;
743 ray[1].y = (part[0].y + part[partVerb].y) / 2;
caryclark@google.comd1688742012-09-18 20:08:37 +0000744 SkASSERT(ray[0] != ray[1]);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000745 roots = (*SegmentRayIntersect[fVerb])(fPts, ray, i);
746 rroots = (*SegmentRayIntersect[rh.fVerb])(rh.fPts, ray, ri);
caryclark@google.comd1688742012-09-18 20:08:37 +0000747 } while ((roots == 0 || rroots == 0) && (flip ^= true));
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000748 if (roots == 0 || rroots == 0) {
749 // FIXME: we don't have a solution in this case. The interim solution
750 // is to mark the edges as unsortable, exclude them from this and
751 // future computations, and allow the returned path to be fragmented
752 fUnsortable = true;
753 rh.fUnsortable = true;
754 return this < &rh; // even with no solution, return a stable sort
755 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000756 _Point loc;
757 double best = SK_ScalarInfinity;
758 double dx, dy, dist;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000759 int index;
760 for (index = 0; index < roots; ++index) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000761 (*SegmentXYAtT2[fVerb])(fPts, i.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000762 dx = loc.x - ray[0].x;
763 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000764 dist = dx * dx + dy * dy;
765 if (best > dist) {
766 best = dist;
767 }
768 }
769 for (index = 0; index < rroots; ++index) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000770 (*SegmentXYAtT2[rh.fVerb])(rh.fPts, ri.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000771 dx = loc.x - ray[0].x;
772 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000773 dist = dx * dx + dy * dy;
774 if (best > dist) {
775 return fSide < 0;
776 }
777 }
778 return fSide > 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000779 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000780
caryclark@google.com47580692012-07-23 12:14:49 +0000781 double dx() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000782 return fTangent1.dx();
caryclark@google.com47580692012-07-23 12:14:49 +0000783 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000784
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000785 double dy() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000786 return fTangent1.dy();
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000787 }
788
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000789 int end() const {
790 return fEnd;
791 }
792
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000793 bool isHorizontal() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000794 return dy() == 0 && fVerb == SkPath::kLine_Verb;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000795 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000796
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000797 bool lengthen() {
798 int newEnd = fEnd;
799 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
800 fEnd = newEnd;
801 setSpans();
802 return true;
803 }
804 return false;
805 }
806
caryclark@google.coma461ff02012-10-11 12:54:23 +0000807 bool reverseLengthen() {
808 if (fReversed) {
809 return false;
810 }
811 int newEnd = fStart;
812 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
813 fEnd = newEnd;
814 fReversed = true;
815 setSpans();
816 return true;
817 }
818 return false;
819 }
820
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000821 void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000822 int start, int end, const SkTDArray<Span>& spans) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000823 fSegment = segment;
824 fStart = start;
825 fEnd = end;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000826 fPts = orig;
827 fVerb = verb;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000828 fSpans = &spans;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000829 fReversed = false;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000830 fUnsortable = false;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000831 setSpans();
832 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000833
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000834
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000835 void setSpans() {
836 double startT = (*fSpans)[fStart].fT;
837 double endT = (*fSpans)[fEnd].fT;
838 switch (fVerb) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000839 case SkPath::kLine_Verb:
840 _Line l;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000841 LineSubDivideHD(fPts, startT, endT, l);
caryclark@google.com32546db2012-08-31 20:55:07 +0000842 // OPTIMIZATION: for pure line compares, we never need fTangent1.c
843 fTangent1.lineEndPoints(l);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000844 fSide = 0;
caryclark@google.com32546db2012-08-31 20:55:07 +0000845 break;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000846 case SkPath::kQuad_Verb: {
847 Quadratic& quad = (Quadratic&)fCurvePart;
848 QuadSubDivideHD(fPts, startT, endT, quad);
849 fTangent1.quadEndPoints(quad, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000850 #if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
851 if (dx() == 0 && dy() == 0) {
caryclark@google.combeda3892013-02-07 13:13:41 +0000852 // SkDebugf("*** %s quad is line\n", __FUNCTION__);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000853 fTangent1.quadEndPoints(quad);
caryclark@google.comaa358312013-01-29 20:28:49 +0000854 }
855 #endif
caryclark@google.comf9502d72013-02-04 14:06:49 +0000856 fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- compare sign only
857 } break;
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000858 case SkPath::kCubic_Verb: {
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000859 int nextC = 2;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000860 CubicSubDivideHD(fPts, startT, endT, fCurvePart);
861 fTangent1.cubicEndPoints(fCurvePart, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000862 if (dx() == 0 && dy() == 0) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000863 fTangent1.cubicEndPoints(fCurvePart, 0, 2);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000864 nextC = 3;
caryclark@google.comaa358312013-01-29 20:28:49 +0000865 #if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
866 if (dx() == 0 && dy() == 0) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000867 SkDebugf("*** %s cubic is line\n", __FUNCTION__);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000868 fTangent1.cubicEndPoints(fCurvePart, 0, 3);
caryclark@google.comaa358312013-01-29 20:28:49 +0000869 }
870 #endif
871 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000872 fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign only
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000873 if (nextC == 2 && approximately_zero(fSide)) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000874 fSide = -fTangent1.pointDistance(fCurvePart[3]);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000875 }
876 } break;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000877 default:
878 SkASSERT(0);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000879 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000880 fUnsortable = dx() == 0 && dy() == 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000881 if (fUnsortable) {
882 return;
883 }
884 SkASSERT(fStart != fEnd);
885 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
886 for (int index = fStart; index != fEnd; index += step) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000887#if 1
888 const Span& thisSpan = (*fSpans)[index];
889 const Span& nextSpan = (*fSpans)[index + step];
890 if (thisSpan.fTiny || thisSpan.fT == nextSpan.fT) {
891 continue;
caryclark@google.comf839c032012-10-26 21:03:50 +0000892 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000893 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
894#if DEBUG_UNSORTABLE
895 if (fUnsortable) {
896 SkPoint iPt, ePt;
897 (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt);
898 (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt);
899 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
900 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
901 }
902#endif
903 return;
904#else
905 if ((*fSpans)[index].fUnsortableStart) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000906 fUnsortable = true;
907 return;
908 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000909#endif
caryclark@google.comf839c032012-10-26 21:03:50 +0000910 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000911#if 1
912#if DEBUG_UNSORTABLE
913 SkPoint iPt, ePt;
914 (*SegmentXYAtT[fVerb])(fPts, startT, &iPt);
915 (*SegmentXYAtT[fVerb])(fPts, endT, &ePt);
916 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
917 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
918#endif
919 fUnsortable = true;
920#endif
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000921 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000922
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000923 Segment* segment() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000924 return const_cast<Segment*>(fSegment);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000925 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000926
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000927 int sign() const {
caryclark@google.com495f8e42012-05-31 13:13:11 +0000928 return SkSign32(fStart - fEnd);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000929 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000930
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000931 const SkTDArray<Span>* spans() const {
932 return fSpans;
933 }
934
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000935 int start() const {
936 return fStart;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000937 }
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +0000938
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000939 bool unsortable() const {
940 return fUnsortable;
941 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000942
caryclark@google.comc899ad92012-08-23 15:24:42 +0000943#if DEBUG_ANGLE
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000944 const SkPoint* pts() const {
945 return fPts;
946 }
947
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000948 SkPath::Verb verb() const {
949 return fVerb;
950 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000951
caryclark@google.comc899ad92012-08-23 15:24:42 +0000952 void debugShow(const SkPoint& a) const {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000953 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
caryclark@google.comc899ad92012-08-23 15:24:42 +0000954 }
955#endif
956
caryclark@google.com15fa1382012-05-07 20:49:36 +0000957private:
caryclark@google.com235f56a2012-09-14 14:19:30 +0000958 const SkPoint* fPts;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000959 Cubic fCurvePart;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000960 SkPath::Verb fVerb;
961 double fSide;
962 LineParameters fTangent1;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000963 const SkTDArray<Span>* fSpans;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000964 const Segment* fSegment;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000965 int fStart;
966 int fEnd;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000967 bool fReversed;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000968 mutable bool fUnsortable; // this alone is editable by the less than operator
caryclark@google.com15fa1382012-05-07 20:49:36 +0000969};
970
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000971// Bounds, unlike Rect, does not consider a line to be empty.
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000972struct Bounds : public SkRect {
973 static bool Intersects(const Bounds& a, const Bounds& b) {
974 return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
975 a.fTop <= b.fBottom && b.fTop <= a.fBottom;
976 }
977
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000978 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
979 if (left < fLeft) {
980 fLeft = left;
981 }
982 if (top < fTop) {
983 fTop = top;
984 }
985 if (right > fRight) {
986 fRight = right;
987 }
988 if (bottom > fBottom) {
989 fBottom = bottom;
990 }
991 }
992
993 void add(const Bounds& toAdd) {
994 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
995 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000996
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000997 void add(const SkPoint& pt) {
998 if (pt.fX < fLeft) fLeft = pt.fX;
999 if (pt.fY < fTop) fTop = pt.fY;
1000 if (pt.fX > fRight) fRight = pt.fX;
1001 if (pt.fY > fBottom) fBottom = pt.fY;
1002 }
1003
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001004 bool isEmpty() {
1005 return fLeft > fRight || fTop > fBottom
caryclark@google.com235f56a2012-09-14 14:19:30 +00001006 || (fLeft == fRight && fTop == fBottom)
caryclark@google.combeda3892013-02-07 13:13:41 +00001007 || sk_double_isnan(fLeft) || sk_double_isnan(fRight)
1008 || sk_double_isnan(fTop) || sk_double_isnan(fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001009 }
1010
1011 void setCubicBounds(const SkPoint a[4]) {
1012 _Rect dRect;
caryclark@google.com32546db2012-08-31 20:55:07 +00001013 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001014 dRect.setBounds(cubic);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001015 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1016 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001017 }
1018
1019 void setQuadBounds(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +00001020 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001021 _Rect dRect;
1022 dRect.setBounds(quad);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001023 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1024 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001025 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001026
1027 void setPoint(const SkPoint& pt) {
1028 fLeft = fRight = pt.fX;
1029 fTop = fBottom = pt.fY;
1030 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001031};
1032
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001033// OPTIMIZATION: does the following also work, and is it any faster?
1034// return outerWinding * innerWinding > 0
1035// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
caryclark@google.com2ddff932012-08-07 21:25:27 +00001036static bool useInnerWinding(int outerWinding, int innerWinding) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001037 // SkASSERT(outerWinding != innerWinding);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001038 int absOut = abs(outerWinding);
1039 int absIn = abs(innerWinding);
1040 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1041 if (outerWinding * innerWinding < 0) {
1042#if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00001043 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
caryclark@google.com2ddff932012-08-07 21:25:27 +00001044 outerWinding, innerWinding, result ? "true" : "false");
1045#endif
1046 }
1047 return result;
1048}
1049
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001050#define F (false) // discard the edge
1051#define T (true) // keep the edge
1052
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001053static const bool gUnaryActiveEdge[2][2] = {
1054// from=0 from=1
1055// to=0,1 to=0,1
1056 {F, T}, {T, F},
1057};
1058
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001059static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
1060// miFrom=0 miFrom=1
1061// miTo=0 miTo=1 miTo=0 miTo=1
1062// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
1063// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
1064 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
1065 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
1066 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
1067 {{{{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 +00001068};
1069
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001070#undef F
1071#undef T
caryclark@google.com235f56a2012-09-14 14:19:30 +00001072
caryclark@google.comf839c032012-10-26 21:03:50 +00001073// wrap path to keep track of whether the contour is initialized and non-empty
1074class PathWrapper {
1075public:
1076 PathWrapper(SkPath& path)
1077 : fPathPtr(&path)
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001078 , fCloses(0)
1079 , fMoves(0)
caryclark@google.comf839c032012-10-26 21:03:50 +00001080 {
1081 init();
1082 }
1083
1084 void close() {
1085 if (!fHasMove) {
1086 return;
1087 }
1088 bool callClose = isClosed();
1089 lineTo();
1090 if (fEmpty) {
1091 return;
1092 }
1093 if (callClose) {
1094 #if DEBUG_PATH_CONSTRUCTION
1095 SkDebugf("path.close();\n");
1096 #endif
1097 fPathPtr->close();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001098 fCloses++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001099 }
1100 init();
1101 }
1102
1103 void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
1104 lineTo();
1105 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001106 fDefer[1] = pt3;
1107 nudge();
1108 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001109#if DEBUG_PATH_CONSTRUCTION
1110 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001111 pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001112#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001113 fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001114 fEmpty = false;
1115 }
1116
1117 void deferredLine(const SkPoint& pt) {
1118 if (pt == fDefer[1]) {
1119 return;
1120 }
1121 if (changedSlopes(pt)) {
1122 lineTo();
1123 fDefer[0] = fDefer[1];
1124 }
1125 fDefer[1] = pt;
1126 }
1127
1128 void deferredMove(const SkPoint& pt) {
1129 fMoved = true;
1130 fHasMove = true;
1131 fEmpty = true;
1132 fDefer[0] = fDefer[1] = pt;
1133 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001134
caryclark@google.comf839c032012-10-26 21:03:50 +00001135 void deferredMoveLine(const SkPoint& pt) {
1136 if (!fHasMove) {
1137 deferredMove(pt);
1138 }
1139 deferredLine(pt);
1140 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001141
caryclark@google.comf839c032012-10-26 21:03:50 +00001142 bool hasMove() const {
1143 return fHasMove;
1144 }
1145
1146 void init() {
1147 fEmpty = true;
1148 fHasMove = false;
1149 fMoved = false;
1150 }
1151
1152 bool isClosed() const {
1153 return !fEmpty && fFirstPt == fDefer[1];
1154 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001155
caryclark@google.comf839c032012-10-26 21:03:50 +00001156 void lineTo() {
1157 if (fDefer[0] == fDefer[1]) {
1158 return;
1159 }
1160 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001161 nudge();
caryclark@google.comf839c032012-10-26 21:03:50 +00001162 fEmpty = false;
1163#if DEBUG_PATH_CONSTRUCTION
1164 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
1165#endif
1166 fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
1167 fDefer[0] = fDefer[1];
1168 }
1169
1170 const SkPath* nativePath() const {
1171 return fPathPtr;
1172 }
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +00001173
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001174 void nudge() {
1175 if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX)
1176 || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) {
1177 return;
1178 }
1179 fDefer[1] = fFirstPt;
1180 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001181
1182 void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
1183 lineTo();
1184 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001185 fDefer[1] = pt2;
1186 nudge();
1187 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001188#if DEBUG_PATH_CONSTRUCTION
1189 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001190 pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001191#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001192 fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001193 fEmpty = false;
1194 }
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00001195
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001196 bool someAssemblyRequired() const {
1197 return fCloses < fMoves;
1198 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001199
1200protected:
1201 bool changedSlopes(const SkPoint& pt) const {
1202 if (fDefer[0] == fDefer[1]) {
1203 return false;
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001204 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001205 SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
1206 SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
1207 SkScalar lineDx = pt.fX - fDefer[1].fX;
1208 SkScalar lineDy = pt.fY - fDefer[1].fY;
1209 return deferDx * lineDy != deferDy * lineDx;
1210 }
1211
1212 void moveTo() {
1213 if (!fMoved) {
1214 return;
1215 }
1216 fFirstPt = fDefer[0];
1217#if DEBUG_PATH_CONSTRUCTION
1218 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
1219#endif
1220 fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
1221 fMoved = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001222 fMoves++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001223 }
1224
1225private:
1226 SkPath* fPathPtr;
1227 SkPoint fDefer[2];
1228 SkPoint fFirstPt;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001229 int fCloses;
1230 int fMoves;
caryclark@google.comf839c032012-10-26 21:03:50 +00001231 bool fEmpty;
1232 bool fHasMove;
1233 bool fMoved;
1234};
1235
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001236class Segment {
1237public:
1238 Segment() {
1239#if DEBUG_DUMP
1240 fID = ++gSegmentID;
1241#endif
1242 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00001243
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001244 bool operator<(const Segment& rh) const {
1245 return fBounds.fTop < rh.fBounds.fTop;
1246 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001247
caryclark@google.com4eeda372012-12-06 21:47:48 +00001248 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001249 if (activeAngleInner(index, done, angles)) {
1250 return true;
1251 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001252 int lesser = index;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001253 while (--lesser >= 0 && equalPoints(index, lesser)) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001254 if (activeAngleOther(lesser, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001255 return true;
1256 }
1257 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001258 lesser = index;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001259 do {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001260 if (activeAngleOther(index, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001261 return true;
1262 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001263 } while (++index < fTs.count() && equalPoints(index, lesser));
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001264 return false;
1265 }
1266
caryclark@google.com4eeda372012-12-06 21:47:48 +00001267 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001268 Span* span = &fTs[index];
1269 Segment* other = span->fOther;
1270 int oIndex = span->fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001271 return other->activeAngleInner(oIndex, done, angles);
1272 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001273
caryclark@google.com4eeda372012-12-06 21:47:48 +00001274 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001275 int next = nextExactSpan(index, 1);
caryclark@google.com9764cc62012-07-12 19:29:45 +00001276 if (next > 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001277 Span& upSpan = fTs[index];
1278 if (upSpan.fWindValue || upSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001279 addAngle(angles, index, next);
caryclark@google.comf839c032012-10-26 21:03:50 +00001280 if (upSpan.fDone || upSpan.fUnsortableEnd) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001281 done++;
1282 } else if (upSpan.fWindSum != SK_MinS32) {
1283 return true;
1284 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001285 } else if (!upSpan.fDone) {
1286 upSpan.fDone = true;
1287 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001288 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001289 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001290 int prev = nextExactSpan(index, -1);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001291 // edge leading into junction
caryclark@google.com9764cc62012-07-12 19:29:45 +00001292 if (prev >= 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001293 Span& downSpan = fTs[prev];
1294 if (downSpan.fWindValue || downSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001295 addAngle(angles, index, prev);
1296 if (downSpan.fDone) {
1297 done++;
1298 } else if (downSpan.fWindSum != SK_MinS32) {
1299 return true;
1300 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001301 } else if (!downSpan.fDone) {
1302 downSpan.fDone = true;
1303 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001304 }
1305 }
1306 return false;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001307 }
1308
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001309 SkPoint activeLeftTop(bool onlySortable, int* firstT) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001310 SkASSERT(!done());
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001311 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001312 int count = fTs.count();
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001313 // see if either end is not done since we want smaller Y of the pair
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001314 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00001315 bool lastUnsortable = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001316 double lastT = -1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001317 for (int index = 0; index < count; ++index) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001318 const Span& span = fTs[index];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001319 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001320 goto next;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001321 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001322 if (span.fDone && lastDone) {
1323 goto next;
1324 }
1325 if (approximately_negative(span.fT - lastT)) {
1326 goto next;
1327 }
1328 {
1329 const SkPoint& xy = xyAtT(&span);
1330 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
1331 topPt = xy;
1332 if (firstT) {
1333 *firstT = index;
1334 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001335 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001336 if (fVerb != SkPath::kLine_Verb && !lastDone) {
1337 SkPoint curveTop = (*SegmentTop[fVerb])(fPts, lastT, span.fT);
1338 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
1339 && topPt.fX > curveTop.fX)) {
1340 topPt = curveTop;
1341 if (firstT) {
1342 *firstT = index;
1343 }
1344 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001345 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001346 lastT = span.fT;
caryclark@google.comf839c032012-10-26 21:03:50 +00001347 }
1348 next:
1349 lastDone = span.fDone;
1350 lastUnsortable = span.fUnsortableEnd;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001351 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001352 return topPt;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001353 }
1354
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001355 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
1356 int sumMiWinding = updateWinding(endIndex, index);
1357 int sumSuWinding = updateOppWinding(endIndex, index);
1358 if (fOperand) {
1359 SkTSwap<int>(sumMiWinding, sumSuWinding);
1360 }
1361 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1362 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001363 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001364 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001365
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001366 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00001367 int& sumMiWinding, int& sumSuWinding,
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001368 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
1369 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1370 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001371 bool miFrom;
1372 bool miTo;
1373 bool suFrom;
1374 bool suTo;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001375 if (operand()) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001376 miFrom = (oppMaxWinding & xorMiMask) != 0;
1377 miTo = (oppSumWinding & xorMiMask) != 0;
1378 suFrom = (maxWinding & xorSuMask) != 0;
1379 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001380 } else {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001381 miFrom = (maxWinding & xorMiMask) != 0;
1382 miTo = (sumWinding & xorMiMask) != 0;
1383 suFrom = (oppMaxWinding & xorSuMask) != 0;
1384 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001385 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001386 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
caryclark@google.combeda3892013-02-07 13:13:41 +00001387#if DEBUG_ACTIVE_OP
1388 SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__,
1389 kShapeOpStr[op], miFrom, miTo, suFrom, suTo, result);
1390#endif
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001391 SkASSERT(result != -1);
1392 return result;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001393 }
1394
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001395 bool activeWinding(int index, int endIndex) {
1396 int sumWinding = updateWinding(endIndex, index);
1397 int maxWinding;
1398 return activeWinding(index, endIndex, maxWinding, sumWinding);
1399 }
1400
1401 bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
1402 setUpWinding(index, endIndex, maxWinding, sumWinding);
1403 bool from = maxWinding != 0;
1404 bool to = sumWinding != 0;
1405 bool result = gUnaryActiveEdge[from][to];
1406 SkASSERT(result != -1);
1407 return result;
1408 }
1409
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001410 void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001411 SkASSERT(start != end);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001412 Angle* angle = angles.append();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001413#if DEBUG_ANGLE
caryclark@google.com31143cf2012-11-09 22:14:19 +00001414 if (angles.count() > 1 && !fTs[start].fTiny) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001415 SkPoint angle0Pt, newPt;
1416 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
1417 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
1418 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
caryclark@google.com6d0032a2013-01-04 19:41:13 +00001419 SkASSERT(AlmostEqualUlps(angle0Pt.fX, newPt.fX));
1420 SkASSERT(AlmostEqualUlps(angle0Pt.fY, newPt.fY));
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001421 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001422#endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001423 angle->set(fPts, fVerb, this, start, end, fTs);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001424 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001425
caryclark@google.com2ddff932012-08-07 21:25:27 +00001426 void addCancelOutsides(double tStart, double oStart, Segment& other,
caryclark@google.comcc905052012-07-25 20:59:42 +00001427 double oEnd) {
1428 int tIndex = -1;
1429 int tCount = fTs.count();
1430 int oIndex = -1;
1431 int oCount = other.fTs.count();
caryclark@google.comcc905052012-07-25 20:59:42 +00001432 do {
1433 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001434 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001435 int tIndexStart = tIndex;
1436 do {
1437 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001438 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001439 int oIndexStart = oIndex;
1440 double nextT;
1441 do {
1442 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001443 } while (nextT < 1 && approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001444 double oNextT;
1445 do {
1446 oNextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001447 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001448 // at this point, spans before and after are at:
1449 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1450 // if tIndexStart == 0, no prior span
1451 // if nextT == 1, no following span
rmistry@google.comd6176b02012-08-23 18:14:13 +00001452
caryclark@google.comcc905052012-07-25 20:59:42 +00001453 // advance the span with zero winding
1454 // if the following span exists (not past the end, non-zero winding)
1455 // connect the two edges
1456 if (!fTs[tIndexStart].fWindValue) {
1457 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1458 #if DEBUG_CONCIDENT
1459 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1460 __FUNCTION__, fID, other.fID, tIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001461 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
1462 xyAtT(tIndexStart).fY);
caryclark@google.comcc905052012-07-25 20:59:42 +00001463 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001464 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false,
1465 fTs[tIndexStart].fPt);
caryclark@google.comcc905052012-07-25 20:59:42 +00001466 }
1467 if (nextT < 1 && fTs[tIndex].fWindValue) {
1468 #if DEBUG_CONCIDENT
1469 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1470 __FUNCTION__, fID, other.fID, tIndex,
1471 fTs[tIndex].fT, xyAtT(tIndex).fX,
1472 xyAtT(tIndex).fY);
1473 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001474 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false, fTs[tIndex].fPt);
caryclark@google.comcc905052012-07-25 20:59:42 +00001475 }
1476 } else {
1477 SkASSERT(!other.fTs[oIndexStart].fWindValue);
1478 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1479 #if DEBUG_CONCIDENT
1480 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1481 __FUNCTION__, fID, other.fID, oIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001482 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
1483 other.xyAtT(oIndexStart).fY);
1484 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
caryclark@google.comcc905052012-07-25 20:59:42 +00001485 #endif
caryclark@google.comcc905052012-07-25 20:59:42 +00001486 }
1487 if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1488 #if DEBUG_CONCIDENT
1489 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1490 __FUNCTION__, fID, other.fID, oIndex,
1491 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1492 other.xyAtT(oIndex).fY);
1493 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1494 #endif
1495 }
1496 }
1497 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001498
caryclark@google.comcc905052012-07-25 20:59:42 +00001499 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1500 double oEnd) {
1501 // walk this to outsideTs[0]
1502 // walk other to outsideTs[1]
1503 // if either is > 0, add a pointer to the other, copying adjacent winding
1504 int tIndex = -1;
1505 int oIndex = -1;
1506 double tStart = outsideTs[0];
1507 double oStart = outsideTs[1];
1508 do {
1509 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001510 } while (!approximately_negative(tStart - fTs[tIndex].fT));
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001511 SkPoint ptStart = fTs[tIndex].fPt;
caryclark@google.comcc905052012-07-25 20:59:42 +00001512 do {
1513 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001514 } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001515 if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001516 addTPair(tStart, other, oStart, false, ptStart);
caryclark@google.comcc905052012-07-25 20:59:42 +00001517 }
1518 tStart = fTs[tIndex].fT;
1519 oStart = other.fTs[oIndex].fT;
1520 do {
1521 double nextT;
1522 do {
1523 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001524 } while (approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001525 tStart = nextT;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001526 ptStart = fTs[tIndex].fPt;
caryclark@google.comcc905052012-07-25 20:59:42 +00001527 do {
1528 nextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001529 } while (approximately_negative(nextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001530 oStart = nextT;
caryclark@google.com4eeda372012-12-06 21:47:48 +00001531 if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001532 break;
1533 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001534 addTPair(tStart, other, oStart, false, ptStart);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001535 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001536 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001537
caryclark@google.com4eeda372012-12-06 21:47:48 +00001538 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
1539 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001540 fBounds.setCubicBounds(pts);
1541 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001542
caryclark@google.comf839c032012-10-26 21:03:50 +00001543 /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001544 SkPoint edge[4];
caryclark@google.comf839c032012-10-26 21:03:50 +00001545 const SkPoint* ePtr;
1546 int lastT = fTs.count() - 1;
1547 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1548 ePtr = fPts;
1549 } else {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001550 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
caryclark@google.comf839c032012-10-26 21:03:50 +00001551 (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
1552 ePtr = edge;
1553 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001554 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001555 bool reverse = ePtr == fPts && start != 0;
1556 if (reverse) {
1557 path.deferredMoveLine(ePtr[fVerb]);
1558 switch (fVerb) {
1559 case SkPath::kLine_Verb:
1560 path.deferredLine(ePtr[0]);
1561 break;
1562 case SkPath::kQuad_Verb:
1563 path.quadTo(ePtr[1], ePtr[0]);
1564 break;
1565 case SkPath::kCubic_Verb:
1566 path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1567 break;
1568 default:
1569 SkASSERT(0);
1570 }
1571 // return ePtr[0];
1572 } else {
1573 path.deferredMoveLine(ePtr[0]);
1574 switch (fVerb) {
1575 case SkPath::kLine_Verb:
1576 path.deferredLine(ePtr[1]);
1577 break;
1578 case SkPath::kQuad_Verb:
1579 path.quadTo(ePtr[1], ePtr[2]);
1580 break;
1581 case SkPath::kCubic_Verb:
1582 path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1583 break;
1584 default:
1585 SkASSERT(0);
1586 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001587 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001588 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001589 // return ePtr[fVerb];
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001590 }
1591
caryclark@google.com4eeda372012-12-06 21:47:48 +00001592 void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
1593 init(pts, SkPath::kLine_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001594 fBounds.set(pts, 2);
1595 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001596
caryclark@google.comf839c032012-10-26 21:03:50 +00001597#if 0
1598 const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001599 const SkPoint& pt = xyAtT(tIndex);
1600 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001601 path.deferredMove(pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001602 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00001603 return pt;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001604 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001605#endif
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001606
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001607 // add 2 to edge or out of range values to get T extremes
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001608 void addOtherT(int index, double otherT, int otherIndex) {
1609 Span& span = fTs[index];
caryclark@google.comf839c032012-10-26 21:03:50 +00001610 #if PIN_ADD_T
caryclark@google.com185c7c42012-10-19 18:26:24 +00001611 if (precisely_less_than_zero(otherT)) {
1612 otherT = 0;
1613 } else if (precisely_greater_than_one(otherT)) {
1614 otherT = 1;
1615 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001616 #endif
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001617 span.fOtherT = otherT;
1618 span.fOtherIndex = otherIndex;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001619 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001620
caryclark@google.com4eeda372012-12-06 21:47:48 +00001621 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
1622 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001623 fBounds.setQuadBounds(pts);
1624 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001625
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001626 // Defer all coincident edge processing until
1627 // after normal intersections have been computed
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001628
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001629// no need to be tricky; insert in normal T order
1630// resolve overlapping ts when considering coincidence later
1631
1632 // add non-coincident intersection. Resulting edges are sorted in T.
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001633 int addT(double newT, Segment* other, const SkPoint& pt) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001634 // FIXME: in the pathological case where there is a ton of intercepts,
1635 // binary search?
1636 int insertedAt = -1;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001637 size_t tCount = fTs.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00001638 #if PIN_ADD_T
caryclark@google.comc899ad92012-08-23 15:24:42 +00001639 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
caryclark@google.com185c7c42012-10-19 18:26:24 +00001640 if (precisely_less_than_zero(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001641 newT = 0;
caryclark@google.com185c7c42012-10-19 18:26:24 +00001642 } else if (precisely_greater_than_one(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001643 newT = 1;
1644 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001645 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001646 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001647 // OPTIMIZATION: if there are three or more identical Ts, then
1648 // the fourth and following could be further insertion-sorted so
1649 // that all the edges are clockwise or counterclockwise.
1650 // This could later limit segment tests to the two adjacent
1651 // neighbors, although it doesn't help with determining which
1652 // circular direction to go in.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001653 if (newT < fTs[index].fT) {
1654 insertedAt = index;
1655 break;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001656 }
1657 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001658 Span* span;
1659 if (insertedAt >= 0) {
1660 span = fTs.insert(insertedAt);
1661 } else {
1662 insertedAt = tCount;
1663 span = fTs.append();
1664 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001665 span->fT = newT;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001666 span->fOther = other;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001667 span->fPt = pt;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001668 span->fWindSum = SK_MinS32;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001669 span->fOppSum = SK_MinS32;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001670 span->fWindValue = 1;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001671 span->fOppValue = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00001672 span->fTiny = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001673 if ((span->fDone = newT == 1)) {
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00001674 ++fDoneSpans;
rmistry@google.comd6176b02012-08-23 18:14:13 +00001675 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001676 span->fUnsortableStart = false;
1677 span->fUnsortableEnd = false;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001678 int less = -1;
1679 while (&span[less + 1] - fTs.begin() > 0 && !span[less].fDone
1680 && !precisely_negative(newT - span[less].fT)
1681 // && approximately_negative(newT - span[less].fT)
1682 && xyAtT(&span[less]) == xyAtT(span)) {
1683 span[less].fTiny = true;
1684 span[less].fDone = true;
1685 if (approximately_negative(newT - span[less].fT)) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00001686 if (approximately_greater_than_one(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001687 span[less].fUnsortableStart = true;
1688 span[less - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001689 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001690 if (approximately_less_than_zero(span[less].fT)) {
1691 span[less + 1].fUnsortableStart = true;
1692 span[less].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001693 }
1694 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001695 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001696 --less;
caryclark@google.comf839c032012-10-26 21:03:50 +00001697 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001698 int more = 1;
1699 while (fTs.end() - &span[more - 1] > 1 && !span[more - 1].fDone
1700 && !precisely_negative(span[more].fT - newT)
1701 // && approximately_negative(span[more].fT - newT)
1702 && xyAtT(&span[more]) == xyAtT(span)) {
1703 span[more - 1].fTiny = true;
1704 span[more - 1].fDone = true;
1705 if (approximately_negative(span[more].fT - newT)) {
1706 if (approximately_greater_than_one(span[more].fT)) {
1707 span[more + 1].fUnsortableStart = true;
1708 span[more].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001709 }
1710 if (approximately_less_than_zero(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001711 span[more].fUnsortableStart = true;
1712 span[more - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001713 }
1714 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001715 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001716 ++more;
caryclark@google.comf839c032012-10-26 21:03:50 +00001717 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001718 return insertedAt;
1719 }
1720
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001721 // set spans from start to end to decrement by one
1722 // note this walks other backwards
1723 // FIMXE: there's probably an edge case that can be constructed where
1724 // two span in one segment are separated by float epsilon on one span but
1725 // not the other, if one segment is very small. For this
1726 // case the counts asserted below may or may not be enough to separate the
caryclark@google.com2ddff932012-08-07 21:25:27 +00001727 // spans. Even if the counts work out, what if the spans aren't correctly
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001728 // sorted? It feels better in such a case to match the span's other span
1729 // pointer since both coincident segments must contain the same spans.
1730 void addTCancel(double startT, double endT, Segment& other,
1731 double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001732 SkASSERT(!approximately_negative(endT - startT));
1733 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00001734 bool binary = fOperand != other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001735 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001736 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001737 ++index;
1738 }
caryclark@google.comb9738012012-07-03 19:53:30 +00001739 int oIndex = other.fTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001740 while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001741 ;
caryclark@google.com59823f72012-08-09 18:17:47 +00001742 double tRatio = (oEndT - oStartT) / (endT - startT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001743 Span* test = &fTs[index];
1744 Span* oTest = &other.fTs[oIndex];
caryclark@google.com18063442012-07-25 12:05:18 +00001745 SkTDArray<double> outsideTs;
1746 SkTDArray<double> oOutsideTs;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001747 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001748 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
caryclark@google.comcc905052012-07-25 20:59:42 +00001749 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.com200c2112012-08-03 15:05:04 +00001750 double testT = test->fT;
1751 double oTestT = oTest->fT;
1752 Span* span = test;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001753 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001754 if (decrement) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001755 decrementSpan(span);
caryclark@google.com200c2112012-08-03 15:05:04 +00001756 } else if (track && span->fT < 1 && oTestT < 1) {
1757 TrackOutside(outsideTs, span->fT, oTestT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001758 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001759 span = &fTs[++index];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001760 } while (approximately_negative(span->fT - testT));
caryclark@google.com200c2112012-08-03 15:05:04 +00001761 Span* oSpan = oTest;
caryclark@google.com59823f72012-08-09 18:17:47 +00001762 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1763 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1764 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001765 while (approximately_negative(otherTMatchStart - oSpan->fT)
1766 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
caryclark@google.com03f97062012-08-21 13:13:52 +00001767 #ifdef SK_DEBUG
caryclark@google.com59823f72012-08-09 18:17:47 +00001768 SkASSERT(originalWindValue == oSpan->fWindValue);
caryclark@google.com03f97062012-08-21 13:13:52 +00001769 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001770 if (decrement) {
caryclark@google.com200c2112012-08-03 15:05:04 +00001771 other.decrementSpan(oSpan);
1772 } else if (track && oSpan->fT < 1 && testT < 1) {
1773 TrackOutside(oOutsideTs, oSpan->fT, testT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001774 }
1775 if (!oIndex) {
1776 break;
1777 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001778 oSpan = &other.fTs[--oIndex];
rmistry@google.comd6176b02012-08-23 18:14:13 +00001779 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001780 test = span;
1781 oTest = oSpan;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001782 } while (!approximately_negative(endT - test->fT));
1783 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
caryclark@google.com18063442012-07-25 12:05:18 +00001784 // FIXME: determine if canceled edges need outside ts added
caryclark@google.comcc905052012-07-25 20:59:42 +00001785 if (!done() && outsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001786 double tStart = outsideTs[0];
1787 double oStart = outsideTs[1];
1788 addCancelOutsides(tStart, oStart, other, oEndT);
1789 int count = outsideTs.count();
1790 if (count > 2) {
1791 double tStart = outsideTs[count - 2];
1792 double oStart = outsideTs[count - 1];
1793 addCancelOutsides(tStart, oStart, other, oEndT);
1794 }
caryclark@google.com18063442012-07-25 12:05:18 +00001795 }
caryclark@google.comcc905052012-07-25 20:59:42 +00001796 if (!other.done() && oOutsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001797 double tStart = oOutsideTs[0];
1798 double oStart = oOutsideTs[1];
1799 other.addCancelOutsides(tStart, oStart, *this, endT);
caryclark@google.com18063442012-07-25 12:05:18 +00001800 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001801 }
skia.committer@gmail.com15dd3002013-01-18 07:07:28 +00001802
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001803 int addUnsortableT(double newT, Segment* other, bool start, const SkPoint& pt) {
1804 int result = addT(newT, other, pt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00001805 Span* span = &fTs[result];
1806 if (start) {
1807 if (result > 0) {
1808 span[result - 1].fUnsortableEnd = true;
1809 }
1810 span[result].fUnsortableStart = true;
1811 } else {
1812 span[result].fUnsortableEnd = true;
1813 if (result + 1 < fTs.count()) {
1814 span[result + 1].fUnsortableStart = true;
1815 }
1816 }
1817 return result;
1818 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00001819
caryclark@google.com4eeda372012-12-06 21:47:48 +00001820 int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1821 SkTDArray<double>& outsideTs) {
1822 int oWindValue = oTest->fWindValue;
1823 int oOppValue = oTest->fOppValue;
1824 if (opp) {
1825 SkTSwap<int>(oWindValue, oOppValue);
1826 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001827 Span* const test = &fTs[index];
1828 Span* end = test;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001829 const double oStartT = oTest->fT;
1830 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001831 if (bumpSpan(end, oWindValue, oOppValue)) {
1832 TrackOutside(outsideTs, end->fT, oStartT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001833 }
1834 end = &fTs[++index];
1835 } while (approximately_negative(end->fT - test->fT));
1836 return index;
1837 }
1838
1839 // because of the order in which coincidences are resolved, this and other
1840 // may not have the same intermediate points. Compute the corresponding
1841 // intermediate T values (using this as the master, other as the follower)
1842 // and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com4eeda372012-12-06 21:47:48 +00001843 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1844 SkTDArray<double>& oOutsideTs) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001845 Span* const oTest = &fTs[oIndex];
1846 Span* oEnd = oTest;
1847 const double startT = test->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001848 const double oStartT = oTest->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001849 while (!approximately_negative(oEndT - oEnd->fT)
caryclark@google.com4eeda372012-12-06 21:47:48 +00001850 && approximately_negative(oEnd->fT - oStartT)) {
1851 zeroSpan(oEnd);
1852 TrackOutside(oOutsideTs, oEnd->fT, startT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001853 oEnd = &fTs[++oIndex];
1854 }
1855 return oIndex;
1856 }
1857
1858 // FIXME: need to test this case:
1859 // contourA has two segments that are coincident
1860 // contourB has two segments that are coincident in the same place
1861 // each ends up with +2/0 pairs for winding count
1862 // since logic below doesn't transfer count (only increments/decrements) can this be
1863 // resolved to +4/0 ?
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001864
1865 // set spans from start to end to increment the greater by one and decrement
1866 // the lesser
caryclark@google.com4eeda372012-12-06 21:47:48 +00001867 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001868 SkASSERT(!approximately_negative(endT - startT));
1869 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001870 bool opp = fOperand ^ other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001871 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001872 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001873 ++index;
1874 }
1875 int oIndex = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001876 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001877 ++oIndex;
1878 }
1879 Span* test = &fTs[index];
1880 Span* oTest = &other.fTs[oIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001881 SkTDArray<double> outsideTs;
1882 SkTDArray<double> oOutsideTs;
1883 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001884 // if either span has an opposite value and the operands don't match, resolve first
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001885 // SkASSERT(!test->fDone || !oTest->fDone);
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001886 if (test->fDone || oTest->fDone) {
1887 index = advanceCoincidentThis(oTest, opp, index);
1888 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
1889 } else {
1890 index = bumpCoincidentThis(oTest, opp, index, outsideTs);
1891 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
1892 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001893 test = &fTs[index];
1894 oTest = &other.fTs[oIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001895 } while (!approximately_negative(endT - test->fT));
1896 SkASSERT(approximately_negative(oTest->fT - oEndT));
1897 SkASSERT(approximately_negative(oEndT - oTest->fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001898 if (!done() && outsideTs.count()) {
1899 addCoinOutsides(outsideTs, other, oEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001900 }
1901 if (!other.done() && oOutsideTs.count()) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001902 other.addCoinOutsides(oOutsideTs, *this, endT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001903 }
1904 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001905
caryclark@google.comcc905052012-07-25 20:59:42 +00001906 // FIXME: this doesn't prevent the same span from being added twice
caryclark@google.comaa358312013-01-29 20:28:49 +00001907 // fix in caller, SkASSERT here?
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001908 void addTPair(double t, Segment& other, double otherT, bool borrowWind, const SkPoint& pt) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001909 int tCount = fTs.count();
1910 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1911 const Span& span = fTs[tIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001912 if (!approximately_negative(span.fT - t)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001913 break;
1914 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001915 if (approximately_negative(span.fT - t) && span.fOther == &other
1916 && approximately_equal(span.fOtherT, otherT)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001917#if DEBUG_ADD_T_PAIR
1918 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1919 __FUNCTION__, fID, t, other.fID, otherT);
1920#endif
1921 return;
1922 }
1923 }
caryclark@google.com47580692012-07-23 12:14:49 +00001924#if DEBUG_ADD_T_PAIR
1925 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1926 __FUNCTION__, fID, t, other.fID, otherT);
1927#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001928 int insertedAt = addT(t, &other, pt);
1929 int otherInsertedAt = other.addT(otherT, this, pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001930 addOtherT(insertedAt, otherT, otherInsertedAt);
caryclark@google.comb9738012012-07-03 19:53:30 +00001931 other.addOtherT(otherInsertedAt, t, insertedAt);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001932 matchWindingValue(insertedAt, t, borrowWind);
1933 other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001934 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001935
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001936 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001937 // add edge leading into junction
caryclark@google.com4eeda372012-12-06 21:47:48 +00001938 int min = SkMin32(end, start);
1939 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001940 addAngle(angles, end, start);
1941 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001942 // add edge leading away from junction
caryclark@google.com495f8e42012-05-31 13:13:11 +00001943 int step = SkSign32(end - start);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001944 int tIndex = nextExactSpan(end, step);
caryclark@google.com4eeda372012-12-06 21:47:48 +00001945 min = SkMin32(end, tIndex);
1946 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001947 addAngle(angles, end, tIndex);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001948 }
1949 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001950
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001951 int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
1952 Span* const test = &fTs[index];
1953 Span* end = test;
1954 do {
1955 end = &fTs[++index];
1956 } while (approximately_negative(end->fT - test->fT));
1957 return index;
1958 }
1959
1960 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
1961 Span* const oTest = &fTs[oIndex];
1962 Span* oEnd = oTest;
1963 const double oStartT = oTest->fT;
1964 while (!approximately_negative(oEndT - oEnd->fT)
1965 && approximately_negative(oEnd->fT - oStartT)) {
1966 oEnd = &fTs[++oIndex];
1967 }
1968 return oIndex;
1969 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00001970
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001971 bool betweenTs(int lesser, double testT, int greater) {
1972 if (lesser > greater) {
1973 SkTSwap<int>(lesser, greater);
1974 }
1975 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
1976 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001977
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001978 const Bounds& bounds() const {
1979 return fBounds;
1980 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001981
caryclark@google.com31143cf2012-11-09 22:14:19 +00001982 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001983 double referenceT = fTs[index].fT;
1984 int lesser = index;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001985 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
1986 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00001987 buildAnglesInner(lesser, angles);
1988 }
1989 do {
1990 buildAnglesInner(index, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001991 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
1992 && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001993 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001994
1995 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
1996 Span* span = &fTs[index];
1997 Segment* other = span->fOther;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001998 // if there is only one live crossing, and no coincidence, continue
1999 // in the same direction
2000 // if there is coincidence, the only choice may be to reverse direction
2001 // find edge on either side of intersection
2002 int oIndex = span->fOtherIndex;
2003 // if done == -1, prior span has already been processed
2004 int step = 1;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002005 int next = other->nextExactSpan(oIndex, step);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002006 if (next < 0) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002007 step = -step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002008 next = other->nextExactSpan(oIndex, step);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002009 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002010 // add candidate into and away from junction
2011 other->addTwoAngles(next, oIndex, angles);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002012 }
2013
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002014 int computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002015 SkTDArray<Angle> angles;
2016 addTwoAngles(startIndex, endIndex, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002017 buildAngles(endIndex, angles, false);
caryclark@google.comd1688742012-09-18 20:08:37 +00002018 // OPTIMIZATION: check all angles to see if any have computed wind sum
2019 // before sorting (early exit if none)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002020 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002021 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002022#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002023 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002024#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002025 if (!sortable) {
2026 return SK_MinS32;
2027 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002028 int angleCount = angles.count();
2029 const Angle* angle;
2030 const Segment* base;
2031 int winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002032 int oWinding;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002033 int firstIndex = 0;
2034 do {
2035 angle = sorted[firstIndex];
2036 base = angle->segment();
2037 winding = base->windSum(angle);
2038 if (winding != SK_MinS32) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002039 oWinding = base->oppSum(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002040 break;
2041 }
2042 if (++firstIndex == angleCount) {
2043 return SK_MinS32;
2044 }
2045 } while (true);
2046 // turn winding into contourWinding
caryclark@google.com2ddff932012-08-07 21:25:27 +00002047 int spanWinding = base->spanSign(angle);
2048 bool inner = useInnerWinding(winding + spanWinding, winding);
2049 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00002050 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
caryclark@google.com59823f72012-08-09 18:17:47 +00002051 spanWinding, winding, angle->sign(), inner,
caryclark@google.com2ddff932012-08-07 21:25:27 +00002052 inner ? winding + spanWinding : winding);
2053 #endif
2054 if (inner) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002055 winding += spanWinding;
2056 }
2057 #if DEBUG_SORT
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002058 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002059 #endif
2060 int nextIndex = firstIndex + 1;
2061 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com2ddff932012-08-07 21:25:27 +00002062 winding -= base->spanSign(angle);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002063 oWinding -= base->oppSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002064 do {
2065 if (nextIndex == angleCount) {
2066 nextIndex = 0;
2067 }
2068 angle = sorted[nextIndex];
2069 Segment* segment = angle->segment();
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002070 bool opp = base->fOperand ^ segment->fOperand;
2071 int maxWinding, oMaxWinding;
2072 int spanSign = segment->spanSign(angle);
2073 int oppoSign = segment->oppSign(angle);
2074 if (opp) {
2075 oMaxWinding = oWinding;
2076 oWinding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002077 maxWinding = winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002078 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002079 winding -= oppoSign;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002080 }
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002081 } else {
2082 maxWinding = winding;
2083 winding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002084 oMaxWinding = oWinding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002085 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002086 oWinding -= oppoSign;
2087 }
2088 }
2089 if (segment->windSum(angle) == SK_MinS32) {
2090 if (opp) {
2091 if (useInnerWinding(oMaxWinding, oWinding)) {
2092 oMaxWinding = oWinding;
2093 }
2094 if (oppoSign && useInnerWinding(maxWinding, winding)) {
2095 maxWinding = winding;
2096 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002097 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002098 } else {
2099 if (useInnerWinding(maxWinding, winding)) {
2100 maxWinding = winding;
2101 }
2102 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
2103 oMaxWinding = oWinding;
2104 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002105 (void) segment->markAndChaseWinding(angle, maxWinding,
2106 binary ? oMaxWinding : 0);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002107 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002108 }
2109 } while (++nextIndex != lastIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002110 int minIndex = SkMin32(startIndex, endIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002111 return windSum(minIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002112 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002113
caryclark@google.com3586ece2012-12-27 18:46:58 +00002114 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
caryclark@google.com10227bf2012-12-28 22:10:41 +00002115 double mid, bool opp, bool current) const {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002116 SkScalar bottom = fBounds.fBottom;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002117 int bestTIndex = -1;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002118 if (bottom <= bestY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002119 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002120 }
2121 SkScalar top = fBounds.fTop;
2122 if (top >= basePt.fY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002123 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002124 }
2125 if (fBounds.fLeft > basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002126 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002127 }
2128 if (fBounds.fRight < basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002129 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002130 }
2131 if (fBounds.fLeft == fBounds.fRight) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002132 // if vertical, and directly above test point, wait for another one
caryclark@google.com6d0032a2013-01-04 19:41:13 +00002133 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002134 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002135 // intersect ray starting at basePt with edge
2136 Intersections intersections;
2137 // OPTIMIZE: use specialty function that intersects ray with curve,
2138 // returning t values only for curve (we don't care about t on ray)
2139 int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
2140 if (pts == 0 || (current && pts == 1)) {
2141 return bestTIndex;
2142 }
2143 if (current) {
2144 SkASSERT(pts > 1);
2145 int closestIdx = 0;
2146 double closest = fabs(intersections.fT[0][0] - mid);
2147 for (int idx = 1; idx < pts; ++idx) {
2148 double test = fabs(intersections.fT[0][idx] - mid);
2149 if (closest > test) {
2150 closestIdx = idx;
2151 closest = test;
2152 }
2153 }
2154 if (closestIdx < pts - 1) {
2155 intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
2156 }
2157 --pts;
2158 }
2159 double bestT = -1;
2160 for (int index = 0; index < pts; ++index) {
2161 double foundT = intersections.fT[0][index];
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002162 if (approximately_less_than_zero(foundT)
2163 || approximately_greater_than_one(foundT)) {
2164 continue;
2165 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002166 SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
2167 if (approximately_negative(testY - bestY)
2168 || approximately_negative(basePt.fY - testY)) {
caryclark@google.com47580692012-07-23 12:14:49 +00002169 continue;
2170 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002171 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002172 return SK_MinS32; // if the intersection is edge on, wait for another one
caryclark@google.com10227bf2012-12-28 22:10:41 +00002173 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002174 if (fVerb > SkPath::kLine_Verb) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002175 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
2176 if (approximately_zero(dx)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002177 return SK_MinS32; // hit vertical, wait for another one
caryclark@google.com3586ece2012-12-27 18:46:58 +00002178 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00002179 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002180 bestY = testY;
2181 bestT = foundT;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002182 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002183 if (bestT < 0) {
2184 return bestTIndex;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002185 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002186 SkASSERT(bestT >= 0);
2187 SkASSERT(bestT <= 1);
2188 int start;
2189 int end = 0;
2190 do {
2191 start = end;
2192 end = nextSpan(start, 1);
2193 } while (fTs[end].fT < bestT);
2194 // FIXME: see next candidate for a better pattern to find the next start/end pair
2195 while (start + 1 < end && fTs[start].fDone) {
2196 ++start;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002197 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002198 if (!isCanceled(start)) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002199 hitT = bestT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002200 bestTIndex = start;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002201 hitSomething = true;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002202 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002203 return bestTIndex;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002204 }
caryclark@google.com18063442012-07-25 12:05:18 +00002205
caryclark@google.com4eeda372012-12-06 21:47:48 +00002206 void decrementSpan(Span* span) {
caryclark@google.com18063442012-07-25 12:05:18 +00002207 SkASSERT(span->fWindValue > 0);
2208 if (--(span->fWindValue) == 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002209 if (!span->fOppValue && !span->fDone) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002210 span->fDone = true;
2211 ++fDoneSpans;
2212 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002213 }
2214 }
2215
2216 bool bumpSpan(Span* span, int windDelta, int oppDelta) {
2217 SkASSERT(!span->fDone);
2218 span->fWindValue += windDelta;
2219 SkASSERT(span->fWindValue >= 0);
2220 span->fOppValue += oppDelta;
2221 SkASSERT(span->fOppValue >= 0);
2222 if (fXor) {
2223 span->fWindValue &= 1;
2224 }
2225 if (fOppXor) {
2226 span->fOppValue &= 1;
2227 }
2228 if (!span->fWindValue && !span->fOppValue) {
2229 span->fDone = true;
2230 ++fDoneSpans;
caryclark@google.com18063442012-07-25 12:05:18 +00002231 return true;
2232 }
2233 return false;
2234 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002235
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002236 // OPTIMIZE
2237 // when the edges are initially walked, they don't automatically get the prior and next
2238 // 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 +00002239 // and would additionally remove the need for similar checks in condition edges. It would
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002240 // also allow intersection code to assume end of segment intersections (maybe?)
2241 bool complete() const {
2242 int count = fTs.count();
2243 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
2244 }
caryclark@google.com18063442012-07-25 12:05:18 +00002245
caryclark@google.com15fa1382012-05-07 20:49:36 +00002246 bool done() const {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002247 SkASSERT(fDoneSpans <= fTs.count());
2248 return fDoneSpans == fTs.count();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002249 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002250
caryclark@google.comf839c032012-10-26 21:03:50 +00002251 bool done(int min) const {
2252 return fTs[min].fDone;
2253 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002254
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002255 bool done(const Angle* angle) const {
2256 return done(SkMin32(angle->start(), angle->end()));
caryclark@google.com47580692012-07-23 12:14:49 +00002257 }
skia.committer@gmail.com044679e2013-02-15 07:16:57 +00002258
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002259 SkPoint dxdy(int index) const {
2260 return (*SegmentDXDYAtT[fVerb])(fPts, fTs[index].fT);
2261 }
2262
2263 SkScalar dy(int index) const {
2264 return (*SegmentDYAtT[fVerb])(fPts, fTs[index].fT);
2265 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00002266
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002267 bool equalPoints(int greaterTIndex, int lesserTIndex) {
2268 SkASSERT(greaterTIndex >= lesserTIndex);
2269 double greaterT = fTs[greaterTIndex].fT;
2270 double lesserT = fTs[lesserTIndex].fT;
2271 if (greaterT == lesserT) {
2272 return true;
2273 }
2274 if (!approximately_negative(greaterT - lesserT)) {
2275 return false;
2276 }
2277 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2278 }
2279
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002280 /*
2281 The M and S variable name parts stand for the operators.
2282 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2283 Su stands for Subtrahend
2284 The Opp variable name part designates that the value is for the Opposite operator.
2285 Opposite values result from combining coincident spans.
2286 */
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002287
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002288 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2289 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002290 const int startIndex = nextStart;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002291 const int endIndex = nextEnd;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002292 SkASSERT(startIndex != endIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002293 const int count = fTs.count();
2294 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2295 const int step = SkSign32(endIndex - startIndex);
2296 const int end = nextExactSpan(startIndex, step);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002297 SkASSERT(end >= 0);
2298 Span* endSpan = &fTs[end];
2299 Segment* other;
2300 if (isSimple(end)) {
2301 // mark the smaller of startIndex, endIndex done, and all adjacent
2302 // spans with the same T value (but not 'other' spans)
2303 #if DEBUG_WINDING
2304 SkDebugf("%s simple\n", __FUNCTION__);
2305 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002306 int min = SkMin32(startIndex, endIndex);
2307 if (fTs[min].fDone) {
2308 return NULL;
2309 }
2310 markDoneBinary(min);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002311 other = endSpan->fOther;
2312 nextStart = endSpan->fOtherIndex;
2313 double startT = other->fTs[nextStart].fT;
2314 nextEnd = nextStart;
2315 do {
2316 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002317 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002318 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002319 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2320 return other;
2321 }
2322 // more than one viable candidate -- measure angles to find best
2323 SkTDArray<Angle> angles;
2324 SkASSERT(startIndex - endIndex != 0);
2325 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2326 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002327 buildAngles(end, angles, true);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002328 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002329 bool sortable = SortAngles(angles, sorted);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002330 int angleCount = angles.count();
2331 int firstIndex = findStartingEdge(sorted, startIndex, end);
2332 SkASSERT(firstIndex >= 0);
2333 #if DEBUG_SORT
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002334 debugShowSort(__FUNCTION__, sorted, firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002335 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002336 if (!sortable) {
2337 unsortable = true;
2338 return NULL;
2339 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002340 SkASSERT(sorted[firstIndex]->segment() == this);
2341 #if DEBUG_WINDING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002342 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2343 sorted[firstIndex]->sign());
caryclark@google.com235f56a2012-09-14 14:19:30 +00002344 #endif
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002345 int sumMiWinding = updateWinding(endIndex, startIndex);
2346 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2347 if (operand()) {
2348 SkTSwap<int>(sumMiWinding, sumSuWinding);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002349 }
2350 int nextIndex = firstIndex + 1;
2351 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2352 const Angle* foundAngle = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002353 bool foundDone = false;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002354 // iterate through the angle, and compute everyone's winding
caryclark@google.com235f56a2012-09-14 14:19:30 +00002355 Segment* nextSegment;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002356 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002357 SkASSERT(nextIndex != firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002358 if (nextIndex == angleCount) {
2359 nextIndex = 0;
2360 }
2361 const Angle* nextAngle = sorted[nextIndex];
2362 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002363 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2364 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2365 nextAngle->end(), op, sumMiWinding, sumSuWinding,
2366 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
2367 if (activeAngle && (!foundAngle || foundDone)) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002368 foundAngle = nextAngle;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002369 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002370 }
2371 if (nextSegment->done()) {
2372 continue;
2373 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002374 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2375 continue;
2376 }
2377 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2378 oppSumWinding, activeAngle, nextAngle);
2379 if (last) {
2380 *chase.append() = last;
2381#if DEBUG_WINDING
2382 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2383 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2384#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002385 }
2386 } while (++nextIndex != lastIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002387 markDoneBinary(SkMin32(startIndex, endIndex));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002388 if (!foundAngle) {
2389 return NULL;
2390 }
2391 nextStart = foundAngle->start();
2392 nextEnd = foundAngle->end();
2393 nextSegment = foundAngle->segment();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002394
caryclark@google.com235f56a2012-09-14 14:19:30 +00002395 #if DEBUG_WINDING
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002396 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2397 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002398 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002399 return nextSegment;
2400 }
caryclark@google.com47580692012-07-23 12:14:49 +00002401
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002402 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2403 bool& unsortable) {
2404 const int startIndex = nextStart;
2405 const int endIndex = nextEnd;
2406 SkASSERT(startIndex != endIndex);
2407 const int count = fTs.count();
2408 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2409 const int step = SkSign32(endIndex - startIndex);
2410 const int end = nextExactSpan(startIndex, step);
2411 SkASSERT(end >= 0);
2412 Span* endSpan = &fTs[end];
2413 Segment* other;
2414 if (isSimple(end)) {
2415 // mark the smaller of startIndex, endIndex done, and all adjacent
2416 // spans with the same T value (but not 'other' spans)
2417 #if DEBUG_WINDING
2418 SkDebugf("%s simple\n", __FUNCTION__);
2419 #endif
2420 int min = SkMin32(startIndex, endIndex);
2421 if (fTs[min].fDone) {
2422 return NULL;
2423 }
2424 markDoneUnary(min);
2425 other = endSpan->fOther;
2426 nextStart = endSpan->fOtherIndex;
2427 double startT = other->fTs[nextStart].fT;
2428 nextEnd = nextStart;
2429 do {
2430 nextEnd += step;
2431 }
2432 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2433 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2434 return other;
2435 }
2436 // more than one viable candidate -- measure angles to find best
2437 SkTDArray<Angle> angles;
2438 SkASSERT(startIndex - endIndex != 0);
2439 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2440 addTwoAngles(startIndex, end, angles);
2441 buildAngles(end, angles, true);
2442 SkTDArray<Angle*> sorted;
2443 bool sortable = SortAngles(angles, sorted);
2444 int angleCount = angles.count();
2445 int firstIndex = findStartingEdge(sorted, startIndex, end);
2446 SkASSERT(firstIndex >= 0);
2447 #if DEBUG_SORT
2448 debugShowSort(__FUNCTION__, sorted, firstIndex);
2449 #endif
2450 if (!sortable) {
2451 unsortable = true;
2452 return NULL;
2453 }
2454 SkASSERT(sorted[firstIndex]->segment() == this);
2455 #if DEBUG_WINDING
2456 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2457 sorted[firstIndex]->sign());
2458 #endif
2459 int sumWinding = updateWinding(endIndex, startIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002460 int nextIndex = firstIndex + 1;
2461 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2462 const Angle* foundAngle = NULL;
2463 bool foundDone = false;
2464 // iterate through the angle, and compute everyone's winding
2465 Segment* nextSegment;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002466 int activeCount = 0;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002467 do {
2468 SkASSERT(nextIndex != firstIndex);
2469 if (nextIndex == angleCount) {
2470 nextIndex = 0;
2471 }
2472 const Angle* nextAngle = sorted[nextIndex];
2473 nextSegment = nextAngle->segment();
2474 int maxWinding;
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00002475 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002476 maxWinding, sumWinding);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002477 if (activeAngle) {
2478 ++activeCount;
2479 if (!foundAngle || (foundDone && activeCount & 1)) {
2480 if (nextSegment->tiny(nextAngle)) {
2481 unsortable = true;
2482 return NULL;
2483 }
2484 foundAngle = nextAngle;
2485 foundDone = nextSegment->done(nextAngle);
2486 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002487 }
2488 if (nextSegment->done()) {
2489 continue;
2490 }
2491 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2492 continue;
2493 }
2494 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2495 if (last) {
2496 *chase.append() = last;
2497#if DEBUG_WINDING
2498 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2499 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2500#endif
2501 }
2502 } while (++nextIndex != lastIndex);
2503 markDoneUnary(SkMin32(startIndex, endIndex));
2504 if (!foundAngle) {
2505 return NULL;
2506 }
2507 nextStart = foundAngle->start();
2508 nextEnd = foundAngle->end();
2509 nextSegment = foundAngle->segment();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002510 #if DEBUG_WINDING
2511 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2512 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2513 #endif
2514 return nextSegment;
2515 }
2516
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002517 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002518 const int startIndex = nextStart;
2519 const int endIndex = nextEnd;
2520 SkASSERT(startIndex != endIndex);
2521 int count = fTs.count();
2522 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2523 : startIndex > 0);
2524 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002525 int end = nextExactSpan(startIndex, step);
caryclark@google.com24bec792012-08-20 12:43:57 +00002526 SkASSERT(end >= 0);
2527 Span* endSpan = &fTs[end];
2528 Segment* other;
caryclark@google.com24bec792012-08-20 12:43:57 +00002529 if (isSimple(end)) {
2530 #if DEBUG_WINDING
2531 SkDebugf("%s simple\n", __FUNCTION__);
2532 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002533 int min = SkMin32(startIndex, endIndex);
2534 if (fTs[min].fDone) {
2535 return NULL;
2536 }
2537 markDone(min, 1);
caryclark@google.com24bec792012-08-20 12:43:57 +00002538 other = endSpan->fOther;
2539 nextStart = endSpan->fOtherIndex;
2540 double startT = other->fTs[nextStart].fT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002541 #if 01 // FIXME: I don't know why the logic here is difference from the winding case
caryclark@google.com24bec792012-08-20 12:43:57 +00002542 SkDEBUGCODE(bool firstLoop = true;)
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002543 if ((approximately_less_than_zero(startT) && step < 0)
2544 || (approximately_greater_than_one(startT) && step > 0)) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002545 step = -step;
2546 SkDEBUGCODE(firstLoop = false;)
2547 }
2548 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002549 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002550 nextEnd = nextStart;
2551 do {
2552 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002553 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002554 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002555 #if 01
caryclark@google.com24bec792012-08-20 12:43:57 +00002556 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2557 break;
2558 }
caryclark@google.com03f97062012-08-21 13:13:52 +00002559 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00002560 SkASSERT(firstLoop);
caryclark@google.com03f97062012-08-21 13:13:52 +00002561 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002562 SkDEBUGCODE(firstLoop = false;)
2563 step = -step;
2564 } while (true);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002565 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002566 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2567 return other;
2568 }
2569 SkTDArray<Angle> angles;
2570 SkASSERT(startIndex - endIndex != 0);
2571 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2572 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002573 buildAngles(end, angles, false);
caryclark@google.com24bec792012-08-20 12:43:57 +00002574 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002575 bool sortable = SortAngles(angles, sorted);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002576 if (!sortable) {
2577 unsortable = true;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002578 #if DEBUG_SORT
2579 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
2580 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002581 return NULL;
2582 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002583 int angleCount = angles.count();
2584 int firstIndex = findStartingEdge(sorted, startIndex, end);
2585 SkASSERT(firstIndex >= 0);
2586 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002587 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
caryclark@google.com24bec792012-08-20 12:43:57 +00002588 #endif
2589 SkASSERT(sorted[firstIndex]->segment() == this);
2590 int nextIndex = firstIndex + 1;
2591 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002592 const Angle* foundAngle = NULL;
2593 bool foundDone = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002594 Segment* nextSegment;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002595 int activeCount = 0;
caryclark@google.com24bec792012-08-20 12:43:57 +00002596 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002597 SkASSERT(nextIndex != firstIndex);
caryclark@google.com24bec792012-08-20 12:43:57 +00002598 if (nextIndex == angleCount) {
2599 nextIndex = 0;
2600 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002601 const Angle* nextAngle = sorted[nextIndex];
caryclark@google.com24bec792012-08-20 12:43:57 +00002602 nextSegment = nextAngle->segment();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002603 ++activeCount;
2604 if (!foundAngle || (foundDone && activeCount & 1)) {
2605 if (nextSegment->tiny(nextAngle)) {
2606 unsortable = true;
2607 return NULL;
2608 }
2609 foundAngle = nextAngle;
2610 foundDone = nextSegment->done(nextAngle);
2611 }
2612 if (nextSegment->done()) {
2613 continue;
caryclark@google.com24bec792012-08-20 12:43:57 +00002614 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002615 } while (++nextIndex != lastIndex);
2616 markDone(SkMin32(startIndex, endIndex), 1);
2617 if (!foundAngle) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002618 return NULL;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002619 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002620 nextStart = foundAngle->start();
2621 nextEnd = foundAngle->end();
2622 nextSegment = foundAngle->segment();
2623 #if DEBUG_WINDING
2624 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2625 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2626 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002627 return nextSegment;
2628 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002629
2630 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2631 int angleCount = sorted.count();
2632 int firstIndex = -1;
2633 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2634 const Angle* angle = sorted[angleIndex];
2635 if (angle->segment() == this && angle->start() == end &&
2636 angle->end() == start) {
2637 firstIndex = angleIndex;
2638 break;
2639 }
2640 }
2641 return firstIndex;
2642 }
2643
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002644 // FIXME: this is tricky code; needs its own unit test
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002645 // note that fOtherIndex isn't computed yet, so it can't be used here
caryclark@google.com4eeda372012-12-06 21:47:48 +00002646 void findTooCloseToCall() {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002647 int count = fTs.count();
2648 if (count < 3) { // require t=0, x, 1 at minimum
2649 return;
2650 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002651 int matchIndex = 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002652 int moCount;
2653 Span* match;
2654 Segment* mOther;
2655 do {
2656 match = &fTs[matchIndex];
2657 mOther = match->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002658 // FIXME: allow quads, cubics to be near coincident?
2659 if (mOther->fVerb == SkPath::kLine_Verb) {
2660 moCount = mOther->fTs.count();
2661 if (moCount >= 3) {
2662 break;
2663 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002664 }
2665 if (++matchIndex >= count) {
2666 return;
2667 }
2668 } while (true); // require t=0, x, 1 at minimum
caryclark@google.com15fa1382012-05-07 20:49:36 +00002669 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002670 const SkPoint* matchPt = &xyAtT(match);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002671 // look for a pair of nearby T values that map to the same (x,y) value
2672 // if found, see if the pair of other segments share a common point. If
2673 // so, the span from here to there is coincident.
caryclark@google.com15fa1382012-05-07 20:49:36 +00002674 for (int index = matchIndex + 1; index < count; ++index) {
2675 Span* test = &fTs[index];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002676 if (test->fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002677 continue;
2678 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002679 Segment* tOther = test->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002680 if (tOther->fVerb != SkPath::kLine_Verb) {
2681 continue; // FIXME: allow quads, cubics to be near coincident?
2682 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002683 int toCount = tOther->fTs.count();
2684 if (toCount < 3) { // require t=0, x, 1 at minimum
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002685 continue;
2686 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002687 const SkPoint* testPt = &xyAtT(test);
2688 if (*matchPt != *testPt) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002689 matchIndex = index;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002690 moCount = toCount;
2691 match = test;
2692 mOther = tOther;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002693 matchPt = testPt;
2694 continue;
2695 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002696 int moStart = -1;
2697 int moEnd = -1;
2698 double moStartT, moEndT;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002699 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002700 Span& moSpan = mOther->fTs[moIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002701 if (moSpan.fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002702 continue;
2703 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002704 if (moSpan.fOther == this) {
2705 if (moSpan.fOtherT == match->fT) {
2706 moStart = moIndex;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002707 moStartT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002708 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002709 continue;
2710 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002711 if (moSpan.fOther == tOther) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002712 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002713 moStart = -1;
2714 break;
2715 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002716 SkASSERT(moEnd == -1);
2717 moEnd = moIndex;
2718 moEndT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002719 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002720 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002721 if (moStart < 0 || moEnd < 0) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002722 continue;
2723 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002724 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002725 if (approximately_equal(moStartT, moEndT)) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002726 continue;
2727 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002728 int toStart = -1;
2729 int toEnd = -1;
2730 double toStartT, toEndT;
2731 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2732 Span& toSpan = tOther->fTs[toIndex];
caryclark@google.comc899ad92012-08-23 15:24:42 +00002733 if (toSpan.fDone) {
2734 continue;
2735 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002736 if (toSpan.fOther == this) {
2737 if (toSpan.fOtherT == test->fT) {
2738 toStart = toIndex;
2739 toStartT = toSpan.fT;
2740 }
2741 continue;
2742 }
2743 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002744 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002745 moStart = -1;
2746 break;
2747 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002748 SkASSERT(toEnd == -1);
2749 toEnd = toIndex;
2750 toEndT = toSpan.fT;
2751 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002752 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002753 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2754 if (toStart <= 0 || toEnd <= 0) {
2755 continue;
2756 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002757 if (approximately_equal(toStartT, toEndT)) {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002758 continue;
2759 }
2760 // test to see if the segment between there and here is linear
2761 if (!mOther->isLinear(moStart, moEnd)
2762 || !tOther->isLinear(toStart, toEnd)) {
2763 continue;
2764 }
caryclark@google.comc899ad92012-08-23 15:24:42 +00002765 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002766 if (flipped) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002767 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002768 } else {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002769 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002770 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002771 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002772 }
2773
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002774 // FIXME: either:
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002775 // a) mark spans with either end unsortable as done, or
2776 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2777 // when encountering an unsortable span
2778
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002779 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2780 // and use more concise logic like the old edge walker code?
2781 // FIXME: this needs to deal with coincident edges
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002782 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002783 // iterate through T intersections and return topmost
2784 // topmost tangent from y-min to first pt is closer to horizontal
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002785 SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002786 int firstT = -1;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002787 SkPoint topPt = activeLeftTop(onlySortable, &firstT);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002788 SkASSERT(firstT >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002789 // sort the edges to find the leftmost
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002790 int step = 1;
2791 int end = nextSpan(firstT, step);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002792 if (end == -1) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002793 step = -1;
2794 end = nextSpan(firstT, step);
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00002795 SkASSERT(end != -1);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002796 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002797 // if the topmost T is not on end, or is three-way or more, find left
2798 // look for left-ness from tLeft to firstT (matching y of other)
2799 SkTDArray<Angle> angles;
2800 SkASSERT(firstT - end != 0);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002801 addTwoAngles(end, firstT, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002802 buildAngles(firstT, angles, true);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002803 SkTDArray<Angle*> sorted;
caryclark@google.comf839c032012-10-26 21:03:50 +00002804 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002805 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002806 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002807 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002808 if (onlySortable && !sortable) {
2809 unsortable = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002810 return NULL;
2811 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002812 // skip edges that have already been processed
2813 firstT = -1;
2814 Segment* leftSegment;
2815 do {
2816 const Angle* angle = sorted[++firstT];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002817 SkASSERT(!onlySortable || !angle->unsortable());
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002818 leftSegment = angle->segment();
2819 tIndex = angle->end();
2820 endIndex = angle->start();
2821 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002822 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
2823 SkScalar dyE = leftSegment->dy(endIndex);
2824 SkScalar dyS = leftSegment->dy(tIndex);
2825 if (dyE < 0 && dyS > 0) {
2826 SkTSwap(tIndex, endIndex);
2827 }
2828 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002829 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002830 return leftSegment;
2831 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002832
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002833 // FIXME: not crazy about this
2834 // when the intersections are performed, the other index is into an
2835 // incomplete array. as the array grows, the indices become incorrect
2836 // while the following fixes the indices up again, it isn't smart about
2837 // skipping segments whose indices are already correct
2838 // assuming we leave the code that wrote the index in the first place
2839 void fixOtherTIndex() {
2840 int iCount = fTs.count();
2841 for (int i = 0; i < iCount; ++i) {
2842 Span& iSpan = fTs[i];
2843 double oT = iSpan.fOtherT;
2844 Segment* other = iSpan.fOther;
2845 int oCount = other->fTs.count();
2846 for (int o = 0; o < oCount; ++o) {
2847 Span& oSpan = other->fTs[o];
2848 if (oT == oSpan.fT && this == oSpan.fOther) {
2849 iSpan.fOtherIndex = o;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002850 break;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002851 }
2852 }
2853 }
2854 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002855
caryclark@google.com4eeda372012-12-06 21:47:48 +00002856 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002857 fDoneSpans = 0;
2858 fOperand = operand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00002859 fXor = evenOdd;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002860 fPts = pts;
2861 fVerb = verb;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002862 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00002863
caryclark@google.com3586ece2012-12-27 18:46:58 +00002864 void initWinding(int start, int end) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002865 int local = spanSign(start, end);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002866 int oppLocal = oppSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002867 (void) markAndChaseWinding(start, end, local, oppLocal);
caryclark@google.com73ca6242013-01-17 21:02:47 +00002868 // OPTIMIZATION: the reverse mark and chase could skip the first marking
2869 (void) markAndChaseWinding(end, start, local, oppLocal);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002870 }
2871
caryclark@google.com3586ece2012-12-27 18:46:58 +00002872 void initWinding(int start, int end, int winding, int oppWinding) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002873 int local = spanSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002874 if (local * winding >= 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002875 winding += local;
2876 }
2877 int oppLocal = oppSign(start, end);
2878 if (oppLocal * oppWinding >= 0) {
2879 oppWinding += oppLocal;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002880 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002881 (void) markAndChaseWinding(start, end, winding, oppWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002882 }
2883
caryclark@google.com3586ece2012-12-27 18:46:58 +00002884/*
2885when we start with a vertical intersect, we try to use the dx to determine if the edge is to
2886the 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 +00002887sign or not. However, this isn't enough.
2888If 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 +00002889If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
2890from 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 +00002891the same winding is shared by both.
caryclark@google.com3586ece2012-12-27 18:46:58 +00002892*/
2893 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
2894 SkScalar hitOppDx) {
2895 SkASSERT(hitDx || !winding);
2896 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
2897 SkASSERT(dx);
2898 int windVal = windValue(SkMin32(start, end));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002899 #if DEBUG_WINDING_AT_T
2900 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
2901 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
2902 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002903 if (!winding) {
2904 winding = dx < 0 ? windVal : -windVal;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002905 } else if (winding * dx < 0) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00002906 int sideWind = winding + (dx < 0 ? windVal : -windVal);
2907 if (abs(winding) < abs(sideWind)) {
2908 winding = sideWind;
2909 }
2910 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002911 #if DEBUG_WINDING_AT_T
2912 SkDebugf(" winding=%d\n", winding);
2913 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002914 int oppLocal = oppSign(start, end);
2915 SkASSERT(hitOppDx || !oppWind || !oppLocal);
2916 int oppWindVal = oppValue(SkMin32(start, end));
2917 if (!oppWind) {
2918 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
2919 } else if (hitOppDx * dx >= 0) {
2920 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
2921 if (abs(oppWind) < abs(oppSideWind)) {
2922 oppWind = oppSideWind;
2923 }
2924 }
2925 (void) markAndChaseWinding(start, end, winding, oppWind);
2926 }
2927
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002928 bool intersected() const {
2929 return fTs.count() > 0;
2930 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002931
caryclark@google.com10227bf2012-12-28 22:10:41 +00002932 bool isCanceled(int tIndex) const {
2933 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
2934 }
2935
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002936 bool isConnected(int startIndex, int endIndex) const {
2937 return fTs[startIndex].fWindSum != SK_MinS32
2938 || fTs[endIndex].fWindSum != SK_MinS32;
2939 }
2940
caryclark@google.com235f56a2012-09-14 14:19:30 +00002941 bool isHorizontal() const {
2942 return fBounds.fTop == fBounds.fBottom;
2943 }
2944
caryclark@google.com15fa1382012-05-07 20:49:36 +00002945 bool isLinear(int start, int end) const {
2946 if (fVerb == SkPath::kLine_Verb) {
2947 return true;
2948 }
2949 if (fVerb == SkPath::kQuad_Verb) {
2950 SkPoint qPart[3];
2951 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
2952 return QuadIsLinear(qPart);
2953 } else {
2954 SkASSERT(fVerb == SkPath::kCubic_Verb);
2955 SkPoint cPart[4];
2956 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
2957 return CubicIsLinear(cPart);
2958 }
2959 }
caryclark@google.comb9738012012-07-03 19:53:30 +00002960
2961 // OPTIMIZE: successive calls could start were the last leaves off
2962 // or calls could specialize to walk forwards or backwards
2963 bool isMissing(double startT) const {
2964 size_t tCount = fTs.count();
2965 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002966 if (approximately_zero(startT - fTs[index].fT)) {
caryclark@google.comb9738012012-07-03 19:53:30 +00002967 return false;
2968 }
2969 }
2970 return true;
2971 }
2972
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002973 bool isSimple(int end) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002974 int count = fTs.count();
2975 if (count == 2) {
2976 return true;
2977 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002978 double t = fTs[end].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002979 if (approximately_less_than_zero(t)) {
2980 return !approximately_less_than_zero(fTs[1].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002981 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002982 if (approximately_greater_than_one(t)) {
2983 return !approximately_greater_than_one(fTs[count - 2].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002984 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002985 return false;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002986 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002987
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002988 bool isVertical() const {
2989 return fBounds.fLeft == fBounds.fRight;
2990 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00002991
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002992 bool isVertical(int start, int end) const {
2993 return (*SegmentVertical[fVerb])(fPts, start, end);
2994 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002995
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002996 SkScalar leftMost(int start, int end) const {
2997 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
2998 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002999
caryclark@google.com495f8e42012-05-31 13:13:11 +00003000 // this span is excluded by the winding rule -- chase the ends
3001 // as long as they are unambiguous to mark connections as done
3002 // and give them the same winding value
caryclark@google.com59823f72012-08-09 18:17:47 +00003003 Span* markAndChaseDone(const Angle* angle, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003004 int index = angle->start();
3005 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003006 return markAndChaseDone(index, endIndex, winding);
3007 }
3008
caryclark@google.com31143cf2012-11-09 22:14:19 +00003009 Span* markAndChaseDone(int index, int endIndex, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003010 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003011 int min = SkMin32(index, endIndex);
3012 markDone(min, winding);
3013 Span* last;
3014 Segment* other = this;
3015 while ((other = other->nextChase(index, step, min, last))) {
3016 other->markDone(min, winding);
3017 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003018 return last;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003019 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003020
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003021 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
3022 int index = angle->start();
3023 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003024 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003025 int min = SkMin32(index, endIndex);
3026 markDoneBinary(min, winding, oppWinding);
3027 Span* last;
3028 Segment* other = this;
3029 while ((other = other->nextChase(index, step, min, last))) {
3030 other->markDoneBinary(min, winding, oppWinding);
3031 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003032 return last;
3033 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003034
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003035 Span* markAndChaseDoneBinary(int index, int endIndex) {
3036 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003037 int min = SkMin32(index, endIndex);
3038 markDoneBinary(min);
3039 Span* last;
3040 Segment* other = this;
3041 while ((other = other->nextChase(index, step, min, last))) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003042 if (other->done()) {
3043 return NULL;
3044 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003045 other->markDoneBinary(min);
3046 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003047 return last;
3048 }
3049
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003050 Span* markAndChaseDoneUnary(int index, int endIndex) {
3051 int step = SkSign32(endIndex - index);
3052 int min = SkMin32(index, endIndex);
3053 markDoneUnary(min);
3054 Span* last;
3055 Segment* other = this;
3056 while ((other = other->nextChase(index, step, min, last))) {
3057 if (other->done()) {
3058 return NULL;
3059 }
3060 other->markDoneUnary(min);
3061 }
3062 return last;
3063 }
3064
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003065 Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
3066 int index = angle->start();
3067 int endIndex = angle->end();
3068 return markAndChaseDone(index, endIndex, winding);
3069 }
3070
caryclark@google.com4eeda372012-12-06 21:47:48 +00003071 Span* markAndChaseWinding(const Angle* angle, const int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003072 int index = angle->start();
3073 int endIndex = angle->end();
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003074 int step = SkSign32(endIndex - index);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003075 int min = SkMin32(index, endIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00003076 markWinding(min, winding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003077 Span* last;
3078 Segment* other = this;
3079 while ((other = other->nextChase(index, step, min, last))) {
3080 if (other->fTs[min].fWindSum != SK_MinS32) {
3081 SkASSERT(other->fTs[min].fWindSum == winding);
3082 return NULL;
3083 }
3084 other->markWinding(min, winding);
3085 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003086 return last;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003087 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003088
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003089 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003090 int min = SkMin32(index, endIndex);
3091 int step = SkSign32(endIndex - index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003092 markWinding(min, winding, oppWinding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003093 Span* last;
3094 Segment* other = this;
3095 while ((other = other->nextChase(index, step, min, last))) {
3096 if (other->fTs[min].fWindSum != SK_MinS32) {
3097 SkASSERT(other->fTs[min].fWindSum == winding);
3098 return NULL;
3099 }
3100 other->markWinding(min, winding, oppWinding);
3101 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003102 return last;
3103 }
3104
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003105 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
3106 int start = angle->start();
3107 int end = angle->end();
3108 return markAndChaseWinding(start, end, winding, oppWinding);
3109 }
3110
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003111 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
3112 SkASSERT(angle->segment() == this);
3113 if (useInnerWinding(maxWinding, sumWinding)) {
3114 maxWinding = sumWinding;
3115 }
3116 Span* last;
3117 if (activeAngle) {
3118 last = markAndChaseWinding(angle, maxWinding);
3119 } else {
3120 last = markAndChaseDoneUnary(angle, maxWinding);
3121 }
3122 return last;
3123 }
3124
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003125 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
3126 bool activeAngle, const Angle* angle) {
3127 SkASSERT(angle->segment() == this);
3128 if (useInnerWinding(maxWinding, sumWinding)) {
3129 maxWinding = sumWinding;
3130 }
3131 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
3132 oppMaxWinding = oppSumWinding;
3133 }
3134 Span* last;
3135 if (activeAngle) {
3136 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3137 } else {
3138 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
3139 }
3140 return last;
3141 }
3142
caryclark@google.com495f8e42012-05-31 13:13:11 +00003143 // FIXME: this should also mark spans with equal (x,y)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003144 // This may be called when the segment is already marked done. While this
3145 // wastes time, it shouldn't do any more than spin through the T spans.
rmistry@google.comd6176b02012-08-23 18:14:13 +00003146 // OPTIMIZATION: abort on first done found (assuming that this code is
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003147 // always called to mark segments done).
caryclark@google.com59823f72012-08-09 18:17:47 +00003148 void markDone(int index, int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003149 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003150 SkASSERT(winding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003151 double referenceT = fTs[index].fT;
3152 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003153 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3154 markOneDone(__FUNCTION__, lesser, winding);
3155 }
3156 do {
3157 markOneDone(__FUNCTION__, index, winding);
3158 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003159 }
3160
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003161 void markDoneBinary(int index, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003162 // SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003163 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003164 double referenceT = fTs[index].fT;
3165 int lesser = index;
3166 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003167 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003168 }
3169 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003170 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
3171 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3172 }
3173
3174 void markDoneBinary(int index) {
3175 double referenceT = fTs[index].fT;
3176 int lesser = index;
3177 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3178 markOneDoneBinary(__FUNCTION__, lesser);
3179 }
3180 do {
3181 markOneDoneBinary(__FUNCTION__, index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003182 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003183 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00003184
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003185 void markDoneUnary(int index, int winding) {
3186 // SkASSERT(!done());
3187 SkASSERT(winding);
3188 double referenceT = fTs[index].fT;
3189 int lesser = index;
3190 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3191 markOneDoneUnary(__FUNCTION__, lesser, winding);
3192 }
3193 do {
3194 markOneDoneUnary(__FUNCTION__, index, winding);
3195 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3196 }
3197
3198 void markDoneUnary(int index) {
3199 double referenceT = fTs[index].fT;
3200 int lesser = index;
3201 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3202 markOneDoneUnary(__FUNCTION__, lesser);
3203 }
3204 do {
3205 markOneDoneUnary(__FUNCTION__, index);
3206 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3207 }
3208
caryclark@google.com24bec792012-08-20 12:43:57 +00003209 void markOneDone(const char* funName, int tIndex, int winding) {
3210 Span* span = markOneWinding(funName, tIndex, winding);
3211 if (!span) {
3212 return;
3213 }
3214 span->fDone = true;
3215 fDoneSpans++;
3216 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003217
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003218 void markOneDoneBinary(const char* funName, int tIndex) {
3219 Span* span = verifyOneWinding(funName, tIndex);
3220 if (!span) {
3221 return;
3222 }
3223 span->fDone = true;
3224 fDoneSpans++;
3225 }
3226
3227 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003228 Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
3229 if (!span) {
3230 return;
3231 }
3232 span->fDone = true;
3233 fDoneSpans++;
3234 }
3235
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003236 void markOneDoneUnary(const char* funName, int tIndex) {
3237 Span* span = verifyOneWindingU(funName, tIndex);
3238 if (!span) {
3239 return;
3240 }
3241 span->fDone = true;
3242 fDoneSpans++;
3243 }
3244
3245 void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3246 Span* span = markOneWinding(funName, tIndex, winding);
3247 if (!span) {
3248 return;
3249 }
3250 span->fDone = true;
3251 fDoneSpans++;
3252 }
3253
caryclark@google.com24bec792012-08-20 12:43:57 +00003254 Span* markOneWinding(const char* funName, int tIndex, int winding) {
3255 Span& span = fTs[tIndex];
3256 if (span.fDone) {
3257 return NULL;
3258 }
3259 #if DEBUG_MARK_DONE
3260 debugShowNewWinding(funName, span, winding);
3261 #endif
3262 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com03f97062012-08-21 13:13:52 +00003263 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00003264 SkASSERT(abs(winding) <= gDebugMaxWindSum);
caryclark@google.com03f97062012-08-21 13:13:52 +00003265 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00003266 span.fWindSum = winding;
3267 return &span;
3268 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003269
caryclark@google.com31143cf2012-11-09 22:14:19 +00003270 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
3271 Span& span = fTs[tIndex];
3272 if (span.fDone) {
3273 return NULL;
3274 }
3275 #if DEBUG_MARK_DONE
3276 debugShowNewWinding(funName, span, winding, oppWinding);
3277 #endif
3278 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3279 #ifdef SK_DEBUG
3280 SkASSERT(abs(winding) <= gDebugMaxWindSum);
3281 #endif
3282 span.fWindSum = winding;
3283 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3284 #ifdef SK_DEBUG
3285 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
3286 #endif
3287 span.fOppSum = oppWinding;
3288 return &span;
3289 }
3290
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003291 Span* verifyOneWinding(const char* funName, int tIndex) {
3292 Span& span = fTs[tIndex];
3293 if (span.fDone) {
3294 return NULL;
3295 }
3296 #if DEBUG_MARK_DONE
3297 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3298 #endif
3299 SkASSERT(span.fWindSum != SK_MinS32);
3300 SkASSERT(span.fOppSum != SK_MinS32);
3301 return &span;
3302 }
3303
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003304 Span* verifyOneWindingU(const char* funName, int tIndex) {
3305 Span& span = fTs[tIndex];
3306 if (span.fDone) {
3307 return NULL;
3308 }
3309 #if DEBUG_MARK_DONE
3310 debugShowNewWinding(funName, span, span.fWindSum);
3311 #endif
3312 SkASSERT(span.fWindSum != SK_MinS32);
3313 return &span;
3314 }
3315
caryclark@google.comf839c032012-10-26 21:03:50 +00003316 // note that just because a span has one end that is unsortable, that's
3317 // not enough to mark it done. The other end may be sortable, allowing the
3318 // span to be added.
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003319 // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003320 void markUnsortable(int start, int end) {
3321 Span* span = &fTs[start];
3322 if (start < end) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003323#if DEBUG_UNSORTABLE
3324 SkDebugf("%s start id=%d [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fID, start,
3325 xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003326#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003327 span->fUnsortableStart = true;
3328 } else {
3329 --span;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003330#if DEBUG_UNSORTABLE
3331 SkDebugf("%s end id=%d [%d] (%1.9g,%1.9g) next:(%1.9g,%1.9g)\n", __FUNCTION__, fID,
3332 start - 1, xAtT(start - 1), yAtT(start - 1), xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003333#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003334 span->fUnsortableEnd = true;
3335 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003336 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003337 return;
3338 }
3339 span->fDone = true;
3340 fDoneSpans++;
3341 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003342
caryclark@google.com59823f72012-08-09 18:17:47 +00003343 void markWinding(int index, int winding) {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003344 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003345 SkASSERT(winding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003346 double referenceT = fTs[index].fT;
3347 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003348 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3349 markOneWinding(__FUNCTION__, lesser, winding);
3350 }
3351 do {
3352 markOneWinding(__FUNCTION__, index, winding);
3353 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003354 }
3355
3356 void markWinding(int index, int winding, int oppWinding) {
3357 // SkASSERT(!done());
caryclark@google.com4eeda372012-12-06 21:47:48 +00003358 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003359 double referenceT = fTs[index].fT;
3360 int lesser = index;
3361 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3362 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003363 }
3364 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003365 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3366 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003367 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003368
caryclark@google.com2ddff932012-08-07 21:25:27 +00003369 void matchWindingValue(int tIndex, double t, bool borrowWind) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003370 int nextDoorWind = SK_MaxS32;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003371 int nextOppWind = SK_MaxS32;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003372 if (tIndex > 0) {
3373 const Span& below = fTs[tIndex - 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003374 if (approximately_negative(t - below.fT)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003375 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003376 nextOppWind = below.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003377 }
3378 }
3379 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3380 const Span& above = fTs[tIndex + 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003381 if (approximately_negative(above.fT - t)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003382 nextDoorWind = above.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003383 nextOppWind = above.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003384 }
3385 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003386 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3387 const Span& below = fTs[tIndex - 1];
3388 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003389 nextOppWind = below.fOppValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003390 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003391 if (nextDoorWind != SK_MaxS32) {
3392 Span& newSpan = fTs[tIndex];
3393 newSpan.fWindValue = nextDoorWind;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003394 newSpan.fOppValue = nextOppWind;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003395 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003396 newSpan.fDone = true;
3397 ++fDoneSpans;
3398 }
3399 }
3400 }
3401
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003402 bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3403 // find bounds
3404 Bounds bounds;
3405 bounds.setPoint(xyAtT(index));
3406 bounds.add(xyAtT(endIndex));
3407 SkScalar width = bounds.width();
3408 SkScalar height = bounds.height();
3409 if (width > height) {
3410 if (approximately_negative(width)) {
3411 unsortable = true; // edge is too small to resolve meaningfully
3412 }
3413 return false;
3414 } else {
3415 if (approximately_negative(height)) {
3416 unsortable = true; // edge is too small to resolve meaningfully
3417 }
3418 return true;
3419 }
3420 }
3421
caryclark@google.com9764cc62012-07-12 19:29:45 +00003422 // return span if when chasing, two or more radiating spans are not done
3423 // OPTIMIZATION: ? multiple spans is detected when there is only one valid
3424 // candidate and the remaining spans have windValue == 0 (canceled by
3425 // coincidence). The coincident edges could either be removed altogether,
3426 // or this code could be more complicated in detecting this case. Worth it?
3427 bool multipleSpans(int end) const {
3428 return end > 0 && end < fTs.count() - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00003429 }
3430
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003431 bool nextCandidate(int& start, int& end) const {
caryclark@google.com10227bf2012-12-28 22:10:41 +00003432 while (fTs[end].fDone) {
3433 if (fTs[end].fT == 1) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003434 return false;
3435 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00003436 ++end;
3437 }
3438 start = end;
3439 end = nextExactSpan(start, 1);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003440 return true;
3441 }
3442
caryclark@google.com4eeda372012-12-06 21:47:48 +00003443 Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
3444 int end = nextExactSpan(index, step);
3445 SkASSERT(end >= 0);
3446 if (multipleSpans(end)) {
3447 last = &fTs[end];
3448 return NULL;
3449 }
3450 const Span& endSpan = fTs[end];
3451 Segment* other = endSpan.fOther;
3452 index = endSpan.fOtherIndex;
caryclark@google.comaa358312013-01-29 20:28:49 +00003453 SkASSERT(index >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003454 int otherEnd = other->nextExactSpan(index, step);
caryclark@google.comaa358312013-01-29 20:28:49 +00003455 SkASSERT(otherEnd >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003456 min = SkMin32(index, otherEnd);
3457 return other;
3458 }
3459
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003460 // This has callers for two different situations: one establishes the end
3461 // of the current span, and one establishes the beginning of the next span
3462 // (thus the name). When this is looking for the end of the current span,
3463 // coincidence is found when the beginning Ts contain -step and the end
3464 // contains step. When it is looking for the beginning of the next, the
3465 // first Ts found can be ignored and the last Ts should contain -step.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003466 // OPTIMIZATION: probably should split into two functions
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003467 int nextSpan(int from, int step) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003468 const Span& fromSpan = fTs[from];
caryclark@google.com495f8e42012-05-31 13:13:11 +00003469 int count = fTs.count();
3470 int to = from;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003471 while (step > 0 ? ++to < count : --to >= 0) {
3472 const Span& span = fTs[to];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003473 if (approximately_zero(span.fT - fromSpan.fT)) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003474 continue;
3475 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003476 return to;
3477 }
3478 return -1;
3479 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +00003480
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003481 // FIXME
3482 // this returns at any difference in T, vs. a preset minimum. It may be
3483 // that all callers to nextSpan should use this instead.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003484 // OPTIMIZATION splitting this into separate loops for up/down steps
3485 // would allow using precisely_negative instead of precisely_zero
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003486 int nextExactSpan(int from, int step) const {
3487 const Span& fromSpan = fTs[from];
3488 int count = fTs.count();
3489 int to = from;
3490 while (step > 0 ? ++to < count : --to >= 0) {
3491 const Span& span = fTs[to];
caryclark@google.coma461ff02012-10-11 12:54:23 +00003492 if (precisely_zero(span.fT - fromSpan.fT)) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003493 continue;
3494 }
3495 return to;
3496 }
3497 return -1;
3498 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003499
caryclark@google.com235f56a2012-09-14 14:19:30 +00003500 bool operand() const {
3501 return fOperand;
3502 }
3503
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003504 int oppSign(const Angle* angle) const {
3505 SkASSERT(angle->segment() == this);
3506 return oppSign(angle->start(), angle->end());
3507 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003508
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003509 int oppSign(int startIndex, int endIndex) const {
3510 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3511 : fTs[endIndex].fOppValue;
3512#if DEBUG_WIND_BUMP
3513 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3514#endif
3515 return result;
3516 }
3517
caryclark@google.com31143cf2012-11-09 22:14:19 +00003518 int oppSum(int tIndex) const {
3519 return fTs[tIndex].fOppSum;
3520 }
3521
3522 int oppSum(const Angle* angle) const {
3523 int lesser = SkMin32(angle->start(), angle->end());
3524 return fTs[lesser].fOppSum;
caryclark@google.com235f56a2012-09-14 14:19:30 +00003525 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003526
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003527 int oppValue(int tIndex) const {
3528 return fTs[tIndex].fOppValue;
3529 }
3530
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003531 int oppValue(const Angle* angle) const {
3532 int lesser = SkMin32(angle->start(), angle->end());
3533 return fTs[lesser].fOppValue;
3534 }
3535
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003536 const SkPoint* pts() const {
3537 return fPts;
3538 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003539
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003540 void reset() {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003541 init(NULL, (SkPath::Verb) -1, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003542 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3543 fTs.reset();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003544 }
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +00003545
caryclark@google.com4eeda372012-12-06 21:47:48 +00003546 void setOppXor(bool isOppXor) {
3547 fOppXor = isOppXor;
3548 }
3549
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003550 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3551 int deltaSum = spanSign(index, endIndex);
3552 maxWinding = sumWinding;
3553 sumWinding = sumWinding -= deltaSum;
3554 }
3555
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003556 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3557 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3558 int deltaSum = spanSign(index, endIndex);
3559 int oppDeltaSum = oppSign(index, endIndex);
3560 if (operand()) {
3561 maxWinding = sumSuWinding;
3562 sumWinding = sumSuWinding -= deltaSum;
3563 oppMaxWinding = sumMiWinding;
3564 oppSumWinding = sumMiWinding -= oppDeltaSum;
3565 } else {
3566 maxWinding = sumMiWinding;
3567 sumWinding = sumMiWinding -= deltaSum;
3568 oppMaxWinding = sumSuWinding;
3569 oppSumWinding = sumSuWinding -= oppDeltaSum;
3570 }
3571 }
3572
caryclark@google.comf839c032012-10-26 21:03:50 +00003573 // This marks all spans unsortable so that this info is available for early
3574 // exclusion in find top and others. This could be optimized to only mark
3575 // adjacent spans that unsortable. However, this makes it difficult to later
3576 // determine starting points for edge detection in find top and the like.
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003577 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
caryclark@google.comf839c032012-10-26 21:03:50 +00003578 bool sortable = true;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003579 int angleCount = angles.count();
3580 int angleIndex;
3581 angleList.setReserve(angleCount);
3582 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003583 Angle& angle = angles[angleIndex];
caryclark@google.comf839c032012-10-26 21:03:50 +00003584 *angleList.append() = &angle;
3585 sortable &= !angle.unsortable();
3586 }
3587 if (sortable) {
3588 QSort<Angle>(angleList.begin(), angleList.end() - 1);
3589 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3590 if (angles[angleIndex].unsortable()) {
3591 sortable = false;
3592 break;
3593 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003594 }
3595 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003596 if (!sortable) {
3597 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3598 Angle& angle = angles[angleIndex];
3599 angle.segment()->markUnsortable(angle.start(), angle.end());
3600 }
3601 }
3602 return sortable;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003603 }
3604
caryclark@google.com1577e8f2012-05-22 17:01:14 +00003605 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003606 const Span& span(int tIndex) const {
3607 return fTs[tIndex];
3608 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003609
caryclark@google.com235f56a2012-09-14 14:19:30 +00003610 int spanSign(const Angle* angle) const {
3611 SkASSERT(angle->segment() == this);
3612 return spanSign(angle->start(), angle->end());
3613 }
3614
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003615 int spanSign(int startIndex, int endIndex) const {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003616 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3617 : fTs[endIndex].fWindValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003618#if DEBUG_WIND_BUMP
3619 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3620#endif
3621 return result;
3622 }
3623
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003624 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003625 double t(int tIndex) const {
3626 return fTs[tIndex].fT;
3627 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003628
caryclark@google.com10227bf2012-12-28 22:10:41 +00003629 double tAtMid(int start, int end, double mid) const {
3630 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
3631 }
3632
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003633 bool tiny(const Angle* angle) const {
3634 int start = angle->start();
3635 int end = angle->end();
caryclark@google.comf839c032012-10-26 21:03:50 +00003636 const Span& mSpan = fTs[SkMin32(start, end)];
3637 return mSpan.fTiny;
3638 }
3639
caryclark@google.com18063442012-07-25 12:05:18 +00003640 static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3641 double start) {
3642 int outCount = outsideTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003643 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
caryclark@google.com18063442012-07-25 12:05:18 +00003644 *outsideTs.append() = end;
3645 *outsideTs.append() = start;
3646 }
3647 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003648
caryclark@google.com24bec792012-08-20 12:43:57 +00003649 void undoneSpan(int& start, int& end) {
3650 size_t tCount = fTs.count();
3651 size_t index;
3652 for (index = 0; index < tCount; ++index) {
3653 if (!fTs[index].fDone) {
3654 break;
3655 }
3656 }
3657 SkASSERT(index < tCount - 1);
3658 start = index;
3659 double startT = fTs[index].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003660 while (approximately_negative(fTs[++index].fT - startT))
caryclark@google.com24bec792012-08-20 12:43:57 +00003661 SkASSERT(index < tCount);
3662 SkASSERT(index < tCount);
3663 end = index;
3664 }
caryclark@google.com18063442012-07-25 12:05:18 +00003665
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003666 bool unsortable(int index) const {
3667 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3668 }
3669
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003670 void updatePts(const SkPoint pts[]) {
3671 fPts = pts;
3672 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003673
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003674 int updateOppWinding(int index, int endIndex) const {
3675 int lesser = SkMin32(index, endIndex);
3676 int oppWinding = oppSum(lesser);
3677 int oppSpanWinding = oppSign(index, endIndex);
3678 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)) {
3679 oppWinding -= oppSpanWinding;
3680 }
3681 return oppWinding;
3682 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003683
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003684 int updateOppWinding(const Angle* angle) const {
3685 int startIndex = angle->start();
3686 int endIndex = angle->end();
3687 return updateOppWinding(endIndex, startIndex);
3688 }
3689
3690 int updateOppWindingReverse(const Angle* angle) const {
3691 int startIndex = angle->start();
3692 int endIndex = angle->end();
3693 return updateOppWinding(startIndex, endIndex);
3694 }
3695
3696 int updateWinding(int index, int endIndex) const {
3697 int lesser = SkMin32(index, endIndex);
3698 int winding = windSum(lesser);
3699 int spanWinding = spanSign(index, endIndex);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003700 if (winding && useInnerWinding(winding - spanWinding, winding)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003701 winding -= spanWinding;
3702 }
3703 return winding;
3704 }
3705
3706 int updateWinding(const Angle* angle) const {
3707 int startIndex = angle->start();
3708 int endIndex = angle->end();
3709 return updateWinding(endIndex, startIndex);
3710 }
3711
3712 int updateWindingReverse(const Angle* angle) const {
3713 int startIndex = angle->start();
3714 int endIndex = angle->end();
3715 return updateWinding(startIndex, endIndex);
3716 }
3717
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003718 SkPath::Verb verb() const {
3719 return fVerb;
3720 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003721
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003722 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003723 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3724 return SK_MinS32;
3725 }
3726 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3727 SkASSERT(winding != SK_MinS32);
3728 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003729 #if DEBUG_WINDING_AT_T
3730 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003731 #endif
3732 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark@google.com3586ece2012-12-27 18:46:58 +00003733 dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003734 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3735 dx = fPts[2].fX - fPts[1].fX - dx;
3736 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003737 if (dx == 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003738 #if DEBUG_WINDING_AT_T
3739 SkDebugf(" dx=0 winding=SK_MinS32\n");
3740 #endif
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003741 return SK_MinS32;
3742 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003743 if (winding * dx > 0) { // if same signs, result is negative
3744 winding += dx > 0 ? -windVal : windVal;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003745 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003746 #if DEBUG_WINDING_AT_T
3747 SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding);
3748 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003749 return winding;
3750 }
3751
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003752 int windSum(int tIndex) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003753 return fTs[tIndex].fWindSum;
3754 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003755
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003756 int windSum(const Angle* angle) const {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003757 int start = angle->start();
3758 int end = angle->end();
3759 int index = SkMin32(start, end);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003760 return windSum(index);
caryclark@google.com495f8e42012-05-31 13:13:11 +00003761 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003762
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003763 int windValue(int tIndex) const {
3764 return fTs[tIndex].fWindValue;
3765 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003766
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003767 int windValue(const Angle* angle) const {
3768 int start = angle->start();
3769 int end = angle->end();
3770 int index = SkMin32(start, end);
3771 return windValue(index);
3772 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00003773
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003774 int windValueAt(double t) const {
3775 int count = fTs.count();
3776 for (int index = 0; index < count; ++index) {
3777 if (fTs[index].fT == t) {
3778 return fTs[index].fWindValue;
3779 }
3780 }
3781 SkASSERT(0);
3782 return 0;
3783 }
3784
caryclark@google.com3586ece2012-12-27 18:46:58 +00003785 SkScalar xAtT(int index) const {
3786 return xAtT(&fTs[index]);
3787 }
3788
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003789 SkScalar xAtT(const Span* span) const {
3790 return xyAtT(span).fX;
3791 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003792
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003793 const SkPoint& xyAtT(int index) const {
3794 return xyAtT(&fTs[index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003795 }
3796
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003797 const SkPoint& xyAtT(const Span* span) const {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003798 if (SkScalarIsNaN(span->fPt.fX)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003799 if (span->fT == 0) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003800 span->fPt = fPts[0];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003801 } else if (span->fT == 1) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003802 span->fPt = fPts[fVerb];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003803 } else {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003804 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003805 }
3806 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00003807 return span->fPt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003808 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003809
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003810 // used only by right angle winding finding
caryclark@google.com10227bf2012-12-28 22:10:41 +00003811 void xyAtT(double mid, SkPoint& pt) const {
3812 (*SegmentXYAtT[fVerb])(fPts, mid, &pt);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003813 }
3814
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003815 SkScalar yAtT(int index) const {
3816 return yAtT(&fTs[index]);
3817 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003818
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003819 SkScalar yAtT(const Span* span) const {
3820 return xyAtT(span).fY;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003821 }
3822
caryclark@google.com4eeda372012-12-06 21:47:48 +00003823 void zeroCoincidentOpp(Span* oTest, int index) {
3824 Span* const test = &fTs[index];
3825 Span* end = test;
3826 do {
3827 end->fOppValue = 0;
3828 end = &fTs[++index];
3829 } while (approximately_negative(end->fT - test->fT));
3830 }
3831
3832 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
3833 Span* const oTest = &fTs[oIndex];
3834 Span* oEnd = oTest;
3835 const double startT = test->fT;
3836 const double oStartT = oTest->fT;
3837 double otherTMatch = (test->fT - startT) * tRatio + oStartT;
3838 while (!approximately_negative(oEndT - oEnd->fT)
3839 && approximately_negative(oEnd->fT - otherTMatch)) {
3840 oEnd->fOppValue = 0;
3841 oEnd = &fTs[++oIndex];
3842 }
3843 }
3844
3845 void zeroSpan(Span* span) {
3846 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
caryclark@google.com6ec15262012-11-16 20:16:50 +00003847 span->fWindValue = 0;
caryclark@google.com729e1c42012-11-21 21:36:34 +00003848 span->fOppValue = 0;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003849 SkASSERT(!span->fDone);
3850 span->fDone = true;
3851 ++fDoneSpans;
caryclark@google.com6ec15262012-11-16 20:16:50 +00003852 }
3853
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003854#if DEBUG_DUMP
3855 void dump() const {
3856 const char className[] = "Segment";
3857 const int tab = 4;
3858 for (int i = 0; i < fTs.count(); ++i) {
3859 SkPoint out;
3860 (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
3861 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003862 " otherT=%1.9g windSum=%d\n",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003863 tab + sizeof(className), className, fID,
3864 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003865 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003866 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00003867 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003868 tab + sizeof(className), className, fID,
caryclark@google.com15fa1382012-05-07 20:49:36 +00003869 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003870 }
3871#endif
3872
caryclark@google.com47580692012-07-23 12:14:49 +00003873#if DEBUG_CONCIDENT
caryclark@google.comaa358312013-01-29 20:28:49 +00003874 // SkASSERT if pair has not already been added
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003875 void debugAddTPair(double t, const Segment& other, double otherT) const {
caryclark@google.comcc905052012-07-25 20:59:42 +00003876 for (int i = 0; i < fTs.count(); ++i) {
3877 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
3878 return;
3879 }
3880 }
3881 SkASSERT(0);
3882 }
3883#endif
3884
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003885#if DEBUG_DUMP
3886 int debugID() const {
3887 return fID;
3888 }
3889#endif
3890
caryclark@google.com24bec792012-08-20 12:43:57 +00003891#if DEBUG_WINDING
3892 void debugShowSums() const {
3893 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
3894 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
3895 for (int i = 0; i < fTs.count(); ++i) {
3896 const Span& span = fTs[i];
3897 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
3898 if (span.fWindSum == SK_MinS32) {
3899 SkDebugf("?");
3900 } else {
3901 SkDebugf("%d", span.fWindSum);
3902 }
3903 SkDebugf("]");
3904 }
3905 SkDebugf("\n");
3906 }
3907#endif
3908
caryclark@google.comcc905052012-07-25 20:59:42 +00003909#if DEBUG_CONCIDENT
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003910 void debugShowTs() const {
caryclark@google.com24bec792012-08-20 12:43:57 +00003911 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003912 int lastWind = -1;
3913 int lastOpp = -1;
3914 double lastT = -1;
3915 int i;
3916 for (i = 0; i < fTs.count(); ++i) {
3917 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
3918 || lastOpp != fTs[i].fOppValue;
3919 if (change && lastWind >= 0) {
3920 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3921 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3922 }
3923 if (change) {
3924 SkDebugf(" [o=%d", fTs[i].fOther->fID);
3925 lastWind = fTs[i].fWindValue;
3926 lastOpp = fTs[i].fOppValue;
3927 lastT = fTs[i].fT;
3928 } else {
3929 SkDebugf(",%d", fTs[i].fOther->fID);
3930 }
3931 }
3932 if (i <= 0) {
3933 return;
3934 }
3935 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3936 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3937 if (fOperand) {
3938 SkDebugf(" operand");
3939 }
3940 if (done()) {
3941 SkDebugf(" done");
caryclark@google.com47580692012-07-23 12:14:49 +00003942 }
3943 SkDebugf("\n");
3944 }
3945#endif
3946
caryclark@google.com027de222012-07-12 12:52:50 +00003947#if DEBUG_ACTIVE_SPANS
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003948 void debugShowActiveSpans() const {
caryclark@google.com027de222012-07-12 12:52:50 +00003949 if (done()) {
3950 return;
3951 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003952#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3953 int lastId = -1;
3954 double lastT = -1;
3955#endif
caryclark@google.com027de222012-07-12 12:52:50 +00003956 for (int i = 0; i < fTs.count(); ++i) {
3957 if (fTs[i].fDone) {
3958 continue;
3959 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003960#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3961 if (lastId == fID && lastT == fTs[i].fT) {
3962 continue;
3963 }
3964 lastId = fID;
3965 lastT = fTs[i].fT;
3966#endif
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003967 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com027de222012-07-12 12:52:50 +00003968 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3969 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3970 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3971 }
3972 const Span* span = &fTs[i];
rmistry@google.comd6176b02012-08-23 18:14:13 +00003973 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
caryclark@google.com0c803d02012-08-06 11:15:47 +00003974 xAtT(span), yAtT(span));
caryclark@google.com027de222012-07-12 12:52:50 +00003975 const Segment* other = fTs[i].fOther;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003976 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
3977 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
3978 if (fTs[i].fWindSum == SK_MinS32) {
3979 SkDebugf("?");
3980 } else {
3981 SkDebugf("%d", fTs[i].fWindSum);
3982 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003983 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
caryclark@google.com027de222012-07-12 12:52:50 +00003984 }
3985 }
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +00003986
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003987 // This isn't useful yet -- but leaving it in for now in case i think of something
3988 // to use it for
3989 void validateActiveSpans() const {
3990 if (done()) {
3991 return;
3992 }
3993 int tCount = fTs.count();
3994 for (int index = 0; index < tCount; ++index) {
3995 if (fTs[index].fDone) {
3996 continue;
3997 }
3998 // count number of connections which are not done
3999 int first = index;
4000 double baseT = fTs[index].fT;
4001 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
4002 --first;
4003 }
4004 int last = index;
4005 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
4006 ++last;
4007 }
4008 int connections = 0;
4009 connections += first > 0 && !fTs[first - 1].fDone;
4010 for (int test = first; test <= last; ++test) {
4011 connections += !fTs[test].fDone;
4012 const Segment* other = fTs[test].fOther;
4013 int oIndex = fTs[test].fOtherIndex;
4014 connections += !other->fTs[oIndex].fDone;
4015 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
4016 }
4017 // SkASSERT(!(connections & 1));
4018 }
4019 }
caryclark@google.com027de222012-07-12 12:52:50 +00004020#endif
4021
caryclark@google.com0c803d02012-08-06 11:15:47 +00004022#if DEBUG_MARK_DONE
4023 void debugShowNewWinding(const char* fun, const Span& span, int winding) {
4024 const SkPoint& pt = xyAtT(&span);
4025 SkDebugf("%s id=%d", fun, fID);
4026 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4027 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4028 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4029 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004030 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4031 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4032 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d windSum=",
4033 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, winding);
caryclark@google.com0c803d02012-08-06 11:15:47 +00004034 if (span.fWindSum == SK_MinS32) {
4035 SkDebugf("?");
4036 } else {
4037 SkDebugf("%d", span.fWindSum);
4038 }
4039 SkDebugf(" windValue=%d\n", span.fWindValue);
4040 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004041
4042 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
4043 const SkPoint& pt = xyAtT(&span);
4044 SkDebugf("%s id=%d", fun, fID);
4045 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4046 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4047 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4048 }
4049 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4050 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4051 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=",
4052 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
4053 winding, oppWinding);
4054 if (span.fOppSum == SK_MinS32) {
4055 SkDebugf("?");
4056 } else {
4057 SkDebugf("%d", span.fOppSum);
4058 }
4059 SkDebugf(" windSum=");
4060 if (span.fWindSum == SK_MinS32) {
4061 SkDebugf("?");
4062 } else {
4063 SkDebugf("%d", span.fWindSum);
4064 }
4065 SkDebugf(" windValue=%d\n", span.fWindValue);
4066 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00004067#endif
4068
caryclark@google.com47580692012-07-23 12:14:49 +00004069#if DEBUG_SORT
caryclark@google.com03f97062012-08-21 13:13:52 +00004070 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
caryclark@google.com31143cf2012-11-09 22:14:19 +00004071 const int contourWinding, const int oppContourWinding) const {
caryclark@google.comafe56de2012-07-24 18:11:03 +00004072 SkASSERT(angles[first]->segment() == this);
caryclark@google.com200c2112012-08-03 15:05:04 +00004073 SkASSERT(angles.count() > 1);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004074 int lastSum = contourWinding;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004075 int oppLastSum = oppContourWinding;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004076 const Angle* firstAngle = angles[first];
4077 int windSum = lastSum - spanSign(firstAngle);
4078 int oppoSign = oppSign(firstAngle);
4079 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004080 SkDebugf("%s %s contourWinding=%d oppContourWinding=%d sign=%d\n", fun, __FUNCTION__,
4081 contourWinding, oppContourWinding, spanSign(angles[first]));
caryclark@google.comafe56de2012-07-24 18:11:03 +00004082 int index = first;
4083 bool firstTime = true;
caryclark@google.com47580692012-07-23 12:14:49 +00004084 do {
4085 const Angle& angle = *angles[index];
4086 const Segment& segment = *angle.segment();
4087 int start = angle.start();
4088 int end = angle.end();
4089 const Span& sSpan = segment.fTs[start];
4090 const Span& eSpan = segment.fTs[end];
4091 const Span& mSpan = segment.fTs[SkMin32(start, end)];
caryclark@google.com31143cf2012-11-09 22:14:19 +00004092 bool opp = segment.fOperand ^ fOperand;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004093 if (!firstTime) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004094 oppoSign = segment.oppSign(&angle);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004095 if (opp) {
4096 oppLastSum = oppWindSum;
4097 oppWindSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004098 if (oppoSign) {
4099 lastSum = windSum;
4100 windSum -= oppoSign;
4101 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004102 } else {
4103 lastSum = windSum;
4104 windSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004105 if (oppoSign) {
4106 oppLastSum = oppWindSum;
4107 oppWindSum -= oppoSign;
4108 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004109 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004110 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004111 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 +00004112 " sign=%d windValue=%d windSum=",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004113 __FUNCTION__, index, angle.unsortable() ? "*** UNSORTABLE *** " : "",
caryclark@google.comc91dfe42012-10-16 12:06:27 +00004114 segment.fID, kLVerbStr[segment.fVerb],
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004115 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
4116 segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(),
4117 mSpan.fWindValue);
4118 if (mSpan.fWindSum == SK_MinS32) {
4119 SkDebugf("?");
4120 } else {
4121 SkDebugf("%d", mSpan.fWindSum);
4122 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004123 int last, wind;
4124 if (opp) {
4125 last = oppLastSum;
4126 wind = oppWindSum;
4127 } else {
4128 last = lastSum;
4129 wind = windSum;
4130 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004131 if (!oppoSign) {
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00004132 SkDebugf(" %d->%d (max=%d)", last, wind,
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004133 useInnerWinding(last, wind) ? wind : last);
4134 } else {
4135 SkDebugf(" %d->%d (%d->%d)", last, wind, opp ? lastSum : oppLastSum,
4136 opp ? windSum : oppWindSum);
4137 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004138 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004139#if false && DEBUG_ANGLE
caryclark@google.comc899ad92012-08-23 15:24:42 +00004140 angle.debugShow(segment.xyAtT(&sSpan));
4141#endif
caryclark@google.com47580692012-07-23 12:14:49 +00004142 ++index;
4143 if (index == angles.count()) {
4144 index = 0;
4145 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004146 if (firstTime) {
4147 firstTime = false;
4148 }
caryclark@google.com47580692012-07-23 12:14:49 +00004149 } while (index != first);
4150 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00004151
4152 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
4153 const Angle* firstAngle = angles[first];
4154 const Segment* segment = firstAngle->segment();
4155 int winding = segment->updateWinding(firstAngle);
4156 int oppWinding = segment->updateOppWinding(firstAngle);
4157 debugShowSort(fun, angles, first, winding, oppWinding);
4158 }
4159
caryclark@google.com47580692012-07-23 12:14:49 +00004160#endif
4161
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004162#if DEBUG_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004163 static char as_digit(int value) {
4164 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
4165 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004166#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004167
caryclark@google.com729e1c42012-11-21 21:36:34 +00004168#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004169 int debugShowWindingValues(int slotCount, int ofInterest) const {
4170 if (!(1 << fID & ofInterest)) {
4171 return 0;
4172 }
4173 int sum = 0;
4174 SkTDArray<char> slots;
4175 slots.setCount(slotCount * 2);
4176 memset(slots.begin(), ' ', slotCount * 2);
4177 for (int i = 0; i < fTs.count(); ++i) {
4178 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
4179 // continue;
4180 // }
4181 sum += fTs[i].fWindValue;
4182 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
4183 sum += fTs[i].fOppValue;
4184 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
4185 }
4186 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
4187 slots.begin() + slotCount);
4188 return sum;
4189 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004190#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004191
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004192private:
4193 const SkPoint* fPts;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004194 Bounds fBounds;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004195 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
caryclark@google.com4eeda372012-12-06 21:47:48 +00004196 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
caryclark@google.com24bec792012-08-20 12:43:57 +00004197 int fDoneSpans; // quick check that segment is finished
caryclark@google.com4eeda372012-12-06 21:47:48 +00004198 // OPTIMIZATION: force the following to be byte-sized
4199 SkPath::Verb fVerb;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004200 bool fOperand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004201 bool fXor; // set if original contour had even-odd fill
4202 bool fOppXor; // set if opposite operand had even-odd fill
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004203#if DEBUG_DUMP
4204 int fID;
4205#endif
4206};
4207
caryclark@google.comb9738012012-07-03 19:53:30 +00004208class Contour;
4209
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004210struct Coincidence {
caryclark@google.comb9738012012-07-03 19:53:30 +00004211 Contour* fContours[2];
4212 int fSegments[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004213 double fTs[2][2];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004214 SkPoint fPts[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004215};
4216
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004217class Contour {
4218public:
4219 Contour() {
4220 reset();
4221#if DEBUG_DUMP
4222 fID = ++gContourID;
4223#endif
4224 }
4225
4226 bool operator<(const Contour& rh) const {
4227 return fBounds.fTop == rh.fBounds.fTop
4228 ? fBounds.fLeft < rh.fBounds.fLeft
4229 : fBounds.fTop < rh.fBounds.fTop;
4230 }
4231
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004232 void addCoincident(int index, Contour* other, int otherIndex,
4233 const Intersections& ts, bool swap) {
4234 Coincidence& coincidence = *fCoincidences.append();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004235 coincidence.fContours[0] = this; // FIXME: no need to store
caryclark@google.comb9738012012-07-03 19:53:30 +00004236 coincidence.fContours[1] = other;
4237 coincidence.fSegments[0] = index;
4238 coincidence.fSegments[1] = otherIndex;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004239 coincidence.fTs[swap][0] = ts.fT[0][0];
4240 coincidence.fTs[swap][1] = ts.fT[0][1];
4241 coincidence.fTs[!swap][0] = ts.fT[1][0];
4242 coincidence.fTs[!swap][1] = ts.fT[1][1];
4243 coincidence.fPts[0] = ts.fPt[0].asSkPoint();
4244 coincidence.fPts[1] = ts.fPt[1].asSkPoint();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004245 }
4246
4247 void addCross(const Contour* crosser) {
4248#ifdef DEBUG_CROSS
4249 for (int index = 0; index < fCrosses.count(); ++index) {
4250 SkASSERT(fCrosses[index] != crosser);
4251 }
4252#endif
4253 *fCrosses.append() = crosser;
4254 }
4255
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004256 void addCubic(const SkPoint pts[4]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004257 fSegments.push_back().addCubic(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004258 fContainsCurves = true;
4259 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004260
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004261 int addLine(const SkPoint pts[2]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004262 fSegments.push_back().addLine(pts, fOperand, fXor);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004263 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004264 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004265
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004266 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
4267 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
4268 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004269
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004270 int addQuad(const SkPoint pts[3]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004271 fSegments.push_back().addQuad(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004272 fContainsCurves = true;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004273 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004274 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004275
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004276 int addT(int segIndex, double newT, Contour* other, int otherIndex, const SkPoint& pt) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004277 containsIntercepts();
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004278 return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex], pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004279 }
4280
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004281 int addUnsortableT(int segIndex, double newT, Contour* other, int otherIndex, bool start,
4282 const SkPoint& pt) {
4283 return fSegments[segIndex].addUnsortableT(newT, &other->fSegments[otherIndex], start, pt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00004284 }
4285
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004286 const Bounds& bounds() const {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004287 return fBounds;
4288 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004289
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004290 void complete() {
4291 setBounds();
4292 fContainsIntercepts = false;
4293 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004294
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004295 void containsIntercepts() {
4296 fContainsIntercepts = true;
4297 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004298
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004299 bool crosses(const Contour* crosser) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004300 for (int index = 0; index < fCrosses.count(); ++index) {
4301 if (fCrosses[index] == crosser) {
4302 return true;
4303 }
4304 }
4305 return false;
4306 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004307
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004308 bool done() const {
4309 return fDone;
4310 }
4311
caryclark@google.comf839c032012-10-26 21:03:50 +00004312 const SkPoint& end() const {
4313 const Segment& segment = fSegments.back();
4314 return segment.pts()[segment.verb()];
4315 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004316
caryclark@google.com4eeda372012-12-06 21:47:48 +00004317 void findTooCloseToCall() {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004318 int segmentCount = fSegments.count();
4319 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004320 fSegments[sIndex].findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004321 }
4322 }
4323
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004324 void fixOtherTIndex() {
4325 int segmentCount = fSegments.count();
4326 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4327 fSegments[sIndex].fixOtherTIndex();
4328 }
4329 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004330
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004331 Segment* nonVerticalSegment(int& start, int& end) {
4332 int segmentCount = fSortedSegments.count();
4333 SkASSERT(segmentCount > 0);
4334 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4335 Segment* testSegment = fSortedSegments[sortedIndex];
4336 if (testSegment->done()) {
4337 continue;
4338 }
4339 start = end = 0;
4340 while (testSegment->nextCandidate(start, end)) {
4341 if (!testSegment->isVertical(start, end)) {
4342 return testSegment;
4343 }
4344 }
4345 }
4346 return NULL;
4347 }
4348
caryclark@google.com31143cf2012-11-09 22:14:19 +00004349 bool operand() const {
4350 return fOperand;
4351 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004352
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004353 void reset() {
4354 fSegments.reset();
4355 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004356 fContainsCurves = fContainsIntercepts = fDone = false;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004357 }
caryclark@google.comb9738012012-07-03 19:53:30 +00004358
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004359 void resolveCoincidence(SkTDArray<Contour*>& contourList) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004360 int count = fCoincidences.count();
4361 for (int index = 0; index < count; ++index) {
4362 Coincidence& coincidence = fCoincidences[index];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004363 SkASSERT(coincidence.fContours[0] == this);
caryclark@google.comb9738012012-07-03 19:53:30 +00004364 int thisIndex = coincidence.fSegments[0];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004365 Segment& thisOne = fSegments[thisIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004366 Contour* otherContour = coincidence.fContours[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004367 int otherIndex = coincidence.fSegments[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004368 Segment& other = otherContour->fSegments[otherIndex];
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004369 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004370 continue;
4371 }
caryclark@google.com47580692012-07-23 12:14:49 +00004372 #if DEBUG_CONCIDENT
4373 thisOne.debugShowTs();
4374 other.debugShowTs();
4375 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004376 double startT = coincidence.fTs[0][0];
4377 double endT = coincidence.fTs[0][1];
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004378 bool cancelers = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004379 if (startT > endT) {
4380 SkTSwap<double>(startT, endT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004381 cancelers ^= true; // FIXME: just assign true
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004382 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004383 SkASSERT(!approximately_negative(endT - startT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004384 double oStartT = coincidence.fTs[1][0];
4385 double oEndT = coincidence.fTs[1][1];
4386 if (oStartT > oEndT) {
4387 SkTSwap<double>(oStartT, oEndT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004388 cancelers ^= true;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004389 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004390 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00004391 bool opp = fOperand ^ otherContour->fOperand;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004392 if (cancelers && !opp) {
4393 // make sure startT and endT have t entries
caryclark@google.com2ddff932012-08-07 21:25:27 +00004394 if (startT > 0 || oEndT < 1
4395 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004396 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004397 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00004398 if (oStartT > 0 || endT < 1
4399 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004400 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004401 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004402 if (!thisOne.done() && !other.done()) {
4403 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4404 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004405 } else {
caryclark@google.com200c2112012-08-03 15:05:04 +00004406 if (startT > 0 || oStartT > 0
4407 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004408 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004409 }
caryclark@google.com200c2112012-08-03 15:05:04 +00004410 if (endT < 1 || oEndT < 1
4411 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004412 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004413 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004414 if (!thisOne.done() && !other.done()) {
4415 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4416 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004417 }
caryclark@google.com47580692012-07-23 12:14:49 +00004418 #if DEBUG_CONCIDENT
4419 thisOne.debugShowTs();
4420 other.debugShowTs();
4421 #endif
caryclark@google.com729e1c42012-11-21 21:36:34 +00004422 #if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004423 debugShowWindingValues(contourList);
4424 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004425 }
4426 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004427
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004428 // first pass, add missing T values
4429 // second pass, determine winding values of overlaps
4430 void addCoincidentPoints() {
4431 int count = fCoincidences.count();
4432 for (int index = 0; index < count; ++index) {
4433 Coincidence& coincidence = fCoincidences[index];
4434 SkASSERT(coincidence.fContours[0] == this);
4435 int thisIndex = coincidence.fSegments[0];
4436 Segment& thisOne = fSegments[thisIndex];
4437 Contour* otherContour = coincidence.fContours[1];
4438 int otherIndex = coincidence.fSegments[1];
4439 Segment& other = otherContour->fSegments[otherIndex];
4440 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
4441 // OPTIMIZATION: remove from array
4442 continue;
4443 }
4444 #if DEBUG_CONCIDENT
4445 thisOne.debugShowTs();
4446 other.debugShowTs();
4447 #endif
4448 double startT = coincidence.fTs[0][0];
4449 double endT = coincidence.fTs[0][1];
4450 bool cancelers;
4451 if ((cancelers = startT > endT)) {
4452 SkTSwap<double>(startT, endT);
4453 }
4454 SkASSERT(!approximately_negative(endT - startT));
4455 double oStartT = coincidence.fTs[1][0];
4456 double oEndT = coincidence.fTs[1][1];
4457 if (oStartT > oEndT) {
4458 SkTSwap<double>(oStartT, oEndT);
4459 cancelers ^= true;
4460 }
4461 SkASSERT(!approximately_negative(oEndT - oStartT));
4462 bool opp = fOperand ^ otherContour->fOperand;
4463 if (cancelers && !opp) {
4464 // make sure startT and endT have t entries
4465 if (startT > 0 || oEndT < 1
4466 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004467 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004468 }
4469 if (oStartT > 0 || endT < 1
4470 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004471 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004472 }
4473 } else {
4474 if (startT > 0 || oStartT > 0
4475 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004476 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004477 }
4478 if (endT < 1 || oEndT < 1
4479 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004480 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004481 }
4482 }
4483 #if DEBUG_CONCIDENT
4484 thisOne.debugShowTs();
4485 other.debugShowTs();
4486 #endif
4487 }
4488 }
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00004489
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004490 void calcCoincidentWinding() {
4491 int count = fCoincidences.count();
4492 for (int index = 0; index < count; ++index) {
4493 Coincidence& coincidence = fCoincidences[index];
4494 SkASSERT(coincidence.fContours[0] == this);
4495 int thisIndex = coincidence.fSegments[0];
4496 Segment& thisOne = fSegments[thisIndex];
4497 if (thisOne.done()) {
4498 continue;
4499 }
4500 Contour* otherContour = coincidence.fContours[1];
4501 int otherIndex = coincidence.fSegments[1];
4502 Segment& other = otherContour->fSegments[otherIndex];
4503 if (other.done()) {
4504 continue;
4505 }
4506 double startT = coincidence.fTs[0][0];
4507 double endT = coincidence.fTs[0][1];
4508 bool cancelers;
4509 if ((cancelers = startT > endT)) {
4510 SkTSwap<double>(startT, endT);
4511 }
4512 SkASSERT(!approximately_negative(endT - startT));
4513 double oStartT = coincidence.fTs[1][0];
4514 double oEndT = coincidence.fTs[1][1];
4515 if (oStartT > oEndT) {
4516 SkTSwap<double>(oStartT, oEndT);
4517 cancelers ^= true;
4518 }
4519 SkASSERT(!approximately_negative(oEndT - oStartT));
4520 bool opp = fOperand ^ otherContour->fOperand;
4521 if (cancelers && !opp) {
4522 // make sure startT and endT have t entries
4523 if (!thisOne.done() && !other.done()) {
4524 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4525 }
4526 } else {
4527 if (!thisOne.done() && !other.done()) {
4528 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4529 }
4530 }
4531 #if DEBUG_CONCIDENT
4532 thisOne.debugShowTs();
4533 other.debugShowTs();
4534 #endif
4535 }
4536 }
4537
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004538 SkTArray<Segment>& segments() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004539 return fSegments;
4540 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004541
caryclark@google.com235f56a2012-09-14 14:19:30 +00004542 void setOperand(bool isOp) {
4543 fOperand = isOp;
4544 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00004545
caryclark@google.com4eeda372012-12-06 21:47:48 +00004546 void setOppXor(bool isOppXor) {
4547 fOppXor = isOppXor;
4548 int segmentCount = fSegments.count();
4549 for (int test = 0; test < segmentCount; ++test) {
4550 fSegments[test].setOppXor(isOppXor);
4551 }
4552 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004553
caryclark@google.com235f56a2012-09-14 14:19:30 +00004554 void setXor(bool isXor) {
4555 fXor = isXor;
4556 }
4557
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004558 void sortSegments() {
4559 int segmentCount = fSegments.count();
4560 fSortedSegments.setReserve(segmentCount);
4561 for (int test = 0; test < segmentCount; ++test) {
4562 *fSortedSegments.append() = &fSegments[test];
4563 }
4564 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4565 fFirstSorted = 0;
4566 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004567
caryclark@google.comf839c032012-10-26 21:03:50 +00004568 const SkPoint& start() const {
4569 return fSegments.front().pts()[0];
4570 }
4571
4572 void toPath(PathWrapper& path) const {
4573 int segmentCount = fSegments.count();
4574 const SkPoint& pt = fSegments.front().pts()[0];
4575 path.deferredMove(pt);
4576 for (int test = 0; test < segmentCount; ++test) {
4577 fSegments[test].addCurveTo(0, 1, path, true);
4578 }
4579 path.close();
4580 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004581
caryclark@google.comf839c032012-10-26 21:03:50 +00004582 void toPartialBackward(PathWrapper& path) const {
4583 int segmentCount = fSegments.count();
4584 for (int test = segmentCount - 1; test >= 0; --test) {
4585 fSegments[test].addCurveTo(1, 0, path, true);
4586 }
4587 }
4588
4589 void toPartialForward(PathWrapper& path) const {
4590 int segmentCount = fSegments.count();
4591 for (int test = 0; test < segmentCount; ++test) {
4592 fSegments[test].addCurveTo(0, 1, path, true);
4593 }
4594 }
4595
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004596 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004597 int segmentCount = fSortedSegments.count();
4598 SkASSERT(segmentCount > 0);
caryclark@google.comf839c032012-10-26 21:03:50 +00004599 int sortedIndex = fFirstSorted;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004600 fDone = true; // may be cleared below
caryclark@google.comf839c032012-10-26 21:03:50 +00004601 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4602 Segment* testSegment = fSortedSegments[sortedIndex];
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004603 if (testSegment->done()) {
caryclark@google.comf839c032012-10-26 21:03:50 +00004604 if (sortedIndex == fFirstSorted) {
4605 ++fFirstSorted;
4606 }
4607 continue;
4608 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004609 fDone = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004610 SkPoint testXY = testSegment->activeLeftTop(true, NULL);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004611 if (topStart) {
4612 if (testXY.fY < topLeft.fY) {
4613 continue;
4614 }
4615 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4616 continue;
4617 }
4618 if (bestXY.fY < testXY.fY) {
4619 continue;
4620 }
4621 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4622 continue;
4623 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004624 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004625 topStart = testSegment;
caryclark@google.comf839c032012-10-26 21:03:50 +00004626 bestXY = testXY;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004627 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004628 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004629
caryclark@google.com24bec792012-08-20 12:43:57 +00004630 Segment* undoneSegment(int& start, int& end) {
4631 int segmentCount = fSegments.count();
4632 for (int test = 0; test < segmentCount; ++test) {
4633 Segment* testSegment = &fSegments[test];
4634 if (testSegment->done()) {
4635 continue;
4636 }
4637 testSegment->undoneSpan(start, end);
4638 return testSegment;
4639 }
4640 return NULL;
4641 }
4642
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004643 int updateSegment(int index, const SkPoint* pts) {
4644 Segment& segment = fSegments[index];
4645 segment.updatePts(pts);
4646 return segment.verb() + 1;
4647 }
4648
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004649#if DEBUG_TEST
4650 SkTArray<Segment>& debugSegments() {
4651 return fSegments;
4652 }
4653#endif
4654
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004655#if DEBUG_DUMP
4656 void dump() {
4657 int i;
4658 const char className[] = "Contour";
4659 const int tab = 4;
4660 SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4661 for (i = 0; i < fSegments.count(); ++i) {
4662 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4663 className, i);
4664 fSegments[i].dump();
4665 }
4666 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4667 tab + sizeof(className), className,
4668 fBounds.fLeft, fBounds.fTop,
4669 fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004670 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4671 className, fContainsIntercepts);
4672 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4673 className, fContainsCurves);
4674 }
4675#endif
4676
caryclark@google.com027de222012-07-12 12:52:50 +00004677#if DEBUG_ACTIVE_SPANS
4678 void debugShowActiveSpans() {
4679 for (int index = 0; index < fSegments.count(); ++index) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004680 fSegments[index].debugShowActiveSpans();
caryclark@google.com027de222012-07-12 12:52:50 +00004681 }
4682 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004683
4684 void validateActiveSpans() {
4685 for (int index = 0; index < fSegments.count(); ++index) {
4686 fSegments[index].validateActiveSpans();
4687 }
4688 }
caryclark@google.com027de222012-07-12 12:52:50 +00004689#endif
4690
caryclark@google.com729e1c42012-11-21 21:36:34 +00004691#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004692 int debugShowWindingValues(int totalSegments, int ofInterest) {
4693 int count = fSegments.count();
4694 int sum = 0;
4695 for (int index = 0; index < count; ++index) {
4696 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4697 }
4698 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4699 return sum;
4700 }
4701
4702 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4703 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4704 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4705 int ofInterest = 1 << 5 | 1 << 8;
4706 int total = 0;
4707 int index;
4708 for (index = 0; index < contourList.count(); ++index) {
4709 total += contourList[index]->segments().count();
4710 }
4711 int sum = 0;
4712 for (index = 0; index < contourList.count(); ++index) {
4713 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4714 }
4715 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4716 }
4717#endif
4718
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004719protected:
4720 void setBounds() {
4721 int count = fSegments.count();
4722 if (count == 0) {
4723 SkDebugf("%s empty contour\n", __FUNCTION__);
4724 SkASSERT(0);
4725 // FIXME: delete empty contour?
4726 return;
4727 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004728 fBounds = fSegments.front().bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004729 for (int index = 1; index < count; ++index) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004730 fBounds.add(fSegments[index].bounds());
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004731 }
4732 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004733
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004734private:
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004735 SkTArray<Segment> fSegments;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004736 SkTDArray<Segment*> fSortedSegments;
4737 int fFirstSorted;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004738 SkTDArray<Coincidence> fCoincidences;
4739 SkTDArray<const Contour*> fCrosses;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004740 Bounds fBounds;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004741 bool fContainsIntercepts;
4742 bool fContainsCurves;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004743 bool fDone;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004744 bool fOperand; // true for the second argument to a binary operator
4745 bool fXor;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004746 bool fOppXor;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004747#if DEBUG_DUMP
4748 int fID;
4749#endif
4750};
4751
4752class EdgeBuilder {
4753public:
4754
caryclark@google.comf839c032012-10-26 21:03:50 +00004755EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
4756 : fPath(path.nativePath())
4757 , fContours(contours)
4758{
4759 init();
4760}
4761
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004762EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
caryclark@google.com235f56a2012-09-14 14:19:30 +00004763 : fPath(&path)
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004764 , fContours(contours)
4765{
caryclark@google.comf839c032012-10-26 21:03:50 +00004766 init();
4767}
4768
4769void init() {
4770 fCurrentContour = NULL;
4771 fOperand = false;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004772 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004773#if DEBUG_DUMP
4774 gContourID = 0;
4775 gSegmentID = 0;
4776#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00004777 fSecondHalf = preFetch();
4778}
4779
4780void addOperand(const SkPath& path) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00004781 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
4782 fPathVerbs.pop();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004783 fPath = &path;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004784 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004785 preFetch();
4786}
4787
4788void finish() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004789 walk();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004790 complete();
4791 if (fCurrentContour && !fCurrentContour->segments().count()) {
4792 fContours.pop_back();
4793 }
4794 // correct pointers in contours since fReducePts may have moved as it grew
4795 int cIndex = 0;
4796 int extraCount = fExtra.count();
4797 SkASSERT(extraCount == 0 || fExtra[0] == -1);
4798 int eIndex = 0;
4799 int rIndex = 0;
4800 while (++eIndex < extraCount) {
4801 int offset = fExtra[eIndex];
4802 if (offset < 0) {
4803 ++cIndex;
4804 continue;
4805 }
4806 fCurrentContour = &fContours[cIndex];
4807 rIndex += fCurrentContour->updateSegment(offset - 1,
4808 &fReducePts[rIndex]);
4809 }
4810 fExtra.reset(); // we're done with this
4811}
4812
4813ShapeOpMask xorMask() const {
caryclark@google.com729e1c42012-11-21 21:36:34 +00004814 return fXorMask[fOperand];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004815}
4816
4817protected:
4818
4819void complete() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004820 if (fCurrentContour && fCurrentContour->segments().count()) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004821 fCurrentContour->complete();
4822 fCurrentContour = NULL;
4823 }
4824}
4825
caryclark@google.com235f56a2012-09-14 14:19:30 +00004826// FIXME:remove once we can access path pts directly
4827int preFetch() {
4828 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004829 SkPoint pts[4];
4830 SkPath::Verb verb;
4831 do {
4832 verb = iter.next(pts);
4833 *fPathVerbs.append() = verb;
4834 if (verb == SkPath::kMove_Verb) {
4835 *fPathPts.append() = pts[0];
4836 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
4837 fPathPts.append(verb, &pts[1]);
4838 }
4839 } while (verb != SkPath::kDone_Verb);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004840 return fPathVerbs.count() - 1;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004841}
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004842
caryclark@google.com235f56a2012-09-14 14:19:30 +00004843void walk() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004844 SkPath::Verb reducedVerb;
4845 uint8_t* verbPtr = fPathVerbs.begin();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004846 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004847 const SkPoint* pointsPtr = fPathPts.begin();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004848 const SkPoint* finalCurveStart = NULL;
4849 const SkPoint* finalCurveEnd = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004850 SkPath::Verb verb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004851 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
4852 switch (verb) {
4853 case SkPath::kMove_Verb:
4854 complete();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004855 if (!fCurrentContour) {
4856 fCurrentContour = fContours.push_back_n(1);
caryclark@google.com235f56a2012-09-14 14:19:30 +00004857 fCurrentContour->setOperand(fOperand);
caryclark@google.com729e1c42012-11-21 21:36:34 +00004858 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004859 *fExtra.append() = -1; // start new contour
4860 }
caryclark@google.com59823f72012-08-09 18:17:47 +00004861 finalCurveEnd = pointsPtr++;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004862 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004863 case SkPath::kLine_Verb:
4864 // skip degenerate points
4865 if (pointsPtr[-1].fX != pointsPtr[0].fX
4866 || pointsPtr[-1].fY != pointsPtr[0].fY) {
4867 fCurrentContour->addLine(&pointsPtr[-1]);
4868 }
4869 break;
4870 case SkPath::kQuad_Verb:
rmistry@google.comd6176b02012-08-23 18:14:13 +00004871
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004872 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
4873 if (reducedVerb == 0) {
4874 break; // skip degenerate points
4875 }
4876 if (reducedVerb == 1) {
rmistry@google.comd6176b02012-08-23 18:14:13 +00004877 *fExtra.append() =
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004878 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004879 break;
4880 }
4881 fCurrentContour->addQuad(&pointsPtr[-1]);
4882 break;
4883 case SkPath::kCubic_Verb:
4884 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
4885 if (reducedVerb == 0) {
4886 break; // skip degenerate points
4887 }
4888 if (reducedVerb == 1) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004889 *fExtra.append() =
4890 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004891 break;
4892 }
4893 if (reducedVerb == 2) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004894 *fExtra.append() =
4895 fCurrentContour->addQuad(fReducePts.end() - 3);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004896 break;
4897 }
4898 fCurrentContour->addCubic(&pointsPtr[-1]);
4899 break;
4900 case SkPath::kClose_Verb:
4901 SkASSERT(fCurrentContour);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004902 if (finalCurveStart && finalCurveEnd
4903 && *finalCurveStart != *finalCurveEnd) {
4904 *fReducePts.append() = *finalCurveStart;
4905 *fReducePts.append() = *finalCurveEnd;
4906 *fExtra.append() =
4907 fCurrentContour->addLine(fReducePts.end() - 2);
4908 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004909 complete();
caryclark@google.com31143cf2012-11-09 22:14:19 +00004910 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004911 default:
4912 SkDEBUGFAIL("bad verb");
4913 return;
4914 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004915 finalCurveStart = &pointsPtr[verb - 1];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004916 pointsPtr += verb;
4917 SkASSERT(fCurrentContour);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004918 nextVerb:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004919 if (verbPtr == endOfFirstHalf) {
4920 fOperand = true;
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004921 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004922 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004923}
4924
4925private:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004926 const SkPath* fPath;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004927 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004928 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004929 Contour* fCurrentContour;
4930 SkTArray<Contour>& fContours;
4931 SkTDArray<SkPoint> fReducePts; // segments created on the fly
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004932 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
caryclark@google.com729e1c42012-11-21 21:36:34 +00004933 ShapeOpMask fXorMask[2];
caryclark@google.com235f56a2012-09-14 14:19:30 +00004934 int fSecondHalf;
4935 bool fOperand;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004936};
4937
4938class Work {
4939public:
4940 enum SegmentType {
4941 kHorizontalLine_Segment = -1,
4942 kVerticalLine_Segment = 0,
4943 kLine_Segment = SkPath::kLine_Verb,
4944 kQuad_Segment = SkPath::kQuad_Verb,
4945 kCubic_Segment = SkPath::kCubic_Verb,
4946 };
rmistry@google.comd6176b02012-08-23 18:14:13 +00004947
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004948 void addCoincident(Work& other, const Intersections& ts, bool swap) {
4949 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
4950 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004951
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004952 // FIXME: does it make sense to write otherIndex now if we're going to
4953 // fix it up later?
4954 void addOtherT(int index, double otherT, int otherIndex) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004955 fContour->addOtherT(fIndex, index, otherT, otherIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004956 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004957
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004958 // Avoid collapsing t values that are close to the same since
4959 // we walk ts to describe consecutive intersections. Since a pair of ts can
4960 // be nearly equal, any problems caused by this should be taken care
4961 // of later.
4962 // On the edge or out of range values are negative; add 2 to get end
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004963 int addT(double newT, const Work& other, const SkPoint& pt) {
4964 return fContour->addT(fIndex, newT, other.fContour, other.fIndex, pt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004965 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004966
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004967 int addUnsortableT(double newT, const Work& other, bool start, const SkPoint& pt) {
4968 return fContour->addUnsortableT(fIndex, newT, other.fContour, other.fIndex, start, pt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00004969 }
4970
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004971 bool advance() {
4972 return ++fIndex < fLast;
4973 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004974
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004975 SkScalar bottom() const {
4976 return bounds().fBottom;
4977 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004978
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004979 const Bounds& bounds() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004980 return fContour->segments()[fIndex].bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004981 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004982
caryclark@google.com73ca6242013-01-17 21:02:47 +00004983#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004984 const SkPoint* cubic() const {
4985 return fCubic;
4986 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00004987#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004988
4989 void init(Contour* contour) {
4990 fContour = contour;
4991 fIndex = 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004992 fLast = contour->segments().count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004993 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004994
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00004995 bool isAdjacent(const Work& next) {
4996 return fContour == next.fContour && fIndex + 1 == next.fIndex;
4997 }
4998
4999 bool isFirstLast(const Work& next) {
5000 return fContour == next.fContour && fIndex == 0
5001 && next.fIndex == fLast - 1;
5002 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005003
5004 SkScalar left() const {
5005 return bounds().fLeft;
5006 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005007
caryclark@google.com73ca6242013-01-17 21:02:47 +00005008#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005009 void promoteToCubic() {
5010 fCubic[0] = pts()[0];
5011 fCubic[2] = pts()[1];
5012 fCubic[3] = pts()[2];
5013 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
5014 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
5015 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
5016 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
5017 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005018#endif
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005019
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005020 const SkPoint* pts() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005021 return fContour->segments()[fIndex].pts();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005022 }
5023
5024 SkScalar right() const {
5025 return bounds().fRight;
5026 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005027
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005028 ptrdiff_t segmentIndex() const {
5029 return fIndex;
5030 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005031
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005032 SegmentType segmentType() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005033 const Segment& segment = fContour->segments()[fIndex];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005034 SegmentType type = (SegmentType) segment.verb();
5035 if (type != kLine_Segment) {
5036 return type;
5037 }
5038 if (segment.isHorizontal()) {
5039 return kHorizontalLine_Segment;
5040 }
5041 if (segment.isVertical()) {
5042 return kVerticalLine_Segment;
5043 }
5044 return kLine_Segment;
5045 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005046
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005047 bool startAfter(const Work& after) {
5048 fIndex = after.fIndex;
5049 return advance();
5050 }
5051
5052 SkScalar top() const {
5053 return bounds().fTop;
5054 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005055
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005056 SkPath::Verb verb() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005057 return fContour->segments()[fIndex].verb();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005058 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005059
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005060 SkScalar x() const {
5061 return bounds().fLeft;
5062 }
5063
5064 bool xFlipped() const {
5065 return x() != pts()[0].fX;
5066 }
5067
5068 SkScalar y() const {
5069 return bounds().fTop;
5070 }
5071
5072 bool yFlipped() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005073 return y() != pts()[0].fY;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005074 }
5075
5076protected:
5077 Contour* fContour;
caryclark@google.com73ca6242013-01-17 21:02:47 +00005078#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005079 SkPoint fCubic[4];
caryclark@google.com73ca6242013-01-17 21:02:47 +00005080#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005081 int fIndex;
5082 int fLast;
5083};
5084
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005085#if DEBUG_ADD_INTERSECTING_TS
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005086static void debugShowLineIntersection(int pts, const Work& wt, const Work& wn,
5087 const Intersections& i) {
5088 SkASSERT(i.used() == pts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005089 if (!pts) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005090 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n",
5091 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
5092 wt.pts()[1].fX, wt.pts()[1].fY, wn.pts()[0].fX, wn.pts()[0].fY,
5093 wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005094 return;
5095 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00005096 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 +00005097 __FUNCTION__,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005098 i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY,
5099 wt.pts()[1].fX, wt.pts()[1].fY, i.fPt[0].x, i.fPt[0].y);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005100 if (pts == 2) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005101 SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", i.fT[0][1], i.fPt[1].x, i.fPt[1].y);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005102 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005103 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g)", i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY,
5104 wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005105 if (pts == 2) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005106 SkDebugf(" wnTs[1]=%1.9g", i.fT[1][1]);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005107 }
5108 SkDebugf("\n");
5109}
5110
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005111static void debugShowQuadLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005112 const Work& wn, const Intersections& i) {
5113 SkASSERT(i.used() == pts);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005114 if (!pts) {
5115 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
caryclark@google.com0b7da432012-10-31 19:00:20 +00005116 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005117 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
5118 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005119 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005120 return;
5121 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005122 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)", __FUNCTION__,
5123 i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY,
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005124 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005125 i.fPt[0].x, i.fPt[0].y);
5126 for (int index = 1; index < pts; ++index) {
5127 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index],
5128 i.fPt[index].x, i.fPt[index].y);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005129 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005130 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g)", i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY,
5131 wn.pts()[1].fX, wn.pts()[1].fY);
5132 for (int index = 1; index < pts; ++index) {
5133 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005134 }
5135 SkDebugf("\n");
5136}
5137
caryclark@google.coma461ff02012-10-11 12:54:23 +00005138static void debugShowQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005139 const Work& wn, const Intersections& i) {
5140 SkASSERT(i.used() == pts);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005141 if (!pts) {
5142 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5143 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5144 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
skia.committer@gmail.com5b6f9162012-10-12 02:01:15 +00005145 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.coma461ff02012-10-11 12:54:23 +00005146 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005147 wn.pts()[2].fX, wn.pts()[2].fY );
caryclark@google.coma461ff02012-10-11 12:54:23 +00005148 return;
5149 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005150 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)", __FUNCTION__,
5151 i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY,
caryclark@google.coma461ff02012-10-11 12:54:23 +00005152 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005153 i.fPt[0].x, i.fPt[0].y);
5154 for (int index = 1; index < pts; ++index) {
5155 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
5156 i.fPt[index].y);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005157 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005158 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)",
5159 i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY,
5160 wn.pts()[1].fX, wn.pts()[1].fY, wn.pts()[2].fX, wn.pts()[2].fY);
5161 for (int index = 1; index < pts; ++index) {
5162 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005163 }
caryclark@google.comb9738012012-07-03 19:53:30 +00005164 SkDebugf("\n");
5165}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005166
5167static void debugShowCubicLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005168 const Work& wn, const Intersections& i) {
5169 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005170 if (!pts) {
5171 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5172 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
5173 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5174 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5175 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
5176 return;
5177 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005178 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5179 __FUNCTION__,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005180 i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
caryclark@google.com73ca6242013-01-17 21:02:47 +00005181 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005182 i.fPt[0].x, i.fPt[0].y);
5183 for (int index = 1; index < pts; ++index) {
5184 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
5185 i.fPt[index].y);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005186 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005187 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g)",
5188 i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
5189 for (int index = 1; index < pts; ++index) {
5190 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005191 }
5192 SkDebugf("\n");
5193}
5194
caryclark@google.com73ca6242013-01-17 21:02:47 +00005195// FIXME: show more than two intersection points
5196static void debugShowCubicQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005197 const Work& wn, const Intersections& i) {
5198 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005199 if (!pts) {
5200 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5201 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5202 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5203 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5204 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5205 wn.pts()[2].fX, wn.pts()[2].fY );
5206 return;
5207 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005208 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5209 __FUNCTION__,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005210 i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
caryclark@google.com73ca6242013-01-17 21:02:47 +00005211 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005212 i.fPt[0].x, i.fPt[0].y);
5213 for (int index = 1; index < pts; ++index) {
5214 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
5215 i.fPt[index].y);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005216 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005217 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)",
5218 i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5219 wn.pts()[2].fX, wn.pts()[2].fY);
5220 for (int index = 1; index < pts; ++index) {
5221 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005222 }
5223 SkDebugf("\n");
5224}
5225
5226// FIXME: show more than two intersection points
5227static void debugShowCubicIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005228 const Work& wn, const Intersections& i) {
5229 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005230 if (!pts) {
5231 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5232 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5233 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5234 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5235 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5236 wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY );
5237 return;
5238 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005239 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5240 __FUNCTION__,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005241 i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
caryclark@google.com73ca6242013-01-17 21:02:47 +00005242 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005243 i.fPt[0].x, i.fPt[0].y);
5244 for (int index = 1; index < pts; ++index) {
5245 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
5246 i.fPt[index].y);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005247 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005248 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)",
5249 i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5250 wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY);
5251 for (int index = 1; index < pts; ++index) {
5252 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[0][index]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005253 }
5254 SkDebugf("\n");
5255}
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005256
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005257#else
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005258static void debugShowLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005259}
caryclark@google.coma461ff02012-10-11 12:54:23 +00005260
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005261static void debugShowQuadLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005262}
5263
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005264static void debugShowQuadIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005265}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005266
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005267static void debugShowCubicLineIntersection(int , const Work& , const Work& ,
5268 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005269}
5270
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005271static void debugShowCubicQuadIntersection(int , const Work& , const Work& ,
5272 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005273}
5274
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005275static void debugShowCubicIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005276}
5277#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005278
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005279static bool addIntersectTs(Contour* test, Contour* next) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005280
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005281 if (test != next) {
5282 if (test->bounds().fBottom < next->bounds().fTop) {
5283 return false;
5284 }
5285 if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5286 return true;
5287 }
5288 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005289 Work wt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005290 wt.init(test);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005291 bool foundCommonContour = test == next;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005292 do {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005293 Work wn;
5294 wn.init(next);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005295 if (test == next && !wn.startAfter(wt)) {
5296 continue;
5297 }
5298 do {
5299 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5300 continue;
5301 }
5302 int pts;
5303 Intersections ts;
5304 bool swap = false;
5305 switch (wt.segmentType()) {
5306 case Work::kHorizontalLine_Segment:
5307 swap = true;
5308 switch (wn.segmentType()) {
5309 case Work::kHorizontalLine_Segment:
5310 case Work::kVerticalLine_Segment:
5311 case Work::kLine_Segment: {
5312 pts = HLineIntersect(wn.pts(), wt.left(),
5313 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005314 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005315 break;
5316 }
5317 case Work::kQuad_Segment: {
5318 pts = HQuadIntersect(wn.pts(), wt.left(),
5319 wt.right(), wt.y(), wt.xFlipped(), ts);
5320 break;
5321 }
5322 case Work::kCubic_Segment: {
5323 pts = HCubicIntersect(wn.pts(), wt.left(),
5324 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005325 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005326 break;
5327 }
5328 default:
5329 SkASSERT(0);
5330 }
5331 break;
5332 case Work::kVerticalLine_Segment:
5333 swap = true;
5334 switch (wn.segmentType()) {
5335 case Work::kHorizontalLine_Segment:
5336 case Work::kVerticalLine_Segment:
5337 case Work::kLine_Segment: {
5338 pts = VLineIntersect(wn.pts(), wt.top(),
5339 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005340 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005341 break;
5342 }
5343 case Work::kQuad_Segment: {
5344 pts = VQuadIntersect(wn.pts(), wt.top(),
5345 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5346 break;
5347 }
5348 case Work::kCubic_Segment: {
5349 pts = VCubicIntersect(wn.pts(), wt.top(),
5350 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005351 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005352 break;
5353 }
5354 default:
5355 SkASSERT(0);
5356 }
5357 break;
5358 case Work::kLine_Segment:
5359 switch (wn.segmentType()) {
5360 case Work::kHorizontalLine_Segment:
5361 pts = HLineIntersect(wt.pts(), wn.left(),
5362 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005363 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005364 break;
5365 case Work::kVerticalLine_Segment:
5366 pts = VLineIntersect(wt.pts(), wn.top(),
5367 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005368 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005369 break;
5370 case Work::kLine_Segment: {
5371 pts = LineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005372 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005373 break;
5374 }
5375 case Work::kQuad_Segment: {
5376 swap = true;
5377 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005378 debugShowQuadLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005379 break;
5380 }
5381 case Work::kCubic_Segment: {
5382 swap = true;
5383 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005384 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005385 break;
5386 }
5387 default:
5388 SkASSERT(0);
5389 }
5390 break;
5391 case Work::kQuad_Segment:
5392 switch (wn.segmentType()) {
5393 case Work::kHorizontalLine_Segment:
5394 pts = HQuadIntersect(wt.pts(), wn.left(),
5395 wn.right(), wn.y(), wn.xFlipped(), ts);
5396 break;
5397 case Work::kVerticalLine_Segment:
5398 pts = VQuadIntersect(wt.pts(), wn.top(),
5399 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5400 break;
5401 case Work::kLine_Segment: {
5402 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005403 debugShowQuadLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005404 break;
5405 }
5406 case Work::kQuad_Segment: {
5407 pts = QuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005408 debugShowQuadIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005409 break;
5410 }
5411 case Work::kCubic_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005412 #if APPROXIMATE_CUBICS
5413 swap = true;
5414 pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005415 debugShowCubicQuadIntersection(pts, wn, wt, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005416 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005417 wt.promoteToCubic();
5418 pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005419 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005420 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005421 break;
5422 }
5423 default:
5424 SkASSERT(0);
5425 }
5426 break;
5427 case Work::kCubic_Segment:
5428 switch (wn.segmentType()) {
5429 case Work::kHorizontalLine_Segment:
5430 pts = HCubicIntersect(wt.pts(), wn.left(),
5431 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005432 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005433 break;
5434 case Work::kVerticalLine_Segment:
5435 pts = VCubicIntersect(wt.pts(), wn.top(),
5436 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005437 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005438 break;
5439 case Work::kLine_Segment: {
5440 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005441 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005442 break;
5443 }
5444 case Work::kQuad_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005445 #if APPROXIMATE_CUBICS
5446 pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005447 debugShowCubicQuadIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005448 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005449 wn.promoteToCubic();
5450 pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005451 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005452 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005453 break;
5454 }
5455 case Work::kCubic_Segment: {
5456 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005457 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005458 break;
5459 }
5460 default:
5461 SkASSERT(0);
5462 }
5463 break;
5464 default:
5465 SkASSERT(0);
5466 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005467 if (!foundCommonContour && pts > 0) {
5468 test->addCross(next);
5469 next->addCross(test);
5470 foundCommonContour = true;
5471 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005472 // in addition to recording T values, record matching segment
caryclark@google.com73ca6242013-01-17 21:02:47 +00005473 if (ts.unsortable()) {
5474 bool start = true;
5475 for (int pt = 0; pt < ts.used(); ++pt) {
5476 // FIXME: if unsortable, the other points to the original. This logic is
5477 // untested downstream.
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005478 SkPoint point = ts.fPt[pt].asSkPoint();
5479 int testTAt = wt.addUnsortableT(ts.fT[swap][pt], wt, start, point);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005480 wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005481 testTAt = wn.addUnsortableT(ts.fT[!swap][pt], wn, start ^ ts.fFlip, point);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005482 wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt);
5483 start ^= true;
5484 }
5485 continue;
5486 }
caryclark@google.com32546db2012-08-31 20:55:07 +00005487 if (pts == 2) {
5488 if (wn.segmentType() <= Work::kLine_Segment
5489 && wt.segmentType() <= Work::kLine_Segment) {
5490 wt.addCoincident(wn, ts, swap);
5491 continue;
5492 }
caryclark@google.combeda3892013-02-07 13:13:41 +00005493 if (wn.segmentType() >= Work::kQuad_Segment
5494 && wt.segmentType() >= Work::kQuad_Segment
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005495 && ts.fIsCoincident[0]) {
5496 SkASSERT(ts.coincidentUsed() == 2);
caryclark@google.com32546db2012-08-31 20:55:07 +00005497 wt.addCoincident(wn, ts, swap);
5498 continue;
5499 }
5500
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00005501 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00005502 for (int pt = 0; pt < pts; ++pt) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005503 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5504 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005505 SkPoint point = ts.fPt[pt].asSkPoint();
5506 int testTAt = wt.addT(ts.fT[swap][pt], wn, point);
5507 int nextTAt = wn.addT(ts.fT[!swap][pt], wt, point);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005508 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
5509 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005510 }
5511 } while (wn.advance());
5512 } while (wt.advance());
5513 return true;
5514}
5515
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005516// resolve any coincident pairs found while intersecting, and
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005517// see if coincidence is formed by clipping non-concident segments
caryclark@google.com4eeda372012-12-06 21:47:48 +00005518static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005519 int contourCount = contourList.count();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005520#if ONE_PASS_COINCIDENCE_CHECK
caryclark@google.comf25edfe2012-06-01 18:20:10 +00005521 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005522 Contour* contour = contourList[cIndex];
caryclark@google.com7ba591e2012-11-20 14:21:54 +00005523 contour->resolveCoincidence(contourList);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005524 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005525#else
5526 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5527 Contour* contour = contourList[cIndex];
5528 contour->addCoincidentPoints();
5529 }
5530 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5531 Contour* contour = contourList[cIndex];
5532 contour->calcCoincidentWinding();
5533 }
5534#endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005535 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5536 Contour* contour = contourList[cIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00005537 contour->findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005538 }
5539}
5540
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005541static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005542 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005543 SkPoint basePt;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005544 double tAtMid = current->tAtMid(index, endIndex, mid);
5545 current->xyAtT(tAtMid, basePt);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005546 int contourCount = contourList.count();
5547 SkScalar bestY = SK_ScalarMin;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005548 Segment* bestSeg = NULL;
5549 int bestTIndex;
5550 bool bestOpp;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005551 bool hitSomething = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005552 for (int cTest = 0; cTest < contourCount; ++cTest) {
5553 Contour* contour = contourList[cTest];
5554 bool testOpp = contour->operand() ^ current->operand() ^ opp;
5555 if (basePt.fY < contour->bounds().fTop) {
5556 continue;
5557 }
5558 if (bestY > contour->bounds().fBottom) {
5559 continue;
5560 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005561 int segmentCount = contour->segments().count();
5562 for (int test = 0; test < segmentCount; ++test) {
5563 Segment* testSeg = &contour->segments()[test];
5564 SkScalar testY = bestY;
5565 double testHit;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005566 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
5567 testOpp, testSeg == current);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005568 if (testTIndex < 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005569 if (testTIndex == SK_MinS32) {
5570 hitSomething = true;
5571 bestSeg = NULL;
5572 goto abortContours; // vertical encountered, return and try different point
5573 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005574 continue;
5575 }
5576 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005577 double baseT = current->t(index);
5578 double endT = current->t(endIndex);
5579 double newMid = (testHit - baseT) / (endT - baseT);
5580#if DEBUG_WINDING
5581 SkPoint midXY, newXY;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005582 double midT = current->tAtMid(index, endIndex, mid);
5583 current->xyAtT(midT, midXY);
5584 double newMidT = current->tAtMid(index, endIndex, newMid);
5585 current->xyAtT(newMidT, newXY);
caryclark@google.com3586ece2012-12-27 18:46:58 +00005586 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
5587 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
5588 current->debugID(), mid, newMid,
5589 baseT, current->xAtT(index), current->yAtT(index),
5590 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
5591 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
5592 endT, current->xAtT(endIndex), current->yAtT(endIndex));
5593#endif
5594 mid = newMid * 2; // calling loop with divide by 2 before continuing
5595 return SK_MinS32;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005596 }
5597 bestSeg = testSeg;
5598 bestHit = testHit;
5599 bestOpp = testOpp;
5600 bestTIndex = testTIndex;
5601 bestY = testY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005602 }
5603 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005604abortContours:
caryclark@google.com10227bf2012-12-28 22:10:41 +00005605 int result;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005606 if (!bestSeg) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00005607 result = hitSomething ? SK_MinS32 : 0;
5608 } else {
5609 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
5610 current = bestSeg;
5611 index = bestTIndex;
5612 endIndex = bestSeg->nextSpan(bestTIndex, 1);
5613 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
5614 tryAgain = true;
5615 return 0;
5616 }
5617 result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
5618 SkASSERT(bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005619 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005620 double baseT = current->t(index);
5621 double endT = current->t(endIndex);
5622 bestHit = baseT + mid * (endT - baseT);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005623 return result;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005624}
5625
caryclark@google.com24bec792012-08-20 12:43:57 +00005626static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
5627 int contourCount = contourList.count();
5628 Segment* result;
5629 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5630 Contour* contour = contourList[cIndex];
5631 result = contour->undoneSegment(start, end);
5632 if (result) {
5633 return result;
5634 }
5635 }
5636 return NULL;
5637}
5638
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005639#define OLD_FIND_CHASE 1
caryclark@google.com24bec792012-08-20 12:43:57 +00005640
caryclark@google.com31143cf2012-11-09 22:14:19 +00005641static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005642 while (chase.count()) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005643 Span* span;
5644 chase.pop(&span);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005645 const Span& backPtr = span->fOther->span(span->fOtherIndex);
5646 Segment* segment = backPtr.fOther;
5647 tIndex = backPtr.fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005648 SkTDArray<Angle> angles;
5649 int done = 0;
5650 if (segment->activeAngle(tIndex, done, angles)) {
5651 Angle* last = angles.end() - 1;
5652 tIndex = last->start();
5653 endIndex = last->end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005654 #if TRY_ROTATE
5655 *chase.insert(0) = span;
5656 #else
5657 *chase.append() = span;
5658 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005659 return last->segment();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005660 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005661 if (done == angles.count()) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00005662 continue;
5663 }
5664 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005665 bool sortable = Segment::SortAngles(angles, sorted);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005666 int angleCount = sorted.count();
caryclark@google.com03f97062012-08-21 13:13:52 +00005667#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005668 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00005669#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005670 if (!sortable) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005671 continue;
5672 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005673 // find first angle, initialize winding to computed fWindSum
5674 int firstIndex = -1;
5675 const Angle* angle;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005676#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005677 int winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005678 do {
5679 angle = sorted[++firstIndex];
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005680 segment = angle->segment();
5681 winding = segment->windSum(angle);
5682 } while (winding == SK_MinS32);
5683 int spanWinding = segment->spanSign(angle->start(), angle->end());
5684 #if DEBUG_WINDING
caryclark@google.com31143cf2012-11-09 22:14:19 +00005685 SkDebugf("%s winding=%d spanWinding=%d\n",
5686 __FUNCTION__, winding, spanWinding);
caryclark@google.com47580692012-07-23 12:14:49 +00005687 #endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005688 // turn span winding into contour winding
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005689 if (spanWinding * winding < 0) {
5690 winding += spanWinding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005691 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005692 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005693 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005694 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005695 // we care about first sign and whether wind sum indicates this
5696 // edge is inside or outside. Maybe need to pass span winding
5697 // or first winding or something into this function?
5698 // advance to first undone angle, then return it and winding
5699 // (to set whether edges are active or not)
5700 int nextIndex = firstIndex + 1;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005701 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005702 angle = sorted[firstIndex];
caryclark@google.com2ddff932012-08-07 21:25:27 +00005703 winding -= angle->segment()->spanSign(angle);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005704#else
5705 do {
5706 angle = sorted[++firstIndex];
5707 segment = angle->segment();
5708 } while (segment->windSum(angle) == SK_MinS32);
5709 #if DEBUG_SORT
5710 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5711 #endif
5712 int sumWinding = segment->updateWindingReverse(angle);
5713 int nextIndex = firstIndex + 1;
5714 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5715 Segment* first = NULL;
5716#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005717 do {
5718 SkASSERT(nextIndex != firstIndex);
5719 if (nextIndex == angleCount) {
5720 nextIndex = 0;
5721 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005722 angle = sorted[nextIndex];
caryclark@google.com9764cc62012-07-12 19:29:45 +00005723 segment = angle->segment();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005724#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005725 int maxWinding = winding;
caryclark@google.com2ddff932012-08-07 21:25:27 +00005726 winding -= segment->spanSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005727 #if DEBUG_SORT
caryclark@google.com2ddff932012-08-07 21:25:27 +00005728 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
5729 segment->debugID(), maxWinding, winding, angle->sign());
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005730 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005731 tIndex = angle->start();
5732 endIndex = angle->end();
5733 int lesser = SkMin32(tIndex, endIndex);
5734 const Span& nextSpan = segment->span(lesser);
5735 if (!nextSpan.fDone) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005736#if 1
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005737 // FIXME: this be wrong? assign startWinding if edge is in
caryclark@google.com9764cc62012-07-12 19:29:45 +00005738 // same direction. If the direction is opposite, winding to
5739 // assign is flipped sign or +/- 1?
caryclark@google.com59823f72012-08-09 18:17:47 +00005740 if (useInnerWinding(maxWinding, winding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005741 maxWinding = winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005742 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005743 segment->markAndChaseWinding(angle, maxWinding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005744#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005745 break;
5746 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005747#else
5748 int start = angle->start();
5749 int end = angle->end();
5750 int maxWinding;
5751 segment->setUpWinding(start, end, maxWinding, sumWinding);
5752 if (!segment->done(angle)) {
5753 if (!first) {
5754 first = segment;
5755 tIndex = start;
5756 endIndex = end;
5757 }
5758 (void) segment->markAngle(maxWinding, sumWinding, true, angle);
5759 }
5760#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005761 } while (++nextIndex != lastIndex);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005762 #if TRY_ROTATE
5763 *chase.insert(0) = span;
5764 #else
5765 *chase.append() = span;
5766 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005767 return segment;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005768 }
5769 return NULL;
5770}
5771
caryclark@google.com027de222012-07-12 12:52:50 +00005772#if DEBUG_ACTIVE_SPANS
5773static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005774 int index;
5775 for (index = 0; index < contourList.count(); ++ index) {
caryclark@google.com027de222012-07-12 12:52:50 +00005776 contourList[index]->debugShowActiveSpans();
5777 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005778 for (index = 0; index < contourList.count(); ++ index) {
5779 contourList[index]->validateActiveSpans();
5780 }
caryclark@google.com027de222012-07-12 12:52:50 +00005781}
5782#endif
5783
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005784static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005785 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005786 Segment* result;
5787 do {
caryclark@google.comf839c032012-10-26 21:03:50 +00005788 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005789 int contourCount = contourList.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00005790 Segment* topStart = NULL;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005791 done = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00005792 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5793 Contour* contour = contourList[cIndex];
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005794 if (contour->done()) {
5795 continue;
5796 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005797 const Bounds& bounds = contour->bounds();
5798 if (bounds.fBottom < topLeft.fY) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005799 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005800 continue;
5801 }
5802 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005803 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005804 continue;
5805 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005806 contour->topSortableSegment(topLeft, bestXY, topStart);
5807 if (!contour->done()) {
5808 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005809 }
5810 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005811 if (!topStart) {
5812 return NULL;
5813 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005814 topLeft = bestXY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005815 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005816 } while (!result);
5817 return result;
5818}
caryclark@google.com31143cf2012-11-09 22:14:19 +00005819
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005820static int rightAngleWinding(SkTDArray<Contour*>& contourList,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005821 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005822 bool opp) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005823 double test = 0.9;
5824 int contourWinding;
5825 do {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005826 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
5827 tryAgain, test, opp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005828 if (contourWinding != SK_MinS32 || tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005829 return contourWinding;
5830 }
5831 test /= 2;
5832 } while (!approximately_negative(test));
5833 SkASSERT(0); // should be OK to comment out, but interested when this hits
5834 return contourWinding;
5835}
5836
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005837static void skipVertical(SkTDArray<Contour*>& contourList,
5838 Segment*& current, int& index, int& endIndex) {
5839 if (!current->isVertical(index, endIndex)) {
5840 return;
5841 }
5842 int contourCount = contourList.count();
5843 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5844 Contour* contour = contourList[cIndex];
5845 if (contour->done()) {
5846 continue;
5847 }
5848 current = contour->nonVerticalSegment(index, endIndex);
5849 if (current) {
5850 return;
5851 }
5852 }
5853}
5854
caryclark@google.com3586ece2012-12-27 18:46:58 +00005855static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005856 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
5857 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
5858 true);
5859 if (!current) {
5860 return NULL;
5861 }
5862 if (firstContour) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005863 current->initWinding(index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005864 firstContour = false;
5865 return current;
5866 }
5867 int minIndex = SkMin32(index, endIndex);
5868 int sumWinding = current->windSum(minIndex);
5869 if (sumWinding != SK_MinS32) {
5870 return current;
5871 }
5872 sumWinding = current->computeSum(index, endIndex, binary);
5873 if (sumWinding != SK_MinS32) {
5874 return current;
5875 }
5876 int contourWinding;
5877 int oppContourWinding = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005878 // the simple upward projection of the unresolved points hit unsortable angles
5879 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005880 bool tryAgain;
5881 double tHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005882 SkScalar hitDx = 0;
5883 SkScalar hitOppDx = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005884 do {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005885 // if current is vertical, find another candidate which is not
5886 // if only remaining candidates are vertical, then they can be marked done
caryclark@google.com10227bf2012-12-28 22:10:41 +00005887 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005888 skipVertical(contourList, current, index, endIndex);
caryclark@google.com10227bf2012-12-28 22:10:41 +00005889 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005890 tryAgain = false;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005891 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005892 tryAgain, false);
5893 if (tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005894 continue;
5895 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005896 if (!binary) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005897 break;
5898 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005899 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005900 tryAgain, true);
5901 } while (tryAgain);
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00005902
caryclark@google.com3586ece2012-12-27 18:46:58 +00005903 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005904 return current;
5905}
5906
5907// rewrite that abandons keeping local track of winding
caryclark@google.com3586ece2012-12-27 18:46:58 +00005908static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005909 bool firstContour = true;
5910 bool unsortable = false;
5911 bool topUnsortable = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005912 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
5913 do {
5914 int index, endIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005915 bool topDone;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005916 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005917 topUnsortable, topDone, false);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005918 if (!current) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005919 if (topUnsortable || !topDone) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005920 topUnsortable = false;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005921 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005922 topLeft.fX = topLeft.fY = SK_ScalarMin;
5923 continue;
5924 }
5925 break;
5926 }
5927 SkTDArray<Span*> chaseArray;
5928 do {
5929 if (current->activeWinding(index, endIndex)) {
5930 do {
5931 #if DEBUG_ACTIVE_SPANS
5932 if (!unsortable && current->done()) {
5933 debugShowActiveSpans(contourList);
5934 }
5935 #endif
5936 SkASSERT(unsortable || !current->done());
5937 int nextStart = index;
5938 int nextEnd = endIndex;
5939 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
5940 unsortable);
5941 if (!next) {
5942 if (!unsortable && simple.hasMove()
5943 && current->verb() != SkPath::kLine_Verb
5944 && !simple.isClosed()) {
5945 current->addCurveTo(index, endIndex, simple, true);
5946 SkASSERT(simple.isClosed());
5947 }
5948 break;
5949 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005950 #if DEBUG_FLOW
5951 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
5952 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
5953 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
5954 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005955 current->addCurveTo(index, endIndex, simple, true);
5956 current = next;
5957 index = nextStart;
5958 endIndex = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005959 } while (!simple.isClosed() && (!unsortable
caryclark@google.com10227bf2012-12-28 22:10:41 +00005960 || !current->done(SkMin32(index, endIndex))));
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005961 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
5962 SkASSERT(unsortable);
5963 int min = SkMin32(index, endIndex);
5964 if (!current->done(min)) {
5965 current->addCurveTo(index, endIndex, simple, true);
5966 current->markDoneUnary(min);
5967 }
5968 }
5969 simple.close();
5970 } else {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005971 Span* last = current->markAndChaseDoneUnary(index, endIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005972 if (last) {
5973 *chaseArray.append() = last;
5974 }
5975 }
5976 current = findChase(chaseArray, index, endIndex);
5977 #if DEBUG_ACTIVE_SPANS
5978 debugShowActiveSpans(contourList);
5979 #endif
5980 if (!current) {
5981 break;
5982 }
5983 } while (true);
5984 } while (true);
5985 return simple.someAssemblyRequired();
5986}
5987
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005988// returns true if all edges were processed
caryclark@google.comf839c032012-10-26 21:03:50 +00005989static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.com24bec792012-08-20 12:43:57 +00005990 Segment* current;
5991 int start, end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005992 bool unsortable = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005993 bool closable = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00005994 while ((current = findUndone(contourList, start, end))) {
caryclark@google.com24bec792012-08-20 12:43:57 +00005995 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005996 #if DEBUG_ACTIVE_SPANS
5997 if (!unsortable && current->done()) {
5998 debugShowActiveSpans(contourList);
5999 }
6000 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006001 SkASSERT(unsortable || !current->done());
caryclark@google.com24bec792012-08-20 12:43:57 +00006002 int nextStart = start;
6003 int nextEnd = end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006004 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
caryclark@google.com24bec792012-08-20 12:43:57 +00006005 if (!next) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006006 if (!unsortable && simple.hasMove()
caryclark@google.comf839c032012-10-26 21:03:50 +00006007 && current->verb() != SkPath::kLine_Verb
6008 && !simple.isClosed()) {
6009 current->addCurveTo(start, end, simple, true);
6010 SkASSERT(simple.isClosed());
caryclark@google.comc899ad92012-08-23 15:24:42 +00006011 }
caryclark@google.com24bec792012-08-20 12:43:57 +00006012 break;
6013 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006014 #if DEBUG_FLOW
6015 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6016 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
6017 current->xyAtT(end).fX, current->xyAtT(end).fY);
6018 #endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006019 current->addCurveTo(start, end, simple, true);
caryclark@google.com24bec792012-08-20 12:43:57 +00006020 current = next;
6021 start = nextStart;
6022 end = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006023 } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006024 if (!simple.isClosed()) {
6025 SkASSERT(unsortable);
6026 int min = SkMin32(start, end);
6027 if (!current->done(min)) {
6028 current->addCurveTo(start, end, simple, true);
6029 current->markDone(min, 1);
6030 }
6031 closable = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00006032 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006033 simple.close();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00006034 #if DEBUG_ACTIVE_SPANS
6035 debugShowActiveSpans(contourList);
6036 #endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00006037 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006038 return closable;
caryclark@google.com24bec792012-08-20 12:43:57 +00006039}
6040
caryclark@google.comb45a1b42012-05-18 20:50:33 +00006041static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
6042 int contourCount = contourList.count();
6043 for (int cTest = 0; cTest < contourCount; ++cTest) {
6044 Contour* contour = contourList[cTest];
6045 contour->fixOtherTIndex();
6046 }
6047}
6048
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006049static void sortSegments(SkTDArray<Contour*>& contourList) {
6050 int contourCount = contourList.count();
6051 for (int cTest = 0; cTest < contourCount; ++cTest) {
6052 Contour* contour = contourList[cTest];
6053 contour->sortSegments();
6054 }
6055}
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006056
caryclark@google.com4eeda372012-12-06 21:47:48 +00006057static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
6058 bool evenOdd, bool oppEvenOdd) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006059 int count = contours.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006060 if (count == 0) {
6061 return;
6062 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006063 for (int index = 0; index < count; ++index) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00006064 Contour& contour = contours[index];
6065 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
6066 *list.append() = &contour;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006067 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006068 QSort<Contour>(list.begin(), list.end() - 1);
6069}
6070
caryclark@google.comf839c032012-10-26 21:03:50 +00006071static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006072 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006073}
6074
caryclark@google.com10227bf2012-12-28 22:10:41 +00006075static bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
6076 return distances[one] < distances[two];
6077}
caryclark@google.comf839c032012-10-26 21:03:50 +00006078 /*
6079 check start and end of each contour
6080 if not the same, record them
6081 match them up
6082 connect closest
6083 reassemble contour pieces into new path
6084 */
6085static void assemble(const PathWrapper& path, PathWrapper& simple) {
6086#if DEBUG_PATH_CONSTRUCTION
6087 SkDebugf("%s\n", __FUNCTION__);
6088#endif
6089 SkTArray<Contour> contours;
6090 EdgeBuilder builder(path, contours);
6091 builder.finish();
6092 int count = contours.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006093 int outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006094 SkTDArray<int> runs; // indices of partial contours
caryclark@google.com0b7da432012-10-31 19:00:20 +00006095 for (outer = 0; outer < count; ++outer) {
6096 const Contour& eContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006097 const SkPoint& eStart = eContour.start();
6098 const SkPoint& eEnd = eContour.end();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006099#if DEBUG_ASSEMBLE
6100 SkDebugf("%s contour", __FUNCTION__);
6101 if (!approximatelyEqual(eStart, eEnd)) {
6102 SkDebugf("[%d]", runs.count());
6103 } else {
6104 SkDebugf(" ");
6105 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006106 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006107 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
6108#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006109 if (approximatelyEqual(eStart, eEnd)) {
6110 eContour.toPath(simple);
6111 continue;
6112 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006113 *runs.append() = outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006114 }
6115 count = runs.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006116 if (count == 0) {
6117 return;
6118 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006119 SkTDArray<int> sLink, eLink;
6120 sLink.setCount(count);
6121 eLink.setCount(count);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006122 int rIndex, iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006123 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006124 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006125 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006126 SkTDArray<double> distances;
6127 const int ends = count * 2; // all starts and ends
6128 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
6129 distances.setCount(entries);
6130 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
6131 outer = runs[rIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006132 const Contour& oContour = contours[outer];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006133 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
6134 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
6135 * ends - rIndex - 1;
6136 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
6137 int inner = runs[iIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006138 const Contour& iContour = contours[inner];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006139 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
6140 double dx = iPt.fX - oPt.fX;
6141 double dy = iPt.fY - oPt.fY;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006142 double dist = dx * dx + dy * dy;
caryclark@google.com10227bf2012-12-28 22:10:41 +00006143 distances[row + iIndex] = dist; // oStart distance from iStart
6144 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006145 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006146 SkTDArray<int> sortedDist;
6147 sortedDist.setCount(entries);
6148 for (rIndex = 0; rIndex < entries; ++rIndex) {
6149 sortedDist[rIndex] = rIndex;
6150 }
6151 QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
6152 int remaining = count; // number of start/end pairs
6153 for (rIndex = 0; rIndex < entries; ++rIndex) {
6154 int pair = sortedDist[rIndex];
6155 int row = pair / ends;
6156 int col = pair - row * ends;
6157 int thingOne = row < col ? row : ends - row - 2;
6158 int ndxOne = thingOne >> 1;
6159 bool endOne = thingOne & 1;
6160 int* linkOne = endOne ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006161 if (linkOne[ndxOne] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006162 continue;
6163 }
6164 int thingTwo = row < col ? col : ends - row + col - 1;
6165 int ndxTwo = thingTwo >> 1;
6166 bool endTwo = thingTwo & 1;
6167 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006168 if (linkTwo[ndxTwo] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006169 continue;
6170 }
6171 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
6172 bool flip = endOne == endTwo;
6173 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
6174 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
6175 if (!--remaining) {
6176 break;
6177 }
6178 }
6179 SkASSERT(!remaining);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006180#if DEBUG_ASSEMBLE
6181 for (rIndex = 0; rIndex < count; ++rIndex) {
6182 int s = sLink[rIndex];
6183 int e = eLink[rIndex];
6184 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
6185 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
caryclark@google.comf839c032012-10-26 21:03:50 +00006186 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006187#endif
6188 rIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00006189 do {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006190 bool forward = true;
6191 bool first = true;
6192 int sIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006193 SkASSERT(sIndex != SK_MaxS32);
6194 sLink[rIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006195 int eIndex;
6196 if (sIndex < 0) {
6197 eIndex = sLink[~sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006198 sLink[~sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006199 } else {
6200 eIndex = eLink[sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006201 eLink[sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006202 }
caryclark@google.comaa358312013-01-29 20:28:49 +00006203 SkASSERT(eIndex != SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006204#if DEBUG_ASSEMBLE
6205 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006206 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
6207 eIndex < 0 ? ~eIndex : eIndex);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006208#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006209 do {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006210 outer = runs[rIndex];
6211 const Contour& contour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006212 if (first) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006213 first = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006214 const SkPoint* startPtr = &contour.start();
caryclark@google.comf839c032012-10-26 21:03:50 +00006215 simple.deferredMove(startPtr[0]);
6216 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006217 if (forward) {
6218 contour.toPartialForward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006219 } else {
6220 contour.toPartialBackward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006221 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006222#if DEBUG_ASSEMBLE
6223 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006224 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006225 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
6226#endif
6227 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006228 simple.close();
caryclark@google.comf839c032012-10-26 21:03:50 +00006229 break;
6230 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006231 if (forward) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006232 eIndex = eLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006233 SkASSERT(eIndex != SK_MaxS32);
6234 eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006235 if (eIndex >= 0) {
6236 SkASSERT(sLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006237 sLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006238 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006239 SkASSERT(eLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006240 eLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006241 }
6242 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006243 eIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006244 SkASSERT(eIndex != SK_MaxS32);
6245 sLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006246 if (eIndex >= 0) {
6247 SkASSERT(eLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006248 eLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006249 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006250 SkASSERT(sLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006251 sLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006252 }
6253 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006254 rIndex = eIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006255 if (rIndex < 0) {
6256 forward ^= 1;
6257 rIndex = ~rIndex;
6258 }
6259 } while (true);
6260 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006261 if (sLink[rIndex] != SK_MaxS32) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006262 break;
6263 }
6264 }
6265 } while (rIndex < count);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006266#if DEBUG_ASSEMBLE
6267 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006268 SkASSERT(sLink[rIndex] == SK_MaxS32);
6269 SkASSERT(eLink[rIndex] == SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006270 }
6271#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006272}
6273
6274void simplifyx(const SkPath& path, SkPath& result) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006275 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
caryclark@google.comf839c032012-10-26 21:03:50 +00006276 result.reset();
6277 result.setFillType(SkPath::kEvenOdd_FillType);
6278 PathWrapper simple(result);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006279
6280 // turn path into list of segments
6281 SkTArray<Contour> contours;
6282 // FIXME: add self-intersecting cubics' T values to segment
6283 EdgeBuilder builder(path, contours);
caryclark@google.com235f56a2012-09-14 14:19:30 +00006284 builder.finish();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006285 SkTDArray<Contour*> contourList;
caryclark@google.com4eeda372012-12-06 21:47:48 +00006286 makeContourList(contours, contourList, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006287 Contour** currentPtr = contourList.begin();
6288 if (!currentPtr) {
6289 return;
6290 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006291 Contour** listEnd = contourList.end();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006292 // find all intersections between segments
6293 do {
6294 Contour** nextPtr = currentPtr;
6295 Contour* current = *currentPtr++;
6296 Contour* next;
6297 do {
6298 next = *nextPtr++;
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00006299 } while (addIntersectTs(current, next) && nextPtr != listEnd);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006300 } while (currentPtr != listEnd);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006301 // eat through coincident edges
caryclark@google.com4eeda372012-12-06 21:47:48 +00006302 coincidenceCheck(contourList, 0);
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00006303 fixOtherTIndex(contourList);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006304 sortSegments(contourList);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006305#if DEBUG_ACTIVE_SPANS
6306 debugShowActiveSpans(contourList);
6307#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006308 // construct closed contours
caryclark@google.com3586ece2012-12-27 18:46:58 +00006309 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00006310 : !bridgeXor(contourList, simple))
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006311 { // if some edges could not be resolved, assemble remaining fragments
caryclark@google.comf839c032012-10-26 21:03:50 +00006312 SkPath temp;
6313 temp.setFillType(SkPath::kEvenOdd_FillType);
6314 PathWrapper assembled(temp);
6315 assemble(simple, assembled);
6316 result = *assembled.nativePath();
caryclark@google.com24bec792012-08-20 12:43:57 +00006317 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006318}