blob: 2c7103950f22e536863efd243c8f271e7b26ad99 [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.com47d73da2013-02-17 01:41:25 +000035#define FORCE_RELEASE 0 // 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.com47d73da2013-02-17 01:41:25 +000055#define DEBUG_SWAP_TOP 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000056#define DEBUG_UNSORTABLE 0
caryclark@google.comafe56de2012-07-24 18:11:03 +000057#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000058#define DEBUG_WINDING 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000059#define DEBUG_WINDING_AT_T 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000060
61#else
62
caryclark@google.com47580692012-07-23 12:14:49 +000063const bool gRunTestsInOneThread = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +000064
caryclark@google.combeda3892013-02-07 13:13:41 +000065#define DEBUG_ACTIVE_OP 1
caryclark@google.comc91dfe42012-10-16 12:06:27 +000066#define DEBUG_ACTIVE_SPANS 1
caryclark@google.com4eeda372012-12-06 21:47:48 +000067#define DEBUG_ACTIVE_SPANS_SHORT_FORM 1
caryclark@google.com6aea33f2012-10-09 14:11:58 +000068#define DEBUG_ADD_INTERSECTING_TS 1
69#define DEBUG_ADD_T_PAIR 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000070#define DEBUG_ANGLE 1
caryclark@google.come7bd5f42012-12-13 19:47:53 +000071#define DEBUG_ASSEMBLE 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000072#define DEBUG_CONCIDENT 1
caryclark@google.com534aa5b2012-08-02 20:08:21 +000073#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000074#define DEBUG_FLOW 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000075#define DEBUG_MARK_DONE 1
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000076#define DEBUG_PATH_CONSTRUCTION 1
caryclark@google.com729e1c42012-11-21 21:36:34 +000077#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000078#define DEBUG_SORT 1
caryclark@google.com47d73da2013-02-17 01:41:25 +000079#define DEBUG_SWAP_TOP 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000080#define DEBUG_UNSORTABLE 1
caryclark@google.comafe56de2012-07-24 18:11:03 +000081#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000082#define DEBUG_WINDING 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000083#define DEBUG_WINDING_AT_T 1
caryclark@google.comfa0588f2012-04-26 21:01:06 +000084
85#endif
86
caryclark@google.combeda3892013-02-07 13:13:41 +000087#define DEBUG_DUMP (DEBUG_ACTIVE_OP | DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | \
88 DEBUG_PATH_CONSTRUCTION)
caryclark@google.com027de222012-07-12 12:52:50 +000089
caryclark@google.comfa0588f2012-04-26 21:01:06 +000090#if DEBUG_DUMP
caryclark@google.combeda3892013-02-07 13:13:41 +000091static const char* kShapeOpStr[] = {"diff", "sect", "union", "xor"};
caryclark@google.comfa0588f2012-04-26 21:01:06 +000092static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000093// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
caryclark@google.comfa0588f2012-04-26 21:01:06 +000094static int gContourID;
95static int gSegmentID;
96#endif
97
caryclark@google.com8dcf1142012-07-02 20:27:02 +000098#ifndef DEBUG_TEST
99#define DEBUG_TEST 0
100#endif
101
caryclark@google.com32546db2012-08-31 20:55:07 +0000102#define MAKE_CONST_LINE(line, pts) \
103 const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}
104#define MAKE_CONST_QUAD(quad, pts) \
105 const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
106 {pts[2].fX, pts[2].fY}}
107#define MAKE_CONST_CUBIC(cubic, pts) \
108 const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
109 {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}}
110
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000111static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
112 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000113 MAKE_CONST_LINE(aLine, a);
114 MAKE_CONST_LINE(bLine, b);
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000115 return intersect(aLine, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000116}
117
118static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
119 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000120 MAKE_CONST_QUAD(aQuad, a);
121 MAKE_CONST_LINE(bLine, b);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000122 return intersect(aQuad, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000123}
124
caryclark@google.com32546db2012-08-31 20:55:07 +0000125static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000126 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000127 MAKE_CONST_CUBIC(aCubic, a);
128 MAKE_CONST_LINE(bLine, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000129 return intersect(aCubic, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000130}
131
132static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
133 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000134 MAKE_CONST_QUAD(aQuad, a);
135 MAKE_CONST_QUAD(bQuad, b);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000136#define TRY_QUARTIC_SOLUTION 1
137#if TRY_QUARTIC_SOLUTION
138 intersect2(aQuad, bQuad, intersections);
139#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000140 intersect(aQuad, bQuad, intersections);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000141#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000142 return intersections.fUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000143}
144
caryclark@google.com73ca6242013-01-17 21:02:47 +0000145#if APPROXIMATE_CUBICS
146static int CubicQuadIntersect(const SkPoint a[4], const SkPoint b[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000147 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000148 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000149 MAKE_CONST_QUAD(bQuad, b);
150 return intersect(aCubic, bQuad, intersections);
151}
152#endif
153
154static int CubicIntersect(const SkPoint a[4], const SkPoint b[4], Intersections& intersections) {
155 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com32546db2012-08-31 20:55:07 +0000156 MAKE_CONST_CUBIC(bCubic, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000157#if APPROXIMATE_CUBICS
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000158 intersect3(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000159#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000160 intersect(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000161#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000162 return intersections.fUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000163}
164
165static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
166 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000167 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000168 return horizontalIntersect(aLine, left, right, y, flipped, intersections);
169}
170
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000171static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
172 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000173 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000174 return horizontalIntersect(aQuad, left, right, y, flipped, intersections);
175}
176
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000177static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
178 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000179 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000180 return horizontalIntersect(aCubic, left, right, y, flipped, intersections);
181}
182
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000183static int (* const HSegmentIntersect[])(const SkPoint [], SkScalar ,
184 SkScalar , SkScalar , bool , Intersections& ) = {
185 NULL,
186 HLineIntersect,
187 HQuadIntersect,
188 HCubicIntersect
189};
190
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000191static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom,
192 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000193 MAKE_CONST_LINE(aLine, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000194 return verticalIntersect(aLine, top, bottom, x, flipped, intersections);
195}
196
197static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom,
198 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000199 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000200 return verticalIntersect(aQuad, top, bottom, x, flipped, intersections);
201}
202
203static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom,
204 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000205 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000206 return verticalIntersect(aCubic, top, bottom, x, flipped, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000207}
208
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000209static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar ,
210 SkScalar , SkScalar , bool , Intersections& ) = {
211 NULL,
212 VLineIntersect,
213 VQuadIntersect,
214 VCubicIntersect
215};
216
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000217static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000218 MAKE_CONST_LINE(line, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000219 double x, y;
220 xy_at_t(line, t, x, y);
221 out->fX = SkDoubleToScalar(x);
222 out->fY = SkDoubleToScalar(y);
223}
224
caryclark@google.comf9502d72013-02-04 14:06:49 +0000225static void LineXYAtT(const SkPoint a[2], double t, _Point* out) {
226 MAKE_CONST_LINE(line, a);
227 xy_at_t(line, t, out->x, out->y);
228}
229
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000230static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000231 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000232 double x, y;
233 xy_at_t(quad, t, x, y);
234 out->fX = SkDoubleToScalar(x);
235 out->fY = SkDoubleToScalar(y);
236}
237
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000238static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
239 MAKE_CONST_QUAD(quad, a);
240 xy_at_t(quad, t, out->x, out->y);
241}
242
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000243static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000244 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000245 double x, y;
246 xy_at_t(cubic, t, x, y);
247 out->fX = SkDoubleToScalar(x);
248 out->fY = SkDoubleToScalar(y);
249}
250
caryclark@google.comf9502d72013-02-04 14:06:49 +0000251static void CubicXYAtT(const SkPoint a[4], double t, _Point* out) {
252 MAKE_CONST_CUBIC(cubic, a);
253 xy_at_t(cubic, t, out->x, out->y);
254}
255
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000256static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
257 NULL,
258 LineXYAtT,
259 QuadXYAtT,
260 CubicXYAtT
261};
262
caryclark@google.comf9502d72013-02-04 14:06:49 +0000263static void (* const SegmentXYAtT2[])(const SkPoint [], double , _Point* ) = {
264 NULL,
265 LineXYAtT,
266 QuadXYAtT,
267 CubicXYAtT
268};
269
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000270static SkScalar LineXAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000271 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000272 double x;
273 xy_at_t(aLine, t, x, *(double*) 0);
274 return SkDoubleToScalar(x);
275}
276
277static SkScalar QuadXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000278 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000279 double x;
280 xy_at_t(quad, t, x, *(double*) 0);
281 return SkDoubleToScalar(x);
282}
283
284static SkScalar CubicXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000285 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000286 double x;
287 xy_at_t(cubic, t, x, *(double*) 0);
288 return SkDoubleToScalar(x);
289}
290
291static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
292 NULL,
293 LineXAtT,
294 QuadXAtT,
295 CubicXAtT
296};
297
298static SkScalar LineYAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000299 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000300 double y;
301 xy_at_t(aLine, t, *(double*) 0, y);
302 return SkDoubleToScalar(y);
303}
304
305static SkScalar QuadYAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000306 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000307 double y;
308 xy_at_t(quad, t, *(double*) 0, y);
309 return SkDoubleToScalar(y);
310}
311
312static SkScalar CubicYAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000313 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000314 double y;
315 xy_at_t(cubic, t, *(double*) 0, y);
316 return SkDoubleToScalar(y);
317}
318
319static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
320 NULL,
321 LineYAtT,
322 QuadYAtT,
323 CubicYAtT
324};
325
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000326static SkScalar LineDXAtT(const SkPoint a[2], double ) {
327 return a[1].fX - a[0].fX;
328}
329
330static SkScalar QuadDXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000331 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000332 double x = dx_at_t(quad, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000333 return SkDoubleToScalar(x);
334}
335
336static SkScalar CubicDXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000337 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000338 double x = dx_at_t(cubic, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000339 return SkDoubleToScalar(x);
340}
341
342static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
343 NULL,
344 LineDXAtT,
345 QuadDXAtT,
346 CubicDXAtT
347};
348
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000349static SkScalar LineDYAtT(const SkPoint a[2], double ) {
350 return a[1].fY - a[0].fY;
351}
352
353static SkScalar QuadDYAtT(const SkPoint a[3], double t) {
354 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000355 double y = dy_at_t(quad, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000356 return SkDoubleToScalar(y);
357}
358
359static SkScalar CubicDYAtT(const SkPoint a[4], double t) {
360 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000361 double y = dy_at_t(cubic, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000362 return SkDoubleToScalar(y);
363}
364
365static SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = {
366 NULL,
367 LineDYAtT,
368 QuadDYAtT,
369 CubicDYAtT
370};
371
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000372static SkPoint LineDXDYAtT(const SkPoint a[2], double ) {
373 return a[1] - a[0];
374}
375
376static SkPoint QuadDXDYAtT(const SkPoint a[3], double t) {
377 MAKE_CONST_QUAD(quad, a);
378 _Point pt;
379 dxdy_at_t(quad, t, pt);
380 return pt.asSkPoint();
381}
382
383static SkPoint CubicDXDYAtT(const SkPoint a[4], double t) {
384 MAKE_CONST_CUBIC(cubic, a);
385 _Point pt;
386 dxdy_at_t(cubic, t, pt);
387 return pt.asSkPoint();
388}
389
390static SkPoint (* const SegmentDXDYAtT[])(const SkPoint [], double ) = {
391 NULL,
392 LineDXDYAtT,
393 QuadDXDYAtT,
394 CubicDXDYAtT
395};
396
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000397static void LineSubDivide(const SkPoint a[2], double startT, double endT,
398 SkPoint sub[2]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000399 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000400 _Line dst;
401 sub_divide(aLine, startT, endT, dst);
402 sub[0].fX = SkDoubleToScalar(dst[0].x);
403 sub[0].fY = SkDoubleToScalar(dst[0].y);
404 sub[1].fX = SkDoubleToScalar(dst[1].x);
405 sub[1].fY = SkDoubleToScalar(dst[1].y);
406}
407
408static void QuadSubDivide(const SkPoint a[3], double startT, double endT,
409 SkPoint sub[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000410 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000411 Quadratic dst;
412 sub_divide(aQuad, startT, endT, dst);
413 sub[0].fX = SkDoubleToScalar(dst[0].x);
414 sub[0].fY = SkDoubleToScalar(dst[0].y);
415 sub[1].fX = SkDoubleToScalar(dst[1].x);
416 sub[1].fY = SkDoubleToScalar(dst[1].y);
417 sub[2].fX = SkDoubleToScalar(dst[2].x);
418 sub[2].fY = SkDoubleToScalar(dst[2].y);
419}
420
421static void CubicSubDivide(const SkPoint a[4], double startT, double endT,
422 SkPoint sub[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000423 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000424 Cubic dst;
425 sub_divide(aCubic, startT, endT, dst);
426 sub[0].fX = SkDoubleToScalar(dst[0].x);
427 sub[0].fY = SkDoubleToScalar(dst[0].y);
428 sub[1].fX = SkDoubleToScalar(dst[1].x);
429 sub[1].fY = SkDoubleToScalar(dst[1].y);
430 sub[2].fX = SkDoubleToScalar(dst[2].x);
431 sub[2].fY = SkDoubleToScalar(dst[2].y);
432 sub[3].fX = SkDoubleToScalar(dst[3].x);
433 sub[3].fY = SkDoubleToScalar(dst[3].y);
434}
435
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000436static void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
437 SkPoint []) = {
438 NULL,
439 LineSubDivide,
440 QuadSubDivide,
441 CubicSubDivide
442};
443
caryclark@google.comaa358312013-01-29 20:28:49 +0000444static void LineSubDivideHD(const SkPoint a[2], double startT, double endT, _Line& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000445 MAKE_CONST_LINE(aLine, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000446 sub_divide(aLine, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000447}
448
caryclark@google.comaa358312013-01-29 20:28:49 +0000449static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT, Quadratic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000450 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000451 sub_divide(aQuad, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000452}
453
caryclark@google.comaa358312013-01-29 20:28:49 +0000454static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT, Cubic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000455 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000456 sub_divide(aCubic, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000457}
458
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000459static SkPoint QuadTop(const SkPoint a[3], double startT, double endT) {
460 MAKE_CONST_QUAD(quad, a);
461 _Point topPt = top(quad, startT, endT);
462 return topPt.asSkPoint();
463}
464
465static SkPoint CubicTop(const SkPoint a[3], double startT, double endT) {
466 MAKE_CONST_CUBIC(cubic, a);
467 _Point topPt = top(cubic, startT, endT);
468 return topPt.asSkPoint();
469}
470
471static SkPoint (* SegmentTop[])(const SkPoint[], double , double ) = {
472 NULL,
473 NULL,
474 QuadTop,
475 CubicTop
476};
477
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000478#if DEBUG_UNUSED
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000479static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
480 SkRect& bounds) {
481 SkPoint dst[3];
482 QuadSubDivide(a, startT, endT, dst);
483 bounds.fLeft = bounds.fRight = dst[0].fX;
484 bounds.fTop = bounds.fBottom = dst[0].fY;
485 for (int index = 1; index < 3; ++index) {
486 bounds.growToInclude(dst[index].fX, dst[index].fY);
487 }
488}
489
490static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
491 SkRect& bounds) {
492 SkPoint dst[4];
493 CubicSubDivide(a, startT, endT, dst);
494 bounds.fLeft = bounds.fRight = dst[0].fX;
495 bounds.fTop = bounds.fBottom = dst[0].fY;
496 for (int index = 1; index < 4; ++index) {
497 bounds.growToInclude(dst[index].fX, dst[index].fY);
498 }
499}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000500#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000501
caryclark@google.com15fa1382012-05-07 20:49:36 +0000502static SkPath::Verb QuadReduceOrder(const SkPoint a[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000503 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000504 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000505 Quadratic dst;
caryclark@google.com47d73da2013-02-17 01:41:25 +0000506 int order = reduceOrder(aQuad, dst, kReduceOrder_TreatAsFill);
caryclark@google.com24bec792012-08-20 12:43:57 +0000507 if (order == 2) { // quad became line
508 for (int index = 0; index < order; ++index) {
509 SkPoint* pt = reducePts.append();
510 pt->fX = SkDoubleToScalar(dst[index].x);
511 pt->fY = SkDoubleToScalar(dst[index].y);
512 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000513 }
514 return (SkPath::Verb) (order - 1);
515}
516
517static SkPath::Verb CubicReduceOrder(const SkPoint a[4],
518 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000519 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000520 Cubic dst;
caryclark@google.com47d73da2013-02-17 01:41:25 +0000521 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed, kReduceOrder_TreatAsFill);
caryclark@google.com24bec792012-08-20 12:43:57 +0000522 if (order == 2 || order == 3) { // cubic became line or quad
523 for (int index = 0; index < order; ++index) {
524 SkPoint* pt = reducePts.append();
525 pt->fX = SkDoubleToScalar(dst[index].x);
526 pt->fY = SkDoubleToScalar(dst[index].y);
527 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000528 }
529 return (SkPath::Verb) (order - 1);
530}
531
caryclark@google.com15fa1382012-05-07 20:49:36 +0000532static bool QuadIsLinear(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000533 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000534 return isLinear(aQuad, 0, 2);
535}
536
537static bool CubicIsLinear(const SkPoint a[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000538 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000539 return isLinear(aCubic, 0, 3);
540}
541
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000542static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000543 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000544 double x[2];
545 xy_at_t(aLine, startT, x[0], *(double*) 0);
caryclark@google.com495f8e42012-05-31 13:13:11 +0000546 xy_at_t(aLine, endT, x[1], *(double*) 0);
547 return SkMinScalar((float) x[0], (float) x[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000548}
549
550static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000551 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000552 return (float) leftMostT(aQuad, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000553}
554
555static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000556 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000557 return (float) leftMostT(aCubic, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000558}
559
560static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
561 NULL,
562 LineLeftMost,
563 QuadLeftMost,
564 CubicLeftMost
565};
566
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000567#if 0 // currently unused
caryclark@google.com235f56a2012-09-14 14:19:30 +0000568static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
569 Intersections& intersections) {
570 MAKE_CONST_QUAD(aQuad, a);
571 MAKE_CONST_LINE(bLine, b);
572 return intersectRay(aQuad, bLine, intersections);
573}
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000574#endif
575
caryclark@google.comf9502d72013-02-04 14:06:49 +0000576static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000577 MAKE_CONST_QUAD(aQuad, a);
578 return intersectRay(aQuad, bLine, intersections);
579}
caryclark@google.com235f56a2012-09-14 14:19:30 +0000580
caryclark@google.comf9502d72013-02-04 14:06:49 +0000581static int CubicRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
582 MAKE_CONST_CUBIC(aCubic, a);
583 return intersectRay(aCubic, bLine, intersections);
584}
585
586static int (* const SegmentRayIntersect[])(const SkPoint [], const _Line& , Intersections&) = {
587 NULL,
588 NULL,
589 QuadRayIntersect,
590 CubicRayIntersect
591};
592
593
594
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000595static bool LineVertical(const SkPoint a[2], double startT, double endT) {
596 MAKE_CONST_LINE(aLine, a);
597 double x[2];
598 xy_at_t(aLine, startT, x[0], *(double*) 0);
599 xy_at_t(aLine, endT, x[1], *(double*) 0);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000600 return AlmostEqualUlps((float) x[0], (float) x[1]);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000601}
602
603static bool QuadVertical(const SkPoint a[3], double startT, double endT) {
604 SkPoint dst[3];
605 QuadSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000606 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000607}
608
609static bool CubicVertical(const SkPoint a[4], double startT, double endT) {
610 SkPoint dst[4];
611 CubicSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000612 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX)
613 && AlmostEqualUlps(dst[2].fX, dst[3].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000614}
615
616static bool (* const SegmentVertical[])(const SkPoint [], double , double) = {
617 NULL,
618 LineVertical,
619 QuadVertical,
620 CubicVertical
621};
622
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000623class Segment;
624
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000625struct Span {
626 Segment* fOther;
627 mutable SkPoint fPt; // lazily computed as needed
628 double fT;
629 double fOtherT; // value at fOther[fOtherIndex].fT
630 int fOtherIndex; // can't be used during intersection
caryclark@google.com31143cf2012-11-09 22:14:19 +0000631 int fWindSum; // accumulated from contours surrounding this one.
632 int fOppSum; // for binary operators: the opposite winding sum
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000633 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
caryclark@google.com57cff8d2012-11-14 21:14:56 +0000634 int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000635 bool fDone; // if set, this span to next higher T has been processed
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000636 bool fUnsortableStart; // set when start is part of an unsortable pair
637 bool fUnsortableEnd; // set when end is part of an unsortable pair
caryclark@google.comf839c032012-10-26 21:03:50 +0000638 bool fTiny; // if set, span may still be considered once for edge following
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000639};
640
caryclark@google.com15fa1382012-05-07 20:49:36 +0000641// sorting angles
642// given angles of {dx dy ddx ddy dddx dddy} sort them
643class Angle {
644public:
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000645 // FIXME: this is bogus for quads and cubics
646 // if the quads and cubics' line from end pt to ctrl pt are coincident,
647 // there's no obvious way to determine the curve ordering from the
648 // derivatives alone. In particular, if one quadratic's coincident tangent
649 // is longer than the other curve, the final control point can place the
650 // longer curve on either side of the shorter one.
651 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
652 // may provide some help, but nothing has been figured out yet.
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000653
caryclark@google.com32546db2012-08-31 20:55:07 +0000654 /*(
655 for quads and cubics, set up a parameterized line (e.g. LineParameters )
656 for points [0] to [1]. See if point [2] is on that line, or on one side
657 or the other. If it both quads' end points are on the same side, choose
658 the shorter tangent. If the tangents are equal, choose the better second
659 tangent angle
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000660
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000661 maybe I could set up LineParameters lazily
caryclark@google.com32546db2012-08-31 20:55:07 +0000662 */
caryclark@google.com15fa1382012-05-07 20:49:36 +0000663 bool operator<(const Angle& rh) const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000664 double y = dy();
665 double ry = rh.dy();
666 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
667 return y < 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000668 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000669 double x = dx();
670 double rx = rh.dx();
671 if (y == 0 && ry == 0 && x * rx < 0) {
672 return x < rx;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000673 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000674 double x_ry = x * ry;
675 double rx_y = rx * y;
676 double cmp = x_ry - rx_y;
caryclark@google.comc899ad92012-08-23 15:24:42 +0000677 if (!approximately_zero(cmp)) {
caryclark@google.com15fa1382012-05-07 20:49:36 +0000678 return cmp < 0;
679 }
caryclark@google.comd1688742012-09-18 20:08:37 +0000680 if (approximately_zero(x_ry) && approximately_zero(rx_y)
681 && !approximately_zero_squared(cmp)) {
682 return cmp < 0;
683 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000684 // at this point, the initial tangent line is coincident
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000685 // see if edges curl away from each other
caryclark@google.com31143cf2012-11-09 22:14:19 +0000686 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
687 || !approximately_zero(rh.fSide))) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000688 // FIXME: running demo will trigger this assertion
689 // (don't know if commenting out will trigger further assertion or not)
690 // commenting it out allows demo to run in release, though
691 // SkASSERT(fSide != rh.fSide);
692 return fSide < rh.fSide;
693 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000694 // see if either curve can be lengthened and try the tangent compare again
695 if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
696 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
697 Angle longer = *this;
698 Angle rhLonger = rh;
699 if (longer.lengthen() | rhLonger.lengthen()) {
700 return longer < rhLonger;
701 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000702 #if 0
caryclark@google.coma461ff02012-10-11 12:54:23 +0000703 // what if we extend in the other direction?
704 longer = *this;
705 rhLonger = rh;
706 if (longer.reverseLengthen() | rhLonger.reverseLengthen()) {
707 return longer < rhLonger;
708 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000709 #endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000710 }
caryclark@google.com185c7c42012-10-19 18:26:24 +0000711 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
caryclark@google.com31143cf2012-11-09 22:14:19 +0000712 || (rh.fVerb == SkPath::kLine_Verb
713 && approximately_zero(rx) && approximately_zero(ry))) {
caryclark@google.com185c7c42012-10-19 18:26:24 +0000714 // See general unsortable comment below. This case can happen when
715 // one line has a non-zero change in t but no change in x and y.
716 fUnsortable = true;
717 rh.fUnsortable = true;
718 return this < &rh; // even with no solution, return a stable sort
719 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000720 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
721 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
722 fUnsortable = true;
723 rh.fUnsortable = true;
724 return this < &rh; // even with no solution, return a stable sort
725 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000726 SkASSERT(fVerb >= SkPath::kQuad_Verb);
727 SkASSERT(rh.fVerb >= SkPath::kQuad_Verb);
skia.committer@gmail.comc1ad0222012-09-19 02:01:47 +0000728 // FIXME: until I can think of something better, project a ray from the
caryclark@google.comd1688742012-09-18 20:08:37 +0000729 // end of the shorter tangent to midway between the end points
730 // through both curves and use the resulting angle to sort
caryclark@google.com235f56a2012-09-14 14:19:30 +0000731 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
732 double len = fTangent1.normalSquared();
733 double rlen = rh.fTangent1.normalSquared();
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000734 _Line ray;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000735 Intersections i, ri;
caryclark@google.comd1688742012-09-18 20:08:37 +0000736 int roots, rroots;
737 bool flip = false;
738 do {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000739 bool useThis = (len < rlen) ^ flip;
740 const Cubic& part = useThis ? fCurvePart : rh.fCurvePart;
741 SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb;
742 ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ?
743 part[2] : part[1];
744 ray[1].x = (part[0].x + part[partVerb].x) / 2;
745 ray[1].y = (part[0].y + part[partVerb].y) / 2;
caryclark@google.comd1688742012-09-18 20:08:37 +0000746 SkASSERT(ray[0] != ray[1]);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000747 roots = (*SegmentRayIntersect[fVerb])(fPts, ray, i);
748 rroots = (*SegmentRayIntersect[rh.fVerb])(rh.fPts, ray, ri);
caryclark@google.comd1688742012-09-18 20:08:37 +0000749 } while ((roots == 0 || rroots == 0) && (flip ^= true));
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000750 if (roots == 0 || rroots == 0) {
751 // FIXME: we don't have a solution in this case. The interim solution
752 // is to mark the edges as unsortable, exclude them from this and
753 // future computations, and allow the returned path to be fragmented
754 fUnsortable = true;
755 rh.fUnsortable = true;
756 return this < &rh; // even with no solution, return a stable sort
757 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000758 _Point loc;
759 double best = SK_ScalarInfinity;
760 double dx, dy, dist;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000761 int index;
762 for (index = 0; index < roots; ++index) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000763 (*SegmentXYAtT2[fVerb])(fPts, i.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000764 dx = loc.x - ray[0].x;
765 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000766 dist = dx * dx + dy * dy;
767 if (best > dist) {
768 best = dist;
769 }
770 }
771 for (index = 0; index < rroots; ++index) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000772 (*SegmentXYAtT2[rh.fVerb])(rh.fPts, ri.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000773 dx = loc.x - ray[0].x;
774 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000775 dist = dx * dx + dy * dy;
776 if (best > dist) {
777 return fSide < 0;
778 }
779 }
780 return fSide > 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000781 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000782
caryclark@google.com47580692012-07-23 12:14:49 +0000783 double dx() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000784 return fTangent1.dx();
caryclark@google.com47580692012-07-23 12:14:49 +0000785 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000786
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000787 double dy() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000788 return fTangent1.dy();
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000789 }
790
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000791 int end() const {
792 return fEnd;
793 }
794
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000795 bool isHorizontal() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000796 return dy() == 0 && fVerb == SkPath::kLine_Verb;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000797 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000798
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000799 bool lengthen() {
800 int newEnd = fEnd;
801 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
802 fEnd = newEnd;
803 setSpans();
804 return true;
805 }
806 return false;
807 }
808
caryclark@google.coma461ff02012-10-11 12:54:23 +0000809 bool reverseLengthen() {
810 if (fReversed) {
811 return false;
812 }
813 int newEnd = fStart;
814 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
815 fEnd = newEnd;
816 fReversed = true;
817 setSpans();
818 return true;
819 }
820 return false;
821 }
822
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000823 void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000824 int start, int end, const SkTDArray<Span>& spans) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000825 fSegment = segment;
826 fStart = start;
827 fEnd = end;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000828 fPts = orig;
829 fVerb = verb;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000830 fSpans = &spans;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000831 fReversed = false;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000832 fUnsortable = false;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000833 setSpans();
834 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000835
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000836
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000837 void setSpans() {
838 double startT = (*fSpans)[fStart].fT;
839 double endT = (*fSpans)[fEnd].fT;
840 switch (fVerb) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000841 case SkPath::kLine_Verb:
842 _Line l;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000843 LineSubDivideHD(fPts, startT, endT, l);
caryclark@google.com32546db2012-08-31 20:55:07 +0000844 // OPTIMIZATION: for pure line compares, we never need fTangent1.c
845 fTangent1.lineEndPoints(l);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000846 fSide = 0;
caryclark@google.com32546db2012-08-31 20:55:07 +0000847 break;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000848 case SkPath::kQuad_Verb: {
849 Quadratic& quad = (Quadratic&)fCurvePart;
850 QuadSubDivideHD(fPts, startT, endT, quad);
851 fTangent1.quadEndPoints(quad, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000852 #if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
853 if (dx() == 0 && dy() == 0) {
caryclark@google.combeda3892013-02-07 13:13:41 +0000854 // SkDebugf("*** %s quad is line\n", __FUNCTION__);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000855 fTangent1.quadEndPoints(quad);
caryclark@google.comaa358312013-01-29 20:28:49 +0000856 }
857 #endif
caryclark@google.comf9502d72013-02-04 14:06:49 +0000858 fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- compare sign only
859 } break;
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000860 case SkPath::kCubic_Verb: {
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000861 int nextC = 2;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000862 CubicSubDivideHD(fPts, startT, endT, fCurvePart);
863 fTangent1.cubicEndPoints(fCurvePart, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000864 if (dx() == 0 && dy() == 0) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000865 fTangent1.cubicEndPoints(fCurvePart, 0, 2);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000866 nextC = 3;
caryclark@google.comaa358312013-01-29 20:28:49 +0000867 #if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
868 if (dx() == 0 && dy() == 0) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000869 SkDebugf("*** %s cubic is line\n", __FUNCTION__);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000870 fTangent1.cubicEndPoints(fCurvePart, 0, 3);
caryclark@google.comaa358312013-01-29 20:28:49 +0000871 }
872 #endif
873 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000874 fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign only
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000875 if (nextC == 2 && approximately_zero(fSide)) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000876 fSide = -fTangent1.pointDistance(fCurvePart[3]);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000877 }
878 } break;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000879 default:
880 SkASSERT(0);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000881 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000882 fUnsortable = dx() == 0 && dy() == 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000883 if (fUnsortable) {
884 return;
885 }
886 SkASSERT(fStart != fEnd);
887 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
888 for (int index = fStart; index != fEnd; index += step) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000889#if 1
890 const Span& thisSpan = (*fSpans)[index];
891 const Span& nextSpan = (*fSpans)[index + step];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000892 if (thisSpan.fTiny || precisely_equal(thisSpan.fT, nextSpan.fT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000893 continue;
caryclark@google.comf839c032012-10-26 21:03:50 +0000894 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000895 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
896#if DEBUG_UNSORTABLE
897 if (fUnsortable) {
898 SkPoint iPt, ePt;
899 (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt);
900 (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt);
901 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
902 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
903 }
904#endif
905 return;
906#else
907 if ((*fSpans)[index].fUnsortableStart) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000908 fUnsortable = true;
909 return;
910 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000911#endif
caryclark@google.comf839c032012-10-26 21:03:50 +0000912 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000913#if 1
914#if DEBUG_UNSORTABLE
915 SkPoint iPt, ePt;
916 (*SegmentXYAtT[fVerb])(fPts, startT, &iPt);
917 (*SegmentXYAtT[fVerb])(fPts, endT, &ePt);
918 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
919 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
920#endif
921 fUnsortable = true;
922#endif
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000923 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000924
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000925 Segment* segment() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000926 return const_cast<Segment*>(fSegment);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000927 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000928
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000929 int sign() const {
caryclark@google.com495f8e42012-05-31 13:13:11 +0000930 return SkSign32(fStart - fEnd);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000931 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000932
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000933 const SkTDArray<Span>* spans() const {
934 return fSpans;
935 }
936
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000937 int start() const {
938 return fStart;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000939 }
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +0000940
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000941 bool unsortable() const {
942 return fUnsortable;
943 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000944
caryclark@google.comc899ad92012-08-23 15:24:42 +0000945#if DEBUG_ANGLE
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000946 const SkPoint* pts() const {
947 return fPts;
948 }
949
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000950 SkPath::Verb verb() const {
951 return fVerb;
952 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000953
caryclark@google.comc899ad92012-08-23 15:24:42 +0000954 void debugShow(const SkPoint& a) const {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000955 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
caryclark@google.comc899ad92012-08-23 15:24:42 +0000956 }
957#endif
958
caryclark@google.com15fa1382012-05-07 20:49:36 +0000959private:
caryclark@google.com235f56a2012-09-14 14:19:30 +0000960 const SkPoint* fPts;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000961 Cubic fCurvePart;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000962 SkPath::Verb fVerb;
963 double fSide;
964 LineParameters fTangent1;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000965 const SkTDArray<Span>* fSpans;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000966 const Segment* fSegment;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000967 int fStart;
968 int fEnd;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000969 bool fReversed;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000970 mutable bool fUnsortable; // this alone is editable by the less than operator
caryclark@google.com15fa1382012-05-07 20:49:36 +0000971};
972
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000973// Bounds, unlike Rect, does not consider a line to be empty.
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000974struct Bounds : public SkRect {
975 static bool Intersects(const Bounds& a, const Bounds& b) {
976 return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
977 a.fTop <= b.fBottom && b.fTop <= a.fBottom;
978 }
979
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000980 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
981 if (left < fLeft) {
982 fLeft = left;
983 }
984 if (top < fTop) {
985 fTop = top;
986 }
987 if (right > fRight) {
988 fRight = right;
989 }
990 if (bottom > fBottom) {
991 fBottom = bottom;
992 }
993 }
994
995 void add(const Bounds& toAdd) {
996 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
997 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000998
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000999 void add(const SkPoint& pt) {
1000 if (pt.fX < fLeft) fLeft = pt.fX;
1001 if (pt.fY < fTop) fTop = pt.fY;
1002 if (pt.fX > fRight) fRight = pt.fX;
1003 if (pt.fY > fBottom) fBottom = pt.fY;
1004 }
1005
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001006 bool isEmpty() {
1007 return fLeft > fRight || fTop > fBottom
caryclark@google.com235f56a2012-09-14 14:19:30 +00001008 || (fLeft == fRight && fTop == fBottom)
caryclark@google.combeda3892013-02-07 13:13:41 +00001009 || sk_double_isnan(fLeft) || sk_double_isnan(fRight)
1010 || sk_double_isnan(fTop) || sk_double_isnan(fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001011 }
1012
1013 void setCubicBounds(const SkPoint a[4]) {
1014 _Rect dRect;
caryclark@google.com32546db2012-08-31 20:55:07 +00001015 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001016 dRect.setBounds(cubic);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001017 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1018 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001019 }
1020
1021 void setQuadBounds(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +00001022 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001023 _Rect dRect;
1024 dRect.setBounds(quad);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001025 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1026 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001027 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001028
1029 void setPoint(const SkPoint& pt) {
1030 fLeft = fRight = pt.fX;
1031 fTop = fBottom = pt.fY;
1032 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001033};
1034
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001035// OPTIMIZATION: does the following also work, and is it any faster?
1036// return outerWinding * innerWinding > 0
1037// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
caryclark@google.com2ddff932012-08-07 21:25:27 +00001038static bool useInnerWinding(int outerWinding, int innerWinding) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001039 // SkASSERT(outerWinding != innerWinding);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001040 int absOut = abs(outerWinding);
1041 int absIn = abs(innerWinding);
1042 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1043 if (outerWinding * innerWinding < 0) {
1044#if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00001045 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
caryclark@google.com2ddff932012-08-07 21:25:27 +00001046 outerWinding, innerWinding, result ? "true" : "false");
1047#endif
1048 }
1049 return result;
1050}
1051
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001052#define F (false) // discard the edge
1053#define T (true) // keep the edge
1054
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001055static const bool gUnaryActiveEdge[2][2] = {
1056// from=0 from=1
1057// to=0,1 to=0,1
1058 {F, T}, {T, F},
1059};
1060
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001061static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
1062// miFrom=0 miFrom=1
1063// miTo=0 miTo=1 miTo=0 miTo=1
1064// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
1065// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
1066 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
1067 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
1068 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
1069 {{{{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 +00001070};
1071
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001072#undef F
1073#undef T
caryclark@google.com235f56a2012-09-14 14:19:30 +00001074
caryclark@google.comf839c032012-10-26 21:03:50 +00001075// wrap path to keep track of whether the contour is initialized and non-empty
1076class PathWrapper {
1077public:
1078 PathWrapper(SkPath& path)
1079 : fPathPtr(&path)
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001080 , fCloses(0)
1081 , fMoves(0)
caryclark@google.comf839c032012-10-26 21:03:50 +00001082 {
1083 init();
1084 }
1085
1086 void close() {
1087 if (!fHasMove) {
1088 return;
1089 }
1090 bool callClose = isClosed();
1091 lineTo();
1092 if (fEmpty) {
1093 return;
1094 }
1095 if (callClose) {
1096 #if DEBUG_PATH_CONSTRUCTION
1097 SkDebugf("path.close();\n");
1098 #endif
1099 fPathPtr->close();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001100 fCloses++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001101 }
1102 init();
1103 }
1104
1105 void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
1106 lineTo();
1107 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001108 fDefer[1] = pt3;
1109 nudge();
1110 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001111#if DEBUG_PATH_CONSTRUCTION
1112 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001113 pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001114#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001115 fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001116 fEmpty = false;
1117 }
1118
1119 void deferredLine(const SkPoint& pt) {
1120 if (pt == fDefer[1]) {
1121 return;
1122 }
1123 if (changedSlopes(pt)) {
1124 lineTo();
1125 fDefer[0] = fDefer[1];
1126 }
1127 fDefer[1] = pt;
1128 }
1129
1130 void deferredMove(const SkPoint& pt) {
1131 fMoved = true;
1132 fHasMove = true;
1133 fEmpty = true;
1134 fDefer[0] = fDefer[1] = pt;
1135 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001136
caryclark@google.comf839c032012-10-26 21:03:50 +00001137 void deferredMoveLine(const SkPoint& pt) {
1138 if (!fHasMove) {
1139 deferredMove(pt);
1140 }
1141 deferredLine(pt);
1142 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001143
caryclark@google.comf839c032012-10-26 21:03:50 +00001144 bool hasMove() const {
1145 return fHasMove;
1146 }
1147
1148 void init() {
1149 fEmpty = true;
1150 fHasMove = false;
1151 fMoved = false;
1152 }
1153
1154 bool isClosed() const {
1155 return !fEmpty && fFirstPt == fDefer[1];
1156 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001157
caryclark@google.comf839c032012-10-26 21:03:50 +00001158 void lineTo() {
1159 if (fDefer[0] == fDefer[1]) {
1160 return;
1161 }
1162 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001163 nudge();
caryclark@google.comf839c032012-10-26 21:03:50 +00001164 fEmpty = false;
1165#if DEBUG_PATH_CONSTRUCTION
1166 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
1167#endif
1168 fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
1169 fDefer[0] = fDefer[1];
1170 }
1171
1172 const SkPath* nativePath() const {
1173 return fPathPtr;
1174 }
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +00001175
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001176 void nudge() {
1177 if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX)
1178 || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) {
1179 return;
1180 }
1181 fDefer[1] = fFirstPt;
1182 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001183
1184 void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
1185 lineTo();
1186 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001187 fDefer[1] = pt2;
1188 nudge();
1189 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001190#if DEBUG_PATH_CONSTRUCTION
1191 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001192 pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001193#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001194 fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001195 fEmpty = false;
1196 }
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00001197
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001198 bool someAssemblyRequired() const {
1199 return fCloses < fMoves;
1200 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001201
1202protected:
1203 bool changedSlopes(const SkPoint& pt) const {
1204 if (fDefer[0] == fDefer[1]) {
1205 return false;
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001206 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001207 SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
1208 SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
1209 SkScalar lineDx = pt.fX - fDefer[1].fX;
1210 SkScalar lineDy = pt.fY - fDefer[1].fY;
1211 return deferDx * lineDy != deferDy * lineDx;
1212 }
1213
1214 void moveTo() {
1215 if (!fMoved) {
1216 return;
1217 }
1218 fFirstPt = fDefer[0];
1219#if DEBUG_PATH_CONSTRUCTION
1220 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
1221#endif
1222 fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
1223 fMoved = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001224 fMoves++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001225 }
1226
1227private:
1228 SkPath* fPathPtr;
1229 SkPoint fDefer[2];
1230 SkPoint fFirstPt;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001231 int fCloses;
1232 int fMoves;
caryclark@google.comf839c032012-10-26 21:03:50 +00001233 bool fEmpty;
1234 bool fHasMove;
1235 bool fMoved;
1236};
1237
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001238class Segment {
1239public:
1240 Segment() {
1241#if DEBUG_DUMP
1242 fID = ++gSegmentID;
1243#endif
1244 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00001245
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001246 bool operator<(const Segment& rh) const {
1247 return fBounds.fTop < rh.fBounds.fTop;
1248 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001249
caryclark@google.com4eeda372012-12-06 21:47:48 +00001250 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001251 if (activeAngleInner(index, done, angles)) {
1252 return true;
1253 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001254 int lesser = index;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001255 while (--lesser >= 0 && equalPoints(index, lesser)) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001256 if (activeAngleOther(lesser, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001257 return true;
1258 }
1259 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001260 lesser = index;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001261 do {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001262 if (activeAngleOther(index, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001263 return true;
1264 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001265 } while (++index < fTs.count() && equalPoints(index, lesser));
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001266 return false;
1267 }
1268
caryclark@google.com4eeda372012-12-06 21:47:48 +00001269 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001270 Span* span = &fTs[index];
1271 Segment* other = span->fOther;
1272 int oIndex = span->fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001273 return other->activeAngleInner(oIndex, done, angles);
1274 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001275
caryclark@google.com4eeda372012-12-06 21:47:48 +00001276 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001277 int next = nextExactSpan(index, 1);
caryclark@google.com9764cc62012-07-12 19:29:45 +00001278 if (next > 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001279 Span& upSpan = fTs[index];
1280 if (upSpan.fWindValue || upSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001281 addAngle(angles, index, next);
caryclark@google.comf839c032012-10-26 21:03:50 +00001282 if (upSpan.fDone || upSpan.fUnsortableEnd) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001283 done++;
1284 } else if (upSpan.fWindSum != SK_MinS32) {
1285 return true;
1286 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001287 } else if (!upSpan.fDone) {
1288 upSpan.fDone = true;
1289 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001290 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001291 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001292 int prev = nextExactSpan(index, -1);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001293 // edge leading into junction
caryclark@google.com9764cc62012-07-12 19:29:45 +00001294 if (prev >= 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001295 Span& downSpan = fTs[prev];
1296 if (downSpan.fWindValue || downSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001297 addAngle(angles, index, prev);
1298 if (downSpan.fDone) {
1299 done++;
1300 } else if (downSpan.fWindSum != SK_MinS32) {
1301 return true;
1302 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001303 } else if (!downSpan.fDone) {
1304 downSpan.fDone = true;
1305 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001306 }
1307 }
1308 return false;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001309 }
1310
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001311 SkPoint activeLeftTop(bool onlySortable, int* firstT) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001312 SkASSERT(!done());
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001313 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001314 int count = fTs.count();
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001315 // see if either end is not done since we want smaller Y of the pair
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001316 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00001317 bool lastUnsortable = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001318 double lastT = -1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001319 for (int index = 0; index < count; ++index) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001320 const Span& span = fTs[index];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001321 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001322 goto next;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001323 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001324 if (span.fDone && lastDone) {
1325 goto next;
1326 }
1327 if (approximately_negative(span.fT - lastT)) {
1328 goto next;
1329 }
1330 {
1331 const SkPoint& xy = xyAtT(&span);
1332 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
1333 topPt = xy;
1334 if (firstT) {
1335 *firstT = index;
1336 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001337 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001338 if (fVerb != SkPath::kLine_Verb && !lastDone) {
1339 SkPoint curveTop = (*SegmentTop[fVerb])(fPts, lastT, span.fT);
1340 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
1341 && topPt.fX > curveTop.fX)) {
1342 topPt = curveTop;
1343 if (firstT) {
1344 *firstT = index;
1345 }
1346 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001347 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001348 lastT = span.fT;
caryclark@google.comf839c032012-10-26 21:03:50 +00001349 }
1350 next:
1351 lastDone = span.fDone;
1352 lastUnsortable = span.fUnsortableEnd;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001353 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001354 return topPt;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001355 }
1356
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001357 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
1358 int sumMiWinding = updateWinding(endIndex, index);
1359 int sumSuWinding = updateOppWinding(endIndex, index);
1360 if (fOperand) {
1361 SkTSwap<int>(sumMiWinding, sumSuWinding);
1362 }
1363 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1364 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001365 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001366 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001367
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001368 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00001369 int& sumMiWinding, int& sumSuWinding,
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001370 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
1371 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1372 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001373 bool miFrom;
1374 bool miTo;
1375 bool suFrom;
1376 bool suTo;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001377 if (operand()) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001378 miFrom = (oppMaxWinding & xorMiMask) != 0;
1379 miTo = (oppSumWinding & xorMiMask) != 0;
1380 suFrom = (maxWinding & xorSuMask) != 0;
1381 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001382 } else {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001383 miFrom = (maxWinding & xorMiMask) != 0;
1384 miTo = (sumWinding & xorMiMask) != 0;
1385 suFrom = (oppMaxWinding & xorSuMask) != 0;
1386 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001387 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001388 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
caryclark@google.combeda3892013-02-07 13:13:41 +00001389#if DEBUG_ACTIVE_OP
1390 SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__,
1391 kShapeOpStr[op], miFrom, miTo, suFrom, suTo, result);
1392#endif
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001393 SkASSERT(result != -1);
1394 return result;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001395 }
1396
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001397 bool activeWinding(int index, int endIndex) {
1398 int sumWinding = updateWinding(endIndex, index);
1399 int maxWinding;
1400 return activeWinding(index, endIndex, maxWinding, sumWinding);
1401 }
1402
1403 bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
1404 setUpWinding(index, endIndex, maxWinding, sumWinding);
1405 bool from = maxWinding != 0;
1406 bool to = sumWinding != 0;
1407 bool result = gUnaryActiveEdge[from][to];
1408 SkASSERT(result != -1);
1409 return result;
1410 }
1411
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001412 void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001413 SkASSERT(start != end);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001414 Angle* angle = angles.append();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001415#if DEBUG_ANGLE
caryclark@google.com31143cf2012-11-09 22:14:19 +00001416 if (angles.count() > 1 && !fTs[start].fTiny) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001417 SkPoint angle0Pt, newPt;
1418 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
1419 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
1420 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
caryclark@google.com6d0032a2013-01-04 19:41:13 +00001421 SkASSERT(AlmostEqualUlps(angle0Pt.fX, newPt.fX));
1422 SkASSERT(AlmostEqualUlps(angle0Pt.fY, newPt.fY));
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001423 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001424#endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001425 angle->set(fPts, fVerb, this, start, end, fTs);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001426 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001427
caryclark@google.com2ddff932012-08-07 21:25:27 +00001428 void addCancelOutsides(double tStart, double oStart, Segment& other,
caryclark@google.comcc905052012-07-25 20:59:42 +00001429 double oEnd) {
1430 int tIndex = -1;
1431 int tCount = fTs.count();
1432 int oIndex = -1;
1433 int oCount = other.fTs.count();
caryclark@google.comcc905052012-07-25 20:59:42 +00001434 do {
1435 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001436 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001437 int tIndexStart = tIndex;
1438 do {
1439 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001440 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001441 int oIndexStart = oIndex;
1442 double nextT;
1443 do {
1444 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001445 } while (nextT < 1 && approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001446 double oNextT;
1447 do {
1448 oNextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001449 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001450 // at this point, spans before and after are at:
1451 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1452 // if tIndexStart == 0, no prior span
1453 // if nextT == 1, no following span
rmistry@google.comd6176b02012-08-23 18:14:13 +00001454
caryclark@google.comcc905052012-07-25 20:59:42 +00001455 // advance the span with zero winding
1456 // if the following span exists (not past the end, non-zero winding)
1457 // connect the two edges
1458 if (!fTs[tIndexStart].fWindValue) {
1459 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1460 #if DEBUG_CONCIDENT
1461 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1462 __FUNCTION__, fID, other.fID, tIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001463 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
1464 xyAtT(tIndexStart).fY);
caryclark@google.comcc905052012-07-25 20:59:42 +00001465 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001466 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false,
1467 fTs[tIndexStart].fPt);
caryclark@google.comcc905052012-07-25 20:59:42 +00001468 }
1469 if (nextT < 1 && fTs[tIndex].fWindValue) {
1470 #if DEBUG_CONCIDENT
1471 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1472 __FUNCTION__, fID, other.fID, tIndex,
1473 fTs[tIndex].fT, xyAtT(tIndex).fX,
1474 xyAtT(tIndex).fY);
1475 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001476 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false, fTs[tIndex].fPt);
caryclark@google.comcc905052012-07-25 20:59:42 +00001477 }
1478 } else {
1479 SkASSERT(!other.fTs[oIndexStart].fWindValue);
1480 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1481 #if DEBUG_CONCIDENT
1482 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1483 __FUNCTION__, fID, other.fID, oIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001484 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
1485 other.xyAtT(oIndexStart).fY);
1486 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
caryclark@google.comcc905052012-07-25 20:59:42 +00001487 #endif
caryclark@google.comcc905052012-07-25 20:59:42 +00001488 }
1489 if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1490 #if DEBUG_CONCIDENT
1491 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1492 __FUNCTION__, fID, other.fID, oIndex,
1493 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1494 other.xyAtT(oIndex).fY);
1495 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1496 #endif
1497 }
1498 }
1499 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001500
caryclark@google.comcc905052012-07-25 20:59:42 +00001501 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1502 double oEnd) {
1503 // walk this to outsideTs[0]
1504 // walk other to outsideTs[1]
1505 // if either is > 0, add a pointer to the other, copying adjacent winding
1506 int tIndex = -1;
1507 int oIndex = -1;
1508 double tStart = outsideTs[0];
1509 double oStart = outsideTs[1];
1510 do {
1511 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001512 } while (!approximately_negative(tStart - fTs[tIndex].fT));
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001513 SkPoint ptStart = fTs[tIndex].fPt;
caryclark@google.comcc905052012-07-25 20:59:42 +00001514 do {
1515 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001516 } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001517 if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001518 addTPair(tStart, other, oStart, false, ptStart);
caryclark@google.comcc905052012-07-25 20:59:42 +00001519 }
1520 tStart = fTs[tIndex].fT;
1521 oStart = other.fTs[oIndex].fT;
1522 do {
1523 double nextT;
1524 do {
1525 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001526 } while (approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001527 tStart = nextT;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001528 ptStart = fTs[tIndex].fPt;
caryclark@google.comcc905052012-07-25 20:59:42 +00001529 do {
1530 nextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001531 } while (approximately_negative(nextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001532 oStart = nextT;
caryclark@google.com4eeda372012-12-06 21:47:48 +00001533 if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001534 break;
1535 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001536 addTPair(tStart, other, oStart, false, ptStart);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001537 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001538 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001539
caryclark@google.com4eeda372012-12-06 21:47:48 +00001540 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
1541 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001542 fBounds.setCubicBounds(pts);
1543 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001544
caryclark@google.comf839c032012-10-26 21:03:50 +00001545 /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001546 SkPoint edge[4];
caryclark@google.comf839c032012-10-26 21:03:50 +00001547 const SkPoint* ePtr;
1548 int lastT = fTs.count() - 1;
1549 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1550 ePtr = fPts;
1551 } else {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001552 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
caryclark@google.comf839c032012-10-26 21:03:50 +00001553 (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
1554 ePtr = edge;
1555 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001556 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001557 bool reverse = ePtr == fPts && start != 0;
1558 if (reverse) {
1559 path.deferredMoveLine(ePtr[fVerb]);
1560 switch (fVerb) {
1561 case SkPath::kLine_Verb:
1562 path.deferredLine(ePtr[0]);
1563 break;
1564 case SkPath::kQuad_Verb:
1565 path.quadTo(ePtr[1], ePtr[0]);
1566 break;
1567 case SkPath::kCubic_Verb:
1568 path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1569 break;
1570 default:
1571 SkASSERT(0);
1572 }
1573 // return ePtr[0];
1574 } else {
1575 path.deferredMoveLine(ePtr[0]);
1576 switch (fVerb) {
1577 case SkPath::kLine_Verb:
1578 path.deferredLine(ePtr[1]);
1579 break;
1580 case SkPath::kQuad_Verb:
1581 path.quadTo(ePtr[1], ePtr[2]);
1582 break;
1583 case SkPath::kCubic_Verb:
1584 path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1585 break;
1586 default:
1587 SkASSERT(0);
1588 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001589 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001590 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001591 // return ePtr[fVerb];
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001592 }
1593
caryclark@google.com4eeda372012-12-06 21:47:48 +00001594 void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
1595 init(pts, SkPath::kLine_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001596 fBounds.set(pts, 2);
1597 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001598
caryclark@google.comf839c032012-10-26 21:03:50 +00001599#if 0
1600 const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001601 const SkPoint& pt = xyAtT(tIndex);
1602 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001603 path.deferredMove(pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001604 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00001605 return pt;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001606 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001607#endif
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001608
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001609 // add 2 to edge or out of range values to get T extremes
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001610 void addOtherT(int index, double otherT, int otherIndex) {
1611 Span& span = fTs[index];
caryclark@google.comf839c032012-10-26 21:03:50 +00001612 #if PIN_ADD_T
caryclark@google.com185c7c42012-10-19 18:26:24 +00001613 if (precisely_less_than_zero(otherT)) {
1614 otherT = 0;
1615 } else if (precisely_greater_than_one(otherT)) {
1616 otherT = 1;
1617 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001618 #endif
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001619 span.fOtherT = otherT;
1620 span.fOtherIndex = otherIndex;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001621 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001622
caryclark@google.com4eeda372012-12-06 21:47:48 +00001623 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
1624 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001625 fBounds.setQuadBounds(pts);
1626 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001627
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001628 // Defer all coincident edge processing until
1629 // after normal intersections have been computed
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001630
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001631// no need to be tricky; insert in normal T order
1632// resolve overlapping ts when considering coincidence later
1633
1634 // add non-coincident intersection. Resulting edges are sorted in T.
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001635 int addT(double newT, Segment* other, const SkPoint& pt) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001636 // FIXME: in the pathological case where there is a ton of intercepts,
1637 // binary search?
1638 int insertedAt = -1;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001639 size_t tCount = fTs.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00001640 #if PIN_ADD_T
caryclark@google.comc899ad92012-08-23 15:24:42 +00001641 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
caryclark@google.com185c7c42012-10-19 18:26:24 +00001642 if (precisely_less_than_zero(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001643 newT = 0;
caryclark@google.com185c7c42012-10-19 18:26:24 +00001644 } else if (precisely_greater_than_one(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001645 newT = 1;
1646 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001647 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001648 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001649 // OPTIMIZATION: if there are three or more identical Ts, then
1650 // the fourth and following could be further insertion-sorted so
1651 // that all the edges are clockwise or counterclockwise.
1652 // This could later limit segment tests to the two adjacent
1653 // neighbors, although it doesn't help with determining which
1654 // circular direction to go in.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001655 if (newT < fTs[index].fT) {
1656 insertedAt = index;
1657 break;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001658 }
1659 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001660 Span* span;
1661 if (insertedAt >= 0) {
1662 span = fTs.insert(insertedAt);
1663 } else {
1664 insertedAt = tCount;
1665 span = fTs.append();
1666 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001667 span->fT = newT;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001668 span->fOther = other;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001669 span->fPt = pt;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001670 span->fWindSum = SK_MinS32;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001671 span->fOppSum = SK_MinS32;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001672 span->fWindValue = 1;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001673 span->fOppValue = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00001674 span->fTiny = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001675 if ((span->fDone = newT == 1)) {
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00001676 ++fDoneSpans;
rmistry@google.comd6176b02012-08-23 18:14:13 +00001677 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001678 span->fUnsortableStart = false;
1679 span->fUnsortableEnd = false;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001680 int less = -1;
1681 while (&span[less + 1] - fTs.begin() > 0 && !span[less].fDone
1682 && !precisely_negative(newT - span[less].fT)
1683 // && approximately_negative(newT - span[less].fT)
1684 && xyAtT(&span[less]) == xyAtT(span)) {
1685 span[less].fTiny = true;
1686 span[less].fDone = true;
1687 if (approximately_negative(newT - span[less].fT)) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00001688 if (approximately_greater_than_one(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001689 span[less].fUnsortableStart = true;
1690 span[less - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001691 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001692 if (approximately_less_than_zero(span[less].fT)) {
1693 span[less + 1].fUnsortableStart = true;
1694 span[less].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001695 }
1696 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001697 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001698 --less;
caryclark@google.comf839c032012-10-26 21:03:50 +00001699 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001700 int more = 1;
1701 while (fTs.end() - &span[more - 1] > 1 && !span[more - 1].fDone
1702 && !precisely_negative(span[more].fT - newT)
1703 // && approximately_negative(span[more].fT - newT)
1704 && xyAtT(&span[more]) == xyAtT(span)) {
1705 span[more - 1].fTiny = true;
1706 span[more - 1].fDone = true;
1707 if (approximately_negative(span[more].fT - newT)) {
1708 if (approximately_greater_than_one(span[more].fT)) {
1709 span[more + 1].fUnsortableStart = true;
1710 span[more].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001711 }
1712 if (approximately_less_than_zero(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001713 span[more].fUnsortableStart = true;
1714 span[more - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001715 }
1716 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001717 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001718 ++more;
caryclark@google.comf839c032012-10-26 21:03:50 +00001719 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001720 return insertedAt;
1721 }
1722
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001723 // set spans from start to end to decrement by one
1724 // note this walks other backwards
1725 // FIMXE: there's probably an edge case that can be constructed where
1726 // two span in one segment are separated by float epsilon on one span but
1727 // not the other, if one segment is very small. For this
1728 // case the counts asserted below may or may not be enough to separate the
caryclark@google.com2ddff932012-08-07 21:25:27 +00001729 // spans. Even if the counts work out, what if the spans aren't correctly
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001730 // sorted? It feels better in such a case to match the span's other span
1731 // pointer since both coincident segments must contain the same spans.
1732 void addTCancel(double startT, double endT, Segment& other,
1733 double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001734 SkASSERT(!approximately_negative(endT - startT));
1735 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00001736 bool binary = fOperand != other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001737 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001738 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001739 ++index;
1740 }
caryclark@google.comb9738012012-07-03 19:53:30 +00001741 int oIndex = other.fTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001742 while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001743 ;
caryclark@google.com59823f72012-08-09 18:17:47 +00001744 double tRatio = (oEndT - oStartT) / (endT - startT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001745 Span* test = &fTs[index];
1746 Span* oTest = &other.fTs[oIndex];
caryclark@google.com18063442012-07-25 12:05:18 +00001747 SkTDArray<double> outsideTs;
1748 SkTDArray<double> oOutsideTs;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001749 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001750 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
caryclark@google.comcc905052012-07-25 20:59:42 +00001751 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.com200c2112012-08-03 15:05:04 +00001752 double testT = test->fT;
1753 double oTestT = oTest->fT;
1754 Span* span = test;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001755 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001756 if (decrement) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001757 decrementSpan(span);
caryclark@google.com200c2112012-08-03 15:05:04 +00001758 } else if (track && span->fT < 1 && oTestT < 1) {
1759 TrackOutside(outsideTs, span->fT, oTestT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001760 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001761 span = &fTs[++index];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001762 } while (approximately_negative(span->fT - testT));
caryclark@google.com200c2112012-08-03 15:05:04 +00001763 Span* oSpan = oTest;
caryclark@google.com59823f72012-08-09 18:17:47 +00001764 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1765 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1766 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001767 while (approximately_negative(otherTMatchStart - oSpan->fT)
1768 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
caryclark@google.com03f97062012-08-21 13:13:52 +00001769 #ifdef SK_DEBUG
caryclark@google.com59823f72012-08-09 18:17:47 +00001770 SkASSERT(originalWindValue == oSpan->fWindValue);
caryclark@google.com03f97062012-08-21 13:13:52 +00001771 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001772 if (decrement) {
caryclark@google.com200c2112012-08-03 15:05:04 +00001773 other.decrementSpan(oSpan);
1774 } else if (track && oSpan->fT < 1 && testT < 1) {
1775 TrackOutside(oOutsideTs, oSpan->fT, testT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001776 }
1777 if (!oIndex) {
1778 break;
1779 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001780 oSpan = &other.fTs[--oIndex];
rmistry@google.comd6176b02012-08-23 18:14:13 +00001781 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001782 test = span;
1783 oTest = oSpan;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001784 } while (!approximately_negative(endT - test->fT));
1785 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
caryclark@google.com18063442012-07-25 12:05:18 +00001786 // FIXME: determine if canceled edges need outside ts added
caryclark@google.comcc905052012-07-25 20:59:42 +00001787 if (!done() && outsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001788 double tStart = outsideTs[0];
1789 double oStart = outsideTs[1];
1790 addCancelOutsides(tStart, oStart, other, oEndT);
1791 int count = outsideTs.count();
1792 if (count > 2) {
1793 double tStart = outsideTs[count - 2];
1794 double oStart = outsideTs[count - 1];
1795 addCancelOutsides(tStart, oStart, other, oEndT);
1796 }
caryclark@google.com18063442012-07-25 12:05:18 +00001797 }
caryclark@google.comcc905052012-07-25 20:59:42 +00001798 if (!other.done() && oOutsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001799 double tStart = oOutsideTs[0];
1800 double oStart = oOutsideTs[1];
1801 other.addCancelOutsides(tStart, oStart, *this, endT);
caryclark@google.com18063442012-07-25 12:05:18 +00001802 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001803 }
skia.committer@gmail.com15dd3002013-01-18 07:07:28 +00001804
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001805 int addUnsortableT(double newT, Segment* other, bool start, const SkPoint& pt) {
1806 int result = addT(newT, other, pt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00001807 Span* span = &fTs[result];
1808 if (start) {
1809 if (result > 0) {
1810 span[result - 1].fUnsortableEnd = true;
1811 }
1812 span[result].fUnsortableStart = true;
1813 } else {
1814 span[result].fUnsortableEnd = true;
1815 if (result + 1 < fTs.count()) {
1816 span[result + 1].fUnsortableStart = true;
1817 }
1818 }
1819 return result;
1820 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00001821
caryclark@google.com4eeda372012-12-06 21:47:48 +00001822 int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1823 SkTDArray<double>& outsideTs) {
1824 int oWindValue = oTest->fWindValue;
1825 int oOppValue = oTest->fOppValue;
1826 if (opp) {
1827 SkTSwap<int>(oWindValue, oOppValue);
1828 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001829 Span* const test = &fTs[index];
1830 Span* end = test;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001831 const double oStartT = oTest->fT;
1832 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001833 if (bumpSpan(end, oWindValue, oOppValue)) {
1834 TrackOutside(outsideTs, end->fT, oStartT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001835 }
1836 end = &fTs[++index];
1837 } while (approximately_negative(end->fT - test->fT));
1838 return index;
1839 }
1840
1841 // because of the order in which coincidences are resolved, this and other
1842 // may not have the same intermediate points. Compute the corresponding
1843 // intermediate T values (using this as the master, other as the follower)
1844 // and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com4eeda372012-12-06 21:47:48 +00001845 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1846 SkTDArray<double>& oOutsideTs) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001847 Span* const oTest = &fTs[oIndex];
1848 Span* oEnd = oTest;
1849 const double startT = test->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001850 const double oStartT = oTest->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001851 while (!approximately_negative(oEndT - oEnd->fT)
caryclark@google.com4eeda372012-12-06 21:47:48 +00001852 && approximately_negative(oEnd->fT - oStartT)) {
1853 zeroSpan(oEnd);
1854 TrackOutside(oOutsideTs, oEnd->fT, startT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001855 oEnd = &fTs[++oIndex];
1856 }
1857 return oIndex;
1858 }
1859
1860 // FIXME: need to test this case:
1861 // contourA has two segments that are coincident
1862 // contourB has two segments that are coincident in the same place
1863 // each ends up with +2/0 pairs for winding count
1864 // since logic below doesn't transfer count (only increments/decrements) can this be
1865 // resolved to +4/0 ?
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001866
1867 // set spans from start to end to increment the greater by one and decrement
1868 // the lesser
caryclark@google.com4eeda372012-12-06 21:47:48 +00001869 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001870 SkASSERT(!approximately_negative(endT - startT));
1871 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001872 bool opp = fOperand ^ other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001873 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001874 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001875 ++index;
1876 }
1877 int oIndex = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001878 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001879 ++oIndex;
1880 }
1881 Span* test = &fTs[index];
1882 Span* oTest = &other.fTs[oIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001883 SkTDArray<double> outsideTs;
1884 SkTDArray<double> oOutsideTs;
1885 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001886 // if either span has an opposite value and the operands don't match, resolve first
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001887 // SkASSERT(!test->fDone || !oTest->fDone);
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001888 if (test->fDone || oTest->fDone) {
1889 index = advanceCoincidentThis(oTest, opp, index);
1890 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
1891 } else {
1892 index = bumpCoincidentThis(oTest, opp, index, outsideTs);
1893 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
1894 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001895 test = &fTs[index];
1896 oTest = &other.fTs[oIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001897 } while (!approximately_negative(endT - test->fT));
1898 SkASSERT(approximately_negative(oTest->fT - oEndT));
1899 SkASSERT(approximately_negative(oEndT - oTest->fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001900 if (!done() && outsideTs.count()) {
1901 addCoinOutsides(outsideTs, other, oEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001902 }
1903 if (!other.done() && oOutsideTs.count()) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001904 other.addCoinOutsides(oOutsideTs, *this, endT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001905 }
1906 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001907
caryclark@google.comcc905052012-07-25 20:59:42 +00001908 // FIXME: this doesn't prevent the same span from being added twice
caryclark@google.comaa358312013-01-29 20:28:49 +00001909 // fix in caller, SkASSERT here?
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001910 void addTPair(double t, Segment& other, double otherT, bool borrowWind, const SkPoint& pt) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001911 int tCount = fTs.count();
1912 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1913 const Span& span = fTs[tIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001914 if (!approximately_negative(span.fT - t)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001915 break;
1916 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001917 if (approximately_negative(span.fT - t) && span.fOther == &other
1918 && approximately_equal(span.fOtherT, otherT)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001919#if DEBUG_ADD_T_PAIR
1920 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1921 __FUNCTION__, fID, t, other.fID, otherT);
1922#endif
1923 return;
1924 }
1925 }
caryclark@google.com47580692012-07-23 12:14:49 +00001926#if DEBUG_ADD_T_PAIR
1927 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1928 __FUNCTION__, fID, t, other.fID, otherT);
1929#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001930 int insertedAt = addT(t, &other, pt);
1931 int otherInsertedAt = other.addT(otherT, this, pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001932 addOtherT(insertedAt, otherT, otherInsertedAt);
caryclark@google.comb9738012012-07-03 19:53:30 +00001933 other.addOtherT(otherInsertedAt, t, insertedAt);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001934 matchWindingValue(insertedAt, t, borrowWind);
1935 other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001936 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001937
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001938 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001939 // add edge leading into junction
caryclark@google.com4eeda372012-12-06 21:47:48 +00001940 int min = SkMin32(end, start);
1941 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001942 addAngle(angles, end, start);
1943 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001944 // add edge leading away from junction
caryclark@google.com495f8e42012-05-31 13:13:11 +00001945 int step = SkSign32(end - start);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001946 int tIndex = nextExactSpan(end, step);
caryclark@google.com4eeda372012-12-06 21:47:48 +00001947 min = SkMin32(end, tIndex);
1948 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001949 addAngle(angles, end, tIndex);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001950 }
1951 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001952
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001953 int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
1954 Span* const test = &fTs[index];
1955 Span* end = test;
1956 do {
1957 end = &fTs[++index];
1958 } while (approximately_negative(end->fT - test->fT));
1959 return index;
1960 }
1961
1962 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
1963 Span* const oTest = &fTs[oIndex];
1964 Span* oEnd = oTest;
1965 const double oStartT = oTest->fT;
1966 while (!approximately_negative(oEndT - oEnd->fT)
1967 && approximately_negative(oEnd->fT - oStartT)) {
1968 oEnd = &fTs[++oIndex];
1969 }
1970 return oIndex;
1971 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00001972
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001973 bool betweenTs(int lesser, double testT, int greater) {
1974 if (lesser > greater) {
1975 SkTSwap<int>(lesser, greater);
1976 }
1977 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
1978 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001979
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001980 const Bounds& bounds() const {
1981 return fBounds;
1982 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001983
caryclark@google.com31143cf2012-11-09 22:14:19 +00001984 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001985 double referenceT = fTs[index].fT;
1986 int lesser = index;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001987 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
1988 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00001989 buildAnglesInner(lesser, angles);
1990 }
1991 do {
1992 buildAnglesInner(index, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001993 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
1994 && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001995 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001996
1997 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
1998 Span* span = &fTs[index];
1999 Segment* other = span->fOther;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002000 // if there is only one live crossing, and no coincidence, continue
2001 // in the same direction
2002 // if there is coincidence, the only choice may be to reverse direction
2003 // find edge on either side of intersection
2004 int oIndex = span->fOtherIndex;
2005 // if done == -1, prior span has already been processed
2006 int step = 1;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002007 int next = other->nextExactSpan(oIndex, step);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002008 if (next < 0) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002009 step = -step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002010 next = other->nextExactSpan(oIndex, step);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002011 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002012 // add candidate into and away from junction
2013 other->addTwoAngles(next, oIndex, angles);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002014 }
2015
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002016 int computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002017 SkTDArray<Angle> angles;
2018 addTwoAngles(startIndex, endIndex, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002019 buildAngles(endIndex, angles, false);
caryclark@google.comd1688742012-09-18 20:08:37 +00002020 // OPTIMIZATION: check all angles to see if any have computed wind sum
2021 // before sorting (early exit if none)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002022 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002023 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002024#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002025 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002026#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002027 if (!sortable) {
2028 return SK_MinS32;
2029 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002030 int angleCount = angles.count();
2031 const Angle* angle;
2032 const Segment* base;
2033 int winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002034 int oWinding;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002035 int firstIndex = 0;
2036 do {
2037 angle = sorted[firstIndex];
2038 base = angle->segment();
2039 winding = base->windSum(angle);
2040 if (winding != SK_MinS32) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002041 oWinding = base->oppSum(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002042 break;
2043 }
2044 if (++firstIndex == angleCount) {
2045 return SK_MinS32;
2046 }
2047 } while (true);
2048 // turn winding into contourWinding
caryclark@google.com2ddff932012-08-07 21:25:27 +00002049 int spanWinding = base->spanSign(angle);
2050 bool inner = useInnerWinding(winding + spanWinding, winding);
2051 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00002052 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
caryclark@google.com59823f72012-08-09 18:17:47 +00002053 spanWinding, winding, angle->sign(), inner,
caryclark@google.com2ddff932012-08-07 21:25:27 +00002054 inner ? winding + spanWinding : winding);
2055 #endif
2056 if (inner) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002057 winding += spanWinding;
2058 }
2059 #if DEBUG_SORT
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002060 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002061 #endif
2062 int nextIndex = firstIndex + 1;
2063 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com2ddff932012-08-07 21:25:27 +00002064 winding -= base->spanSign(angle);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002065 oWinding -= base->oppSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002066 do {
2067 if (nextIndex == angleCount) {
2068 nextIndex = 0;
2069 }
2070 angle = sorted[nextIndex];
2071 Segment* segment = angle->segment();
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002072 bool opp = base->fOperand ^ segment->fOperand;
2073 int maxWinding, oMaxWinding;
2074 int spanSign = segment->spanSign(angle);
2075 int oppoSign = segment->oppSign(angle);
2076 if (opp) {
2077 oMaxWinding = oWinding;
2078 oWinding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002079 maxWinding = winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002080 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002081 winding -= oppoSign;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002082 }
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002083 } else {
2084 maxWinding = winding;
2085 winding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002086 oMaxWinding = oWinding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002087 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002088 oWinding -= oppoSign;
2089 }
2090 }
2091 if (segment->windSum(angle) == SK_MinS32) {
2092 if (opp) {
2093 if (useInnerWinding(oMaxWinding, oWinding)) {
2094 oMaxWinding = oWinding;
2095 }
2096 if (oppoSign && useInnerWinding(maxWinding, winding)) {
2097 maxWinding = winding;
2098 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002099 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002100 } else {
2101 if (useInnerWinding(maxWinding, winding)) {
2102 maxWinding = winding;
2103 }
2104 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
2105 oMaxWinding = oWinding;
2106 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002107 (void) segment->markAndChaseWinding(angle, maxWinding,
2108 binary ? oMaxWinding : 0);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002109 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002110 }
2111 } while (++nextIndex != lastIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002112 int minIndex = SkMin32(startIndex, endIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002113 return windSum(minIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002114 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002115
caryclark@google.com3586ece2012-12-27 18:46:58 +00002116 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
caryclark@google.com10227bf2012-12-28 22:10:41 +00002117 double mid, bool opp, bool current) const {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002118 SkScalar bottom = fBounds.fBottom;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002119 int bestTIndex = -1;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002120 if (bottom <= bestY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002121 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002122 }
2123 SkScalar top = fBounds.fTop;
2124 if (top >= basePt.fY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002125 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002126 }
2127 if (fBounds.fLeft > basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002128 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002129 }
2130 if (fBounds.fRight < basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002131 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002132 }
2133 if (fBounds.fLeft == fBounds.fRight) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002134 // if vertical, and directly above test point, wait for another one
caryclark@google.com6d0032a2013-01-04 19:41:13 +00002135 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002136 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002137 // intersect ray starting at basePt with edge
2138 Intersections intersections;
2139 // OPTIMIZE: use specialty function that intersects ray with curve,
2140 // returning t values only for curve (we don't care about t on ray)
2141 int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
2142 if (pts == 0 || (current && pts == 1)) {
2143 return bestTIndex;
2144 }
2145 if (current) {
2146 SkASSERT(pts > 1);
2147 int closestIdx = 0;
2148 double closest = fabs(intersections.fT[0][0] - mid);
2149 for (int idx = 1; idx < pts; ++idx) {
2150 double test = fabs(intersections.fT[0][idx] - mid);
2151 if (closest > test) {
2152 closestIdx = idx;
2153 closest = test;
2154 }
2155 }
2156 if (closestIdx < pts - 1) {
2157 intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
2158 }
2159 --pts;
2160 }
2161 double bestT = -1;
2162 for (int index = 0; index < pts; ++index) {
2163 double foundT = intersections.fT[0][index];
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002164 if (approximately_less_than_zero(foundT)
2165 || approximately_greater_than_one(foundT)) {
2166 continue;
2167 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002168 SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
2169 if (approximately_negative(testY - bestY)
2170 || approximately_negative(basePt.fY - testY)) {
caryclark@google.com47580692012-07-23 12:14:49 +00002171 continue;
2172 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002173 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002174 return SK_MinS32; // if the intersection is edge on, wait for another one
caryclark@google.com10227bf2012-12-28 22:10:41 +00002175 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002176 if (fVerb > SkPath::kLine_Verb) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002177 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
2178 if (approximately_zero(dx)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002179 return SK_MinS32; // hit vertical, wait for another one
caryclark@google.com3586ece2012-12-27 18:46:58 +00002180 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00002181 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002182 bestY = testY;
2183 bestT = foundT;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002184 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002185 if (bestT < 0) {
2186 return bestTIndex;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002187 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002188 SkASSERT(bestT >= 0);
2189 SkASSERT(bestT <= 1);
2190 int start;
2191 int end = 0;
2192 do {
2193 start = end;
2194 end = nextSpan(start, 1);
2195 } while (fTs[end].fT < bestT);
2196 // FIXME: see next candidate for a better pattern to find the next start/end pair
2197 while (start + 1 < end && fTs[start].fDone) {
2198 ++start;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002199 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002200 if (!isCanceled(start)) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002201 hitT = bestT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002202 bestTIndex = start;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002203 hitSomething = true;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002204 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002205 return bestTIndex;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002206 }
caryclark@google.com18063442012-07-25 12:05:18 +00002207
caryclark@google.com4eeda372012-12-06 21:47:48 +00002208 void decrementSpan(Span* span) {
caryclark@google.com18063442012-07-25 12:05:18 +00002209 SkASSERT(span->fWindValue > 0);
2210 if (--(span->fWindValue) == 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002211 if (!span->fOppValue && !span->fDone) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002212 span->fDone = true;
2213 ++fDoneSpans;
2214 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002215 }
2216 }
2217
2218 bool bumpSpan(Span* span, int windDelta, int oppDelta) {
2219 SkASSERT(!span->fDone);
2220 span->fWindValue += windDelta;
2221 SkASSERT(span->fWindValue >= 0);
2222 span->fOppValue += oppDelta;
2223 SkASSERT(span->fOppValue >= 0);
2224 if (fXor) {
2225 span->fWindValue &= 1;
2226 }
2227 if (fOppXor) {
2228 span->fOppValue &= 1;
2229 }
2230 if (!span->fWindValue && !span->fOppValue) {
2231 span->fDone = true;
2232 ++fDoneSpans;
caryclark@google.com18063442012-07-25 12:05:18 +00002233 return true;
2234 }
2235 return false;
2236 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002237
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002238 // OPTIMIZE
2239 // when the edges are initially walked, they don't automatically get the prior and next
2240 // 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 +00002241 // and would additionally remove the need for similar checks in condition edges. It would
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002242 // also allow intersection code to assume end of segment intersections (maybe?)
2243 bool complete() const {
2244 int count = fTs.count();
2245 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
2246 }
caryclark@google.com18063442012-07-25 12:05:18 +00002247
caryclark@google.com15fa1382012-05-07 20:49:36 +00002248 bool done() const {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002249 SkASSERT(fDoneSpans <= fTs.count());
2250 return fDoneSpans == fTs.count();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002251 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002252
caryclark@google.comf839c032012-10-26 21:03:50 +00002253 bool done(int min) const {
2254 return fTs[min].fDone;
2255 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002256
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002257 bool done(const Angle* angle) const {
2258 return done(SkMin32(angle->start(), angle->end()));
caryclark@google.com47580692012-07-23 12:14:49 +00002259 }
skia.committer@gmail.com044679e2013-02-15 07:16:57 +00002260
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002261 SkPoint dxdy(int index) const {
2262 return (*SegmentDXDYAtT[fVerb])(fPts, fTs[index].fT);
2263 }
2264
2265 SkScalar dy(int index) const {
2266 return (*SegmentDYAtT[fVerb])(fPts, fTs[index].fT);
2267 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00002268
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002269 bool equalPoints(int greaterTIndex, int lesserTIndex) {
2270 SkASSERT(greaterTIndex >= lesserTIndex);
2271 double greaterT = fTs[greaterTIndex].fT;
2272 double lesserT = fTs[lesserTIndex].fT;
2273 if (greaterT == lesserT) {
2274 return true;
2275 }
2276 if (!approximately_negative(greaterT - lesserT)) {
2277 return false;
2278 }
2279 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2280 }
2281
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002282 /*
2283 The M and S variable name parts stand for the operators.
2284 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2285 Su stands for Subtrahend
2286 The Opp variable name part designates that the value is for the Opposite operator.
2287 Opposite values result from combining coincident spans.
2288 */
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002289
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002290 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2291 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002292 const int startIndex = nextStart;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002293 const int endIndex = nextEnd;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002294 SkASSERT(startIndex != endIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002295 const int count = fTs.count();
2296 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2297 const int step = SkSign32(endIndex - startIndex);
2298 const int end = nextExactSpan(startIndex, step);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002299 SkASSERT(end >= 0);
2300 Span* endSpan = &fTs[end];
2301 Segment* other;
2302 if (isSimple(end)) {
2303 // mark the smaller of startIndex, endIndex done, and all adjacent
2304 // spans with the same T value (but not 'other' spans)
2305 #if DEBUG_WINDING
2306 SkDebugf("%s simple\n", __FUNCTION__);
2307 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002308 int min = SkMin32(startIndex, endIndex);
2309 if (fTs[min].fDone) {
2310 return NULL;
2311 }
2312 markDoneBinary(min);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002313 other = endSpan->fOther;
2314 nextStart = endSpan->fOtherIndex;
2315 double startT = other->fTs[nextStart].fT;
2316 nextEnd = nextStart;
2317 do {
2318 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002319 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002320 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002321 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2322 return other;
2323 }
2324 // more than one viable candidate -- measure angles to find best
2325 SkTDArray<Angle> angles;
2326 SkASSERT(startIndex - endIndex != 0);
2327 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2328 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002329 buildAngles(end, angles, true);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002330 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002331 bool sortable = SortAngles(angles, sorted);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002332 int angleCount = angles.count();
2333 int firstIndex = findStartingEdge(sorted, startIndex, end);
2334 SkASSERT(firstIndex >= 0);
2335 #if DEBUG_SORT
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002336 debugShowSort(__FUNCTION__, sorted, firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002337 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002338 if (!sortable) {
2339 unsortable = true;
2340 return NULL;
2341 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002342 SkASSERT(sorted[firstIndex]->segment() == this);
2343 #if DEBUG_WINDING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002344 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2345 sorted[firstIndex]->sign());
caryclark@google.com235f56a2012-09-14 14:19:30 +00002346 #endif
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002347 int sumMiWinding = updateWinding(endIndex, startIndex);
2348 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2349 if (operand()) {
2350 SkTSwap<int>(sumMiWinding, sumSuWinding);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002351 }
2352 int nextIndex = firstIndex + 1;
2353 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2354 const Angle* foundAngle = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002355 bool foundDone = false;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002356 // iterate through the angle, and compute everyone's winding
caryclark@google.com235f56a2012-09-14 14:19:30 +00002357 Segment* nextSegment;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002358 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002359 SkASSERT(nextIndex != firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002360 if (nextIndex == angleCount) {
2361 nextIndex = 0;
2362 }
2363 const Angle* nextAngle = sorted[nextIndex];
2364 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002365 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2366 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2367 nextAngle->end(), op, sumMiWinding, sumSuWinding,
2368 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
2369 if (activeAngle && (!foundAngle || foundDone)) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002370 foundAngle = nextAngle;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002371 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002372 }
2373 if (nextSegment->done()) {
2374 continue;
2375 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002376 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2377 continue;
2378 }
2379 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2380 oppSumWinding, activeAngle, nextAngle);
2381 if (last) {
2382 *chase.append() = last;
2383#if DEBUG_WINDING
2384 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2385 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2386#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002387 }
2388 } while (++nextIndex != lastIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002389 markDoneBinary(SkMin32(startIndex, endIndex));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002390 if (!foundAngle) {
2391 return NULL;
2392 }
2393 nextStart = foundAngle->start();
2394 nextEnd = foundAngle->end();
2395 nextSegment = foundAngle->segment();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002396
caryclark@google.com235f56a2012-09-14 14:19:30 +00002397 #if DEBUG_WINDING
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002398 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2399 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002400 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002401 return nextSegment;
2402 }
caryclark@google.com47580692012-07-23 12:14:49 +00002403
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002404 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2405 bool& unsortable) {
2406 const int startIndex = nextStart;
2407 const int endIndex = nextEnd;
2408 SkASSERT(startIndex != endIndex);
2409 const int count = fTs.count();
2410 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2411 const int step = SkSign32(endIndex - startIndex);
2412 const int end = nextExactSpan(startIndex, step);
2413 SkASSERT(end >= 0);
2414 Span* endSpan = &fTs[end];
2415 Segment* other;
2416 if (isSimple(end)) {
2417 // mark the smaller of startIndex, endIndex done, and all adjacent
2418 // spans with the same T value (but not 'other' spans)
2419 #if DEBUG_WINDING
2420 SkDebugf("%s simple\n", __FUNCTION__);
2421 #endif
2422 int min = SkMin32(startIndex, endIndex);
2423 if (fTs[min].fDone) {
2424 return NULL;
2425 }
2426 markDoneUnary(min);
2427 other = endSpan->fOther;
2428 nextStart = endSpan->fOtherIndex;
2429 double startT = other->fTs[nextStart].fT;
2430 nextEnd = nextStart;
2431 do {
2432 nextEnd += step;
2433 }
2434 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2435 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2436 return other;
2437 }
2438 // more than one viable candidate -- measure angles to find best
2439 SkTDArray<Angle> angles;
2440 SkASSERT(startIndex - endIndex != 0);
2441 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2442 addTwoAngles(startIndex, end, angles);
2443 buildAngles(end, angles, true);
2444 SkTDArray<Angle*> sorted;
2445 bool sortable = SortAngles(angles, sorted);
2446 int angleCount = angles.count();
2447 int firstIndex = findStartingEdge(sorted, startIndex, end);
2448 SkASSERT(firstIndex >= 0);
2449 #if DEBUG_SORT
2450 debugShowSort(__FUNCTION__, sorted, firstIndex);
2451 #endif
2452 if (!sortable) {
2453 unsortable = true;
2454 return NULL;
2455 }
2456 SkASSERT(sorted[firstIndex]->segment() == this);
2457 #if DEBUG_WINDING
2458 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2459 sorted[firstIndex]->sign());
2460 #endif
2461 int sumWinding = updateWinding(endIndex, startIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002462 int nextIndex = firstIndex + 1;
2463 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2464 const Angle* foundAngle = NULL;
2465 bool foundDone = false;
2466 // iterate through the angle, and compute everyone's winding
2467 Segment* nextSegment;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002468 int activeCount = 0;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002469 do {
2470 SkASSERT(nextIndex != firstIndex);
2471 if (nextIndex == angleCount) {
2472 nextIndex = 0;
2473 }
2474 const Angle* nextAngle = sorted[nextIndex];
2475 nextSegment = nextAngle->segment();
2476 int maxWinding;
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00002477 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002478 maxWinding, sumWinding);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002479 if (activeAngle) {
2480 ++activeCount;
2481 if (!foundAngle || (foundDone && activeCount & 1)) {
2482 if (nextSegment->tiny(nextAngle)) {
2483 unsortable = true;
2484 return NULL;
2485 }
2486 foundAngle = nextAngle;
2487 foundDone = nextSegment->done(nextAngle);
2488 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002489 }
2490 if (nextSegment->done()) {
2491 continue;
2492 }
2493 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2494 continue;
2495 }
2496 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2497 if (last) {
2498 *chase.append() = last;
2499#if DEBUG_WINDING
2500 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2501 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2502#endif
2503 }
2504 } while (++nextIndex != lastIndex);
2505 markDoneUnary(SkMin32(startIndex, endIndex));
2506 if (!foundAngle) {
2507 return NULL;
2508 }
2509 nextStart = foundAngle->start();
2510 nextEnd = foundAngle->end();
2511 nextSegment = foundAngle->segment();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002512 #if DEBUG_WINDING
2513 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2514 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2515 #endif
2516 return nextSegment;
2517 }
2518
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002519 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002520 const int startIndex = nextStart;
2521 const int endIndex = nextEnd;
2522 SkASSERT(startIndex != endIndex);
2523 int count = fTs.count();
2524 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2525 : startIndex > 0);
2526 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002527 int end = nextExactSpan(startIndex, step);
caryclark@google.com24bec792012-08-20 12:43:57 +00002528 SkASSERT(end >= 0);
2529 Span* endSpan = &fTs[end];
2530 Segment* other;
caryclark@google.com24bec792012-08-20 12:43:57 +00002531 if (isSimple(end)) {
2532 #if DEBUG_WINDING
2533 SkDebugf("%s simple\n", __FUNCTION__);
2534 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002535 int min = SkMin32(startIndex, endIndex);
2536 if (fTs[min].fDone) {
2537 return NULL;
2538 }
2539 markDone(min, 1);
caryclark@google.com24bec792012-08-20 12:43:57 +00002540 other = endSpan->fOther;
2541 nextStart = endSpan->fOtherIndex;
2542 double startT = other->fTs[nextStart].fT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002543 #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 +00002544 SkDEBUGCODE(bool firstLoop = true;)
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002545 if ((approximately_less_than_zero(startT) && step < 0)
2546 || (approximately_greater_than_one(startT) && step > 0)) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002547 step = -step;
2548 SkDEBUGCODE(firstLoop = false;)
2549 }
2550 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002551 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002552 nextEnd = nextStart;
2553 do {
2554 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002555 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002556 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002557 #if 01
caryclark@google.com24bec792012-08-20 12:43:57 +00002558 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2559 break;
2560 }
caryclark@google.com03f97062012-08-21 13:13:52 +00002561 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00002562 SkASSERT(firstLoop);
caryclark@google.com03f97062012-08-21 13:13:52 +00002563 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002564 SkDEBUGCODE(firstLoop = false;)
2565 step = -step;
2566 } while (true);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002567 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002568 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2569 return other;
2570 }
2571 SkTDArray<Angle> angles;
2572 SkASSERT(startIndex - endIndex != 0);
2573 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2574 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002575 buildAngles(end, angles, false);
caryclark@google.com24bec792012-08-20 12:43:57 +00002576 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002577 bool sortable = SortAngles(angles, sorted);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002578 if (!sortable) {
2579 unsortable = true;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002580 #if DEBUG_SORT
2581 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
2582 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002583 return NULL;
2584 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002585 int angleCount = angles.count();
2586 int firstIndex = findStartingEdge(sorted, startIndex, end);
2587 SkASSERT(firstIndex >= 0);
2588 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002589 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
caryclark@google.com24bec792012-08-20 12:43:57 +00002590 #endif
2591 SkASSERT(sorted[firstIndex]->segment() == this);
2592 int nextIndex = firstIndex + 1;
2593 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002594 const Angle* foundAngle = NULL;
2595 bool foundDone = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002596 Segment* nextSegment;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002597 int activeCount = 0;
caryclark@google.com24bec792012-08-20 12:43:57 +00002598 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002599 SkASSERT(nextIndex != firstIndex);
caryclark@google.com24bec792012-08-20 12:43:57 +00002600 if (nextIndex == angleCount) {
2601 nextIndex = 0;
2602 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002603 const Angle* nextAngle = sorted[nextIndex];
caryclark@google.com24bec792012-08-20 12:43:57 +00002604 nextSegment = nextAngle->segment();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002605 ++activeCount;
2606 if (!foundAngle || (foundDone && activeCount & 1)) {
2607 if (nextSegment->tiny(nextAngle)) {
2608 unsortable = true;
2609 return NULL;
2610 }
2611 foundAngle = nextAngle;
2612 foundDone = nextSegment->done(nextAngle);
2613 }
2614 if (nextSegment->done()) {
2615 continue;
caryclark@google.com24bec792012-08-20 12:43:57 +00002616 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002617 } while (++nextIndex != lastIndex);
2618 markDone(SkMin32(startIndex, endIndex), 1);
2619 if (!foundAngle) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002620 return NULL;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002621 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002622 nextStart = foundAngle->start();
2623 nextEnd = foundAngle->end();
2624 nextSegment = foundAngle->segment();
2625 #if DEBUG_WINDING
2626 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2627 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2628 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002629 return nextSegment;
2630 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002631
2632 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2633 int angleCount = sorted.count();
2634 int firstIndex = -1;
2635 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2636 const Angle* angle = sorted[angleIndex];
2637 if (angle->segment() == this && angle->start() == end &&
2638 angle->end() == start) {
2639 firstIndex = angleIndex;
2640 break;
2641 }
2642 }
2643 return firstIndex;
2644 }
2645
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002646 // FIXME: this is tricky code; needs its own unit test
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002647 // note that fOtherIndex isn't computed yet, so it can't be used here
caryclark@google.com4eeda372012-12-06 21:47:48 +00002648 void findTooCloseToCall() {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002649 int count = fTs.count();
2650 if (count < 3) { // require t=0, x, 1 at minimum
2651 return;
2652 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002653 int matchIndex = 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002654 int moCount;
2655 Span* match;
2656 Segment* mOther;
2657 do {
2658 match = &fTs[matchIndex];
2659 mOther = match->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002660 // FIXME: allow quads, cubics to be near coincident?
2661 if (mOther->fVerb == SkPath::kLine_Verb) {
2662 moCount = mOther->fTs.count();
2663 if (moCount >= 3) {
2664 break;
2665 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002666 }
2667 if (++matchIndex >= count) {
2668 return;
2669 }
2670 } while (true); // require t=0, x, 1 at minimum
caryclark@google.com15fa1382012-05-07 20:49:36 +00002671 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002672 const SkPoint* matchPt = &xyAtT(match);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002673 // look for a pair of nearby T values that map to the same (x,y) value
2674 // if found, see if the pair of other segments share a common point. If
2675 // so, the span from here to there is coincident.
caryclark@google.com15fa1382012-05-07 20:49:36 +00002676 for (int index = matchIndex + 1; index < count; ++index) {
2677 Span* test = &fTs[index];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002678 if (test->fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002679 continue;
2680 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002681 Segment* tOther = test->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002682 if (tOther->fVerb != SkPath::kLine_Verb) {
2683 continue; // FIXME: allow quads, cubics to be near coincident?
2684 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002685 int toCount = tOther->fTs.count();
2686 if (toCount < 3) { // require t=0, x, 1 at minimum
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002687 continue;
2688 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002689 const SkPoint* testPt = &xyAtT(test);
2690 if (*matchPt != *testPt) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002691 matchIndex = index;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002692 moCount = toCount;
2693 match = test;
2694 mOther = tOther;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002695 matchPt = testPt;
2696 continue;
2697 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002698 int moStart = -1;
2699 int moEnd = -1;
2700 double moStartT, moEndT;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002701 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002702 Span& moSpan = mOther->fTs[moIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002703 if (moSpan.fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002704 continue;
2705 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002706 if (moSpan.fOther == this) {
2707 if (moSpan.fOtherT == match->fT) {
2708 moStart = moIndex;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002709 moStartT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002710 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002711 continue;
2712 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002713 if (moSpan.fOther == tOther) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002714 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002715 moStart = -1;
2716 break;
2717 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002718 SkASSERT(moEnd == -1);
2719 moEnd = moIndex;
2720 moEndT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002721 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002722 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002723 if (moStart < 0 || moEnd < 0) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002724 continue;
2725 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002726 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002727 if (approximately_equal(moStartT, moEndT)) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002728 continue;
2729 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002730 int toStart = -1;
2731 int toEnd = -1;
2732 double toStartT, toEndT;
2733 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2734 Span& toSpan = tOther->fTs[toIndex];
caryclark@google.comc899ad92012-08-23 15:24:42 +00002735 if (toSpan.fDone) {
2736 continue;
2737 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002738 if (toSpan.fOther == this) {
2739 if (toSpan.fOtherT == test->fT) {
2740 toStart = toIndex;
2741 toStartT = toSpan.fT;
2742 }
2743 continue;
2744 }
2745 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002746 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002747 moStart = -1;
2748 break;
2749 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002750 SkASSERT(toEnd == -1);
2751 toEnd = toIndex;
2752 toEndT = toSpan.fT;
2753 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002754 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002755 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2756 if (toStart <= 0 || toEnd <= 0) {
2757 continue;
2758 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002759 if (approximately_equal(toStartT, toEndT)) {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002760 continue;
2761 }
2762 // test to see if the segment between there and here is linear
2763 if (!mOther->isLinear(moStart, moEnd)
2764 || !tOther->isLinear(toStart, toEnd)) {
2765 continue;
2766 }
caryclark@google.comc899ad92012-08-23 15:24:42 +00002767 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002768 if (flipped) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002769 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002770 } else {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002771 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002772 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002773 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002774 }
2775
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002776 // FIXME: either:
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002777 // a) mark spans with either end unsortable as done, or
2778 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2779 // when encountering an unsortable span
2780
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002781 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2782 // and use more concise logic like the old edge walker code?
2783 // FIXME: this needs to deal with coincident edges
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002784 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002785 // iterate through T intersections and return topmost
2786 // topmost tangent from y-min to first pt is closer to horizontal
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002787 SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002788 int firstT = -1;
caryclark@google.comd0a19eb2013-02-19 12:49:33 +00002789 /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002790 SkASSERT(firstT >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002791 // sort the edges to find the leftmost
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002792 int step = 1;
2793 int end = nextSpan(firstT, step);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002794 if (end == -1) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002795 step = -1;
2796 end = nextSpan(firstT, step);
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00002797 SkASSERT(end != -1);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002798 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002799 // if the topmost T is not on end, or is three-way or more, find left
2800 // look for left-ness from tLeft to firstT (matching y of other)
2801 SkTDArray<Angle> angles;
2802 SkASSERT(firstT - end != 0);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002803 addTwoAngles(end, firstT, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002804 buildAngles(firstT, angles, true);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002805 SkTDArray<Angle*> sorted;
caryclark@google.comf839c032012-10-26 21:03:50 +00002806 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002807 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002808 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002809 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002810 if (onlySortable && !sortable) {
2811 unsortable = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002812 return NULL;
2813 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002814 // skip edges that have already been processed
2815 firstT = -1;
2816 Segment* leftSegment;
2817 do {
2818 const Angle* angle = sorted[++firstT];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002819 SkASSERT(!onlySortable || !angle->unsortable());
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002820 leftSegment = angle->segment();
2821 tIndex = angle->end();
2822 endIndex = angle->start();
2823 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002824 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
caryclark@google.com47d73da2013-02-17 01:41:25 +00002825 SkPoint dxyE = leftSegment->dxdy(endIndex);
2826 SkPoint dxyS = leftSegment->dxdy(tIndex);
2827 double cross = dxyE.cross(dxyS);
2828 #if DEBUG_SWAP_TOP
2829 SkDebugf("%s dxyE=(%1.9g,%1.9g) dxyS=(%1.9g,%1.9g) cross=%1.9g\n", __FUNCTION__,
2830 dxyE.fX, dxyE.fY, dxyS.fX, dxyS.fY, cross);
2831 #endif
2832 if (cross >= 1) {
2833 #if DEBUG_SWAP_TOP
2834 SkDebugf("%s swap\n", __FUNCTION__);
2835 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002836 SkTSwap(tIndex, endIndex);
2837 }
2838 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002839 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002840 return leftSegment;
2841 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002842
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002843 // FIXME: not crazy about this
2844 // when the intersections are performed, the other index is into an
2845 // incomplete array. as the array grows, the indices become incorrect
2846 // while the following fixes the indices up again, it isn't smart about
2847 // skipping segments whose indices are already correct
2848 // assuming we leave the code that wrote the index in the first place
2849 void fixOtherTIndex() {
2850 int iCount = fTs.count();
2851 for (int i = 0; i < iCount; ++i) {
2852 Span& iSpan = fTs[i];
2853 double oT = iSpan.fOtherT;
2854 Segment* other = iSpan.fOther;
2855 int oCount = other->fTs.count();
2856 for (int o = 0; o < oCount; ++o) {
2857 Span& oSpan = other->fTs[o];
2858 if (oT == oSpan.fT && this == oSpan.fOther) {
2859 iSpan.fOtherIndex = o;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002860 break;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002861 }
2862 }
2863 }
2864 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002865
caryclark@google.com4eeda372012-12-06 21:47:48 +00002866 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002867 fDoneSpans = 0;
2868 fOperand = operand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00002869 fXor = evenOdd;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002870 fPts = pts;
2871 fVerb = verb;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002872 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00002873
caryclark@google.com3586ece2012-12-27 18:46:58 +00002874 void initWinding(int start, int end) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002875 int local = spanSign(start, end);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002876 int oppLocal = oppSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002877 (void) markAndChaseWinding(start, end, local, oppLocal);
caryclark@google.com73ca6242013-01-17 21:02:47 +00002878 // OPTIMIZATION: the reverse mark and chase could skip the first marking
2879 (void) markAndChaseWinding(end, start, local, oppLocal);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002880 }
2881
caryclark@google.com3586ece2012-12-27 18:46:58 +00002882 void initWinding(int start, int end, int winding, int oppWinding) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002883 int local = spanSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002884 if (local * winding >= 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002885 winding += local;
2886 }
2887 int oppLocal = oppSign(start, end);
2888 if (oppLocal * oppWinding >= 0) {
2889 oppWinding += oppLocal;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002890 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002891 (void) markAndChaseWinding(start, end, winding, oppWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002892 }
2893
caryclark@google.com3586ece2012-12-27 18:46:58 +00002894/*
2895when we start with a vertical intersect, we try to use the dx to determine if the edge is to
2896the 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 +00002897sign or not. However, this isn't enough.
2898If 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 +00002899If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
2900from 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 +00002901the same winding is shared by both.
caryclark@google.com3586ece2012-12-27 18:46:58 +00002902*/
2903 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
2904 SkScalar hitOppDx) {
2905 SkASSERT(hitDx || !winding);
2906 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
2907 SkASSERT(dx);
2908 int windVal = windValue(SkMin32(start, end));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002909 #if DEBUG_WINDING_AT_T
2910 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
2911 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
2912 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002913 if (!winding) {
2914 winding = dx < 0 ? windVal : -windVal;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002915 } else if (winding * dx < 0) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00002916 int sideWind = winding + (dx < 0 ? windVal : -windVal);
2917 if (abs(winding) < abs(sideWind)) {
2918 winding = sideWind;
2919 }
2920 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002921 #if DEBUG_WINDING_AT_T
2922 SkDebugf(" winding=%d\n", winding);
2923 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002924 int oppLocal = oppSign(start, end);
2925 SkASSERT(hitOppDx || !oppWind || !oppLocal);
2926 int oppWindVal = oppValue(SkMin32(start, end));
2927 if (!oppWind) {
2928 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
2929 } else if (hitOppDx * dx >= 0) {
2930 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
2931 if (abs(oppWind) < abs(oppSideWind)) {
2932 oppWind = oppSideWind;
2933 }
2934 }
2935 (void) markAndChaseWinding(start, end, winding, oppWind);
2936 }
2937
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002938 bool intersected() const {
2939 return fTs.count() > 0;
2940 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002941
caryclark@google.com10227bf2012-12-28 22:10:41 +00002942 bool isCanceled(int tIndex) const {
2943 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
2944 }
2945
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002946 bool isConnected(int startIndex, int endIndex) const {
2947 return fTs[startIndex].fWindSum != SK_MinS32
2948 || fTs[endIndex].fWindSum != SK_MinS32;
2949 }
2950
caryclark@google.com235f56a2012-09-14 14:19:30 +00002951 bool isHorizontal() const {
2952 return fBounds.fTop == fBounds.fBottom;
2953 }
2954
caryclark@google.com15fa1382012-05-07 20:49:36 +00002955 bool isLinear(int start, int end) const {
2956 if (fVerb == SkPath::kLine_Verb) {
2957 return true;
2958 }
2959 if (fVerb == SkPath::kQuad_Verb) {
2960 SkPoint qPart[3];
2961 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
2962 return QuadIsLinear(qPart);
2963 } else {
2964 SkASSERT(fVerb == SkPath::kCubic_Verb);
2965 SkPoint cPart[4];
2966 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
2967 return CubicIsLinear(cPart);
2968 }
2969 }
caryclark@google.comb9738012012-07-03 19:53:30 +00002970
2971 // OPTIMIZE: successive calls could start were the last leaves off
2972 // or calls could specialize to walk forwards or backwards
2973 bool isMissing(double startT) const {
2974 size_t tCount = fTs.count();
2975 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002976 if (approximately_zero(startT - fTs[index].fT)) {
caryclark@google.comb9738012012-07-03 19:53:30 +00002977 return false;
2978 }
2979 }
2980 return true;
2981 }
2982
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002983 bool isSimple(int end) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002984 int count = fTs.count();
2985 if (count == 2) {
2986 return true;
2987 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002988 double t = fTs[end].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002989 if (approximately_less_than_zero(t)) {
2990 return !approximately_less_than_zero(fTs[1].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002991 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002992 if (approximately_greater_than_one(t)) {
2993 return !approximately_greater_than_one(fTs[count - 2].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002994 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002995 return false;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002996 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002997
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002998 bool isVertical() const {
2999 return fBounds.fLeft == fBounds.fRight;
3000 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003001
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003002 bool isVertical(int start, int end) const {
3003 return (*SegmentVertical[fVerb])(fPts, start, end);
3004 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003005
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003006 SkScalar leftMost(int start, int end) const {
3007 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
3008 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003009
caryclark@google.com495f8e42012-05-31 13:13:11 +00003010 // this span is excluded by the winding rule -- chase the ends
3011 // as long as they are unambiguous to mark connections as done
3012 // and give them the same winding value
caryclark@google.com59823f72012-08-09 18:17:47 +00003013 Span* markAndChaseDone(const Angle* angle, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003014 int index = angle->start();
3015 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003016 return markAndChaseDone(index, endIndex, winding);
3017 }
3018
caryclark@google.com31143cf2012-11-09 22:14:19 +00003019 Span* markAndChaseDone(int index, int endIndex, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003020 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003021 int min = SkMin32(index, endIndex);
3022 markDone(min, winding);
3023 Span* last;
3024 Segment* other = this;
3025 while ((other = other->nextChase(index, step, min, last))) {
3026 other->markDone(min, winding);
3027 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003028 return last;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003029 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003030
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003031 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
3032 int index = angle->start();
3033 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003034 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003035 int min = SkMin32(index, endIndex);
3036 markDoneBinary(min, winding, oppWinding);
3037 Span* last;
3038 Segment* other = this;
3039 while ((other = other->nextChase(index, step, min, last))) {
3040 other->markDoneBinary(min, winding, oppWinding);
3041 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003042 return last;
3043 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003044
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003045 Span* markAndChaseDoneBinary(int index, int endIndex) {
3046 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003047 int min = SkMin32(index, endIndex);
3048 markDoneBinary(min);
3049 Span* last;
3050 Segment* other = this;
3051 while ((other = other->nextChase(index, step, min, last))) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003052 if (other->done()) {
3053 return NULL;
3054 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003055 other->markDoneBinary(min);
3056 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003057 return last;
3058 }
3059
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003060 Span* markAndChaseDoneUnary(int index, int endIndex) {
3061 int step = SkSign32(endIndex - index);
3062 int min = SkMin32(index, endIndex);
3063 markDoneUnary(min);
3064 Span* last;
3065 Segment* other = this;
3066 while ((other = other->nextChase(index, step, min, last))) {
3067 if (other->done()) {
3068 return NULL;
3069 }
3070 other->markDoneUnary(min);
3071 }
3072 return last;
3073 }
3074
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003075 Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
3076 int index = angle->start();
3077 int endIndex = angle->end();
3078 return markAndChaseDone(index, endIndex, winding);
3079 }
3080
caryclark@google.com4eeda372012-12-06 21:47:48 +00003081 Span* markAndChaseWinding(const Angle* angle, const int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003082 int index = angle->start();
3083 int endIndex = angle->end();
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003084 int step = SkSign32(endIndex - index);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003085 int min = SkMin32(index, endIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00003086 markWinding(min, winding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003087 Span* last;
3088 Segment* other = this;
3089 while ((other = other->nextChase(index, step, min, last))) {
3090 if (other->fTs[min].fWindSum != SK_MinS32) {
3091 SkASSERT(other->fTs[min].fWindSum == winding);
3092 return NULL;
3093 }
3094 other->markWinding(min, winding);
3095 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003096 return last;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003097 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003098
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003099 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003100 int min = SkMin32(index, endIndex);
3101 int step = SkSign32(endIndex - index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003102 markWinding(min, winding, oppWinding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003103 Span* last;
3104 Segment* other = this;
3105 while ((other = other->nextChase(index, step, min, last))) {
3106 if (other->fTs[min].fWindSum != SK_MinS32) {
3107 SkASSERT(other->fTs[min].fWindSum == winding);
3108 return NULL;
3109 }
3110 other->markWinding(min, winding, oppWinding);
3111 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003112 return last;
3113 }
3114
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003115 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
3116 int start = angle->start();
3117 int end = angle->end();
3118 return markAndChaseWinding(start, end, winding, oppWinding);
3119 }
3120
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003121 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
3122 SkASSERT(angle->segment() == this);
3123 if (useInnerWinding(maxWinding, sumWinding)) {
3124 maxWinding = sumWinding;
3125 }
3126 Span* last;
3127 if (activeAngle) {
3128 last = markAndChaseWinding(angle, maxWinding);
3129 } else {
3130 last = markAndChaseDoneUnary(angle, maxWinding);
3131 }
3132 return last;
3133 }
3134
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003135 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
3136 bool activeAngle, const Angle* angle) {
3137 SkASSERT(angle->segment() == this);
3138 if (useInnerWinding(maxWinding, sumWinding)) {
3139 maxWinding = sumWinding;
3140 }
3141 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
3142 oppMaxWinding = oppSumWinding;
3143 }
3144 Span* last;
3145 if (activeAngle) {
3146 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3147 } else {
3148 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
3149 }
3150 return last;
3151 }
3152
caryclark@google.com495f8e42012-05-31 13:13:11 +00003153 // FIXME: this should also mark spans with equal (x,y)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003154 // This may be called when the segment is already marked done. While this
3155 // wastes time, it shouldn't do any more than spin through the T spans.
rmistry@google.comd6176b02012-08-23 18:14:13 +00003156 // OPTIMIZATION: abort on first done found (assuming that this code is
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003157 // always called to mark segments done).
caryclark@google.com59823f72012-08-09 18:17:47 +00003158 void markDone(int index, int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003159 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003160 SkASSERT(winding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003161 double referenceT = fTs[index].fT;
3162 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003163 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3164 markOneDone(__FUNCTION__, lesser, winding);
3165 }
3166 do {
3167 markOneDone(__FUNCTION__, index, winding);
3168 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003169 }
3170
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003171 void markDoneBinary(int index, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003172 // SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003173 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003174 double referenceT = fTs[index].fT;
3175 int lesser = index;
3176 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003177 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003178 }
3179 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003180 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
3181 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3182 }
3183
3184 void markDoneBinary(int index) {
3185 double referenceT = fTs[index].fT;
3186 int lesser = index;
3187 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3188 markOneDoneBinary(__FUNCTION__, lesser);
3189 }
3190 do {
3191 markOneDoneBinary(__FUNCTION__, index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003192 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003193 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00003194
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003195 void markDoneUnary(int index, int winding) {
3196 // SkASSERT(!done());
3197 SkASSERT(winding);
3198 double referenceT = fTs[index].fT;
3199 int lesser = index;
3200 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3201 markOneDoneUnary(__FUNCTION__, lesser, winding);
3202 }
3203 do {
3204 markOneDoneUnary(__FUNCTION__, index, winding);
3205 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3206 }
3207
3208 void markDoneUnary(int index) {
3209 double referenceT = fTs[index].fT;
3210 int lesser = index;
3211 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3212 markOneDoneUnary(__FUNCTION__, lesser);
3213 }
3214 do {
3215 markOneDoneUnary(__FUNCTION__, index);
3216 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3217 }
3218
caryclark@google.com24bec792012-08-20 12:43:57 +00003219 void markOneDone(const char* funName, int tIndex, int winding) {
3220 Span* span = markOneWinding(funName, tIndex, winding);
3221 if (!span) {
3222 return;
3223 }
3224 span->fDone = true;
3225 fDoneSpans++;
3226 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003227
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003228 void markOneDoneBinary(const char* funName, int tIndex) {
3229 Span* span = verifyOneWinding(funName, tIndex);
3230 if (!span) {
3231 return;
3232 }
3233 span->fDone = true;
3234 fDoneSpans++;
3235 }
3236
3237 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003238 Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
3239 if (!span) {
3240 return;
3241 }
3242 span->fDone = true;
3243 fDoneSpans++;
3244 }
3245
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003246 void markOneDoneUnary(const char* funName, int tIndex) {
3247 Span* span = verifyOneWindingU(funName, tIndex);
3248 if (!span) {
3249 return;
3250 }
3251 span->fDone = true;
3252 fDoneSpans++;
3253 }
3254
3255 void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3256 Span* span = markOneWinding(funName, tIndex, winding);
3257 if (!span) {
3258 return;
3259 }
3260 span->fDone = true;
3261 fDoneSpans++;
3262 }
3263
caryclark@google.com24bec792012-08-20 12:43:57 +00003264 Span* markOneWinding(const char* funName, int tIndex, int winding) {
3265 Span& span = fTs[tIndex];
3266 if (span.fDone) {
3267 return NULL;
3268 }
3269 #if DEBUG_MARK_DONE
3270 debugShowNewWinding(funName, span, winding);
3271 #endif
3272 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com03f97062012-08-21 13:13:52 +00003273 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00003274 SkASSERT(abs(winding) <= gDebugMaxWindSum);
caryclark@google.com03f97062012-08-21 13:13:52 +00003275 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00003276 span.fWindSum = winding;
3277 return &span;
3278 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003279
caryclark@google.com31143cf2012-11-09 22:14:19 +00003280 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
3281 Span& span = fTs[tIndex];
3282 if (span.fDone) {
3283 return NULL;
3284 }
3285 #if DEBUG_MARK_DONE
3286 debugShowNewWinding(funName, span, winding, oppWinding);
3287 #endif
3288 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3289 #ifdef SK_DEBUG
3290 SkASSERT(abs(winding) <= gDebugMaxWindSum);
3291 #endif
3292 span.fWindSum = winding;
3293 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3294 #ifdef SK_DEBUG
3295 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
3296 #endif
3297 span.fOppSum = oppWinding;
3298 return &span;
3299 }
3300
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003301 Span* verifyOneWinding(const char* funName, int tIndex) {
3302 Span& span = fTs[tIndex];
3303 if (span.fDone) {
3304 return NULL;
3305 }
3306 #if DEBUG_MARK_DONE
3307 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3308 #endif
3309 SkASSERT(span.fWindSum != SK_MinS32);
3310 SkASSERT(span.fOppSum != SK_MinS32);
3311 return &span;
3312 }
3313
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003314 Span* verifyOneWindingU(const char* funName, int tIndex) {
3315 Span& span = fTs[tIndex];
3316 if (span.fDone) {
3317 return NULL;
3318 }
3319 #if DEBUG_MARK_DONE
3320 debugShowNewWinding(funName, span, span.fWindSum);
3321 #endif
3322 SkASSERT(span.fWindSum != SK_MinS32);
3323 return &span;
3324 }
3325
caryclark@google.comf839c032012-10-26 21:03:50 +00003326 // note that just because a span has one end that is unsortable, that's
3327 // not enough to mark it done. The other end may be sortable, allowing the
3328 // span to be added.
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003329 // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003330 void markUnsortable(int start, int end) {
3331 Span* span = &fTs[start];
3332 if (start < end) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003333#if DEBUG_UNSORTABLE
3334 SkDebugf("%s start id=%d [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fID, start,
3335 xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003336#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003337 span->fUnsortableStart = true;
3338 } else {
3339 --span;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003340#if DEBUG_UNSORTABLE
3341 SkDebugf("%s end id=%d [%d] (%1.9g,%1.9g) next:(%1.9g,%1.9g)\n", __FUNCTION__, fID,
3342 start - 1, xAtT(start - 1), yAtT(start - 1), xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003343#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003344 span->fUnsortableEnd = true;
3345 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003346 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003347 return;
3348 }
3349 span->fDone = true;
3350 fDoneSpans++;
3351 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003352
caryclark@google.com59823f72012-08-09 18:17:47 +00003353 void markWinding(int index, int winding) {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003354 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003355 SkASSERT(winding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003356 double referenceT = fTs[index].fT;
3357 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003358 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3359 markOneWinding(__FUNCTION__, lesser, winding);
3360 }
3361 do {
3362 markOneWinding(__FUNCTION__, index, winding);
3363 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003364 }
3365
3366 void markWinding(int index, int winding, int oppWinding) {
3367 // SkASSERT(!done());
caryclark@google.com4eeda372012-12-06 21:47:48 +00003368 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003369 double referenceT = fTs[index].fT;
3370 int lesser = index;
3371 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3372 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003373 }
3374 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003375 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3376 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003377 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003378
caryclark@google.com2ddff932012-08-07 21:25:27 +00003379 void matchWindingValue(int tIndex, double t, bool borrowWind) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003380 int nextDoorWind = SK_MaxS32;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003381 int nextOppWind = SK_MaxS32;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003382 if (tIndex > 0) {
3383 const Span& below = fTs[tIndex - 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003384 if (approximately_negative(t - below.fT)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003385 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003386 nextOppWind = below.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003387 }
3388 }
3389 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3390 const Span& above = fTs[tIndex + 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003391 if (approximately_negative(above.fT - t)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003392 nextDoorWind = above.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003393 nextOppWind = above.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003394 }
3395 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003396 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3397 const Span& below = fTs[tIndex - 1];
3398 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003399 nextOppWind = below.fOppValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003400 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003401 if (nextDoorWind != SK_MaxS32) {
3402 Span& newSpan = fTs[tIndex];
3403 newSpan.fWindValue = nextDoorWind;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003404 newSpan.fOppValue = nextOppWind;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003405 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003406 newSpan.fDone = true;
3407 ++fDoneSpans;
3408 }
3409 }
3410 }
3411
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003412 bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3413 // find bounds
3414 Bounds bounds;
3415 bounds.setPoint(xyAtT(index));
3416 bounds.add(xyAtT(endIndex));
3417 SkScalar width = bounds.width();
3418 SkScalar height = bounds.height();
3419 if (width > height) {
3420 if (approximately_negative(width)) {
3421 unsortable = true; // edge is too small to resolve meaningfully
3422 }
3423 return false;
3424 } else {
3425 if (approximately_negative(height)) {
3426 unsortable = true; // edge is too small to resolve meaningfully
3427 }
3428 return true;
3429 }
3430 }
3431
caryclark@google.com9764cc62012-07-12 19:29:45 +00003432 // return span if when chasing, two or more radiating spans are not done
3433 // OPTIMIZATION: ? multiple spans is detected when there is only one valid
3434 // candidate and the remaining spans have windValue == 0 (canceled by
3435 // coincidence). The coincident edges could either be removed altogether,
3436 // or this code could be more complicated in detecting this case. Worth it?
3437 bool multipleSpans(int end) const {
3438 return end > 0 && end < fTs.count() - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00003439 }
3440
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003441 bool nextCandidate(int& start, int& end) const {
caryclark@google.com10227bf2012-12-28 22:10:41 +00003442 while (fTs[end].fDone) {
3443 if (fTs[end].fT == 1) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003444 return false;
3445 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00003446 ++end;
3447 }
3448 start = end;
3449 end = nextExactSpan(start, 1);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003450 return true;
3451 }
3452
caryclark@google.com4eeda372012-12-06 21:47:48 +00003453 Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
3454 int end = nextExactSpan(index, step);
3455 SkASSERT(end >= 0);
3456 if (multipleSpans(end)) {
3457 last = &fTs[end];
3458 return NULL;
3459 }
3460 const Span& endSpan = fTs[end];
3461 Segment* other = endSpan.fOther;
3462 index = endSpan.fOtherIndex;
caryclark@google.comaa358312013-01-29 20:28:49 +00003463 SkASSERT(index >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003464 int otherEnd = other->nextExactSpan(index, step);
caryclark@google.comaa358312013-01-29 20:28:49 +00003465 SkASSERT(otherEnd >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003466 min = SkMin32(index, otherEnd);
3467 return other;
3468 }
3469
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003470 // This has callers for two different situations: one establishes the end
3471 // of the current span, and one establishes the beginning of the next span
3472 // (thus the name). When this is looking for the end of the current span,
3473 // coincidence is found when the beginning Ts contain -step and the end
3474 // contains step. When it is looking for the beginning of the next, the
3475 // first Ts found can be ignored and the last Ts should contain -step.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003476 // OPTIMIZATION: probably should split into two functions
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003477 int nextSpan(int from, int step) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003478 const Span& fromSpan = fTs[from];
caryclark@google.com495f8e42012-05-31 13:13:11 +00003479 int count = fTs.count();
3480 int to = from;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003481 while (step > 0 ? ++to < count : --to >= 0) {
3482 const Span& span = fTs[to];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003483 if (approximately_zero(span.fT - fromSpan.fT)) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003484 continue;
3485 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003486 return to;
3487 }
3488 return -1;
3489 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +00003490
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003491 // FIXME
3492 // this returns at any difference in T, vs. a preset minimum. It may be
3493 // that all callers to nextSpan should use this instead.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003494 // OPTIMIZATION splitting this into separate loops for up/down steps
3495 // would allow using precisely_negative instead of precisely_zero
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003496 int nextExactSpan(int from, int step) const {
3497 const Span& fromSpan = fTs[from];
3498 int count = fTs.count();
3499 int to = from;
3500 while (step > 0 ? ++to < count : --to >= 0) {
3501 const Span& span = fTs[to];
caryclark@google.coma461ff02012-10-11 12:54:23 +00003502 if (precisely_zero(span.fT - fromSpan.fT)) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003503 continue;
3504 }
3505 return to;
3506 }
3507 return -1;
3508 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003509
caryclark@google.com235f56a2012-09-14 14:19:30 +00003510 bool operand() const {
3511 return fOperand;
3512 }
3513
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003514 int oppSign(const Angle* angle) const {
3515 SkASSERT(angle->segment() == this);
3516 return oppSign(angle->start(), angle->end());
3517 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003518
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003519 int oppSign(int startIndex, int endIndex) const {
3520 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3521 : fTs[endIndex].fOppValue;
3522#if DEBUG_WIND_BUMP
3523 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3524#endif
3525 return result;
3526 }
3527
caryclark@google.com31143cf2012-11-09 22:14:19 +00003528 int oppSum(int tIndex) const {
3529 return fTs[tIndex].fOppSum;
3530 }
3531
3532 int oppSum(const Angle* angle) const {
3533 int lesser = SkMin32(angle->start(), angle->end());
3534 return fTs[lesser].fOppSum;
caryclark@google.com235f56a2012-09-14 14:19:30 +00003535 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003536
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003537 int oppValue(int tIndex) const {
3538 return fTs[tIndex].fOppValue;
3539 }
3540
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003541 int oppValue(const Angle* angle) const {
3542 int lesser = SkMin32(angle->start(), angle->end());
3543 return fTs[lesser].fOppValue;
3544 }
3545
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003546 const SkPoint* pts() const {
3547 return fPts;
3548 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003549
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003550 void reset() {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003551 init(NULL, (SkPath::Verb) -1, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003552 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3553 fTs.reset();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003554 }
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +00003555
caryclark@google.com4eeda372012-12-06 21:47:48 +00003556 void setOppXor(bool isOppXor) {
3557 fOppXor = isOppXor;
3558 }
3559
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003560 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3561 int deltaSum = spanSign(index, endIndex);
3562 maxWinding = sumWinding;
3563 sumWinding = sumWinding -= deltaSum;
3564 }
3565
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003566 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3567 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3568 int deltaSum = spanSign(index, endIndex);
3569 int oppDeltaSum = oppSign(index, endIndex);
3570 if (operand()) {
3571 maxWinding = sumSuWinding;
3572 sumWinding = sumSuWinding -= deltaSum;
3573 oppMaxWinding = sumMiWinding;
3574 oppSumWinding = sumMiWinding -= oppDeltaSum;
3575 } else {
3576 maxWinding = sumMiWinding;
3577 sumWinding = sumMiWinding -= deltaSum;
3578 oppMaxWinding = sumSuWinding;
3579 oppSumWinding = sumSuWinding -= oppDeltaSum;
3580 }
3581 }
3582
caryclark@google.comf839c032012-10-26 21:03:50 +00003583 // This marks all spans unsortable so that this info is available for early
3584 // exclusion in find top and others. This could be optimized to only mark
3585 // adjacent spans that unsortable. However, this makes it difficult to later
3586 // determine starting points for edge detection in find top and the like.
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003587 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
caryclark@google.comf839c032012-10-26 21:03:50 +00003588 bool sortable = true;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003589 int angleCount = angles.count();
3590 int angleIndex;
3591 angleList.setReserve(angleCount);
3592 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003593 Angle& angle = angles[angleIndex];
caryclark@google.comf839c032012-10-26 21:03:50 +00003594 *angleList.append() = &angle;
3595 sortable &= !angle.unsortable();
3596 }
3597 if (sortable) {
3598 QSort<Angle>(angleList.begin(), angleList.end() - 1);
3599 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3600 if (angles[angleIndex].unsortable()) {
3601 sortable = false;
3602 break;
3603 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003604 }
3605 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003606 if (!sortable) {
3607 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3608 Angle& angle = angles[angleIndex];
3609 angle.segment()->markUnsortable(angle.start(), angle.end());
3610 }
3611 }
3612 return sortable;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003613 }
3614
caryclark@google.com1577e8f2012-05-22 17:01:14 +00003615 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003616 const Span& span(int tIndex) const {
3617 return fTs[tIndex];
3618 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003619
caryclark@google.com235f56a2012-09-14 14:19:30 +00003620 int spanSign(const Angle* angle) const {
3621 SkASSERT(angle->segment() == this);
3622 return spanSign(angle->start(), angle->end());
3623 }
3624
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003625 int spanSign(int startIndex, int endIndex) const {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003626 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3627 : fTs[endIndex].fWindValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003628#if DEBUG_WIND_BUMP
3629 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3630#endif
3631 return result;
3632 }
3633
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003634 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003635 double t(int tIndex) const {
3636 return fTs[tIndex].fT;
3637 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003638
caryclark@google.com10227bf2012-12-28 22:10:41 +00003639 double tAtMid(int start, int end, double mid) const {
3640 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
3641 }
3642
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003643 bool tiny(const Angle* angle) const {
3644 int start = angle->start();
3645 int end = angle->end();
caryclark@google.comf839c032012-10-26 21:03:50 +00003646 const Span& mSpan = fTs[SkMin32(start, end)];
3647 return mSpan.fTiny;
3648 }
3649
caryclark@google.com18063442012-07-25 12:05:18 +00003650 static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3651 double start) {
3652 int outCount = outsideTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003653 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
caryclark@google.com18063442012-07-25 12:05:18 +00003654 *outsideTs.append() = end;
3655 *outsideTs.append() = start;
3656 }
3657 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003658
caryclark@google.com24bec792012-08-20 12:43:57 +00003659 void undoneSpan(int& start, int& end) {
3660 size_t tCount = fTs.count();
3661 size_t index;
3662 for (index = 0; index < tCount; ++index) {
3663 if (!fTs[index].fDone) {
3664 break;
3665 }
3666 }
3667 SkASSERT(index < tCount - 1);
3668 start = index;
3669 double startT = fTs[index].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003670 while (approximately_negative(fTs[++index].fT - startT))
caryclark@google.com24bec792012-08-20 12:43:57 +00003671 SkASSERT(index < tCount);
3672 SkASSERT(index < tCount);
3673 end = index;
3674 }
caryclark@google.com18063442012-07-25 12:05:18 +00003675
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003676 bool unsortable(int index) const {
3677 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3678 }
3679
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003680 void updatePts(const SkPoint pts[]) {
3681 fPts = pts;
3682 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003683
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003684 int updateOppWinding(int index, int endIndex) const {
3685 int lesser = SkMin32(index, endIndex);
3686 int oppWinding = oppSum(lesser);
3687 int oppSpanWinding = oppSign(index, endIndex);
3688 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)) {
3689 oppWinding -= oppSpanWinding;
3690 }
3691 return oppWinding;
3692 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003693
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003694 int updateOppWinding(const Angle* angle) const {
3695 int startIndex = angle->start();
3696 int endIndex = angle->end();
3697 return updateOppWinding(endIndex, startIndex);
3698 }
3699
3700 int updateOppWindingReverse(const Angle* angle) const {
3701 int startIndex = angle->start();
3702 int endIndex = angle->end();
3703 return updateOppWinding(startIndex, endIndex);
3704 }
3705
3706 int updateWinding(int index, int endIndex) const {
3707 int lesser = SkMin32(index, endIndex);
3708 int winding = windSum(lesser);
3709 int spanWinding = spanSign(index, endIndex);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003710 if (winding && useInnerWinding(winding - spanWinding, winding)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003711 winding -= spanWinding;
3712 }
3713 return winding;
3714 }
3715
3716 int updateWinding(const Angle* angle) const {
3717 int startIndex = angle->start();
3718 int endIndex = angle->end();
3719 return updateWinding(endIndex, startIndex);
3720 }
3721
3722 int updateWindingReverse(const Angle* angle) const {
3723 int startIndex = angle->start();
3724 int endIndex = angle->end();
3725 return updateWinding(startIndex, endIndex);
3726 }
3727
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003728 SkPath::Verb verb() const {
3729 return fVerb;
3730 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003731
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003732 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003733 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3734 return SK_MinS32;
3735 }
3736 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3737 SkASSERT(winding != SK_MinS32);
3738 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003739 #if DEBUG_WINDING_AT_T
3740 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003741 #endif
3742 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark@google.com3586ece2012-12-27 18:46:58 +00003743 dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003744 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3745 dx = fPts[2].fX - fPts[1].fX - dx;
3746 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003747 if (dx == 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003748 #if DEBUG_WINDING_AT_T
3749 SkDebugf(" dx=0 winding=SK_MinS32\n");
3750 #endif
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003751 return SK_MinS32;
3752 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003753 if (winding * dx > 0) { // if same signs, result is negative
3754 winding += dx > 0 ? -windVal : windVal;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003755 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003756 #if DEBUG_WINDING_AT_T
3757 SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding);
3758 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003759 return winding;
3760 }
3761
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003762 int windSum(int tIndex) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003763 return fTs[tIndex].fWindSum;
3764 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003765
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003766 int windSum(const Angle* angle) const {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003767 int start = angle->start();
3768 int end = angle->end();
3769 int index = SkMin32(start, end);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003770 return windSum(index);
caryclark@google.com495f8e42012-05-31 13:13:11 +00003771 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003772
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003773 int windValue(int tIndex) const {
3774 return fTs[tIndex].fWindValue;
3775 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003776
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003777 int windValue(const Angle* angle) const {
3778 int start = angle->start();
3779 int end = angle->end();
3780 int index = SkMin32(start, end);
3781 return windValue(index);
3782 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00003783
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003784 int windValueAt(double t) const {
3785 int count = fTs.count();
3786 for (int index = 0; index < count; ++index) {
3787 if (fTs[index].fT == t) {
3788 return fTs[index].fWindValue;
3789 }
3790 }
3791 SkASSERT(0);
3792 return 0;
3793 }
3794
caryclark@google.com3586ece2012-12-27 18:46:58 +00003795 SkScalar xAtT(int index) const {
3796 return xAtT(&fTs[index]);
3797 }
3798
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003799 SkScalar xAtT(const Span* span) const {
3800 return xyAtT(span).fX;
3801 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003802
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003803 const SkPoint& xyAtT(int index) const {
3804 return xyAtT(&fTs[index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003805 }
3806
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003807 const SkPoint& xyAtT(const Span* span) const {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003808 if (SkScalarIsNaN(span->fPt.fX)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003809 if (span->fT == 0) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003810 span->fPt = fPts[0];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003811 } else if (span->fT == 1) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003812 span->fPt = fPts[fVerb];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003813 } else {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003814 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003815 }
3816 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00003817 return span->fPt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003818 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003819
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003820 // used only by right angle winding finding
caryclark@google.com10227bf2012-12-28 22:10:41 +00003821 void xyAtT(double mid, SkPoint& pt) const {
3822 (*SegmentXYAtT[fVerb])(fPts, mid, &pt);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003823 }
3824
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003825 SkScalar yAtT(int index) const {
3826 return yAtT(&fTs[index]);
3827 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003828
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003829 SkScalar yAtT(const Span* span) const {
3830 return xyAtT(span).fY;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003831 }
3832
caryclark@google.com4eeda372012-12-06 21:47:48 +00003833 void zeroCoincidentOpp(Span* oTest, int index) {
3834 Span* const test = &fTs[index];
3835 Span* end = test;
3836 do {
3837 end->fOppValue = 0;
3838 end = &fTs[++index];
3839 } while (approximately_negative(end->fT - test->fT));
3840 }
3841
3842 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
3843 Span* const oTest = &fTs[oIndex];
3844 Span* oEnd = oTest;
3845 const double startT = test->fT;
3846 const double oStartT = oTest->fT;
3847 double otherTMatch = (test->fT - startT) * tRatio + oStartT;
3848 while (!approximately_negative(oEndT - oEnd->fT)
3849 && approximately_negative(oEnd->fT - otherTMatch)) {
3850 oEnd->fOppValue = 0;
3851 oEnd = &fTs[++oIndex];
3852 }
3853 }
3854
3855 void zeroSpan(Span* span) {
3856 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
caryclark@google.com6ec15262012-11-16 20:16:50 +00003857 span->fWindValue = 0;
caryclark@google.com729e1c42012-11-21 21:36:34 +00003858 span->fOppValue = 0;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003859 SkASSERT(!span->fDone);
3860 span->fDone = true;
3861 ++fDoneSpans;
caryclark@google.com6ec15262012-11-16 20:16:50 +00003862 }
3863
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003864#if DEBUG_DUMP
3865 void dump() const {
3866 const char className[] = "Segment";
3867 const int tab = 4;
3868 for (int i = 0; i < fTs.count(); ++i) {
3869 SkPoint out;
3870 (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
3871 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003872 " otherT=%1.9g windSum=%d\n",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003873 tab + sizeof(className), className, fID,
3874 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003875 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003876 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00003877 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003878 tab + sizeof(className), className, fID,
caryclark@google.com15fa1382012-05-07 20:49:36 +00003879 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003880 }
3881#endif
3882
caryclark@google.com47580692012-07-23 12:14:49 +00003883#if DEBUG_CONCIDENT
caryclark@google.comaa358312013-01-29 20:28:49 +00003884 // SkASSERT if pair has not already been added
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003885 void debugAddTPair(double t, const Segment& other, double otherT) const {
caryclark@google.comcc905052012-07-25 20:59:42 +00003886 for (int i = 0; i < fTs.count(); ++i) {
3887 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
3888 return;
3889 }
3890 }
3891 SkASSERT(0);
3892 }
3893#endif
3894
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003895#if DEBUG_DUMP
3896 int debugID() const {
3897 return fID;
3898 }
3899#endif
3900
caryclark@google.com24bec792012-08-20 12:43:57 +00003901#if DEBUG_WINDING
3902 void debugShowSums() const {
3903 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
3904 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
3905 for (int i = 0; i < fTs.count(); ++i) {
3906 const Span& span = fTs[i];
3907 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
3908 if (span.fWindSum == SK_MinS32) {
3909 SkDebugf("?");
3910 } else {
3911 SkDebugf("%d", span.fWindSum);
3912 }
3913 SkDebugf("]");
3914 }
3915 SkDebugf("\n");
3916 }
3917#endif
3918
caryclark@google.comcc905052012-07-25 20:59:42 +00003919#if DEBUG_CONCIDENT
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003920 void debugShowTs() const {
caryclark@google.com24bec792012-08-20 12:43:57 +00003921 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003922 int lastWind = -1;
3923 int lastOpp = -1;
3924 double lastT = -1;
3925 int i;
3926 for (i = 0; i < fTs.count(); ++i) {
3927 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
3928 || lastOpp != fTs[i].fOppValue;
3929 if (change && lastWind >= 0) {
3930 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3931 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3932 }
3933 if (change) {
3934 SkDebugf(" [o=%d", fTs[i].fOther->fID);
3935 lastWind = fTs[i].fWindValue;
3936 lastOpp = fTs[i].fOppValue;
3937 lastT = fTs[i].fT;
3938 } else {
3939 SkDebugf(",%d", fTs[i].fOther->fID);
3940 }
3941 }
3942 if (i <= 0) {
3943 return;
3944 }
3945 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3946 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3947 if (fOperand) {
3948 SkDebugf(" operand");
3949 }
3950 if (done()) {
3951 SkDebugf(" done");
caryclark@google.com47580692012-07-23 12:14:49 +00003952 }
3953 SkDebugf("\n");
3954 }
3955#endif
3956
caryclark@google.com027de222012-07-12 12:52:50 +00003957#if DEBUG_ACTIVE_SPANS
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003958 void debugShowActiveSpans() const {
caryclark@google.com027de222012-07-12 12:52:50 +00003959 if (done()) {
3960 return;
3961 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003962#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3963 int lastId = -1;
3964 double lastT = -1;
3965#endif
caryclark@google.com027de222012-07-12 12:52:50 +00003966 for (int i = 0; i < fTs.count(); ++i) {
3967 if (fTs[i].fDone) {
3968 continue;
3969 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003970#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3971 if (lastId == fID && lastT == fTs[i].fT) {
3972 continue;
3973 }
3974 lastId = fID;
3975 lastT = fTs[i].fT;
3976#endif
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003977 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com027de222012-07-12 12:52:50 +00003978 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3979 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3980 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3981 }
3982 const Span* span = &fTs[i];
rmistry@google.comd6176b02012-08-23 18:14:13 +00003983 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
caryclark@google.com0c803d02012-08-06 11:15:47 +00003984 xAtT(span), yAtT(span));
caryclark@google.com47d73da2013-02-17 01:41:25 +00003985 int iEnd = i + 1;
3986 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) {
3987 ++iEnd;
3988 }
3989 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT);
caryclark@google.com027de222012-07-12 12:52:50 +00003990 const Segment* other = fTs[i].fOther;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003991 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
3992 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
3993 if (fTs[i].fWindSum == SK_MinS32) {
3994 SkDebugf("?");
3995 } else {
3996 SkDebugf("%d", fTs[i].fWindSum);
3997 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003998 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
caryclark@google.com027de222012-07-12 12:52:50 +00003999 }
4000 }
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +00004001
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004002 // This isn't useful yet -- but leaving it in for now in case i think of something
4003 // to use it for
4004 void validateActiveSpans() const {
4005 if (done()) {
4006 return;
4007 }
4008 int tCount = fTs.count();
4009 for (int index = 0; index < tCount; ++index) {
4010 if (fTs[index].fDone) {
4011 continue;
4012 }
4013 // count number of connections which are not done
4014 int first = index;
4015 double baseT = fTs[index].fT;
4016 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
4017 --first;
4018 }
4019 int last = index;
4020 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
4021 ++last;
4022 }
4023 int connections = 0;
4024 connections += first > 0 && !fTs[first - 1].fDone;
4025 for (int test = first; test <= last; ++test) {
4026 connections += !fTs[test].fDone;
4027 const Segment* other = fTs[test].fOther;
4028 int oIndex = fTs[test].fOtherIndex;
4029 connections += !other->fTs[oIndex].fDone;
4030 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
4031 }
4032 // SkASSERT(!(connections & 1));
4033 }
4034 }
caryclark@google.com027de222012-07-12 12:52:50 +00004035#endif
4036
caryclark@google.com0c803d02012-08-06 11:15:47 +00004037#if DEBUG_MARK_DONE
4038 void debugShowNewWinding(const char* fun, const Span& span, int winding) {
4039 const SkPoint& pt = xyAtT(&span);
4040 SkDebugf("%s id=%d", fun, fID);
4041 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4042 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4043 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4044 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004045 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4046 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4047 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d windSum=",
4048 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, winding);
caryclark@google.com0c803d02012-08-06 11:15:47 +00004049 if (span.fWindSum == SK_MinS32) {
4050 SkDebugf("?");
4051 } else {
4052 SkDebugf("%d", span.fWindSum);
4053 }
4054 SkDebugf(" windValue=%d\n", span.fWindValue);
4055 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004056
4057 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
4058 const SkPoint& pt = xyAtT(&span);
4059 SkDebugf("%s id=%d", fun, fID);
4060 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4061 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4062 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4063 }
4064 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4065 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4066 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=",
4067 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
4068 winding, oppWinding);
4069 if (span.fOppSum == SK_MinS32) {
4070 SkDebugf("?");
4071 } else {
4072 SkDebugf("%d", span.fOppSum);
4073 }
4074 SkDebugf(" windSum=");
4075 if (span.fWindSum == SK_MinS32) {
4076 SkDebugf("?");
4077 } else {
4078 SkDebugf("%d", span.fWindSum);
4079 }
4080 SkDebugf(" windValue=%d\n", span.fWindValue);
4081 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00004082#endif
4083
caryclark@google.com47580692012-07-23 12:14:49 +00004084#if DEBUG_SORT
caryclark@google.com03f97062012-08-21 13:13:52 +00004085 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
caryclark@google.com31143cf2012-11-09 22:14:19 +00004086 const int contourWinding, const int oppContourWinding) const {
caryclark@google.comafe56de2012-07-24 18:11:03 +00004087 SkASSERT(angles[first]->segment() == this);
caryclark@google.com200c2112012-08-03 15:05:04 +00004088 SkASSERT(angles.count() > 1);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004089 int lastSum = contourWinding;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004090 int oppLastSum = oppContourWinding;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004091 const Angle* firstAngle = angles[first];
4092 int windSum = lastSum - spanSign(firstAngle);
4093 int oppoSign = oppSign(firstAngle);
4094 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004095 SkDebugf("%s %s contourWinding=%d oppContourWinding=%d sign=%d\n", fun, __FUNCTION__,
4096 contourWinding, oppContourWinding, spanSign(angles[first]));
caryclark@google.comafe56de2012-07-24 18:11:03 +00004097 int index = first;
4098 bool firstTime = true;
caryclark@google.com47580692012-07-23 12:14:49 +00004099 do {
4100 const Angle& angle = *angles[index];
4101 const Segment& segment = *angle.segment();
4102 int start = angle.start();
4103 int end = angle.end();
4104 const Span& sSpan = segment.fTs[start];
4105 const Span& eSpan = segment.fTs[end];
4106 const Span& mSpan = segment.fTs[SkMin32(start, end)];
caryclark@google.com31143cf2012-11-09 22:14:19 +00004107 bool opp = segment.fOperand ^ fOperand;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004108 if (!firstTime) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004109 oppoSign = segment.oppSign(&angle);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004110 if (opp) {
4111 oppLastSum = oppWindSum;
4112 oppWindSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004113 if (oppoSign) {
4114 lastSum = windSum;
4115 windSum -= oppoSign;
4116 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004117 } else {
4118 lastSum = windSum;
4119 windSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004120 if (oppoSign) {
4121 oppLastSum = oppWindSum;
4122 oppWindSum -= oppoSign;
4123 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004124 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004125 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004126 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 +00004127 " sign=%d windValue=%d windSum=",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004128 __FUNCTION__, index, angle.unsortable() ? "*** UNSORTABLE *** " : "",
caryclark@google.comc91dfe42012-10-16 12:06:27 +00004129 segment.fID, kLVerbStr[segment.fVerb],
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004130 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
4131 segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(),
4132 mSpan.fWindValue);
4133 if (mSpan.fWindSum == SK_MinS32) {
4134 SkDebugf("?");
4135 } else {
4136 SkDebugf("%d", mSpan.fWindSum);
4137 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004138 int last, wind;
4139 if (opp) {
4140 last = oppLastSum;
4141 wind = oppWindSum;
4142 } else {
4143 last = lastSum;
4144 wind = windSum;
4145 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004146 if (!oppoSign) {
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00004147 SkDebugf(" %d->%d (max=%d)", last, wind,
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004148 useInnerWinding(last, wind) ? wind : last);
4149 } else {
4150 SkDebugf(" %d->%d (%d->%d)", last, wind, opp ? lastSum : oppLastSum,
4151 opp ? windSum : oppWindSum);
4152 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004153 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004154#if false && DEBUG_ANGLE
caryclark@google.comc899ad92012-08-23 15:24:42 +00004155 angle.debugShow(segment.xyAtT(&sSpan));
4156#endif
caryclark@google.com47580692012-07-23 12:14:49 +00004157 ++index;
4158 if (index == angles.count()) {
4159 index = 0;
4160 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004161 if (firstTime) {
4162 firstTime = false;
4163 }
caryclark@google.com47580692012-07-23 12:14:49 +00004164 } while (index != first);
4165 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00004166
4167 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
4168 const Angle* firstAngle = angles[first];
4169 const Segment* segment = firstAngle->segment();
4170 int winding = segment->updateWinding(firstAngle);
4171 int oppWinding = segment->updateOppWinding(firstAngle);
4172 debugShowSort(fun, angles, first, winding, oppWinding);
4173 }
4174
caryclark@google.com47580692012-07-23 12:14:49 +00004175#endif
4176
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004177#if DEBUG_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004178 static char as_digit(int value) {
4179 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
4180 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004181#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004182
caryclark@google.com729e1c42012-11-21 21:36:34 +00004183#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004184 int debugShowWindingValues(int slotCount, int ofInterest) const {
4185 if (!(1 << fID & ofInterest)) {
4186 return 0;
4187 }
4188 int sum = 0;
4189 SkTDArray<char> slots;
4190 slots.setCount(slotCount * 2);
4191 memset(slots.begin(), ' ', slotCount * 2);
4192 for (int i = 0; i < fTs.count(); ++i) {
4193 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
4194 // continue;
4195 // }
4196 sum += fTs[i].fWindValue;
4197 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
4198 sum += fTs[i].fOppValue;
4199 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
4200 }
4201 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
4202 slots.begin() + slotCount);
4203 return sum;
4204 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004205#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004206
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004207private:
4208 const SkPoint* fPts;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004209 Bounds fBounds;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004210 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
caryclark@google.com4eeda372012-12-06 21:47:48 +00004211 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
caryclark@google.com24bec792012-08-20 12:43:57 +00004212 int fDoneSpans; // quick check that segment is finished
caryclark@google.com4eeda372012-12-06 21:47:48 +00004213 // OPTIMIZATION: force the following to be byte-sized
4214 SkPath::Verb fVerb;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004215 bool fOperand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004216 bool fXor; // set if original contour had even-odd fill
4217 bool fOppXor; // set if opposite operand had even-odd fill
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004218#if DEBUG_DUMP
4219 int fID;
4220#endif
4221};
4222
caryclark@google.comb9738012012-07-03 19:53:30 +00004223class Contour;
4224
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004225struct Coincidence {
caryclark@google.comb9738012012-07-03 19:53:30 +00004226 Contour* fContours[2];
4227 int fSegments[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004228 double fTs[2][2];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004229 SkPoint fPts[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004230};
4231
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004232class Contour {
4233public:
4234 Contour() {
4235 reset();
4236#if DEBUG_DUMP
4237 fID = ++gContourID;
4238#endif
4239 }
4240
4241 bool operator<(const Contour& rh) const {
4242 return fBounds.fTop == rh.fBounds.fTop
4243 ? fBounds.fLeft < rh.fBounds.fLeft
4244 : fBounds.fTop < rh.fBounds.fTop;
4245 }
4246
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004247 void addCoincident(int index, Contour* other, int otherIndex,
4248 const Intersections& ts, bool swap) {
4249 Coincidence& coincidence = *fCoincidences.append();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004250 coincidence.fContours[0] = this; // FIXME: no need to store
caryclark@google.comb9738012012-07-03 19:53:30 +00004251 coincidence.fContours[1] = other;
4252 coincidence.fSegments[0] = index;
4253 coincidence.fSegments[1] = otherIndex;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004254 coincidence.fTs[swap][0] = ts.fT[0][0];
4255 coincidence.fTs[swap][1] = ts.fT[0][1];
4256 coincidence.fTs[!swap][0] = ts.fT[1][0];
4257 coincidence.fTs[!swap][1] = ts.fT[1][1];
4258 coincidence.fPts[0] = ts.fPt[0].asSkPoint();
4259 coincidence.fPts[1] = ts.fPt[1].asSkPoint();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004260 }
4261
4262 void addCross(const Contour* crosser) {
4263#ifdef DEBUG_CROSS
4264 for (int index = 0; index < fCrosses.count(); ++index) {
4265 SkASSERT(fCrosses[index] != crosser);
4266 }
4267#endif
4268 *fCrosses.append() = crosser;
4269 }
4270
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004271 void addCubic(const SkPoint pts[4]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004272 fSegments.push_back().addCubic(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004273 fContainsCurves = true;
4274 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004275
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004276 int addLine(const SkPoint pts[2]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004277 fSegments.push_back().addLine(pts, fOperand, fXor);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004278 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004279 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004280
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004281 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
4282 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
4283 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004284
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004285 int addQuad(const SkPoint pts[3]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004286 fSegments.push_back().addQuad(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004287 fContainsCurves = true;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004288 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004289 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004290
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004291 int addT(int segIndex, double newT, Contour* other, int otherIndex, const SkPoint& pt) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004292 containsIntercepts();
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004293 return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex], pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004294 }
4295
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004296 int addUnsortableT(int segIndex, double newT, Contour* other, int otherIndex, bool start,
4297 const SkPoint& pt) {
4298 return fSegments[segIndex].addUnsortableT(newT, &other->fSegments[otherIndex], start, pt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00004299 }
4300
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004301 const Bounds& bounds() const {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004302 return fBounds;
4303 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004304
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004305 void complete() {
4306 setBounds();
4307 fContainsIntercepts = false;
4308 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004309
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004310 void containsIntercepts() {
4311 fContainsIntercepts = true;
4312 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004313
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004314 bool crosses(const Contour* crosser) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004315 for (int index = 0; index < fCrosses.count(); ++index) {
4316 if (fCrosses[index] == crosser) {
4317 return true;
4318 }
4319 }
4320 return false;
4321 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004322
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004323 bool done() const {
4324 return fDone;
4325 }
4326
caryclark@google.comf839c032012-10-26 21:03:50 +00004327 const SkPoint& end() const {
4328 const Segment& segment = fSegments.back();
4329 return segment.pts()[segment.verb()];
4330 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004331
caryclark@google.com4eeda372012-12-06 21:47:48 +00004332 void findTooCloseToCall() {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004333 int segmentCount = fSegments.count();
4334 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004335 fSegments[sIndex].findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004336 }
4337 }
4338
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004339 void fixOtherTIndex() {
4340 int segmentCount = fSegments.count();
4341 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4342 fSegments[sIndex].fixOtherTIndex();
4343 }
4344 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004345
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004346 Segment* nonVerticalSegment(int& start, int& end) {
4347 int segmentCount = fSortedSegments.count();
4348 SkASSERT(segmentCount > 0);
4349 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4350 Segment* testSegment = fSortedSegments[sortedIndex];
4351 if (testSegment->done()) {
4352 continue;
4353 }
4354 start = end = 0;
4355 while (testSegment->nextCandidate(start, end)) {
4356 if (!testSegment->isVertical(start, end)) {
4357 return testSegment;
4358 }
4359 }
4360 }
4361 return NULL;
4362 }
4363
caryclark@google.com31143cf2012-11-09 22:14:19 +00004364 bool operand() const {
4365 return fOperand;
4366 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004367
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004368 void reset() {
4369 fSegments.reset();
4370 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004371 fContainsCurves = fContainsIntercepts = fDone = false;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004372 }
caryclark@google.comb9738012012-07-03 19:53:30 +00004373
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004374 void resolveCoincidence(SkTDArray<Contour*>& contourList) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004375 int count = fCoincidences.count();
4376 for (int index = 0; index < count; ++index) {
4377 Coincidence& coincidence = fCoincidences[index];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004378 SkASSERT(coincidence.fContours[0] == this);
caryclark@google.comb9738012012-07-03 19:53:30 +00004379 int thisIndex = coincidence.fSegments[0];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004380 Segment& thisOne = fSegments[thisIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004381 Contour* otherContour = coincidence.fContours[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004382 int otherIndex = coincidence.fSegments[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004383 Segment& other = otherContour->fSegments[otherIndex];
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004384 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004385 continue;
4386 }
caryclark@google.com47580692012-07-23 12:14:49 +00004387 #if DEBUG_CONCIDENT
4388 thisOne.debugShowTs();
4389 other.debugShowTs();
4390 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004391 double startT = coincidence.fTs[0][0];
4392 double endT = coincidence.fTs[0][1];
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004393 bool cancelers = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004394 if (startT > endT) {
4395 SkTSwap<double>(startT, endT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004396 cancelers ^= true; // FIXME: just assign true
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004397 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004398 SkASSERT(!approximately_negative(endT - startT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004399 double oStartT = coincidence.fTs[1][0];
4400 double oEndT = coincidence.fTs[1][1];
4401 if (oStartT > oEndT) {
4402 SkTSwap<double>(oStartT, oEndT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004403 cancelers ^= true;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004404 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004405 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00004406 bool opp = fOperand ^ otherContour->fOperand;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004407 if (cancelers && !opp) {
4408 // make sure startT and endT have t entries
caryclark@google.com2ddff932012-08-07 21:25:27 +00004409 if (startT > 0 || oEndT < 1
4410 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004411 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004412 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00004413 if (oStartT > 0 || endT < 1
4414 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004415 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004416 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004417 if (!thisOne.done() && !other.done()) {
4418 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4419 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004420 } else {
caryclark@google.com200c2112012-08-03 15:05:04 +00004421 if (startT > 0 || oStartT > 0
4422 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004423 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004424 }
caryclark@google.com200c2112012-08-03 15:05:04 +00004425 if (endT < 1 || oEndT < 1
4426 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004427 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004428 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004429 if (!thisOne.done() && !other.done()) {
4430 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4431 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004432 }
caryclark@google.com47580692012-07-23 12:14:49 +00004433 #if DEBUG_CONCIDENT
4434 thisOne.debugShowTs();
4435 other.debugShowTs();
4436 #endif
caryclark@google.com729e1c42012-11-21 21:36:34 +00004437 #if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004438 debugShowWindingValues(contourList);
4439 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004440 }
4441 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004442
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004443 // first pass, add missing T values
4444 // second pass, determine winding values of overlaps
4445 void addCoincidentPoints() {
4446 int count = fCoincidences.count();
4447 for (int index = 0; index < count; ++index) {
4448 Coincidence& coincidence = fCoincidences[index];
4449 SkASSERT(coincidence.fContours[0] == this);
4450 int thisIndex = coincidence.fSegments[0];
4451 Segment& thisOne = fSegments[thisIndex];
4452 Contour* otherContour = coincidence.fContours[1];
4453 int otherIndex = coincidence.fSegments[1];
4454 Segment& other = otherContour->fSegments[otherIndex];
4455 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
4456 // OPTIMIZATION: remove from array
4457 continue;
4458 }
4459 #if DEBUG_CONCIDENT
4460 thisOne.debugShowTs();
4461 other.debugShowTs();
4462 #endif
4463 double startT = coincidence.fTs[0][0];
4464 double endT = coincidence.fTs[0][1];
4465 bool cancelers;
4466 if ((cancelers = startT > endT)) {
4467 SkTSwap<double>(startT, endT);
4468 }
4469 SkASSERT(!approximately_negative(endT - startT));
4470 double oStartT = coincidence.fTs[1][0];
4471 double oEndT = coincidence.fTs[1][1];
4472 if (oStartT > oEndT) {
4473 SkTSwap<double>(oStartT, oEndT);
4474 cancelers ^= true;
4475 }
4476 SkASSERT(!approximately_negative(oEndT - oStartT));
4477 bool opp = fOperand ^ otherContour->fOperand;
4478 if (cancelers && !opp) {
4479 // make sure startT and endT have t entries
4480 if (startT > 0 || oEndT < 1
4481 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004482 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004483 }
4484 if (oStartT > 0 || endT < 1
4485 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004486 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004487 }
4488 } else {
4489 if (startT > 0 || oStartT > 0
4490 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004491 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004492 }
4493 if (endT < 1 || oEndT < 1
4494 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004495 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004496 }
4497 }
4498 #if DEBUG_CONCIDENT
4499 thisOne.debugShowTs();
4500 other.debugShowTs();
4501 #endif
4502 }
4503 }
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00004504
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004505 void calcCoincidentWinding() {
4506 int count = fCoincidences.count();
4507 for (int index = 0; index < count; ++index) {
4508 Coincidence& coincidence = fCoincidences[index];
4509 SkASSERT(coincidence.fContours[0] == this);
4510 int thisIndex = coincidence.fSegments[0];
4511 Segment& thisOne = fSegments[thisIndex];
4512 if (thisOne.done()) {
4513 continue;
4514 }
4515 Contour* otherContour = coincidence.fContours[1];
4516 int otherIndex = coincidence.fSegments[1];
4517 Segment& other = otherContour->fSegments[otherIndex];
4518 if (other.done()) {
4519 continue;
4520 }
4521 double startT = coincidence.fTs[0][0];
4522 double endT = coincidence.fTs[0][1];
4523 bool cancelers;
4524 if ((cancelers = startT > endT)) {
4525 SkTSwap<double>(startT, endT);
4526 }
4527 SkASSERT(!approximately_negative(endT - startT));
4528 double oStartT = coincidence.fTs[1][0];
4529 double oEndT = coincidence.fTs[1][1];
4530 if (oStartT > oEndT) {
4531 SkTSwap<double>(oStartT, oEndT);
4532 cancelers ^= true;
4533 }
4534 SkASSERT(!approximately_negative(oEndT - oStartT));
4535 bool opp = fOperand ^ otherContour->fOperand;
4536 if (cancelers && !opp) {
4537 // make sure startT and endT have t entries
4538 if (!thisOne.done() && !other.done()) {
4539 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4540 }
4541 } else {
4542 if (!thisOne.done() && !other.done()) {
4543 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4544 }
4545 }
4546 #if DEBUG_CONCIDENT
4547 thisOne.debugShowTs();
4548 other.debugShowTs();
4549 #endif
4550 }
4551 }
4552
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004553 SkTArray<Segment>& segments() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004554 return fSegments;
4555 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004556
caryclark@google.com235f56a2012-09-14 14:19:30 +00004557 void setOperand(bool isOp) {
4558 fOperand = isOp;
4559 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00004560
caryclark@google.com4eeda372012-12-06 21:47:48 +00004561 void setOppXor(bool isOppXor) {
4562 fOppXor = isOppXor;
4563 int segmentCount = fSegments.count();
4564 for (int test = 0; test < segmentCount; ++test) {
4565 fSegments[test].setOppXor(isOppXor);
4566 }
4567 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004568
caryclark@google.com235f56a2012-09-14 14:19:30 +00004569 void setXor(bool isXor) {
4570 fXor = isXor;
4571 }
4572
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004573 void sortSegments() {
4574 int segmentCount = fSegments.count();
4575 fSortedSegments.setReserve(segmentCount);
4576 for (int test = 0; test < segmentCount; ++test) {
4577 *fSortedSegments.append() = &fSegments[test];
4578 }
4579 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4580 fFirstSorted = 0;
4581 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004582
caryclark@google.comf839c032012-10-26 21:03:50 +00004583 const SkPoint& start() const {
4584 return fSegments.front().pts()[0];
4585 }
4586
4587 void toPath(PathWrapper& path) const {
4588 int segmentCount = fSegments.count();
4589 const SkPoint& pt = fSegments.front().pts()[0];
4590 path.deferredMove(pt);
4591 for (int test = 0; test < segmentCount; ++test) {
4592 fSegments[test].addCurveTo(0, 1, path, true);
4593 }
4594 path.close();
4595 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004596
caryclark@google.comf839c032012-10-26 21:03:50 +00004597 void toPartialBackward(PathWrapper& path) const {
4598 int segmentCount = fSegments.count();
4599 for (int test = segmentCount - 1; test >= 0; --test) {
4600 fSegments[test].addCurveTo(1, 0, path, true);
4601 }
4602 }
4603
4604 void toPartialForward(PathWrapper& path) const {
4605 int segmentCount = fSegments.count();
4606 for (int test = 0; test < segmentCount; ++test) {
4607 fSegments[test].addCurveTo(0, 1, path, true);
4608 }
4609 }
4610
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004611 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004612 int segmentCount = fSortedSegments.count();
4613 SkASSERT(segmentCount > 0);
caryclark@google.comf839c032012-10-26 21:03:50 +00004614 int sortedIndex = fFirstSorted;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004615 fDone = true; // may be cleared below
caryclark@google.comf839c032012-10-26 21:03:50 +00004616 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4617 Segment* testSegment = fSortedSegments[sortedIndex];
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004618 if (testSegment->done()) {
caryclark@google.comf839c032012-10-26 21:03:50 +00004619 if (sortedIndex == fFirstSorted) {
4620 ++fFirstSorted;
4621 }
4622 continue;
4623 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004624 fDone = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004625 SkPoint testXY = testSegment->activeLeftTop(true, NULL);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004626 if (topStart) {
4627 if (testXY.fY < topLeft.fY) {
4628 continue;
4629 }
4630 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4631 continue;
4632 }
4633 if (bestXY.fY < testXY.fY) {
4634 continue;
4635 }
4636 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4637 continue;
4638 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004639 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004640 topStart = testSegment;
caryclark@google.comf839c032012-10-26 21:03:50 +00004641 bestXY = testXY;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004642 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004643 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004644
caryclark@google.com24bec792012-08-20 12:43:57 +00004645 Segment* undoneSegment(int& start, int& end) {
4646 int segmentCount = fSegments.count();
4647 for (int test = 0; test < segmentCount; ++test) {
4648 Segment* testSegment = &fSegments[test];
4649 if (testSegment->done()) {
4650 continue;
4651 }
4652 testSegment->undoneSpan(start, end);
4653 return testSegment;
4654 }
4655 return NULL;
4656 }
4657
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004658 int updateSegment(int index, const SkPoint* pts) {
4659 Segment& segment = fSegments[index];
4660 segment.updatePts(pts);
4661 return segment.verb() + 1;
4662 }
4663
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004664#if DEBUG_TEST
4665 SkTArray<Segment>& debugSegments() {
4666 return fSegments;
4667 }
4668#endif
4669
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004670#if DEBUG_DUMP
4671 void dump() {
4672 int i;
4673 const char className[] = "Contour";
4674 const int tab = 4;
4675 SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4676 for (i = 0; i < fSegments.count(); ++i) {
4677 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4678 className, i);
4679 fSegments[i].dump();
4680 }
4681 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4682 tab + sizeof(className), className,
4683 fBounds.fLeft, fBounds.fTop,
4684 fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004685 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4686 className, fContainsIntercepts);
4687 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4688 className, fContainsCurves);
4689 }
4690#endif
4691
caryclark@google.com027de222012-07-12 12:52:50 +00004692#if DEBUG_ACTIVE_SPANS
4693 void debugShowActiveSpans() {
4694 for (int index = 0; index < fSegments.count(); ++index) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004695 fSegments[index].debugShowActiveSpans();
caryclark@google.com027de222012-07-12 12:52:50 +00004696 }
4697 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004698
4699 void validateActiveSpans() {
4700 for (int index = 0; index < fSegments.count(); ++index) {
4701 fSegments[index].validateActiveSpans();
4702 }
4703 }
caryclark@google.com027de222012-07-12 12:52:50 +00004704#endif
4705
caryclark@google.com729e1c42012-11-21 21:36:34 +00004706#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004707 int debugShowWindingValues(int totalSegments, int ofInterest) {
4708 int count = fSegments.count();
4709 int sum = 0;
4710 for (int index = 0; index < count; ++index) {
4711 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4712 }
4713 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4714 return sum;
4715 }
4716
4717 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4718 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4719 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4720 int ofInterest = 1 << 5 | 1 << 8;
4721 int total = 0;
4722 int index;
4723 for (index = 0; index < contourList.count(); ++index) {
4724 total += contourList[index]->segments().count();
4725 }
4726 int sum = 0;
4727 for (index = 0; index < contourList.count(); ++index) {
4728 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4729 }
4730 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4731 }
4732#endif
4733
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004734protected:
4735 void setBounds() {
4736 int count = fSegments.count();
4737 if (count == 0) {
4738 SkDebugf("%s empty contour\n", __FUNCTION__);
4739 SkASSERT(0);
4740 // FIXME: delete empty contour?
4741 return;
4742 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004743 fBounds = fSegments.front().bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004744 for (int index = 1; index < count; ++index) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004745 fBounds.add(fSegments[index].bounds());
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004746 }
4747 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004748
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004749private:
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004750 SkTArray<Segment> fSegments;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004751 SkTDArray<Segment*> fSortedSegments;
4752 int fFirstSorted;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004753 SkTDArray<Coincidence> fCoincidences;
4754 SkTDArray<const Contour*> fCrosses;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004755 Bounds fBounds;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004756 bool fContainsIntercepts;
4757 bool fContainsCurves;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004758 bool fDone;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004759 bool fOperand; // true for the second argument to a binary operator
4760 bool fXor;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004761 bool fOppXor;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004762#if DEBUG_DUMP
4763 int fID;
4764#endif
4765};
4766
4767class EdgeBuilder {
4768public:
4769
caryclark@google.comf839c032012-10-26 21:03:50 +00004770EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
4771 : fPath(path.nativePath())
4772 , fContours(contours)
4773{
4774 init();
4775}
4776
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004777EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
caryclark@google.com235f56a2012-09-14 14:19:30 +00004778 : fPath(&path)
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004779 , fContours(contours)
4780{
caryclark@google.comf839c032012-10-26 21:03:50 +00004781 init();
4782}
4783
4784void init() {
4785 fCurrentContour = NULL;
4786 fOperand = false;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004787 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004788#if DEBUG_DUMP
4789 gContourID = 0;
4790 gSegmentID = 0;
4791#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00004792 fSecondHalf = preFetch();
4793}
4794
4795void addOperand(const SkPath& path) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00004796 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
4797 fPathVerbs.pop();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004798 fPath = &path;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004799 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004800 preFetch();
4801}
4802
4803void finish() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004804 walk();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004805 complete();
4806 if (fCurrentContour && !fCurrentContour->segments().count()) {
4807 fContours.pop_back();
4808 }
4809 // correct pointers in contours since fReducePts may have moved as it grew
4810 int cIndex = 0;
4811 int extraCount = fExtra.count();
4812 SkASSERT(extraCount == 0 || fExtra[0] == -1);
4813 int eIndex = 0;
4814 int rIndex = 0;
4815 while (++eIndex < extraCount) {
4816 int offset = fExtra[eIndex];
4817 if (offset < 0) {
4818 ++cIndex;
4819 continue;
4820 }
4821 fCurrentContour = &fContours[cIndex];
4822 rIndex += fCurrentContour->updateSegment(offset - 1,
4823 &fReducePts[rIndex]);
4824 }
4825 fExtra.reset(); // we're done with this
4826}
4827
4828ShapeOpMask xorMask() const {
caryclark@google.com729e1c42012-11-21 21:36:34 +00004829 return fXorMask[fOperand];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004830}
4831
4832protected:
4833
4834void complete() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004835 if (fCurrentContour && fCurrentContour->segments().count()) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004836 fCurrentContour->complete();
4837 fCurrentContour = NULL;
4838 }
4839}
4840
caryclark@google.com235f56a2012-09-14 14:19:30 +00004841// FIXME:remove once we can access path pts directly
4842int preFetch() {
4843 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004844 SkPoint pts[4];
4845 SkPath::Verb verb;
4846 do {
4847 verb = iter.next(pts);
4848 *fPathVerbs.append() = verb;
4849 if (verb == SkPath::kMove_Verb) {
4850 *fPathPts.append() = pts[0];
4851 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
4852 fPathPts.append(verb, &pts[1]);
4853 }
4854 } while (verb != SkPath::kDone_Verb);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004855 return fPathVerbs.count() - 1;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004856}
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004857
caryclark@google.com235f56a2012-09-14 14:19:30 +00004858void walk() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004859 SkPath::Verb reducedVerb;
4860 uint8_t* verbPtr = fPathVerbs.begin();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004861 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004862 const SkPoint* pointsPtr = fPathPts.begin();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004863 const SkPoint* finalCurveStart = NULL;
4864 const SkPoint* finalCurveEnd = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004865 SkPath::Verb verb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004866 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
4867 switch (verb) {
4868 case SkPath::kMove_Verb:
4869 complete();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004870 if (!fCurrentContour) {
4871 fCurrentContour = fContours.push_back_n(1);
caryclark@google.com235f56a2012-09-14 14:19:30 +00004872 fCurrentContour->setOperand(fOperand);
caryclark@google.com729e1c42012-11-21 21:36:34 +00004873 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004874 *fExtra.append() = -1; // start new contour
4875 }
caryclark@google.com59823f72012-08-09 18:17:47 +00004876 finalCurveEnd = pointsPtr++;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004877 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004878 case SkPath::kLine_Verb:
4879 // skip degenerate points
4880 if (pointsPtr[-1].fX != pointsPtr[0].fX
4881 || pointsPtr[-1].fY != pointsPtr[0].fY) {
4882 fCurrentContour->addLine(&pointsPtr[-1]);
4883 }
4884 break;
4885 case SkPath::kQuad_Verb:
rmistry@google.comd6176b02012-08-23 18:14:13 +00004886
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004887 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
4888 if (reducedVerb == 0) {
4889 break; // skip degenerate points
4890 }
4891 if (reducedVerb == 1) {
rmistry@google.comd6176b02012-08-23 18:14:13 +00004892 *fExtra.append() =
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004893 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004894 break;
4895 }
4896 fCurrentContour->addQuad(&pointsPtr[-1]);
4897 break;
4898 case SkPath::kCubic_Verb:
4899 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
4900 if (reducedVerb == 0) {
4901 break; // skip degenerate points
4902 }
4903 if (reducedVerb == 1) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004904 *fExtra.append() =
4905 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004906 break;
4907 }
4908 if (reducedVerb == 2) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004909 *fExtra.append() =
4910 fCurrentContour->addQuad(fReducePts.end() - 3);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004911 break;
4912 }
4913 fCurrentContour->addCubic(&pointsPtr[-1]);
4914 break;
4915 case SkPath::kClose_Verb:
4916 SkASSERT(fCurrentContour);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004917 if (finalCurveStart && finalCurveEnd
4918 && *finalCurveStart != *finalCurveEnd) {
4919 *fReducePts.append() = *finalCurveStart;
4920 *fReducePts.append() = *finalCurveEnd;
4921 *fExtra.append() =
4922 fCurrentContour->addLine(fReducePts.end() - 2);
4923 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004924 complete();
caryclark@google.com31143cf2012-11-09 22:14:19 +00004925 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004926 default:
4927 SkDEBUGFAIL("bad verb");
4928 return;
4929 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004930 finalCurveStart = &pointsPtr[verb - 1];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004931 pointsPtr += verb;
4932 SkASSERT(fCurrentContour);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004933 nextVerb:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004934 if (verbPtr == endOfFirstHalf) {
4935 fOperand = true;
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004936 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004937 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004938}
4939
4940private:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004941 const SkPath* fPath;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004942 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004943 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004944 Contour* fCurrentContour;
4945 SkTArray<Contour>& fContours;
4946 SkTDArray<SkPoint> fReducePts; // segments created on the fly
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004947 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
caryclark@google.com729e1c42012-11-21 21:36:34 +00004948 ShapeOpMask fXorMask[2];
caryclark@google.com235f56a2012-09-14 14:19:30 +00004949 int fSecondHalf;
4950 bool fOperand;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004951};
4952
4953class Work {
4954public:
4955 enum SegmentType {
4956 kHorizontalLine_Segment = -1,
4957 kVerticalLine_Segment = 0,
4958 kLine_Segment = SkPath::kLine_Verb,
4959 kQuad_Segment = SkPath::kQuad_Verb,
4960 kCubic_Segment = SkPath::kCubic_Verb,
4961 };
rmistry@google.comd6176b02012-08-23 18:14:13 +00004962
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004963 void addCoincident(Work& other, const Intersections& ts, bool swap) {
4964 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
4965 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004966
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004967 // FIXME: does it make sense to write otherIndex now if we're going to
4968 // fix it up later?
4969 void addOtherT(int index, double otherT, int otherIndex) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004970 fContour->addOtherT(fIndex, index, otherT, otherIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004971 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004972
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004973 // Avoid collapsing t values that are close to the same since
4974 // we walk ts to describe consecutive intersections. Since a pair of ts can
4975 // be nearly equal, any problems caused by this should be taken care
4976 // of later.
4977 // On the edge or out of range values are negative; add 2 to get end
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004978 int addT(double newT, const Work& other, const SkPoint& pt) {
4979 return fContour->addT(fIndex, newT, other.fContour, other.fIndex, pt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004980 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004981
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004982 int addUnsortableT(double newT, const Work& other, bool start, const SkPoint& pt) {
4983 return fContour->addUnsortableT(fIndex, newT, other.fContour, other.fIndex, start, pt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00004984 }
4985
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004986 bool advance() {
4987 return ++fIndex < fLast;
4988 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004989
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004990 SkScalar bottom() const {
4991 return bounds().fBottom;
4992 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004993
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004994 const Bounds& bounds() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004995 return fContour->segments()[fIndex].bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004996 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004997
caryclark@google.com73ca6242013-01-17 21:02:47 +00004998#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004999 const SkPoint* cubic() const {
5000 return fCubic;
5001 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005002#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005003
5004 void init(Contour* contour) {
5005 fContour = contour;
5006 fIndex = 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005007 fLast = contour->segments().count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005008 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00005009
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00005010 bool isAdjacent(const Work& next) {
5011 return fContour == next.fContour && fIndex + 1 == next.fIndex;
5012 }
5013
5014 bool isFirstLast(const Work& next) {
5015 return fContour == next.fContour && fIndex == 0
5016 && next.fIndex == fLast - 1;
5017 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005018
5019 SkScalar left() const {
5020 return bounds().fLeft;
5021 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005022
caryclark@google.com73ca6242013-01-17 21:02:47 +00005023#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005024 void promoteToCubic() {
5025 fCubic[0] = pts()[0];
5026 fCubic[2] = pts()[1];
5027 fCubic[3] = pts()[2];
5028 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
5029 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
5030 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
5031 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
5032 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005033#endif
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005034
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005035 const SkPoint* pts() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005036 return fContour->segments()[fIndex].pts();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005037 }
5038
5039 SkScalar right() const {
5040 return bounds().fRight;
5041 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005042
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005043 ptrdiff_t segmentIndex() const {
5044 return fIndex;
5045 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005046
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005047 SegmentType segmentType() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005048 const Segment& segment = fContour->segments()[fIndex];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005049 SegmentType type = (SegmentType) segment.verb();
5050 if (type != kLine_Segment) {
5051 return type;
5052 }
5053 if (segment.isHorizontal()) {
5054 return kHorizontalLine_Segment;
5055 }
5056 if (segment.isVertical()) {
5057 return kVerticalLine_Segment;
5058 }
5059 return kLine_Segment;
5060 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005061
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005062 bool startAfter(const Work& after) {
5063 fIndex = after.fIndex;
5064 return advance();
5065 }
5066
5067 SkScalar top() const {
5068 return bounds().fTop;
5069 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005070
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005071 SkPath::Verb verb() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005072 return fContour->segments()[fIndex].verb();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005073 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005074
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005075 SkScalar x() const {
5076 return bounds().fLeft;
5077 }
5078
5079 bool xFlipped() const {
5080 return x() != pts()[0].fX;
5081 }
5082
5083 SkScalar y() const {
5084 return bounds().fTop;
5085 }
5086
5087 bool yFlipped() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005088 return y() != pts()[0].fY;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005089 }
5090
5091protected:
5092 Contour* fContour;
caryclark@google.com73ca6242013-01-17 21:02:47 +00005093#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005094 SkPoint fCubic[4];
caryclark@google.com73ca6242013-01-17 21:02:47 +00005095#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005096 int fIndex;
5097 int fLast;
5098};
5099
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005100#if DEBUG_ADD_INTERSECTING_TS
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005101static void debugShowLineIntersection(int pts, const Work& wt, const Work& wn,
5102 const Intersections& i) {
5103 SkASSERT(i.used() == pts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005104 if (!pts) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005105 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n",
5106 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
5107 wt.pts()[1].fX, wt.pts()[1].fY, wn.pts()[0].fX, wn.pts()[0].fY,
5108 wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005109 return;
5110 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00005111 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 +00005112 __FUNCTION__,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005113 i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY,
5114 wt.pts()[1].fX, wt.pts()[1].fY, i.fPt[0].x, i.fPt[0].y);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005115 if (pts == 2) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005116 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 +00005117 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005118 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g)", i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY,
5119 wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005120 if (pts == 2) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005121 SkDebugf(" wnTs[1]=%1.9g", i.fT[1][1]);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005122 }
5123 SkDebugf("\n");
5124}
5125
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005126static void debugShowQuadLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005127 const Work& wn, const Intersections& i) {
5128 SkASSERT(i.used() == pts);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005129 if (!pts) {
5130 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
caryclark@google.com0b7da432012-10-31 19:00:20 +00005131 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005132 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
5133 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005134 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005135 return;
5136 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005137 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)", __FUNCTION__,
5138 i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY,
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005139 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005140 i.fPt[0].x, i.fPt[0].y);
5141 for (int index = 1; index < pts; ++index) {
5142 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index],
5143 i.fPt[index].x, i.fPt[index].y);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005144 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005145 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g)", i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY,
5146 wn.pts()[1].fX, wn.pts()[1].fY);
5147 for (int index = 1; index < pts; ++index) {
5148 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005149 }
5150 SkDebugf("\n");
5151}
5152
caryclark@google.coma461ff02012-10-11 12:54:23 +00005153static void debugShowQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005154 const Work& wn, const Intersections& i) {
5155 SkASSERT(i.used() == pts);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005156 if (!pts) {
5157 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5158 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5159 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
skia.committer@gmail.com5b6f9162012-10-12 02:01:15 +00005160 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.coma461ff02012-10-11 12:54:23 +00005161 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005162 wn.pts()[2].fX, wn.pts()[2].fY );
caryclark@google.coma461ff02012-10-11 12:54:23 +00005163 return;
5164 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005165 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)", __FUNCTION__,
5166 i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY,
caryclark@google.coma461ff02012-10-11 12:54:23 +00005167 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005168 i.fPt[0].x, i.fPt[0].y);
5169 for (int index = 1; index < pts; ++index) {
5170 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
5171 i.fPt[index].y);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005172 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005173 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)",
5174 i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY,
5175 wn.pts()[1].fX, wn.pts()[1].fY, wn.pts()[2].fX, wn.pts()[2].fY);
5176 for (int index = 1; index < pts; ++index) {
5177 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005178 }
caryclark@google.comb9738012012-07-03 19:53:30 +00005179 SkDebugf("\n");
5180}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005181
5182static void debugShowCubicLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005183 const Work& wn, const Intersections& i) {
5184 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005185 if (!pts) {
5186 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5187 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
5188 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5189 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5190 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
5191 return;
5192 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005193 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)",
5194 __FUNCTION__,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005195 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 +00005196 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005197 i.fPt[0].x, i.fPt[0].y);
5198 for (int index = 1; index < pts; ++index) {
5199 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
5200 i.fPt[index].y);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005201 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005202 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g)",
5203 i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
5204 for (int index = 1; index < pts; ++index) {
5205 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005206 }
5207 SkDebugf("\n");
5208}
5209
caryclark@google.com73ca6242013-01-17 21:02:47 +00005210// FIXME: show more than two intersection points
5211static void debugShowCubicQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005212 const Work& wn, const Intersections& i) {
5213 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005214 if (!pts) {
5215 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5216 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5217 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5218 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5219 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5220 wn.pts()[2].fX, wn.pts()[2].fY );
5221 return;
5222 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005223 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)",
5224 __FUNCTION__,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005225 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 +00005226 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005227 i.fPt[0].x, i.fPt[0].y);
5228 for (int index = 1; index < pts; ++index) {
5229 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
5230 i.fPt[index].y);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005231 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005232 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)",
5233 i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5234 wn.pts()[2].fX, wn.pts()[2].fY);
5235 for (int index = 1; index < pts; ++index) {
5236 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005237 }
5238 SkDebugf("\n");
5239}
5240
5241// FIXME: show more than two intersection points
5242static void debugShowCubicIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005243 const Work& wn, const Intersections& i) {
5244 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005245 if (!pts) {
5246 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5247 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5248 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5249 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5250 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5251 wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY );
5252 return;
5253 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005254 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)",
5255 __FUNCTION__,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005256 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 +00005257 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005258 i.fPt[0].x, i.fPt[0].y);
5259 for (int index = 1; index < pts; ++index) {
5260 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
5261 i.fPt[index].y);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005262 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005263 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)",
5264 i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5265 wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY);
5266 for (int index = 1; index < pts; ++index) {
5267 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[0][index]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005268 }
5269 SkDebugf("\n");
5270}
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005271
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005272#else
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005273static void debugShowLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005274}
caryclark@google.coma461ff02012-10-11 12:54:23 +00005275
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005276static void debugShowQuadLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005277}
5278
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005279static void debugShowQuadIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005280}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005281
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005282static void debugShowCubicLineIntersection(int , const Work& , const Work& ,
5283 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005284}
5285
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005286static void debugShowCubicQuadIntersection(int , const Work& , const Work& ,
5287 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005288}
5289
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005290static void debugShowCubicIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005291}
5292#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005293
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005294static bool addIntersectTs(Contour* test, Contour* next) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005295
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005296 if (test != next) {
5297 if (test->bounds().fBottom < next->bounds().fTop) {
5298 return false;
5299 }
5300 if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5301 return true;
5302 }
5303 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005304 Work wt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005305 wt.init(test);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005306 bool foundCommonContour = test == next;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005307 do {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005308 Work wn;
5309 wn.init(next);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005310 if (test == next && !wn.startAfter(wt)) {
5311 continue;
5312 }
5313 do {
5314 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5315 continue;
5316 }
5317 int pts;
5318 Intersections ts;
5319 bool swap = false;
5320 switch (wt.segmentType()) {
5321 case Work::kHorizontalLine_Segment:
5322 swap = true;
5323 switch (wn.segmentType()) {
5324 case Work::kHorizontalLine_Segment:
5325 case Work::kVerticalLine_Segment:
5326 case Work::kLine_Segment: {
5327 pts = HLineIntersect(wn.pts(), wt.left(),
5328 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005329 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005330 break;
5331 }
5332 case Work::kQuad_Segment: {
5333 pts = HQuadIntersect(wn.pts(), wt.left(),
5334 wt.right(), wt.y(), wt.xFlipped(), ts);
5335 break;
5336 }
5337 case Work::kCubic_Segment: {
5338 pts = HCubicIntersect(wn.pts(), wt.left(),
5339 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005340 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005341 break;
5342 }
5343 default:
5344 SkASSERT(0);
5345 }
5346 break;
5347 case Work::kVerticalLine_Segment:
5348 swap = true;
5349 switch (wn.segmentType()) {
5350 case Work::kHorizontalLine_Segment:
5351 case Work::kVerticalLine_Segment:
5352 case Work::kLine_Segment: {
5353 pts = VLineIntersect(wn.pts(), wt.top(),
5354 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005355 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005356 break;
5357 }
5358 case Work::kQuad_Segment: {
5359 pts = VQuadIntersect(wn.pts(), wt.top(),
5360 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5361 break;
5362 }
5363 case Work::kCubic_Segment: {
5364 pts = VCubicIntersect(wn.pts(), wt.top(),
5365 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005366 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005367 break;
5368 }
5369 default:
5370 SkASSERT(0);
5371 }
5372 break;
5373 case Work::kLine_Segment:
5374 switch (wn.segmentType()) {
5375 case Work::kHorizontalLine_Segment:
5376 pts = HLineIntersect(wt.pts(), wn.left(),
5377 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005378 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005379 break;
5380 case Work::kVerticalLine_Segment:
5381 pts = VLineIntersect(wt.pts(), wn.top(),
5382 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005383 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005384 break;
5385 case Work::kLine_Segment: {
5386 pts = LineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005387 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005388 break;
5389 }
5390 case Work::kQuad_Segment: {
5391 swap = true;
5392 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005393 debugShowQuadLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005394 break;
5395 }
5396 case Work::kCubic_Segment: {
5397 swap = true;
5398 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005399 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005400 break;
5401 }
5402 default:
5403 SkASSERT(0);
5404 }
5405 break;
5406 case Work::kQuad_Segment:
5407 switch (wn.segmentType()) {
5408 case Work::kHorizontalLine_Segment:
5409 pts = HQuadIntersect(wt.pts(), wn.left(),
5410 wn.right(), wn.y(), wn.xFlipped(), ts);
5411 break;
5412 case Work::kVerticalLine_Segment:
5413 pts = VQuadIntersect(wt.pts(), wn.top(),
5414 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5415 break;
5416 case Work::kLine_Segment: {
5417 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005418 debugShowQuadLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005419 break;
5420 }
5421 case Work::kQuad_Segment: {
5422 pts = QuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005423 debugShowQuadIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005424 break;
5425 }
5426 case Work::kCubic_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005427 #if APPROXIMATE_CUBICS
5428 swap = true;
5429 pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005430 debugShowCubicQuadIntersection(pts, wn, wt, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005431 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005432 wt.promoteToCubic();
5433 pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005434 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005435 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005436 break;
5437 }
5438 default:
5439 SkASSERT(0);
5440 }
5441 break;
5442 case Work::kCubic_Segment:
5443 switch (wn.segmentType()) {
5444 case Work::kHorizontalLine_Segment:
5445 pts = HCubicIntersect(wt.pts(), wn.left(),
5446 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005447 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005448 break;
5449 case Work::kVerticalLine_Segment:
5450 pts = VCubicIntersect(wt.pts(), wn.top(),
5451 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005452 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005453 break;
5454 case Work::kLine_Segment: {
5455 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005456 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005457 break;
5458 }
5459 case Work::kQuad_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005460 #if APPROXIMATE_CUBICS
5461 pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005462 debugShowCubicQuadIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005463 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005464 wn.promoteToCubic();
5465 pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005466 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005467 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005468 break;
5469 }
5470 case Work::kCubic_Segment: {
5471 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005472 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005473 break;
5474 }
5475 default:
5476 SkASSERT(0);
5477 }
5478 break;
5479 default:
5480 SkASSERT(0);
5481 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005482 if (!foundCommonContour && pts > 0) {
5483 test->addCross(next);
5484 next->addCross(test);
5485 foundCommonContour = true;
5486 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005487 // in addition to recording T values, record matching segment
caryclark@google.com73ca6242013-01-17 21:02:47 +00005488 if (ts.unsortable()) {
5489 bool start = true;
5490 for (int pt = 0; pt < ts.used(); ++pt) {
5491 // FIXME: if unsortable, the other points to the original. This logic is
5492 // untested downstream.
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005493 SkPoint point = ts.fPt[pt].asSkPoint();
5494 int testTAt = wt.addUnsortableT(ts.fT[swap][pt], wt, start, point);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005495 wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005496 testTAt = wn.addUnsortableT(ts.fT[!swap][pt], wn, start ^ ts.fFlip, point);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005497 wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt);
5498 start ^= true;
5499 }
5500 continue;
5501 }
caryclark@google.com32546db2012-08-31 20:55:07 +00005502 if (pts == 2) {
5503 if (wn.segmentType() <= Work::kLine_Segment
5504 && wt.segmentType() <= Work::kLine_Segment) {
5505 wt.addCoincident(wn, ts, swap);
5506 continue;
5507 }
caryclark@google.combeda3892013-02-07 13:13:41 +00005508 if (wn.segmentType() >= Work::kQuad_Segment
5509 && wt.segmentType() >= Work::kQuad_Segment
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005510 && ts.fIsCoincident[0]) {
5511 SkASSERT(ts.coincidentUsed() == 2);
caryclark@google.com32546db2012-08-31 20:55:07 +00005512 wt.addCoincident(wn, ts, swap);
5513 continue;
5514 }
5515
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00005516 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00005517 for (int pt = 0; pt < pts; ++pt) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005518 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5519 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005520 SkPoint point = ts.fPt[pt].asSkPoint();
5521 int testTAt = wt.addT(ts.fT[swap][pt], wn, point);
5522 int nextTAt = wn.addT(ts.fT[!swap][pt], wt, point);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005523 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
5524 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005525 }
5526 } while (wn.advance());
5527 } while (wt.advance());
5528 return true;
5529}
5530
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005531// resolve any coincident pairs found while intersecting, and
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005532// see if coincidence is formed by clipping non-concident segments
caryclark@google.com4eeda372012-12-06 21:47:48 +00005533static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005534 int contourCount = contourList.count();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005535#if ONE_PASS_COINCIDENCE_CHECK
caryclark@google.comf25edfe2012-06-01 18:20:10 +00005536 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005537 Contour* contour = contourList[cIndex];
caryclark@google.com7ba591e2012-11-20 14:21:54 +00005538 contour->resolveCoincidence(contourList);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005539 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005540#else
5541 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5542 Contour* contour = contourList[cIndex];
5543 contour->addCoincidentPoints();
5544 }
5545 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5546 Contour* contour = contourList[cIndex];
5547 contour->calcCoincidentWinding();
5548 }
5549#endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005550 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5551 Contour* contour = contourList[cIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00005552 contour->findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005553 }
5554}
5555
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005556static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005557 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005558 SkPoint basePt;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005559 double tAtMid = current->tAtMid(index, endIndex, mid);
5560 current->xyAtT(tAtMid, basePt);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005561 int contourCount = contourList.count();
5562 SkScalar bestY = SK_ScalarMin;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005563 Segment* bestSeg = NULL;
5564 int bestTIndex;
5565 bool bestOpp;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005566 bool hitSomething = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005567 for (int cTest = 0; cTest < contourCount; ++cTest) {
5568 Contour* contour = contourList[cTest];
5569 bool testOpp = contour->operand() ^ current->operand() ^ opp;
5570 if (basePt.fY < contour->bounds().fTop) {
5571 continue;
5572 }
5573 if (bestY > contour->bounds().fBottom) {
5574 continue;
5575 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005576 int segmentCount = contour->segments().count();
5577 for (int test = 0; test < segmentCount; ++test) {
5578 Segment* testSeg = &contour->segments()[test];
5579 SkScalar testY = bestY;
5580 double testHit;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005581 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
5582 testOpp, testSeg == current);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005583 if (testTIndex < 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005584 if (testTIndex == SK_MinS32) {
5585 hitSomething = true;
5586 bestSeg = NULL;
5587 goto abortContours; // vertical encountered, return and try different point
5588 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005589 continue;
5590 }
5591 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005592 double baseT = current->t(index);
5593 double endT = current->t(endIndex);
5594 double newMid = (testHit - baseT) / (endT - baseT);
5595#if DEBUG_WINDING
5596 SkPoint midXY, newXY;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005597 double midT = current->tAtMid(index, endIndex, mid);
5598 current->xyAtT(midT, midXY);
5599 double newMidT = current->tAtMid(index, endIndex, newMid);
5600 current->xyAtT(newMidT, newXY);
caryclark@google.com3586ece2012-12-27 18:46:58 +00005601 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
5602 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
5603 current->debugID(), mid, newMid,
5604 baseT, current->xAtT(index), current->yAtT(index),
5605 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
5606 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
5607 endT, current->xAtT(endIndex), current->yAtT(endIndex));
5608#endif
5609 mid = newMid * 2; // calling loop with divide by 2 before continuing
5610 return SK_MinS32;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005611 }
5612 bestSeg = testSeg;
5613 bestHit = testHit;
5614 bestOpp = testOpp;
5615 bestTIndex = testTIndex;
5616 bestY = testY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005617 }
5618 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005619abortContours:
caryclark@google.com10227bf2012-12-28 22:10:41 +00005620 int result;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005621 if (!bestSeg) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00005622 result = hitSomething ? SK_MinS32 : 0;
5623 } else {
5624 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
5625 current = bestSeg;
5626 index = bestTIndex;
5627 endIndex = bestSeg->nextSpan(bestTIndex, 1);
5628 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
5629 tryAgain = true;
5630 return 0;
5631 }
5632 result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
5633 SkASSERT(bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005634 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005635 double baseT = current->t(index);
5636 double endT = current->t(endIndex);
5637 bestHit = baseT + mid * (endT - baseT);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005638 return result;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005639}
5640
caryclark@google.com24bec792012-08-20 12:43:57 +00005641static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
5642 int contourCount = contourList.count();
5643 Segment* result;
5644 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5645 Contour* contour = contourList[cIndex];
5646 result = contour->undoneSegment(start, end);
5647 if (result) {
5648 return result;
5649 }
5650 }
5651 return NULL;
5652}
5653
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005654#define OLD_FIND_CHASE 1
caryclark@google.com24bec792012-08-20 12:43:57 +00005655
caryclark@google.com31143cf2012-11-09 22:14:19 +00005656static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005657 while (chase.count()) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005658 Span* span;
5659 chase.pop(&span);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005660 const Span& backPtr = span->fOther->span(span->fOtherIndex);
5661 Segment* segment = backPtr.fOther;
5662 tIndex = backPtr.fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005663 SkTDArray<Angle> angles;
5664 int done = 0;
5665 if (segment->activeAngle(tIndex, done, angles)) {
5666 Angle* last = angles.end() - 1;
5667 tIndex = last->start();
5668 endIndex = last->end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005669 #if TRY_ROTATE
5670 *chase.insert(0) = span;
5671 #else
5672 *chase.append() = span;
5673 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005674 return last->segment();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005675 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005676 if (done == angles.count()) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00005677 continue;
5678 }
5679 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005680 bool sortable = Segment::SortAngles(angles, sorted);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005681 int angleCount = sorted.count();
caryclark@google.com03f97062012-08-21 13:13:52 +00005682#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005683 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00005684#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005685 if (!sortable) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005686 continue;
5687 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005688 // find first angle, initialize winding to computed fWindSum
5689 int firstIndex = -1;
5690 const Angle* angle;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005691#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005692 int winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005693 do {
5694 angle = sorted[++firstIndex];
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005695 segment = angle->segment();
5696 winding = segment->windSum(angle);
5697 } while (winding == SK_MinS32);
5698 int spanWinding = segment->spanSign(angle->start(), angle->end());
5699 #if DEBUG_WINDING
caryclark@google.com31143cf2012-11-09 22:14:19 +00005700 SkDebugf("%s winding=%d spanWinding=%d\n",
5701 __FUNCTION__, winding, spanWinding);
caryclark@google.com47580692012-07-23 12:14:49 +00005702 #endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005703 // turn span winding into contour winding
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005704 if (spanWinding * winding < 0) {
5705 winding += spanWinding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005706 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005707 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005708 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005709 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005710 // we care about first sign and whether wind sum indicates this
5711 // edge is inside or outside. Maybe need to pass span winding
5712 // or first winding or something into this function?
5713 // advance to first undone angle, then return it and winding
5714 // (to set whether edges are active or not)
5715 int nextIndex = firstIndex + 1;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005716 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005717 angle = sorted[firstIndex];
caryclark@google.com2ddff932012-08-07 21:25:27 +00005718 winding -= angle->segment()->spanSign(angle);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005719#else
5720 do {
5721 angle = sorted[++firstIndex];
5722 segment = angle->segment();
5723 } while (segment->windSum(angle) == SK_MinS32);
5724 #if DEBUG_SORT
5725 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5726 #endif
5727 int sumWinding = segment->updateWindingReverse(angle);
5728 int nextIndex = firstIndex + 1;
5729 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5730 Segment* first = NULL;
5731#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005732 do {
5733 SkASSERT(nextIndex != firstIndex);
5734 if (nextIndex == angleCount) {
5735 nextIndex = 0;
5736 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005737 angle = sorted[nextIndex];
caryclark@google.com9764cc62012-07-12 19:29:45 +00005738 segment = angle->segment();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005739#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005740 int maxWinding = winding;
caryclark@google.com2ddff932012-08-07 21:25:27 +00005741 winding -= segment->spanSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005742 #if DEBUG_SORT
caryclark@google.com2ddff932012-08-07 21:25:27 +00005743 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
5744 segment->debugID(), maxWinding, winding, angle->sign());
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005745 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005746 tIndex = angle->start();
5747 endIndex = angle->end();
5748 int lesser = SkMin32(tIndex, endIndex);
5749 const Span& nextSpan = segment->span(lesser);
5750 if (!nextSpan.fDone) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005751#if 1
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005752 // FIXME: this be wrong? assign startWinding if edge is in
caryclark@google.com9764cc62012-07-12 19:29:45 +00005753 // same direction. If the direction is opposite, winding to
5754 // assign is flipped sign or +/- 1?
caryclark@google.com59823f72012-08-09 18:17:47 +00005755 if (useInnerWinding(maxWinding, winding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005756 maxWinding = winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005757 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005758 segment->markAndChaseWinding(angle, maxWinding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005759#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005760 break;
5761 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005762#else
5763 int start = angle->start();
5764 int end = angle->end();
5765 int maxWinding;
5766 segment->setUpWinding(start, end, maxWinding, sumWinding);
5767 if (!segment->done(angle)) {
5768 if (!first) {
5769 first = segment;
5770 tIndex = start;
5771 endIndex = end;
5772 }
5773 (void) segment->markAngle(maxWinding, sumWinding, true, angle);
5774 }
5775#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005776 } while (++nextIndex != lastIndex);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005777 #if TRY_ROTATE
5778 *chase.insert(0) = span;
5779 #else
5780 *chase.append() = span;
5781 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005782 return segment;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005783 }
5784 return NULL;
5785}
5786
caryclark@google.com027de222012-07-12 12:52:50 +00005787#if DEBUG_ACTIVE_SPANS
5788static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005789 int index;
5790 for (index = 0; index < contourList.count(); ++ index) {
caryclark@google.com027de222012-07-12 12:52:50 +00005791 contourList[index]->debugShowActiveSpans();
5792 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005793 for (index = 0; index < contourList.count(); ++ index) {
5794 contourList[index]->validateActiveSpans();
5795 }
caryclark@google.com027de222012-07-12 12:52:50 +00005796}
5797#endif
5798
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005799static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005800 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005801 Segment* result;
5802 do {
caryclark@google.comf839c032012-10-26 21:03:50 +00005803 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005804 int contourCount = contourList.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00005805 Segment* topStart = NULL;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005806 done = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00005807 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5808 Contour* contour = contourList[cIndex];
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005809 if (contour->done()) {
5810 continue;
5811 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005812 const Bounds& bounds = contour->bounds();
5813 if (bounds.fBottom < topLeft.fY) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005814 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005815 continue;
5816 }
5817 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005818 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005819 continue;
5820 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005821 contour->topSortableSegment(topLeft, bestXY, topStart);
5822 if (!contour->done()) {
5823 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005824 }
5825 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005826 if (!topStart) {
5827 return NULL;
5828 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005829 topLeft = bestXY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005830 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005831 } while (!result);
5832 return result;
5833}
caryclark@google.com31143cf2012-11-09 22:14:19 +00005834
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005835static int rightAngleWinding(SkTDArray<Contour*>& contourList,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005836 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005837 bool opp) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005838 double test = 0.9;
5839 int contourWinding;
5840 do {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005841 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
5842 tryAgain, test, opp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005843 if (contourWinding != SK_MinS32 || tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005844 return contourWinding;
5845 }
5846 test /= 2;
5847 } while (!approximately_negative(test));
5848 SkASSERT(0); // should be OK to comment out, but interested when this hits
5849 return contourWinding;
5850}
5851
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005852static void skipVertical(SkTDArray<Contour*>& contourList,
5853 Segment*& current, int& index, int& endIndex) {
5854 if (!current->isVertical(index, endIndex)) {
5855 return;
5856 }
5857 int contourCount = contourList.count();
5858 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5859 Contour* contour = contourList[cIndex];
5860 if (contour->done()) {
5861 continue;
5862 }
5863 current = contour->nonVerticalSegment(index, endIndex);
5864 if (current) {
5865 return;
5866 }
5867 }
5868}
5869
caryclark@google.com3586ece2012-12-27 18:46:58 +00005870static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005871 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
5872 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
5873 true);
5874 if (!current) {
5875 return NULL;
5876 }
5877 if (firstContour) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005878 current->initWinding(index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005879 firstContour = false;
5880 return current;
5881 }
5882 int minIndex = SkMin32(index, endIndex);
5883 int sumWinding = current->windSum(minIndex);
5884 if (sumWinding != SK_MinS32) {
5885 return current;
5886 }
5887 sumWinding = current->computeSum(index, endIndex, binary);
5888 if (sumWinding != SK_MinS32) {
5889 return current;
5890 }
5891 int contourWinding;
5892 int oppContourWinding = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005893 // the simple upward projection of the unresolved points hit unsortable angles
5894 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005895 bool tryAgain;
5896 double tHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005897 SkScalar hitDx = 0;
5898 SkScalar hitOppDx = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005899 do {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005900 // if current is vertical, find another candidate which is not
5901 // if only remaining candidates are vertical, then they can be marked done
caryclark@google.com10227bf2012-12-28 22:10:41 +00005902 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005903 skipVertical(contourList, current, index, endIndex);
caryclark@google.com10227bf2012-12-28 22:10:41 +00005904 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005905 tryAgain = false;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005906 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005907 tryAgain, false);
5908 if (tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005909 continue;
5910 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005911 if (!binary) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005912 break;
5913 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005914 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005915 tryAgain, true);
5916 } while (tryAgain);
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00005917
caryclark@google.com3586ece2012-12-27 18:46:58 +00005918 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005919 return current;
5920}
5921
5922// rewrite that abandons keeping local track of winding
caryclark@google.com3586ece2012-12-27 18:46:58 +00005923static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005924 bool firstContour = true;
5925 bool unsortable = false;
5926 bool topUnsortable = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005927 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
5928 do {
5929 int index, endIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005930 bool topDone;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005931 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005932 topUnsortable, topDone, false);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005933 if (!current) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005934 if (topUnsortable || !topDone) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005935 topUnsortable = false;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005936 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005937 topLeft.fX = topLeft.fY = SK_ScalarMin;
5938 continue;
5939 }
5940 break;
5941 }
5942 SkTDArray<Span*> chaseArray;
5943 do {
5944 if (current->activeWinding(index, endIndex)) {
5945 do {
5946 #if DEBUG_ACTIVE_SPANS
5947 if (!unsortable && current->done()) {
5948 debugShowActiveSpans(contourList);
5949 }
5950 #endif
5951 SkASSERT(unsortable || !current->done());
5952 int nextStart = index;
5953 int nextEnd = endIndex;
5954 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
5955 unsortable);
5956 if (!next) {
5957 if (!unsortable && simple.hasMove()
5958 && current->verb() != SkPath::kLine_Verb
5959 && !simple.isClosed()) {
5960 current->addCurveTo(index, endIndex, simple, true);
5961 SkASSERT(simple.isClosed());
5962 }
5963 break;
5964 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005965 #if DEBUG_FLOW
5966 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
5967 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
5968 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
5969 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005970 current->addCurveTo(index, endIndex, simple, true);
5971 current = next;
5972 index = nextStart;
5973 endIndex = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005974 } while (!simple.isClosed() && (!unsortable
caryclark@google.com10227bf2012-12-28 22:10:41 +00005975 || !current->done(SkMin32(index, endIndex))));
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005976 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
5977 SkASSERT(unsortable);
5978 int min = SkMin32(index, endIndex);
5979 if (!current->done(min)) {
5980 current->addCurveTo(index, endIndex, simple, true);
5981 current->markDoneUnary(min);
5982 }
5983 }
5984 simple.close();
5985 } else {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005986 Span* last = current->markAndChaseDoneUnary(index, endIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005987 if (last) {
5988 *chaseArray.append() = last;
5989 }
5990 }
5991 current = findChase(chaseArray, index, endIndex);
5992 #if DEBUG_ACTIVE_SPANS
5993 debugShowActiveSpans(contourList);
5994 #endif
5995 if (!current) {
5996 break;
5997 }
5998 } while (true);
5999 } while (true);
6000 return simple.someAssemblyRequired();
6001}
6002
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006003// returns true if all edges were processed
caryclark@google.comf839c032012-10-26 21:03:50 +00006004static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006005 Segment* current;
6006 int start, end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006007 bool unsortable = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006008 bool closable = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00006009 while ((current = findUndone(contourList, start, end))) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006010 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006011 #if DEBUG_ACTIVE_SPANS
6012 if (!unsortable && current->done()) {
6013 debugShowActiveSpans(contourList);
6014 }
6015 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006016 SkASSERT(unsortable || !current->done());
caryclark@google.com24bec792012-08-20 12:43:57 +00006017 int nextStart = start;
6018 int nextEnd = end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006019 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
caryclark@google.com24bec792012-08-20 12:43:57 +00006020 if (!next) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006021 if (!unsortable && simple.hasMove()
caryclark@google.comf839c032012-10-26 21:03:50 +00006022 && current->verb() != SkPath::kLine_Verb
6023 && !simple.isClosed()) {
6024 current->addCurveTo(start, end, simple, true);
6025 SkASSERT(simple.isClosed());
caryclark@google.comc899ad92012-08-23 15:24:42 +00006026 }
caryclark@google.com24bec792012-08-20 12:43:57 +00006027 break;
6028 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006029 #if DEBUG_FLOW
6030 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6031 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
6032 current->xyAtT(end).fX, current->xyAtT(end).fY);
6033 #endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006034 current->addCurveTo(start, end, simple, true);
caryclark@google.com24bec792012-08-20 12:43:57 +00006035 current = next;
6036 start = nextStart;
6037 end = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006038 } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006039 if (!simple.isClosed()) {
6040 SkASSERT(unsortable);
6041 int min = SkMin32(start, end);
6042 if (!current->done(min)) {
6043 current->addCurveTo(start, end, simple, true);
6044 current->markDone(min, 1);
6045 }
6046 closable = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00006047 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006048 simple.close();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00006049 #if DEBUG_ACTIVE_SPANS
6050 debugShowActiveSpans(contourList);
6051 #endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00006052 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006053 return closable;
caryclark@google.com24bec792012-08-20 12:43:57 +00006054}
6055
caryclark@google.comb45a1b42012-05-18 20:50:33 +00006056static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
6057 int contourCount = contourList.count();
6058 for (int cTest = 0; cTest < contourCount; ++cTest) {
6059 Contour* contour = contourList[cTest];
6060 contour->fixOtherTIndex();
6061 }
6062}
6063
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006064static void sortSegments(SkTDArray<Contour*>& contourList) {
6065 int contourCount = contourList.count();
6066 for (int cTest = 0; cTest < contourCount; ++cTest) {
6067 Contour* contour = contourList[cTest];
6068 contour->sortSegments();
6069 }
6070}
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006071
caryclark@google.com4eeda372012-12-06 21:47:48 +00006072static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
6073 bool evenOdd, bool oppEvenOdd) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006074 int count = contours.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006075 if (count == 0) {
6076 return;
6077 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006078 for (int index = 0; index < count; ++index) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00006079 Contour& contour = contours[index];
6080 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
6081 *list.append() = &contour;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006082 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006083 QSort<Contour>(list.begin(), list.end() - 1);
6084}
6085
caryclark@google.comf839c032012-10-26 21:03:50 +00006086static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006087 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006088}
6089
caryclark@google.com10227bf2012-12-28 22:10:41 +00006090static bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
6091 return distances[one] < distances[two];
6092}
caryclark@google.comf839c032012-10-26 21:03:50 +00006093 /*
6094 check start and end of each contour
6095 if not the same, record them
6096 match them up
6097 connect closest
6098 reassemble contour pieces into new path
6099 */
6100static void assemble(const PathWrapper& path, PathWrapper& simple) {
6101#if DEBUG_PATH_CONSTRUCTION
6102 SkDebugf("%s\n", __FUNCTION__);
6103#endif
6104 SkTArray<Contour> contours;
6105 EdgeBuilder builder(path, contours);
6106 builder.finish();
6107 int count = contours.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006108 int outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006109 SkTDArray<int> runs; // indices of partial contours
caryclark@google.com0b7da432012-10-31 19:00:20 +00006110 for (outer = 0; outer < count; ++outer) {
6111 const Contour& eContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006112 const SkPoint& eStart = eContour.start();
6113 const SkPoint& eEnd = eContour.end();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006114#if DEBUG_ASSEMBLE
6115 SkDebugf("%s contour", __FUNCTION__);
6116 if (!approximatelyEqual(eStart, eEnd)) {
6117 SkDebugf("[%d]", runs.count());
6118 } else {
6119 SkDebugf(" ");
6120 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006121 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006122 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
6123#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006124 if (approximatelyEqual(eStart, eEnd)) {
6125 eContour.toPath(simple);
6126 continue;
6127 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006128 *runs.append() = outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006129 }
6130 count = runs.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006131 if (count == 0) {
6132 return;
6133 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006134 SkTDArray<int> sLink, eLink;
6135 sLink.setCount(count);
6136 eLink.setCount(count);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006137 int rIndex, iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006138 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006139 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006140 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006141 SkTDArray<double> distances;
6142 const int ends = count * 2; // all starts and ends
6143 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
6144 distances.setCount(entries);
6145 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
6146 outer = runs[rIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006147 const Contour& oContour = contours[outer];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006148 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
6149 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
6150 * ends - rIndex - 1;
6151 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
6152 int inner = runs[iIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006153 const Contour& iContour = contours[inner];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006154 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
6155 double dx = iPt.fX - oPt.fX;
6156 double dy = iPt.fY - oPt.fY;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006157 double dist = dx * dx + dy * dy;
caryclark@google.com10227bf2012-12-28 22:10:41 +00006158 distances[row + iIndex] = dist; // oStart distance from iStart
6159 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006160 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006161 SkTDArray<int> sortedDist;
6162 sortedDist.setCount(entries);
6163 for (rIndex = 0; rIndex < entries; ++rIndex) {
6164 sortedDist[rIndex] = rIndex;
6165 }
6166 QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
6167 int remaining = count; // number of start/end pairs
6168 for (rIndex = 0; rIndex < entries; ++rIndex) {
6169 int pair = sortedDist[rIndex];
6170 int row = pair / ends;
6171 int col = pair - row * ends;
6172 int thingOne = row < col ? row : ends - row - 2;
6173 int ndxOne = thingOne >> 1;
6174 bool endOne = thingOne & 1;
6175 int* linkOne = endOne ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006176 if (linkOne[ndxOne] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006177 continue;
6178 }
6179 int thingTwo = row < col ? col : ends - row + col - 1;
6180 int ndxTwo = thingTwo >> 1;
6181 bool endTwo = thingTwo & 1;
6182 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006183 if (linkTwo[ndxTwo] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006184 continue;
6185 }
6186 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
6187 bool flip = endOne == endTwo;
6188 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
6189 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
6190 if (!--remaining) {
6191 break;
6192 }
6193 }
6194 SkASSERT(!remaining);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006195#if DEBUG_ASSEMBLE
6196 for (rIndex = 0; rIndex < count; ++rIndex) {
6197 int s = sLink[rIndex];
6198 int e = eLink[rIndex];
6199 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
6200 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
caryclark@google.comf839c032012-10-26 21:03:50 +00006201 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006202#endif
6203 rIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00006204 do {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006205 bool forward = true;
6206 bool first = true;
6207 int sIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006208 SkASSERT(sIndex != SK_MaxS32);
6209 sLink[rIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006210 int eIndex;
6211 if (sIndex < 0) {
6212 eIndex = sLink[~sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006213 sLink[~sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006214 } else {
6215 eIndex = eLink[sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006216 eLink[sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006217 }
caryclark@google.comaa358312013-01-29 20:28:49 +00006218 SkASSERT(eIndex != SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006219#if DEBUG_ASSEMBLE
6220 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006221 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
6222 eIndex < 0 ? ~eIndex : eIndex);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006223#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006224 do {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006225 outer = runs[rIndex];
6226 const Contour& contour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006227 if (first) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006228 first = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006229 const SkPoint* startPtr = &contour.start();
caryclark@google.comf839c032012-10-26 21:03:50 +00006230 simple.deferredMove(startPtr[0]);
6231 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006232 if (forward) {
6233 contour.toPartialForward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006234 } else {
6235 contour.toPartialBackward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006236 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006237#if DEBUG_ASSEMBLE
6238 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006239 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006240 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
6241#endif
6242 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006243 simple.close();
caryclark@google.comf839c032012-10-26 21:03:50 +00006244 break;
6245 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006246 if (forward) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006247 eIndex = eLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006248 SkASSERT(eIndex != SK_MaxS32);
6249 eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006250 if (eIndex >= 0) {
6251 SkASSERT(sLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006252 sLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006253 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006254 SkASSERT(eLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006255 eLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006256 }
6257 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006258 eIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006259 SkASSERT(eIndex != SK_MaxS32);
6260 sLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006261 if (eIndex >= 0) {
6262 SkASSERT(eLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006263 eLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006264 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006265 SkASSERT(sLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006266 sLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006267 }
6268 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006269 rIndex = eIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006270 if (rIndex < 0) {
6271 forward ^= 1;
6272 rIndex = ~rIndex;
6273 }
6274 } while (true);
6275 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006276 if (sLink[rIndex] != SK_MaxS32) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006277 break;
6278 }
6279 }
6280 } while (rIndex < count);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006281#if DEBUG_ASSEMBLE
6282 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006283 SkASSERT(sLink[rIndex] == SK_MaxS32);
6284 SkASSERT(eLink[rIndex] == SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006285 }
6286#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006287}
6288
6289void simplifyx(const SkPath& path, SkPath& result) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006290 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
caryclark@google.comf839c032012-10-26 21:03:50 +00006291 result.reset();
6292 result.setFillType(SkPath::kEvenOdd_FillType);
6293 PathWrapper simple(result);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006294
6295 // turn path into list of segments
6296 SkTArray<Contour> contours;
6297 // FIXME: add self-intersecting cubics' T values to segment
6298 EdgeBuilder builder(path, contours);
caryclark@google.com235f56a2012-09-14 14:19:30 +00006299 builder.finish();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006300 SkTDArray<Contour*> contourList;
caryclark@google.com4eeda372012-12-06 21:47:48 +00006301 makeContourList(contours, contourList, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006302 Contour** currentPtr = contourList.begin();
6303 if (!currentPtr) {
6304 return;
6305 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006306 Contour** listEnd = contourList.end();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006307 // find all intersections between segments
6308 do {
6309 Contour** nextPtr = currentPtr;
6310 Contour* current = *currentPtr++;
6311 Contour* next;
6312 do {
6313 next = *nextPtr++;
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00006314 } while (addIntersectTs(current, next) && nextPtr != listEnd);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006315 } while (currentPtr != listEnd);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006316 // eat through coincident edges
caryclark@google.com4eeda372012-12-06 21:47:48 +00006317 coincidenceCheck(contourList, 0);
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00006318 fixOtherTIndex(contourList);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006319 sortSegments(contourList);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006320#if DEBUG_ACTIVE_SPANS
6321 debugShowActiveSpans(contourList);
6322#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006323 // construct closed contours
caryclark@google.com3586ece2012-12-27 18:46:58 +00006324 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00006325 : !bridgeXor(contourList, simple))
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006326 { // if some edges could not be resolved, assemble remaining fragments
caryclark@google.comf839c032012-10-26 21:03:50 +00006327 SkPath temp;
6328 temp.setFillType(SkPath::kEvenOdd_FillType);
6329 PathWrapper assembled(temp);
6330 assemble(simple, assembled);
6331 result = *assembled.nativePath();
caryclark@google.com24bec792012-08-20 12:43:57 +00006332 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006333}