blob: 0db33fa77d91fa26a4f66c51c724f4115ab9b4a9 [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.com5e0500f2013-02-20 12:51:37 +000035#define FORCE_RELEASE 1 // set force release to 1 for multiple thread -- no debugging
caryclark@google.comfa0588f2012-04-26 21:01:06 +000036
caryclark@google.com31143cf2012-11-09 22:14:19 +000037#if FORCE_RELEASE || defined SK_RELEASE
caryclark@google.com47580692012-07-23 12:14:49 +000038
39const bool gRunTestsInOneThread = false;
40
caryclark@google.combeda3892013-02-07 13:13:41 +000041#define DEBUG_ACTIVE_OP 0
caryclark@google.com47580692012-07-23 12:14:49 +000042#define DEBUG_ACTIVE_SPANS 0
caryclark@google.com4eeda372012-12-06 21:47:48 +000043#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000044#define DEBUG_ADD_INTERSECTING_TS 0
caryclark@google.com47580692012-07-23 12:14:49 +000045#define DEBUG_ADD_T_PAIR 0
caryclark@google.comc899ad92012-08-23 15:24:42 +000046#define DEBUG_ANGLE 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000047#define DEBUG_ASSEMBLE 0
caryclark@google.com47580692012-07-23 12:14:49 +000048#define DEBUG_CONCIDENT 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000049#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000050#define DEBUG_FLOW 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000051#define DEBUG_MARK_DONE 0
caryclark@google.comf839c032012-10-26 21:03:50 +000052#define DEBUG_PATH_CONSTRUCTION 0
caryclark@google.com729e1c42012-11-21 21:36:34 +000053#define DEBUG_SHOW_WINDING 0
caryclark@google.com5e0500f2013-02-20 12:51:37 +000054#define DEBUG_SORT 1
55#define DEBUG_SWAP_TOP 0
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
91static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000092// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
caryclark@google.comfa0588f2012-04-26 21:01:06 +000093static int gContourID;
94static int gSegmentID;
95#endif
96
caryclark@google.com5e0500f2013-02-20 12:51:37 +000097#if DEBUG_ACTIVE_OP
98static const char* kShapeOpStr[] = {"diff", "sect", "union", "xor"};
99#endif
100
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000101#ifndef DEBUG_TEST
102#define DEBUG_TEST 0
103#endif
104
caryclark@google.com32546db2012-08-31 20:55:07 +0000105#define MAKE_CONST_LINE(line, pts) \
106 const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}
107#define MAKE_CONST_QUAD(quad, pts) \
108 const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
109 {pts[2].fX, pts[2].fY}}
110#define MAKE_CONST_CUBIC(cubic, pts) \
111 const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
112 {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}}
113
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000114static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
115 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000116 MAKE_CONST_LINE(aLine, a);
117 MAKE_CONST_LINE(bLine, b);
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000118 return intersect(aLine, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000119}
120
121static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
122 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000123 MAKE_CONST_QUAD(aQuad, a);
124 MAKE_CONST_LINE(bLine, b);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000125 return intersect(aQuad, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000126}
127
caryclark@google.com32546db2012-08-31 20:55:07 +0000128static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000129 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000130 MAKE_CONST_CUBIC(aCubic, a);
131 MAKE_CONST_LINE(bLine, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000132 return intersect(aCubic, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000133}
134
135static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
136 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000137 MAKE_CONST_QUAD(aQuad, a);
138 MAKE_CONST_QUAD(bQuad, b);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000139#define TRY_QUARTIC_SOLUTION 1
140#if TRY_QUARTIC_SOLUTION
141 intersect2(aQuad, bQuad, intersections);
142#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000143 intersect(aQuad, bQuad, intersections);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000144#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000145 return intersections.fUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000146}
147
caryclark@google.com73ca6242013-01-17 21:02:47 +0000148#if APPROXIMATE_CUBICS
149static int CubicQuadIntersect(const SkPoint a[4], const SkPoint b[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000150 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000151 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000152 MAKE_CONST_QUAD(bQuad, b);
153 return intersect(aCubic, bQuad, intersections);
154}
155#endif
156
157static int CubicIntersect(const SkPoint a[4], const SkPoint b[4], Intersections& intersections) {
158 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com32546db2012-08-31 20:55:07 +0000159 MAKE_CONST_CUBIC(bCubic, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000160#if APPROXIMATE_CUBICS
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000161 intersect3(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000162#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000163 intersect(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000164#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000165 return intersections.fUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000166}
167
168static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
169 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000170 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000171 return horizontalIntersect(aLine, left, right, y, flipped, intersections);
172}
173
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000174static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
175 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000176 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000177 return horizontalIntersect(aQuad, left, right, y, flipped, intersections);
178}
179
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000180static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
181 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000182 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000183 return horizontalIntersect(aCubic, left, right, y, flipped, intersections);
184}
185
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000186static int (* const HSegmentIntersect[])(const SkPoint [], SkScalar ,
187 SkScalar , SkScalar , bool , Intersections& ) = {
188 NULL,
189 HLineIntersect,
190 HQuadIntersect,
191 HCubicIntersect
192};
193
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000194static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom,
195 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000196 MAKE_CONST_LINE(aLine, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000197 return verticalIntersect(aLine, top, bottom, x, flipped, intersections);
198}
199
200static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom,
201 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000202 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000203 return verticalIntersect(aQuad, top, bottom, x, flipped, intersections);
204}
205
206static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom,
207 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000208 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000209 return verticalIntersect(aCubic, top, bottom, x, flipped, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000210}
211
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000212static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar ,
213 SkScalar , SkScalar , bool , Intersections& ) = {
214 NULL,
215 VLineIntersect,
216 VQuadIntersect,
217 VCubicIntersect
218};
219
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000220static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000221 MAKE_CONST_LINE(line, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000222 double x, y;
223 xy_at_t(line, t, x, y);
224 out->fX = SkDoubleToScalar(x);
225 out->fY = SkDoubleToScalar(y);
226}
227
caryclark@google.comf9502d72013-02-04 14:06:49 +0000228static void LineXYAtT(const SkPoint a[2], double t, _Point* out) {
229 MAKE_CONST_LINE(line, a);
230 xy_at_t(line, t, out->x, out->y);
231}
232
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000233static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000234 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000235 double x, y;
236 xy_at_t(quad, t, x, y);
237 out->fX = SkDoubleToScalar(x);
238 out->fY = SkDoubleToScalar(y);
239}
240
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000241static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
242 MAKE_CONST_QUAD(quad, a);
243 xy_at_t(quad, t, out->x, out->y);
244}
245
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000246static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000247 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000248 double x, y;
249 xy_at_t(cubic, t, x, y);
250 out->fX = SkDoubleToScalar(x);
251 out->fY = SkDoubleToScalar(y);
252}
253
caryclark@google.comf9502d72013-02-04 14:06:49 +0000254static void CubicXYAtT(const SkPoint a[4], double t, _Point* out) {
255 MAKE_CONST_CUBIC(cubic, a);
256 xy_at_t(cubic, t, out->x, out->y);
257}
258
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000259static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
260 NULL,
261 LineXYAtT,
262 QuadXYAtT,
263 CubicXYAtT
264};
265
caryclark@google.comf9502d72013-02-04 14:06:49 +0000266static void (* const SegmentXYAtT2[])(const SkPoint [], double , _Point* ) = {
267 NULL,
268 LineXYAtT,
269 QuadXYAtT,
270 CubicXYAtT
271};
272
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000273static SkScalar LineXAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000274 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000275 double x;
276 xy_at_t(aLine, t, x, *(double*) 0);
277 return SkDoubleToScalar(x);
278}
279
280static SkScalar QuadXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000281 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000282 double x;
283 xy_at_t(quad, t, x, *(double*) 0);
284 return SkDoubleToScalar(x);
285}
286
287static SkScalar CubicXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000288 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000289 double x;
290 xy_at_t(cubic, t, x, *(double*) 0);
291 return SkDoubleToScalar(x);
292}
293
294static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
295 NULL,
296 LineXAtT,
297 QuadXAtT,
298 CubicXAtT
299};
300
301static SkScalar LineYAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000302 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000303 double y;
304 xy_at_t(aLine, t, *(double*) 0, y);
305 return SkDoubleToScalar(y);
306}
307
308static SkScalar QuadYAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000309 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000310 double y;
311 xy_at_t(quad, t, *(double*) 0, y);
312 return SkDoubleToScalar(y);
313}
314
315static SkScalar CubicYAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000316 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000317 double y;
318 xy_at_t(cubic, t, *(double*) 0, y);
319 return SkDoubleToScalar(y);
320}
321
322static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
323 NULL,
324 LineYAtT,
325 QuadYAtT,
326 CubicYAtT
327};
328
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000329static SkScalar LineDXAtT(const SkPoint a[2], double ) {
330 return a[1].fX - a[0].fX;
331}
332
333static SkScalar QuadDXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000334 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000335 double x = dx_at_t(quad, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000336 return SkDoubleToScalar(x);
337}
338
339static SkScalar CubicDXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000340 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000341 double x = dx_at_t(cubic, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000342 return SkDoubleToScalar(x);
343}
344
345static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
346 NULL,
347 LineDXAtT,
348 QuadDXAtT,
349 CubicDXAtT
350};
351
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000352static SkScalar LineDYAtT(const SkPoint a[2], double ) {
353 return a[1].fY - a[0].fY;
354}
355
356static SkScalar QuadDYAtT(const SkPoint a[3], double t) {
357 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000358 double y = dy_at_t(quad, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000359 return SkDoubleToScalar(y);
360}
361
362static SkScalar CubicDYAtT(const SkPoint a[4], double t) {
363 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000364 double y = dy_at_t(cubic, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000365 return SkDoubleToScalar(y);
366}
367
368static SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = {
369 NULL,
370 LineDYAtT,
371 QuadDYAtT,
372 CubicDYAtT
373};
374
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000375static SkPoint LineDXDYAtT(const SkPoint a[2], double ) {
376 return a[1] - a[0];
377}
378
379static SkPoint QuadDXDYAtT(const SkPoint a[3], double t) {
380 MAKE_CONST_QUAD(quad, a);
381 _Point pt;
382 dxdy_at_t(quad, t, pt);
383 return pt.asSkPoint();
384}
385
386static SkPoint CubicDXDYAtT(const SkPoint a[4], double t) {
387 MAKE_CONST_CUBIC(cubic, a);
388 _Point pt;
389 dxdy_at_t(cubic, t, pt);
390 return pt.asSkPoint();
391}
392
393static SkPoint (* const SegmentDXDYAtT[])(const SkPoint [], double ) = {
394 NULL,
395 LineDXDYAtT,
396 QuadDXDYAtT,
397 CubicDXDYAtT
398};
399
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000400static void LineSubDivide(const SkPoint a[2], double startT, double endT,
401 SkPoint sub[2]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000402 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000403 _Line dst;
404 sub_divide(aLine, startT, endT, dst);
405 sub[0].fX = SkDoubleToScalar(dst[0].x);
406 sub[0].fY = SkDoubleToScalar(dst[0].y);
407 sub[1].fX = SkDoubleToScalar(dst[1].x);
408 sub[1].fY = SkDoubleToScalar(dst[1].y);
409}
410
411static void QuadSubDivide(const SkPoint a[3], double startT, double endT,
412 SkPoint sub[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000413 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000414 Quadratic dst;
415 sub_divide(aQuad, startT, endT, dst);
416 sub[0].fX = SkDoubleToScalar(dst[0].x);
417 sub[0].fY = SkDoubleToScalar(dst[0].y);
418 sub[1].fX = SkDoubleToScalar(dst[1].x);
419 sub[1].fY = SkDoubleToScalar(dst[1].y);
420 sub[2].fX = SkDoubleToScalar(dst[2].x);
421 sub[2].fY = SkDoubleToScalar(dst[2].y);
422}
423
424static void CubicSubDivide(const SkPoint a[4], double startT, double endT,
425 SkPoint sub[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000426 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000427 Cubic dst;
428 sub_divide(aCubic, startT, endT, dst);
429 sub[0].fX = SkDoubleToScalar(dst[0].x);
430 sub[0].fY = SkDoubleToScalar(dst[0].y);
431 sub[1].fX = SkDoubleToScalar(dst[1].x);
432 sub[1].fY = SkDoubleToScalar(dst[1].y);
433 sub[2].fX = SkDoubleToScalar(dst[2].x);
434 sub[2].fY = SkDoubleToScalar(dst[2].y);
435 sub[3].fX = SkDoubleToScalar(dst[3].x);
436 sub[3].fY = SkDoubleToScalar(dst[3].y);
437}
438
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000439static void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
440 SkPoint []) = {
441 NULL,
442 LineSubDivide,
443 QuadSubDivide,
444 CubicSubDivide
445};
446
caryclark@google.comaa358312013-01-29 20:28:49 +0000447static void LineSubDivideHD(const SkPoint a[2], double startT, double endT, _Line& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000448 MAKE_CONST_LINE(aLine, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000449 sub_divide(aLine, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000450}
451
caryclark@google.comaa358312013-01-29 20:28:49 +0000452static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT, Quadratic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000453 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000454 sub_divide(aQuad, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000455}
456
caryclark@google.comaa358312013-01-29 20:28:49 +0000457static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT, Cubic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000458 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000459 sub_divide(aCubic, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000460}
461
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000462static SkPoint QuadTop(const SkPoint a[3], double startT, double endT) {
463 MAKE_CONST_QUAD(quad, a);
464 _Point topPt = top(quad, startT, endT);
465 return topPt.asSkPoint();
466}
467
468static SkPoint CubicTop(const SkPoint a[3], double startT, double endT) {
469 MAKE_CONST_CUBIC(cubic, a);
470 _Point topPt = top(cubic, startT, endT);
471 return topPt.asSkPoint();
472}
473
474static SkPoint (* SegmentTop[])(const SkPoint[], double , double ) = {
475 NULL,
476 NULL,
477 QuadTop,
478 CubicTop
479};
480
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000481#if DEBUG_UNUSED
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000482static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
483 SkRect& bounds) {
484 SkPoint dst[3];
485 QuadSubDivide(a, startT, endT, dst);
486 bounds.fLeft = bounds.fRight = dst[0].fX;
487 bounds.fTop = bounds.fBottom = dst[0].fY;
488 for (int index = 1; index < 3; ++index) {
489 bounds.growToInclude(dst[index].fX, dst[index].fY);
490 }
491}
492
493static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
494 SkRect& bounds) {
495 SkPoint dst[4];
496 CubicSubDivide(a, startT, endT, dst);
497 bounds.fLeft = bounds.fRight = dst[0].fX;
498 bounds.fTop = bounds.fBottom = dst[0].fY;
499 for (int index = 1; index < 4; ++index) {
500 bounds.growToInclude(dst[index].fX, dst[index].fY);
501 }
502}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000503#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000504
caryclark@google.com15fa1382012-05-07 20:49:36 +0000505static SkPath::Verb QuadReduceOrder(const SkPoint a[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000506 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000507 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000508 Quadratic dst;
caryclark@google.com47d73da2013-02-17 01:41:25 +0000509 int order = reduceOrder(aQuad, dst, kReduceOrder_TreatAsFill);
caryclark@google.com24bec792012-08-20 12:43:57 +0000510 if (order == 2) { // quad became line
511 for (int index = 0; index < order; ++index) {
512 SkPoint* pt = reducePts.append();
513 pt->fX = SkDoubleToScalar(dst[index].x);
514 pt->fY = SkDoubleToScalar(dst[index].y);
515 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000516 }
517 return (SkPath::Verb) (order - 1);
518}
519
520static SkPath::Verb CubicReduceOrder(const SkPoint a[4],
521 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000522 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000523 Cubic dst;
caryclark@google.com47d73da2013-02-17 01:41:25 +0000524 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed, kReduceOrder_TreatAsFill);
caryclark@google.com24bec792012-08-20 12:43:57 +0000525 if (order == 2 || order == 3) { // cubic became line or quad
526 for (int index = 0; index < order; ++index) {
527 SkPoint* pt = reducePts.append();
528 pt->fX = SkDoubleToScalar(dst[index].x);
529 pt->fY = SkDoubleToScalar(dst[index].y);
530 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000531 }
532 return (SkPath::Verb) (order - 1);
533}
534
caryclark@google.com15fa1382012-05-07 20:49:36 +0000535static bool QuadIsLinear(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000536 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000537 return isLinear(aQuad, 0, 2);
538}
539
540static bool CubicIsLinear(const SkPoint a[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000541 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000542 return isLinear(aCubic, 0, 3);
543}
544
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000545static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000546 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000547 double x[2];
548 xy_at_t(aLine, startT, x[0], *(double*) 0);
caryclark@google.com495f8e42012-05-31 13:13:11 +0000549 xy_at_t(aLine, endT, x[1], *(double*) 0);
550 return SkMinScalar((float) x[0], (float) x[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000551}
552
553static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000554 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000555 return (float) leftMostT(aQuad, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000556}
557
558static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000559 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000560 return (float) leftMostT(aCubic, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000561}
562
563static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
564 NULL,
565 LineLeftMost,
566 QuadLeftMost,
567 CubicLeftMost
568};
569
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000570#if 0 // currently unused
caryclark@google.com235f56a2012-09-14 14:19:30 +0000571static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
572 Intersections& intersections) {
573 MAKE_CONST_QUAD(aQuad, a);
574 MAKE_CONST_LINE(bLine, b);
575 return intersectRay(aQuad, bLine, intersections);
576}
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000577#endif
578
caryclark@google.comf9502d72013-02-04 14:06:49 +0000579static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000580 MAKE_CONST_QUAD(aQuad, a);
581 return intersectRay(aQuad, bLine, intersections);
582}
caryclark@google.com235f56a2012-09-14 14:19:30 +0000583
caryclark@google.comf9502d72013-02-04 14:06:49 +0000584static int CubicRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) {
585 MAKE_CONST_CUBIC(aCubic, a);
586 return intersectRay(aCubic, bLine, intersections);
587}
588
589static int (* const SegmentRayIntersect[])(const SkPoint [], const _Line& , Intersections&) = {
590 NULL,
591 NULL,
592 QuadRayIntersect,
593 CubicRayIntersect
594};
595
596
597
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000598static bool LineVertical(const SkPoint a[2], double startT, double endT) {
599 MAKE_CONST_LINE(aLine, a);
600 double x[2];
601 xy_at_t(aLine, startT, x[0], *(double*) 0);
602 xy_at_t(aLine, endT, x[1], *(double*) 0);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000603 return AlmostEqualUlps((float) x[0], (float) x[1]);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000604}
605
606static bool QuadVertical(const SkPoint a[3], double startT, double endT) {
607 SkPoint dst[3];
608 QuadSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000609 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000610}
611
612static bool CubicVertical(const SkPoint a[4], double startT, double endT) {
613 SkPoint dst[4];
614 CubicSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000615 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX)
616 && AlmostEqualUlps(dst[2].fX, dst[3].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000617}
618
619static bool (* const SegmentVertical[])(const SkPoint [], double , double) = {
620 NULL,
621 LineVertical,
622 QuadVertical,
623 CubicVertical
624};
625
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000626class Segment;
627
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000628struct Span {
629 Segment* fOther;
630 mutable SkPoint fPt; // lazily computed as needed
631 double fT;
632 double fOtherT; // value at fOther[fOtherIndex].fT
633 int fOtherIndex; // can't be used during intersection
caryclark@google.com31143cf2012-11-09 22:14:19 +0000634 int fWindSum; // accumulated from contours surrounding this one.
635 int fOppSum; // for binary operators: the opposite winding sum
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000636 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
caryclark@google.com57cff8d2012-11-14 21:14:56 +0000637 int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000638 bool fDone; // if set, this span to next higher T has been processed
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000639 bool fUnsortableStart; // set when start is part of an unsortable pair
640 bool fUnsortableEnd; // set when end is part of an unsortable pair
caryclark@google.comf839c032012-10-26 21:03:50 +0000641 bool fTiny; // if set, span may still be considered once for edge following
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000642};
643
caryclark@google.com15fa1382012-05-07 20:49:36 +0000644// sorting angles
645// given angles of {dx dy ddx ddy dddx dddy} sort them
646class Angle {
647public:
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000648 // FIXME: this is bogus for quads and cubics
649 // if the quads and cubics' line from end pt to ctrl pt are coincident,
650 // there's no obvious way to determine the curve ordering from the
651 // derivatives alone. In particular, if one quadratic's coincident tangent
652 // is longer than the other curve, the final control point can place the
653 // longer curve on either side of the shorter one.
654 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
655 // may provide some help, but nothing has been figured out yet.
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000656
caryclark@google.com32546db2012-08-31 20:55:07 +0000657 /*(
658 for quads and cubics, set up a parameterized line (e.g. LineParameters )
659 for points [0] to [1]. See if point [2] is on that line, or on one side
660 or the other. If it both quads' end points are on the same side, choose
661 the shorter tangent. If the tangents are equal, choose the better second
662 tangent angle
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000663
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000664 maybe I could set up LineParameters lazily
caryclark@google.com32546db2012-08-31 20:55:07 +0000665 */
caryclark@google.com15fa1382012-05-07 20:49:36 +0000666 bool operator<(const Angle& rh) const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000667 double y = dy();
668 double ry = rh.dy();
669 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
670 return y < 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000671 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000672 double x = dx();
673 double rx = rh.dx();
674 if (y == 0 && ry == 0 && x * rx < 0) {
675 return x < rx;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000676 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000677 double x_ry = x * ry;
678 double rx_y = rx * y;
679 double cmp = x_ry - rx_y;
caryclark@google.comc899ad92012-08-23 15:24:42 +0000680 if (!approximately_zero(cmp)) {
caryclark@google.com15fa1382012-05-07 20:49:36 +0000681 return cmp < 0;
682 }
caryclark@google.comd1688742012-09-18 20:08:37 +0000683 if (approximately_zero(x_ry) && approximately_zero(rx_y)
684 && !approximately_zero_squared(cmp)) {
685 return cmp < 0;
686 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000687 // at this point, the initial tangent line is coincident
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000688 // see if edges curl away from each other
caryclark@google.com31143cf2012-11-09 22:14:19 +0000689 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
690 || !approximately_zero(rh.fSide))) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000691 // FIXME: running demo will trigger this assertion
692 // (don't know if commenting out will trigger further assertion or not)
693 // commenting it out allows demo to run in release, though
694 // SkASSERT(fSide != rh.fSide);
695 return fSide < rh.fSide;
696 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000697 // see if either curve can be lengthened and try the tangent compare again
698 if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
699 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
700 Angle longer = *this;
701 Angle rhLonger = rh;
702 if (longer.lengthen() | rhLonger.lengthen()) {
703 return longer < rhLonger;
704 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000705 #if 0
caryclark@google.coma461ff02012-10-11 12:54:23 +0000706 // what if we extend in the other direction?
707 longer = *this;
708 rhLonger = rh;
709 if (longer.reverseLengthen() | rhLonger.reverseLengthen()) {
710 return longer < rhLonger;
711 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000712 #endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000713 }
caryclark@google.com185c7c42012-10-19 18:26:24 +0000714 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
caryclark@google.com31143cf2012-11-09 22:14:19 +0000715 || (rh.fVerb == SkPath::kLine_Verb
716 && approximately_zero(rx) && approximately_zero(ry))) {
caryclark@google.com185c7c42012-10-19 18:26:24 +0000717 // See general unsortable comment below. This case can happen when
718 // one line has a non-zero change in t but no change in x and y.
719 fUnsortable = true;
720 rh.fUnsortable = true;
721 return this < &rh; // even with no solution, return a stable sort
722 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000723 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
724 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
725 fUnsortable = true;
726 rh.fUnsortable = true;
727 return this < &rh; // even with no solution, return a stable sort
728 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000729 SkASSERT(fVerb >= SkPath::kQuad_Verb);
730 SkASSERT(rh.fVerb >= SkPath::kQuad_Verb);
skia.committer@gmail.comc1ad0222012-09-19 02:01:47 +0000731 // FIXME: until I can think of something better, project a ray from the
caryclark@google.comd1688742012-09-18 20:08:37 +0000732 // end of the shorter tangent to midway between the end points
733 // through both curves and use the resulting angle to sort
caryclark@google.com235f56a2012-09-14 14:19:30 +0000734 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
735 double len = fTangent1.normalSquared();
736 double rlen = rh.fTangent1.normalSquared();
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000737 _Line ray;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000738 Intersections i, ri;
caryclark@google.comd1688742012-09-18 20:08:37 +0000739 int roots, rroots;
740 bool flip = false;
741 do {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000742 bool useThis = (len < rlen) ^ flip;
743 const Cubic& part = useThis ? fCurvePart : rh.fCurvePart;
744 SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb;
745 ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ?
746 part[2] : part[1];
747 ray[1].x = (part[0].x + part[partVerb].x) / 2;
748 ray[1].y = (part[0].y + part[partVerb].y) / 2;
caryclark@google.comd1688742012-09-18 20:08:37 +0000749 SkASSERT(ray[0] != ray[1]);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000750 roots = (*SegmentRayIntersect[fVerb])(fPts, ray, i);
751 rroots = (*SegmentRayIntersect[rh.fVerb])(rh.fPts, ray, ri);
caryclark@google.comd1688742012-09-18 20:08:37 +0000752 } while ((roots == 0 || rroots == 0) && (flip ^= true));
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000753 if (roots == 0 || rroots == 0) {
754 // FIXME: we don't have a solution in this case. The interim solution
755 // is to mark the edges as unsortable, exclude them from this and
756 // future computations, and allow the returned path to be fragmented
757 fUnsortable = true;
758 rh.fUnsortable = true;
759 return this < &rh; // even with no solution, return a stable sort
760 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000761 _Point loc;
762 double best = SK_ScalarInfinity;
763 double dx, dy, dist;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000764 int index;
765 for (index = 0; index < roots; ++index) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000766 (*SegmentXYAtT2[fVerb])(fPts, i.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000767 dx = loc.x - ray[0].x;
768 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000769 dist = dx * dx + dy * dy;
770 if (best > dist) {
771 best = dist;
772 }
773 }
774 for (index = 0; index < rroots; ++index) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000775 (*SegmentXYAtT2[rh.fVerb])(rh.fPts, ri.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000776 dx = loc.x - ray[0].x;
777 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000778 dist = dx * dx + dy * dy;
779 if (best > dist) {
780 return fSide < 0;
781 }
782 }
783 return fSide > 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000784 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000785
caryclark@google.com47580692012-07-23 12:14:49 +0000786 double dx() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000787 return fTangent1.dx();
caryclark@google.com47580692012-07-23 12:14:49 +0000788 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000789
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000790 double dy() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000791 return fTangent1.dy();
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000792 }
793
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000794 int end() const {
795 return fEnd;
796 }
797
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000798 bool isHorizontal() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000799 return dy() == 0 && fVerb == SkPath::kLine_Verb;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000800 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000801
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000802 bool lengthen() {
803 int newEnd = fEnd;
804 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
805 fEnd = newEnd;
806 setSpans();
807 return true;
808 }
809 return false;
810 }
811
caryclark@google.coma461ff02012-10-11 12:54:23 +0000812 bool reverseLengthen() {
813 if (fReversed) {
814 return false;
815 }
816 int newEnd = fStart;
817 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
818 fEnd = newEnd;
819 fReversed = true;
820 setSpans();
821 return true;
822 }
823 return false;
824 }
825
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000826 void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000827 int start, int end, const SkTDArray<Span>& spans) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000828 fSegment = segment;
829 fStart = start;
830 fEnd = end;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000831 fPts = orig;
832 fVerb = verb;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000833 fSpans = &spans;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000834 fReversed = false;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000835 fUnsortable = false;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000836 setSpans();
837 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000838
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000839
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000840 void setSpans() {
841 double startT = (*fSpans)[fStart].fT;
842 double endT = (*fSpans)[fEnd].fT;
843 switch (fVerb) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000844 case SkPath::kLine_Verb:
845 _Line l;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000846 LineSubDivideHD(fPts, startT, endT, l);
caryclark@google.com32546db2012-08-31 20:55:07 +0000847 // OPTIMIZATION: for pure line compares, we never need fTangent1.c
848 fTangent1.lineEndPoints(l);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000849 fSide = 0;
caryclark@google.com32546db2012-08-31 20:55:07 +0000850 break;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000851 case SkPath::kQuad_Verb: {
852 Quadratic& quad = (Quadratic&)fCurvePart;
853 QuadSubDivideHD(fPts, startT, endT, quad);
854 fTangent1.quadEndPoints(quad, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000855 #if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
856 if (dx() == 0 && dy() == 0) {
caryclark@google.combeda3892013-02-07 13:13:41 +0000857 // SkDebugf("*** %s quad is line\n", __FUNCTION__);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000858 fTangent1.quadEndPoints(quad);
caryclark@google.comaa358312013-01-29 20:28:49 +0000859 }
860 #endif
caryclark@google.comf9502d72013-02-04 14:06:49 +0000861 fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- compare sign only
862 } break;
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000863 case SkPath::kCubic_Verb: {
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000864 int nextC = 2;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000865 CubicSubDivideHD(fPts, startT, endT, fCurvePart);
866 fTangent1.cubicEndPoints(fCurvePart, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000867 if (dx() == 0 && dy() == 0) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000868 fTangent1.cubicEndPoints(fCurvePart, 0, 2);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000869 nextC = 3;
caryclark@google.comaa358312013-01-29 20:28:49 +0000870 #if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
871 if (dx() == 0 && dy() == 0) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +0000872 SkDebugf("*** %s cubic is line\n", __FUNCTION__);
caryclark@google.comf9502d72013-02-04 14:06:49 +0000873 fTangent1.cubicEndPoints(fCurvePart, 0, 3);
caryclark@google.comaa358312013-01-29 20:28:49 +0000874 }
875 #endif
876 }
caryclark@google.comf9502d72013-02-04 14:06:49 +0000877 fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign only
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000878 if (nextC == 2 && approximately_zero(fSide)) {
caryclark@google.comf9502d72013-02-04 14:06:49 +0000879 fSide = -fTangent1.pointDistance(fCurvePart[3]);
caryclark@google.com86adc0d2013-01-30 12:50:38 +0000880 }
881 } break;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000882 default:
883 SkASSERT(0);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000884 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000885 fUnsortable = dx() == 0 && dy() == 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000886 if (fUnsortable) {
887 return;
888 }
889 SkASSERT(fStart != fEnd);
890 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
891 for (int index = fStart; index != fEnd; index += step) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000892#if 1
893 const Span& thisSpan = (*fSpans)[index];
894 const Span& nextSpan = (*fSpans)[index + step];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000895 if (thisSpan.fTiny || precisely_equal(thisSpan.fT, nextSpan.fT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000896 continue;
caryclark@google.comf839c032012-10-26 21:03:50 +0000897 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000898 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
899#if DEBUG_UNSORTABLE
900 if (fUnsortable) {
901 SkPoint iPt, ePt;
902 (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt);
903 (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt);
904 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
905 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
906 }
907#endif
908 return;
909#else
910 if ((*fSpans)[index].fUnsortableStart) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000911 fUnsortable = true;
912 return;
913 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000914#endif
caryclark@google.comf839c032012-10-26 21:03:50 +0000915 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000916#if 1
917#if DEBUG_UNSORTABLE
918 SkPoint iPt, ePt;
919 (*SegmentXYAtT[fVerb])(fPts, startT, &iPt);
920 (*SegmentXYAtT[fVerb])(fPts, endT, &ePt);
921 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
922 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
923#endif
924 fUnsortable = true;
925#endif
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000926 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000927
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000928 Segment* segment() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000929 return const_cast<Segment*>(fSegment);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000930 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000931
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000932 int sign() const {
caryclark@google.com495f8e42012-05-31 13:13:11 +0000933 return SkSign32(fStart - fEnd);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000934 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000935
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000936 const SkTDArray<Span>* spans() const {
937 return fSpans;
938 }
939
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000940 int start() const {
941 return fStart;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000942 }
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +0000943
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000944 bool unsortable() const {
945 return fUnsortable;
946 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000947
caryclark@google.comc899ad92012-08-23 15:24:42 +0000948#if DEBUG_ANGLE
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000949 const SkPoint* pts() const {
950 return fPts;
951 }
952
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000953 SkPath::Verb verb() const {
954 return fVerb;
955 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000956
caryclark@google.comc899ad92012-08-23 15:24:42 +0000957 void debugShow(const SkPoint& a) const {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000958 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
caryclark@google.comc899ad92012-08-23 15:24:42 +0000959 }
960#endif
961
caryclark@google.com15fa1382012-05-07 20:49:36 +0000962private:
caryclark@google.com235f56a2012-09-14 14:19:30 +0000963 const SkPoint* fPts;
caryclark@google.comf9502d72013-02-04 14:06:49 +0000964 Cubic fCurvePart;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000965 SkPath::Verb fVerb;
966 double fSide;
967 LineParameters fTangent1;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000968 const SkTDArray<Span>* fSpans;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000969 const Segment* fSegment;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000970 int fStart;
971 int fEnd;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000972 bool fReversed;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000973 mutable bool fUnsortable; // this alone is editable by the less than operator
caryclark@google.com15fa1382012-05-07 20:49:36 +0000974};
975
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000976// Bounds, unlike Rect, does not consider a line to be empty.
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000977struct Bounds : public SkRect {
978 static bool Intersects(const Bounds& a, const Bounds& b) {
979 return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
980 a.fTop <= b.fBottom && b.fTop <= a.fBottom;
981 }
982
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000983 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
984 if (left < fLeft) {
985 fLeft = left;
986 }
987 if (top < fTop) {
988 fTop = top;
989 }
990 if (right > fRight) {
991 fRight = right;
992 }
993 if (bottom > fBottom) {
994 fBottom = bottom;
995 }
996 }
997
998 void add(const Bounds& toAdd) {
999 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
1000 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001001
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001002 void add(const SkPoint& pt) {
1003 if (pt.fX < fLeft) fLeft = pt.fX;
1004 if (pt.fY < fTop) fTop = pt.fY;
1005 if (pt.fX > fRight) fRight = pt.fX;
1006 if (pt.fY > fBottom) fBottom = pt.fY;
1007 }
1008
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001009 bool isEmpty() {
1010 return fLeft > fRight || fTop > fBottom
caryclark@google.com235f56a2012-09-14 14:19:30 +00001011 || (fLeft == fRight && fTop == fBottom)
caryclark@google.combeda3892013-02-07 13:13:41 +00001012 || sk_double_isnan(fLeft) || sk_double_isnan(fRight)
1013 || sk_double_isnan(fTop) || sk_double_isnan(fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001014 }
1015
1016 void setCubicBounds(const SkPoint a[4]) {
1017 _Rect dRect;
caryclark@google.com32546db2012-08-31 20:55:07 +00001018 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001019 dRect.setBounds(cubic);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001020 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1021 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001022 }
1023
1024 void setQuadBounds(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +00001025 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001026 _Rect dRect;
1027 dRect.setBounds(quad);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001028 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
1029 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001030 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001031
1032 void setPoint(const SkPoint& pt) {
1033 fLeft = fRight = pt.fX;
1034 fTop = fBottom = pt.fY;
1035 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001036};
1037
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001038// OPTIMIZATION: does the following also work, and is it any faster?
1039// return outerWinding * innerWinding > 0
1040// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
caryclark@google.com2ddff932012-08-07 21:25:27 +00001041static bool useInnerWinding(int outerWinding, int innerWinding) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001042 // SkASSERT(outerWinding != innerWinding);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001043 int absOut = abs(outerWinding);
1044 int absIn = abs(innerWinding);
1045 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1046 if (outerWinding * innerWinding < 0) {
caryclark@google.com5e0500f2013-02-20 12:51:37 +00001047#if 0 && DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00001048 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
caryclark@google.com2ddff932012-08-07 21:25:27 +00001049 outerWinding, innerWinding, result ? "true" : "false");
1050#endif
1051 }
1052 return result;
1053}
1054
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001055#define F (false) // discard the edge
1056#define T (true) // keep the edge
1057
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001058static const bool gUnaryActiveEdge[2][2] = {
1059// from=0 from=1
1060// to=0,1 to=0,1
1061 {F, T}, {T, F},
1062};
1063
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001064static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
1065// miFrom=0 miFrom=1
1066// miTo=0 miTo=1 miTo=0 miTo=1
1067// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
1068// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
1069 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
1070 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
1071 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
1072 {{{{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 +00001073};
1074
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001075#undef F
1076#undef T
caryclark@google.com235f56a2012-09-14 14:19:30 +00001077
caryclark@google.comf839c032012-10-26 21:03:50 +00001078// wrap path to keep track of whether the contour is initialized and non-empty
1079class PathWrapper {
1080public:
1081 PathWrapper(SkPath& path)
1082 : fPathPtr(&path)
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001083 , fCloses(0)
1084 , fMoves(0)
caryclark@google.comf839c032012-10-26 21:03:50 +00001085 {
1086 init();
1087 }
1088
1089 void close() {
1090 if (!fHasMove) {
1091 return;
1092 }
1093 bool callClose = isClosed();
1094 lineTo();
1095 if (fEmpty) {
1096 return;
1097 }
1098 if (callClose) {
1099 #if DEBUG_PATH_CONSTRUCTION
1100 SkDebugf("path.close();\n");
1101 #endif
1102 fPathPtr->close();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001103 fCloses++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001104 }
1105 init();
1106 }
1107
1108 void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
1109 lineTo();
1110 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001111 fDefer[1] = pt3;
1112 nudge();
1113 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001114#if DEBUG_PATH_CONSTRUCTION
1115 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001116 pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001117#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001118 fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001119 fEmpty = false;
1120 }
1121
1122 void deferredLine(const SkPoint& pt) {
1123 if (pt == fDefer[1]) {
1124 return;
1125 }
1126 if (changedSlopes(pt)) {
1127 lineTo();
1128 fDefer[0] = fDefer[1];
1129 }
1130 fDefer[1] = pt;
1131 }
1132
1133 void deferredMove(const SkPoint& pt) {
1134 fMoved = true;
1135 fHasMove = true;
1136 fEmpty = true;
1137 fDefer[0] = fDefer[1] = pt;
1138 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001139
caryclark@google.comf839c032012-10-26 21:03:50 +00001140 void deferredMoveLine(const SkPoint& pt) {
1141 if (!fHasMove) {
1142 deferredMove(pt);
1143 }
1144 deferredLine(pt);
1145 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001146
caryclark@google.comf839c032012-10-26 21:03:50 +00001147 bool hasMove() const {
1148 return fHasMove;
1149 }
1150
1151 void init() {
1152 fEmpty = true;
1153 fHasMove = false;
1154 fMoved = false;
1155 }
1156
1157 bool isClosed() const {
1158 return !fEmpty && fFirstPt == fDefer[1];
1159 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001160
caryclark@google.comf839c032012-10-26 21:03:50 +00001161 void lineTo() {
1162 if (fDefer[0] == fDefer[1]) {
1163 return;
1164 }
1165 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001166 nudge();
caryclark@google.comf839c032012-10-26 21:03:50 +00001167 fEmpty = false;
1168#if DEBUG_PATH_CONSTRUCTION
1169 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
1170#endif
1171 fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
1172 fDefer[0] = fDefer[1];
1173 }
1174
1175 const SkPath* nativePath() const {
1176 return fPathPtr;
1177 }
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +00001178
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001179 void nudge() {
1180 if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX)
1181 || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) {
1182 return;
1183 }
1184 fDefer[1] = fFirstPt;
1185 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001186
1187 void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
1188 lineTo();
1189 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001190 fDefer[1] = pt2;
1191 nudge();
1192 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001193#if DEBUG_PATH_CONSTRUCTION
1194 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001195 pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001196#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001197 fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001198 fEmpty = false;
1199 }
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00001200
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001201 bool someAssemblyRequired() const {
1202 return fCloses < fMoves;
1203 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001204
1205protected:
1206 bool changedSlopes(const SkPoint& pt) const {
1207 if (fDefer[0] == fDefer[1]) {
1208 return false;
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001209 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001210 SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
1211 SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
1212 SkScalar lineDx = pt.fX - fDefer[1].fX;
1213 SkScalar lineDy = pt.fY - fDefer[1].fY;
1214 return deferDx * lineDy != deferDy * lineDx;
1215 }
1216
1217 void moveTo() {
1218 if (!fMoved) {
1219 return;
1220 }
1221 fFirstPt = fDefer[0];
1222#if DEBUG_PATH_CONSTRUCTION
1223 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
1224#endif
1225 fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
1226 fMoved = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001227 fMoves++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001228 }
1229
1230private:
1231 SkPath* fPathPtr;
1232 SkPoint fDefer[2];
1233 SkPoint fFirstPt;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001234 int fCloses;
1235 int fMoves;
caryclark@google.comf839c032012-10-26 21:03:50 +00001236 bool fEmpty;
1237 bool fHasMove;
1238 bool fMoved;
1239};
1240
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001241class Segment {
1242public:
1243 Segment() {
1244#if DEBUG_DUMP
1245 fID = ++gSegmentID;
1246#endif
1247 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00001248
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001249 bool operator<(const Segment& rh) const {
1250 return fBounds.fTop < rh.fBounds.fTop;
1251 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001252
caryclark@google.com4eeda372012-12-06 21:47:48 +00001253 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001254 if (activeAngleInner(index, done, angles)) {
1255 return true;
1256 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001257 int lesser = index;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001258 while (--lesser >= 0 && equalPoints(index, lesser)) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001259 if (activeAngleOther(lesser, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001260 return true;
1261 }
1262 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001263 lesser = index;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001264 do {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001265 if (activeAngleOther(index, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001266 return true;
1267 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001268 } while (++index < fTs.count() && equalPoints(index, lesser));
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001269 return false;
1270 }
1271
caryclark@google.com4eeda372012-12-06 21:47:48 +00001272 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001273 Span* span = &fTs[index];
1274 Segment* other = span->fOther;
1275 int oIndex = span->fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001276 return other->activeAngleInner(oIndex, done, angles);
1277 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001278
caryclark@google.com4eeda372012-12-06 21:47:48 +00001279 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001280 int next = nextExactSpan(index, 1);
caryclark@google.com9764cc62012-07-12 19:29:45 +00001281 if (next > 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001282 Span& upSpan = fTs[index];
1283 if (upSpan.fWindValue || upSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001284 addAngle(angles, index, next);
caryclark@google.comf839c032012-10-26 21:03:50 +00001285 if (upSpan.fDone || upSpan.fUnsortableEnd) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001286 done++;
1287 } else if (upSpan.fWindSum != SK_MinS32) {
1288 return true;
1289 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001290 } else if (!upSpan.fDone) {
1291 upSpan.fDone = true;
1292 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001293 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001294 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001295 int prev = nextExactSpan(index, -1);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001296 // edge leading into junction
caryclark@google.com9764cc62012-07-12 19:29:45 +00001297 if (prev >= 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001298 Span& downSpan = fTs[prev];
1299 if (downSpan.fWindValue || downSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001300 addAngle(angles, index, prev);
1301 if (downSpan.fDone) {
1302 done++;
1303 } else if (downSpan.fWindSum != SK_MinS32) {
1304 return true;
1305 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001306 } else if (!downSpan.fDone) {
1307 downSpan.fDone = true;
1308 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001309 }
1310 }
1311 return false;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001312 }
1313
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001314 SkPoint activeLeftTop(bool onlySortable, int* firstT) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001315 SkASSERT(!done());
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001316 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001317 int count = fTs.count();
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001318 // see if either end is not done since we want smaller Y of the pair
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001319 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00001320 bool lastUnsortable = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001321 double lastT = -1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001322 for (int index = 0; index < count; ++index) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001323 const Span& span = fTs[index];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001324 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001325 goto next;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001326 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001327 if (span.fDone && lastDone) {
1328 goto next;
1329 }
1330 if (approximately_negative(span.fT - lastT)) {
1331 goto next;
1332 }
1333 {
1334 const SkPoint& xy = xyAtT(&span);
1335 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
1336 topPt = xy;
1337 if (firstT) {
1338 *firstT = index;
1339 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001340 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001341 if (fVerb != SkPath::kLine_Verb && !lastDone) {
1342 SkPoint curveTop = (*SegmentTop[fVerb])(fPts, lastT, span.fT);
1343 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
1344 && topPt.fX > curveTop.fX)) {
1345 topPt = curveTop;
1346 if (firstT) {
1347 *firstT = index;
1348 }
1349 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001350 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001351 lastT = span.fT;
caryclark@google.comf839c032012-10-26 21:03:50 +00001352 }
1353 next:
1354 lastDone = span.fDone;
1355 lastUnsortable = span.fUnsortableEnd;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001356 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001357 return topPt;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001358 }
1359
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001360 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
1361 int sumMiWinding = updateWinding(endIndex, index);
1362 int sumSuWinding = updateOppWinding(endIndex, index);
1363 if (fOperand) {
1364 SkTSwap<int>(sumMiWinding, sumSuWinding);
1365 }
1366 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1367 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001368 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001369 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001370
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001371 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00001372 int& sumMiWinding, int& sumSuWinding,
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001373 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
1374 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1375 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001376 bool miFrom;
1377 bool miTo;
1378 bool suFrom;
1379 bool suTo;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001380 if (operand()) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001381 miFrom = (oppMaxWinding & xorMiMask) != 0;
1382 miTo = (oppSumWinding & xorMiMask) != 0;
1383 suFrom = (maxWinding & xorSuMask) != 0;
1384 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001385 } else {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001386 miFrom = (maxWinding & xorMiMask) != 0;
1387 miTo = (sumWinding & xorMiMask) != 0;
1388 suFrom = (oppMaxWinding & xorSuMask) != 0;
1389 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001390 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001391 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
caryclark@google.combeda3892013-02-07 13:13:41 +00001392#if DEBUG_ACTIVE_OP
1393 SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__,
1394 kShapeOpStr[op], miFrom, miTo, suFrom, suTo, result);
1395#endif
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001396 SkASSERT(result != -1);
1397 return result;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001398 }
1399
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001400 bool activeWinding(int index, int endIndex) {
1401 int sumWinding = updateWinding(endIndex, index);
1402 int maxWinding;
1403 return activeWinding(index, endIndex, maxWinding, sumWinding);
1404 }
1405
1406 bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
1407 setUpWinding(index, endIndex, maxWinding, sumWinding);
1408 bool from = maxWinding != 0;
1409 bool to = sumWinding != 0;
1410 bool result = gUnaryActiveEdge[from][to];
1411 SkASSERT(result != -1);
1412 return result;
1413 }
1414
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001415 void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001416 SkASSERT(start != end);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001417 Angle* angle = angles.append();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001418#if DEBUG_ANGLE
caryclark@google.com31143cf2012-11-09 22:14:19 +00001419 if (angles.count() > 1 && !fTs[start].fTiny) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001420 SkPoint angle0Pt, newPt;
1421 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
1422 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
1423 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
caryclark@google.com6d0032a2013-01-04 19:41:13 +00001424 SkASSERT(AlmostEqualUlps(angle0Pt.fX, newPt.fX));
1425 SkASSERT(AlmostEqualUlps(angle0Pt.fY, newPt.fY));
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001426 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001427#endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001428 angle->set(fPts, fVerb, this, start, end, fTs);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001429 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001430
caryclark@google.com2ddff932012-08-07 21:25:27 +00001431 void addCancelOutsides(double tStart, double oStart, Segment& other,
caryclark@google.comcc905052012-07-25 20:59:42 +00001432 double oEnd) {
1433 int tIndex = -1;
1434 int tCount = fTs.count();
1435 int oIndex = -1;
1436 int oCount = other.fTs.count();
caryclark@google.comcc905052012-07-25 20:59:42 +00001437 do {
1438 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001439 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001440 int tIndexStart = tIndex;
1441 do {
1442 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001443 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001444 int oIndexStart = oIndex;
1445 double nextT;
1446 do {
1447 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001448 } while (nextT < 1 && approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001449 double oNextT;
1450 do {
1451 oNextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001452 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001453 // at this point, spans before and after are at:
1454 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1455 // if tIndexStart == 0, no prior span
1456 // if nextT == 1, no following span
rmistry@google.comd6176b02012-08-23 18:14:13 +00001457
caryclark@google.comcc905052012-07-25 20:59:42 +00001458 // advance the span with zero winding
1459 // if the following span exists (not past the end, non-zero winding)
1460 // connect the two edges
1461 if (!fTs[tIndexStart].fWindValue) {
1462 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1463 #if DEBUG_CONCIDENT
1464 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1465 __FUNCTION__, fID, other.fID, tIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001466 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
1467 xyAtT(tIndexStart).fY);
caryclark@google.comcc905052012-07-25 20:59:42 +00001468 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001469 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false,
1470 fTs[tIndexStart].fPt);
caryclark@google.comcc905052012-07-25 20:59:42 +00001471 }
1472 if (nextT < 1 && fTs[tIndex].fWindValue) {
1473 #if DEBUG_CONCIDENT
1474 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1475 __FUNCTION__, fID, other.fID, tIndex,
1476 fTs[tIndex].fT, xyAtT(tIndex).fX,
1477 xyAtT(tIndex).fY);
1478 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001479 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false, fTs[tIndex].fPt);
caryclark@google.comcc905052012-07-25 20:59:42 +00001480 }
1481 } else {
1482 SkASSERT(!other.fTs[oIndexStart].fWindValue);
1483 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1484 #if DEBUG_CONCIDENT
1485 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1486 __FUNCTION__, fID, other.fID, oIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001487 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
1488 other.xyAtT(oIndexStart).fY);
1489 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
caryclark@google.comcc905052012-07-25 20:59:42 +00001490 #endif
caryclark@google.comcc905052012-07-25 20:59:42 +00001491 }
1492 if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1493 #if DEBUG_CONCIDENT
1494 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1495 __FUNCTION__, fID, other.fID, oIndex,
1496 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1497 other.xyAtT(oIndex).fY);
1498 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1499 #endif
1500 }
1501 }
1502 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001503
caryclark@google.comcc905052012-07-25 20:59:42 +00001504 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1505 double oEnd) {
1506 // walk this to outsideTs[0]
1507 // walk other to outsideTs[1]
1508 // if either is > 0, add a pointer to the other, copying adjacent winding
1509 int tIndex = -1;
1510 int oIndex = -1;
1511 double tStart = outsideTs[0];
1512 double oStart = outsideTs[1];
1513 do {
1514 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001515 } while (!approximately_negative(tStart - fTs[tIndex].fT));
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001516 SkPoint ptStart = fTs[tIndex].fPt;
caryclark@google.comcc905052012-07-25 20:59:42 +00001517 do {
1518 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001519 } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001520 if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001521 addTPair(tStart, other, oStart, false, ptStart);
caryclark@google.comcc905052012-07-25 20:59:42 +00001522 }
1523 tStart = fTs[tIndex].fT;
1524 oStart = other.fTs[oIndex].fT;
1525 do {
1526 double nextT;
1527 do {
1528 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001529 } while (approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001530 tStart = nextT;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001531 ptStart = fTs[tIndex].fPt;
caryclark@google.comcc905052012-07-25 20:59:42 +00001532 do {
1533 nextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001534 } while (approximately_negative(nextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001535 oStart = nextT;
caryclark@google.com4eeda372012-12-06 21:47:48 +00001536 if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001537 break;
1538 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001539 addTPair(tStart, other, oStart, false, ptStart);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001540 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001541 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001542
caryclark@google.com4eeda372012-12-06 21:47:48 +00001543 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
1544 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001545 fBounds.setCubicBounds(pts);
1546 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001547
caryclark@google.comf839c032012-10-26 21:03:50 +00001548 /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001549 SkPoint edge[4];
caryclark@google.comf839c032012-10-26 21:03:50 +00001550 const SkPoint* ePtr;
1551 int lastT = fTs.count() - 1;
1552 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1553 ePtr = fPts;
1554 } else {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001555 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
caryclark@google.comf839c032012-10-26 21:03:50 +00001556 (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
1557 ePtr = edge;
1558 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001559 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001560 bool reverse = ePtr == fPts && start != 0;
1561 if (reverse) {
1562 path.deferredMoveLine(ePtr[fVerb]);
1563 switch (fVerb) {
1564 case SkPath::kLine_Verb:
1565 path.deferredLine(ePtr[0]);
1566 break;
1567 case SkPath::kQuad_Verb:
1568 path.quadTo(ePtr[1], ePtr[0]);
1569 break;
1570 case SkPath::kCubic_Verb:
1571 path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1572 break;
1573 default:
1574 SkASSERT(0);
1575 }
1576 // return ePtr[0];
1577 } else {
1578 path.deferredMoveLine(ePtr[0]);
1579 switch (fVerb) {
1580 case SkPath::kLine_Verb:
1581 path.deferredLine(ePtr[1]);
1582 break;
1583 case SkPath::kQuad_Verb:
1584 path.quadTo(ePtr[1], ePtr[2]);
1585 break;
1586 case SkPath::kCubic_Verb:
1587 path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1588 break;
1589 default:
1590 SkASSERT(0);
1591 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001592 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001593 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001594 // return ePtr[fVerb];
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001595 }
1596
caryclark@google.com4eeda372012-12-06 21:47:48 +00001597 void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
1598 init(pts, SkPath::kLine_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001599 fBounds.set(pts, 2);
1600 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001601
caryclark@google.comf839c032012-10-26 21:03:50 +00001602#if 0
1603 const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001604 const SkPoint& pt = xyAtT(tIndex);
1605 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001606 path.deferredMove(pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001607 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00001608 return pt;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001609 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001610#endif
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001611
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001612 // add 2 to edge or out of range values to get T extremes
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001613 void addOtherT(int index, double otherT, int otherIndex) {
1614 Span& span = fTs[index];
caryclark@google.comf839c032012-10-26 21:03:50 +00001615 #if PIN_ADD_T
caryclark@google.com185c7c42012-10-19 18:26:24 +00001616 if (precisely_less_than_zero(otherT)) {
1617 otherT = 0;
1618 } else if (precisely_greater_than_one(otherT)) {
1619 otherT = 1;
1620 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001621 #endif
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001622 span.fOtherT = otherT;
1623 span.fOtherIndex = otherIndex;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001624 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001625
caryclark@google.com4eeda372012-12-06 21:47:48 +00001626 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
1627 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001628 fBounds.setQuadBounds(pts);
1629 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001630
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001631 // Defer all coincident edge processing until
1632 // after normal intersections have been computed
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001633
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001634// no need to be tricky; insert in normal T order
1635// resolve overlapping ts when considering coincidence later
1636
1637 // add non-coincident intersection. Resulting edges are sorted in T.
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001638 int addT(double newT, Segment* other, const SkPoint& pt) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001639 // FIXME: in the pathological case where there is a ton of intercepts,
1640 // binary search?
1641 int insertedAt = -1;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001642 size_t tCount = fTs.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00001643 #if PIN_ADD_T
caryclark@google.comc899ad92012-08-23 15:24:42 +00001644 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
caryclark@google.com185c7c42012-10-19 18:26:24 +00001645 if (precisely_less_than_zero(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001646 newT = 0;
caryclark@google.com185c7c42012-10-19 18:26:24 +00001647 } else if (precisely_greater_than_one(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001648 newT = 1;
1649 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001650 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001651 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001652 // OPTIMIZATION: if there are three or more identical Ts, then
1653 // the fourth and following could be further insertion-sorted so
1654 // that all the edges are clockwise or counterclockwise.
1655 // This could later limit segment tests to the two adjacent
1656 // neighbors, although it doesn't help with determining which
1657 // circular direction to go in.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001658 if (newT < fTs[index].fT) {
1659 insertedAt = index;
1660 break;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001661 }
1662 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001663 Span* span;
1664 if (insertedAt >= 0) {
1665 span = fTs.insert(insertedAt);
1666 } else {
1667 insertedAt = tCount;
1668 span = fTs.append();
1669 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001670 span->fT = newT;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001671 span->fOther = other;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001672 span->fPt = pt;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001673 span->fWindSum = SK_MinS32;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001674 span->fOppSum = SK_MinS32;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001675 span->fWindValue = 1;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001676 span->fOppValue = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00001677 span->fTiny = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001678 if ((span->fDone = newT == 1)) {
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00001679 ++fDoneSpans;
rmistry@google.comd6176b02012-08-23 18:14:13 +00001680 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001681 span->fUnsortableStart = false;
1682 span->fUnsortableEnd = false;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001683 int less = -1;
1684 while (&span[less + 1] - fTs.begin() > 0 && !span[less].fDone
1685 && !precisely_negative(newT - span[less].fT)
1686 // && approximately_negative(newT - span[less].fT)
1687 && xyAtT(&span[less]) == xyAtT(span)) {
1688 span[less].fTiny = true;
1689 span[less].fDone = true;
1690 if (approximately_negative(newT - span[less].fT)) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00001691 if (approximately_greater_than_one(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001692 span[less].fUnsortableStart = true;
1693 span[less - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001694 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001695 if (approximately_less_than_zero(span[less].fT)) {
1696 span[less + 1].fUnsortableStart = true;
1697 span[less].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001698 }
1699 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001700 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001701 --less;
caryclark@google.comf839c032012-10-26 21:03:50 +00001702 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001703 int more = 1;
1704 while (fTs.end() - &span[more - 1] > 1 && !span[more - 1].fDone
1705 && !precisely_negative(span[more].fT - newT)
1706 // && approximately_negative(span[more].fT - newT)
1707 && xyAtT(&span[more]) == xyAtT(span)) {
1708 span[more - 1].fTiny = true;
1709 span[more - 1].fDone = true;
1710 if (approximately_negative(span[more].fT - newT)) {
1711 if (approximately_greater_than_one(span[more].fT)) {
1712 span[more + 1].fUnsortableStart = true;
1713 span[more].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001714 }
1715 if (approximately_less_than_zero(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001716 span[more].fUnsortableStart = true;
1717 span[more - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001718 }
1719 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001720 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001721 ++more;
caryclark@google.comf839c032012-10-26 21:03:50 +00001722 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001723 return insertedAt;
1724 }
1725
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001726 // set spans from start to end to decrement by one
1727 // note this walks other backwards
1728 // FIMXE: there's probably an edge case that can be constructed where
1729 // two span in one segment are separated by float epsilon on one span but
1730 // not the other, if one segment is very small. For this
1731 // case the counts asserted below may or may not be enough to separate the
caryclark@google.com2ddff932012-08-07 21:25:27 +00001732 // spans. Even if the counts work out, what if the spans aren't correctly
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001733 // sorted? It feels better in such a case to match the span's other span
1734 // pointer since both coincident segments must contain the same spans.
1735 void addTCancel(double startT, double endT, Segment& other,
1736 double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001737 SkASSERT(!approximately_negative(endT - startT));
1738 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00001739 bool binary = fOperand != other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001740 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001741 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001742 ++index;
1743 }
caryclark@google.comb9738012012-07-03 19:53:30 +00001744 int oIndex = other.fTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001745 while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001746 ;
caryclark@google.com59823f72012-08-09 18:17:47 +00001747 double tRatio = (oEndT - oStartT) / (endT - startT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001748 Span* test = &fTs[index];
1749 Span* oTest = &other.fTs[oIndex];
caryclark@google.com18063442012-07-25 12:05:18 +00001750 SkTDArray<double> outsideTs;
1751 SkTDArray<double> oOutsideTs;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001752 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001753 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
caryclark@google.comcc905052012-07-25 20:59:42 +00001754 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.com200c2112012-08-03 15:05:04 +00001755 double testT = test->fT;
1756 double oTestT = oTest->fT;
1757 Span* span = test;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001758 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001759 if (decrement) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001760 decrementSpan(span);
caryclark@google.com200c2112012-08-03 15:05:04 +00001761 } else if (track && span->fT < 1 && oTestT < 1) {
1762 TrackOutside(outsideTs, span->fT, oTestT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001763 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001764 span = &fTs[++index];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001765 } while (approximately_negative(span->fT - testT));
caryclark@google.com200c2112012-08-03 15:05:04 +00001766 Span* oSpan = oTest;
caryclark@google.com59823f72012-08-09 18:17:47 +00001767 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1768 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1769 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001770 while (approximately_negative(otherTMatchStart - oSpan->fT)
1771 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
caryclark@google.com03f97062012-08-21 13:13:52 +00001772 #ifdef SK_DEBUG
caryclark@google.com59823f72012-08-09 18:17:47 +00001773 SkASSERT(originalWindValue == oSpan->fWindValue);
caryclark@google.com03f97062012-08-21 13:13:52 +00001774 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001775 if (decrement) {
caryclark@google.com200c2112012-08-03 15:05:04 +00001776 other.decrementSpan(oSpan);
1777 } else if (track && oSpan->fT < 1 && testT < 1) {
1778 TrackOutside(oOutsideTs, oSpan->fT, testT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001779 }
1780 if (!oIndex) {
1781 break;
1782 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001783 oSpan = &other.fTs[--oIndex];
rmistry@google.comd6176b02012-08-23 18:14:13 +00001784 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001785 test = span;
1786 oTest = oSpan;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001787 } while (!approximately_negative(endT - test->fT));
1788 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
caryclark@google.com18063442012-07-25 12:05:18 +00001789 // FIXME: determine if canceled edges need outside ts added
caryclark@google.comcc905052012-07-25 20:59:42 +00001790 if (!done() && outsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001791 double tStart = outsideTs[0];
1792 double oStart = outsideTs[1];
1793 addCancelOutsides(tStart, oStart, other, oEndT);
1794 int count = outsideTs.count();
1795 if (count > 2) {
1796 double tStart = outsideTs[count - 2];
1797 double oStart = outsideTs[count - 1];
1798 addCancelOutsides(tStart, oStart, other, oEndT);
1799 }
caryclark@google.com18063442012-07-25 12:05:18 +00001800 }
caryclark@google.comcc905052012-07-25 20:59:42 +00001801 if (!other.done() && oOutsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001802 double tStart = oOutsideTs[0];
1803 double oStart = oOutsideTs[1];
1804 other.addCancelOutsides(tStart, oStart, *this, endT);
caryclark@google.com18063442012-07-25 12:05:18 +00001805 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001806 }
skia.committer@gmail.com15dd3002013-01-18 07:07:28 +00001807
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001808 int addUnsortableT(double newT, Segment* other, bool start, const SkPoint& pt) {
1809 int result = addT(newT, other, pt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00001810 Span* span = &fTs[result];
1811 if (start) {
1812 if (result > 0) {
1813 span[result - 1].fUnsortableEnd = true;
1814 }
1815 span[result].fUnsortableStart = true;
1816 } else {
1817 span[result].fUnsortableEnd = true;
1818 if (result + 1 < fTs.count()) {
1819 span[result + 1].fUnsortableStart = true;
1820 }
1821 }
1822 return result;
1823 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00001824
caryclark@google.com4eeda372012-12-06 21:47:48 +00001825 int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1826 SkTDArray<double>& outsideTs) {
1827 int oWindValue = oTest->fWindValue;
1828 int oOppValue = oTest->fOppValue;
1829 if (opp) {
1830 SkTSwap<int>(oWindValue, oOppValue);
1831 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001832 Span* const test = &fTs[index];
1833 Span* end = test;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001834 const double oStartT = oTest->fT;
1835 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001836 if (bumpSpan(end, oWindValue, oOppValue)) {
1837 TrackOutside(outsideTs, end->fT, oStartT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001838 }
1839 end = &fTs[++index];
1840 } while (approximately_negative(end->fT - test->fT));
1841 return index;
1842 }
1843
1844 // because of the order in which coincidences are resolved, this and other
1845 // may not have the same intermediate points. Compute the corresponding
1846 // intermediate T values (using this as the master, other as the follower)
1847 // and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com4eeda372012-12-06 21:47:48 +00001848 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1849 SkTDArray<double>& oOutsideTs) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001850 Span* const oTest = &fTs[oIndex];
1851 Span* oEnd = oTest;
1852 const double startT = test->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001853 const double oStartT = oTest->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001854 while (!approximately_negative(oEndT - oEnd->fT)
caryclark@google.com4eeda372012-12-06 21:47:48 +00001855 && approximately_negative(oEnd->fT - oStartT)) {
1856 zeroSpan(oEnd);
1857 TrackOutside(oOutsideTs, oEnd->fT, startT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001858 oEnd = &fTs[++oIndex];
1859 }
1860 return oIndex;
1861 }
1862
1863 // FIXME: need to test this case:
1864 // contourA has two segments that are coincident
1865 // contourB has two segments that are coincident in the same place
1866 // each ends up with +2/0 pairs for winding count
1867 // since logic below doesn't transfer count (only increments/decrements) can this be
1868 // resolved to +4/0 ?
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001869
1870 // set spans from start to end to increment the greater by one and decrement
1871 // the lesser
caryclark@google.com4eeda372012-12-06 21:47:48 +00001872 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001873 SkASSERT(!approximately_negative(endT - startT));
1874 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001875 bool opp = fOperand ^ other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001876 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001877 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001878 ++index;
1879 }
1880 int oIndex = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001881 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001882 ++oIndex;
1883 }
1884 Span* test = &fTs[index];
1885 Span* oTest = &other.fTs[oIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001886 SkTDArray<double> outsideTs;
1887 SkTDArray<double> oOutsideTs;
1888 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001889 // if either span has an opposite value and the operands don't match, resolve first
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001890 // SkASSERT(!test->fDone || !oTest->fDone);
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001891 if (test->fDone || oTest->fDone) {
1892 index = advanceCoincidentThis(oTest, opp, index);
1893 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
1894 } else {
1895 index = bumpCoincidentThis(oTest, opp, index, outsideTs);
1896 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
1897 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001898 test = &fTs[index];
1899 oTest = &other.fTs[oIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001900 } while (!approximately_negative(endT - test->fT));
1901 SkASSERT(approximately_negative(oTest->fT - oEndT));
1902 SkASSERT(approximately_negative(oEndT - oTest->fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001903 if (!done() && outsideTs.count()) {
1904 addCoinOutsides(outsideTs, other, oEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001905 }
1906 if (!other.done() && oOutsideTs.count()) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001907 other.addCoinOutsides(oOutsideTs, *this, endT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001908 }
1909 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001910
caryclark@google.comcc905052012-07-25 20:59:42 +00001911 // FIXME: this doesn't prevent the same span from being added twice
caryclark@google.comaa358312013-01-29 20:28:49 +00001912 // fix in caller, SkASSERT here?
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001913 void addTPair(double t, Segment& other, double otherT, bool borrowWind, const SkPoint& pt) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001914 int tCount = fTs.count();
1915 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1916 const Span& span = fTs[tIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001917 if (!approximately_negative(span.fT - t)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001918 break;
1919 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001920 if (approximately_negative(span.fT - t) && span.fOther == &other
1921 && approximately_equal(span.fOtherT, otherT)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001922#if DEBUG_ADD_T_PAIR
1923 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1924 __FUNCTION__, fID, t, other.fID, otherT);
1925#endif
1926 return;
1927 }
1928 }
caryclark@google.com47580692012-07-23 12:14:49 +00001929#if DEBUG_ADD_T_PAIR
1930 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1931 __FUNCTION__, fID, t, other.fID, otherT);
1932#endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00001933 int insertedAt = addT(t, &other, pt);
1934 int otherInsertedAt = other.addT(otherT, this, pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001935 addOtherT(insertedAt, otherT, otherInsertedAt);
caryclark@google.comb9738012012-07-03 19:53:30 +00001936 other.addOtherT(otherInsertedAt, t, insertedAt);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001937 matchWindingValue(insertedAt, t, borrowWind);
1938 other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001939 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001940
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001941 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001942 // add edge leading into junction
caryclark@google.com4eeda372012-12-06 21:47:48 +00001943 int min = SkMin32(end, start);
1944 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001945 addAngle(angles, end, start);
1946 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001947 // add edge leading away from junction
caryclark@google.com495f8e42012-05-31 13:13:11 +00001948 int step = SkSign32(end - start);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001949 int tIndex = nextExactSpan(end, step);
caryclark@google.com4eeda372012-12-06 21:47:48 +00001950 min = SkMin32(end, tIndex);
1951 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001952 addAngle(angles, end, tIndex);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001953 }
1954 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001955
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001956 int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
1957 Span* const test = &fTs[index];
1958 Span* end = test;
1959 do {
1960 end = &fTs[++index];
1961 } while (approximately_negative(end->fT - test->fT));
1962 return index;
1963 }
1964
1965 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
1966 Span* const oTest = &fTs[oIndex];
1967 Span* oEnd = oTest;
1968 const double oStartT = oTest->fT;
1969 while (!approximately_negative(oEndT - oEnd->fT)
1970 && approximately_negative(oEnd->fT - oStartT)) {
1971 oEnd = &fTs[++oIndex];
1972 }
1973 return oIndex;
1974 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00001975
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001976 bool betweenTs(int lesser, double testT, int greater) {
1977 if (lesser > greater) {
1978 SkTSwap<int>(lesser, greater);
1979 }
1980 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
1981 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001982
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001983 const Bounds& bounds() const {
1984 return fBounds;
1985 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001986
caryclark@google.com31143cf2012-11-09 22:14:19 +00001987 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001988 double referenceT = fTs[index].fT;
1989 int lesser = index;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001990 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
1991 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00001992 buildAnglesInner(lesser, angles);
1993 }
1994 do {
1995 buildAnglesInner(index, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001996 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
1997 && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001998 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001999
2000 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
2001 Span* span = &fTs[index];
2002 Segment* other = span->fOther;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002003 // if there is only one live crossing, and no coincidence, continue
2004 // in the same direction
2005 // if there is coincidence, the only choice may be to reverse direction
2006 // find edge on either side of intersection
2007 int oIndex = span->fOtherIndex;
2008 // if done == -1, prior span has already been processed
2009 int step = 1;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002010 int next = other->nextExactSpan(oIndex, step);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002011 if (next < 0) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002012 step = -step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002013 next = other->nextExactSpan(oIndex, step);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002014 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002015 // add candidate into and away from junction
2016 other->addTwoAngles(next, oIndex, angles);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002017 }
2018
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002019 int computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002020 SkTDArray<Angle> angles;
2021 addTwoAngles(startIndex, endIndex, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002022 buildAngles(endIndex, angles, false);
caryclark@google.comd1688742012-09-18 20:08:37 +00002023 // OPTIMIZATION: check all angles to see if any have computed wind sum
2024 // before sorting (early exit if none)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002025 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002026 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002027#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002028 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002029#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002030 if (!sortable) {
2031 return SK_MinS32;
2032 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002033 int angleCount = angles.count();
2034 const Angle* angle;
2035 const Segment* base;
2036 int winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002037 int oWinding;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002038 int firstIndex = 0;
2039 do {
2040 angle = sorted[firstIndex];
2041 base = angle->segment();
2042 winding = base->windSum(angle);
2043 if (winding != SK_MinS32) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002044 oWinding = base->oppSum(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002045 break;
2046 }
2047 if (++firstIndex == angleCount) {
2048 return SK_MinS32;
2049 }
2050 } while (true);
2051 // turn winding into contourWinding
caryclark@google.com2ddff932012-08-07 21:25:27 +00002052 int spanWinding = base->spanSign(angle);
2053 bool inner = useInnerWinding(winding + spanWinding, winding);
2054 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00002055 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
caryclark@google.com59823f72012-08-09 18:17:47 +00002056 spanWinding, winding, angle->sign(), inner,
caryclark@google.com2ddff932012-08-07 21:25:27 +00002057 inner ? winding + spanWinding : winding);
2058 #endif
2059 if (inner) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002060 winding += spanWinding;
2061 }
2062 #if DEBUG_SORT
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002063 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002064 #endif
2065 int nextIndex = firstIndex + 1;
2066 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com2ddff932012-08-07 21:25:27 +00002067 winding -= base->spanSign(angle);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002068 oWinding -= base->oppSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002069 do {
2070 if (nextIndex == angleCount) {
2071 nextIndex = 0;
2072 }
2073 angle = sorted[nextIndex];
2074 Segment* segment = angle->segment();
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002075 bool opp = base->fOperand ^ segment->fOperand;
2076 int maxWinding, oMaxWinding;
2077 int spanSign = segment->spanSign(angle);
2078 int oppoSign = segment->oppSign(angle);
2079 if (opp) {
2080 oMaxWinding = oWinding;
2081 oWinding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002082 maxWinding = winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002083 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002084 winding -= oppoSign;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002085 }
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002086 } else {
2087 maxWinding = winding;
2088 winding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00002089 oMaxWinding = oWinding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002090 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002091 oWinding -= oppoSign;
2092 }
2093 }
2094 if (segment->windSum(angle) == SK_MinS32) {
2095 if (opp) {
2096 if (useInnerWinding(oMaxWinding, oWinding)) {
2097 oMaxWinding = oWinding;
2098 }
2099 if (oppoSign && useInnerWinding(maxWinding, winding)) {
2100 maxWinding = winding;
2101 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002102 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002103 } else {
2104 if (useInnerWinding(maxWinding, winding)) {
2105 maxWinding = winding;
2106 }
2107 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
2108 oMaxWinding = oWinding;
2109 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002110 (void) segment->markAndChaseWinding(angle, maxWinding,
2111 binary ? oMaxWinding : 0);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00002112 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002113 }
2114 } while (++nextIndex != lastIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002115 int minIndex = SkMin32(startIndex, endIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00002116 return windSum(minIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002117 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002118
caryclark@google.com3586ece2012-12-27 18:46:58 +00002119 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
caryclark@google.com10227bf2012-12-28 22:10:41 +00002120 double mid, bool opp, bool current) const {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002121 SkScalar bottom = fBounds.fBottom;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002122 int bestTIndex = -1;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002123 if (bottom <= bestY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002124 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002125 }
2126 SkScalar top = fBounds.fTop;
2127 if (top >= basePt.fY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002128 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002129 }
2130 if (fBounds.fLeft > 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.fRight < basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002134 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002135 }
2136 if (fBounds.fLeft == fBounds.fRight) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002137 // if vertical, and directly above test point, wait for another one
caryclark@google.com6d0032a2013-01-04 19:41:13 +00002138 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002139 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002140 // intersect ray starting at basePt with edge
2141 Intersections intersections;
2142 // OPTIMIZE: use specialty function that intersects ray with curve,
2143 // returning t values only for curve (we don't care about t on ray)
2144 int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
2145 if (pts == 0 || (current && pts == 1)) {
2146 return bestTIndex;
2147 }
2148 if (current) {
2149 SkASSERT(pts > 1);
2150 int closestIdx = 0;
2151 double closest = fabs(intersections.fT[0][0] - mid);
2152 for (int idx = 1; idx < pts; ++idx) {
2153 double test = fabs(intersections.fT[0][idx] - mid);
2154 if (closest > test) {
2155 closestIdx = idx;
2156 closest = test;
2157 }
2158 }
2159 if (closestIdx < pts - 1) {
2160 intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
2161 }
2162 --pts;
2163 }
2164 double bestT = -1;
2165 for (int index = 0; index < pts; ++index) {
2166 double foundT = intersections.fT[0][index];
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002167 if (approximately_less_than_zero(foundT)
2168 || approximately_greater_than_one(foundT)) {
2169 continue;
2170 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002171 SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
2172 if (approximately_negative(testY - bestY)
2173 || approximately_negative(basePt.fY - testY)) {
caryclark@google.com47580692012-07-23 12:14:49 +00002174 continue;
2175 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002176 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002177 return SK_MinS32; // if the intersection is edge on, wait for another one
caryclark@google.com10227bf2012-12-28 22:10:41 +00002178 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002179 if (fVerb > SkPath::kLine_Verb) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002180 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
2181 if (approximately_zero(dx)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002182 return SK_MinS32; // hit vertical, wait for another one
caryclark@google.com3586ece2012-12-27 18:46:58 +00002183 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00002184 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002185 bestY = testY;
2186 bestT = foundT;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002187 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002188 if (bestT < 0) {
2189 return bestTIndex;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002190 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002191 SkASSERT(bestT >= 0);
2192 SkASSERT(bestT <= 1);
2193 int start;
2194 int end = 0;
2195 do {
2196 start = end;
2197 end = nextSpan(start, 1);
2198 } while (fTs[end].fT < bestT);
2199 // FIXME: see next candidate for a better pattern to find the next start/end pair
2200 while (start + 1 < end && fTs[start].fDone) {
2201 ++start;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002202 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002203 if (!isCanceled(start)) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002204 hitT = bestT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002205 bestTIndex = start;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002206 hitSomething = true;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002207 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002208 return bestTIndex;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002209 }
caryclark@google.com18063442012-07-25 12:05:18 +00002210
caryclark@google.com4eeda372012-12-06 21:47:48 +00002211 void decrementSpan(Span* span) {
caryclark@google.com18063442012-07-25 12:05:18 +00002212 SkASSERT(span->fWindValue > 0);
2213 if (--(span->fWindValue) == 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002214 if (!span->fOppValue && !span->fDone) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002215 span->fDone = true;
2216 ++fDoneSpans;
2217 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002218 }
2219 }
2220
2221 bool bumpSpan(Span* span, int windDelta, int oppDelta) {
2222 SkASSERT(!span->fDone);
2223 span->fWindValue += windDelta;
2224 SkASSERT(span->fWindValue >= 0);
2225 span->fOppValue += oppDelta;
2226 SkASSERT(span->fOppValue >= 0);
2227 if (fXor) {
2228 span->fWindValue &= 1;
2229 }
2230 if (fOppXor) {
2231 span->fOppValue &= 1;
2232 }
2233 if (!span->fWindValue && !span->fOppValue) {
2234 span->fDone = true;
2235 ++fDoneSpans;
caryclark@google.com18063442012-07-25 12:05:18 +00002236 return true;
2237 }
2238 return false;
2239 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002240
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002241 // OPTIMIZE
2242 // when the edges are initially walked, they don't automatically get the prior and next
2243 // 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 +00002244 // and would additionally remove the need for similar checks in condition edges. It would
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002245 // also allow intersection code to assume end of segment intersections (maybe?)
2246 bool complete() const {
2247 int count = fTs.count();
2248 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
2249 }
caryclark@google.com18063442012-07-25 12:05:18 +00002250
caryclark@google.com15fa1382012-05-07 20:49:36 +00002251 bool done() const {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002252 SkASSERT(fDoneSpans <= fTs.count());
2253 return fDoneSpans == fTs.count();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002254 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002255
caryclark@google.comf839c032012-10-26 21:03:50 +00002256 bool done(int min) const {
2257 return fTs[min].fDone;
2258 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002259
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002260 bool done(const Angle* angle) const {
2261 return done(SkMin32(angle->start(), angle->end()));
caryclark@google.com47580692012-07-23 12:14:49 +00002262 }
skia.committer@gmail.com044679e2013-02-15 07:16:57 +00002263
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002264 SkPoint dxdy(int index) const {
2265 return (*SegmentDXDYAtT[fVerb])(fPts, fTs[index].fT);
2266 }
2267
2268 SkScalar dy(int index) const {
2269 return (*SegmentDYAtT[fVerb])(fPts, fTs[index].fT);
2270 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00002271
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002272 bool equalPoints(int greaterTIndex, int lesserTIndex) {
2273 SkASSERT(greaterTIndex >= lesserTIndex);
2274 double greaterT = fTs[greaterTIndex].fT;
2275 double lesserT = fTs[lesserTIndex].fT;
2276 if (greaterT == lesserT) {
2277 return true;
2278 }
2279 if (!approximately_negative(greaterT - lesserT)) {
2280 return false;
2281 }
2282 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2283 }
2284
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002285 /*
2286 The M and S variable name parts stand for the operators.
2287 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2288 Su stands for Subtrahend
2289 The Opp variable name part designates that the value is for the Opposite operator.
2290 Opposite values result from combining coincident spans.
2291 */
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002292
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002293 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2294 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002295 const int startIndex = nextStart;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002296 const int endIndex = nextEnd;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002297 SkASSERT(startIndex != endIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002298 const int count = fTs.count();
2299 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2300 const int step = SkSign32(endIndex - startIndex);
2301 const int end = nextExactSpan(startIndex, step);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002302 SkASSERT(end >= 0);
2303 Span* endSpan = &fTs[end];
2304 Segment* other;
2305 if (isSimple(end)) {
2306 // mark the smaller of startIndex, endIndex done, and all adjacent
2307 // spans with the same T value (but not 'other' spans)
2308 #if DEBUG_WINDING
2309 SkDebugf("%s simple\n", __FUNCTION__);
2310 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002311 int min = SkMin32(startIndex, endIndex);
2312 if (fTs[min].fDone) {
2313 return NULL;
2314 }
2315 markDoneBinary(min);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002316 other = endSpan->fOther;
2317 nextStart = endSpan->fOtherIndex;
2318 double startT = other->fTs[nextStart].fT;
2319 nextEnd = nextStart;
2320 do {
2321 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002322 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002323 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002324 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2325 return other;
2326 }
2327 // more than one viable candidate -- measure angles to find best
2328 SkTDArray<Angle> angles;
2329 SkASSERT(startIndex - endIndex != 0);
2330 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2331 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002332 buildAngles(end, angles, true);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002333 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002334 bool sortable = SortAngles(angles, sorted);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002335 int angleCount = angles.count();
2336 int firstIndex = findStartingEdge(sorted, startIndex, end);
2337 SkASSERT(firstIndex >= 0);
2338 #if DEBUG_SORT
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002339 debugShowSort(__FUNCTION__, sorted, firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002340 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002341 if (!sortable) {
2342 unsortable = true;
2343 return NULL;
2344 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002345 SkASSERT(sorted[firstIndex]->segment() == this);
2346 #if DEBUG_WINDING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002347 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2348 sorted[firstIndex]->sign());
caryclark@google.com235f56a2012-09-14 14:19:30 +00002349 #endif
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002350 int sumMiWinding = updateWinding(endIndex, startIndex);
2351 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2352 if (operand()) {
2353 SkTSwap<int>(sumMiWinding, sumSuWinding);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002354 }
2355 int nextIndex = firstIndex + 1;
2356 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2357 const Angle* foundAngle = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002358 bool foundDone = false;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002359 // iterate through the angle, and compute everyone's winding
caryclark@google.com235f56a2012-09-14 14:19:30 +00002360 Segment* nextSegment;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002361 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002362 SkASSERT(nextIndex != firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002363 if (nextIndex == angleCount) {
2364 nextIndex = 0;
2365 }
2366 const Angle* nextAngle = sorted[nextIndex];
2367 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002368 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2369 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2370 nextAngle->end(), op, sumMiWinding, sumSuWinding,
2371 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
2372 if (activeAngle && (!foundAngle || foundDone)) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002373 foundAngle = nextAngle;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002374 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002375 }
2376 if (nextSegment->done()) {
2377 continue;
2378 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002379 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2380 continue;
2381 }
2382 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2383 oppSumWinding, activeAngle, nextAngle);
2384 if (last) {
2385 *chase.append() = last;
2386#if DEBUG_WINDING
2387 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2388 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2389#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002390 }
2391 } while (++nextIndex != lastIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002392 markDoneBinary(SkMin32(startIndex, endIndex));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002393 if (!foundAngle) {
2394 return NULL;
2395 }
2396 nextStart = foundAngle->start();
2397 nextEnd = foundAngle->end();
2398 nextSegment = foundAngle->segment();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002399
caryclark@google.com235f56a2012-09-14 14:19:30 +00002400 #if DEBUG_WINDING
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002401 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2402 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002403 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002404 return nextSegment;
2405 }
caryclark@google.com47580692012-07-23 12:14:49 +00002406
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002407 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2408 bool& unsortable) {
2409 const int startIndex = nextStart;
2410 const int endIndex = nextEnd;
2411 SkASSERT(startIndex != endIndex);
2412 const int count = fTs.count();
2413 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2414 const int step = SkSign32(endIndex - startIndex);
2415 const int end = nextExactSpan(startIndex, step);
2416 SkASSERT(end >= 0);
2417 Span* endSpan = &fTs[end];
2418 Segment* other;
2419 if (isSimple(end)) {
2420 // mark the smaller of startIndex, endIndex done, and all adjacent
2421 // spans with the same T value (but not 'other' spans)
2422 #if DEBUG_WINDING
2423 SkDebugf("%s simple\n", __FUNCTION__);
2424 #endif
2425 int min = SkMin32(startIndex, endIndex);
2426 if (fTs[min].fDone) {
2427 return NULL;
2428 }
2429 markDoneUnary(min);
2430 other = endSpan->fOther;
2431 nextStart = endSpan->fOtherIndex;
2432 double startT = other->fTs[nextStart].fT;
2433 nextEnd = nextStart;
2434 do {
2435 nextEnd += step;
2436 }
2437 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2438 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2439 return other;
2440 }
2441 // more than one viable candidate -- measure angles to find best
2442 SkTDArray<Angle> angles;
2443 SkASSERT(startIndex - endIndex != 0);
2444 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2445 addTwoAngles(startIndex, end, angles);
2446 buildAngles(end, angles, true);
2447 SkTDArray<Angle*> sorted;
2448 bool sortable = SortAngles(angles, sorted);
2449 int angleCount = angles.count();
2450 int firstIndex = findStartingEdge(sorted, startIndex, end);
2451 SkASSERT(firstIndex >= 0);
2452 #if DEBUG_SORT
2453 debugShowSort(__FUNCTION__, sorted, firstIndex);
2454 #endif
2455 if (!sortable) {
2456 unsortable = true;
2457 return NULL;
2458 }
2459 SkASSERT(sorted[firstIndex]->segment() == this);
2460 #if DEBUG_WINDING
2461 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2462 sorted[firstIndex]->sign());
2463 #endif
2464 int sumWinding = updateWinding(endIndex, startIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002465 int nextIndex = firstIndex + 1;
2466 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2467 const Angle* foundAngle = NULL;
2468 bool foundDone = false;
2469 // iterate through the angle, and compute everyone's winding
2470 Segment* nextSegment;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002471 int activeCount = 0;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002472 do {
2473 SkASSERT(nextIndex != firstIndex);
2474 if (nextIndex == angleCount) {
2475 nextIndex = 0;
2476 }
2477 const Angle* nextAngle = sorted[nextIndex];
2478 nextSegment = nextAngle->segment();
2479 int maxWinding;
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00002480 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002481 maxWinding, sumWinding);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002482 if (activeAngle) {
2483 ++activeCount;
2484 if (!foundAngle || (foundDone && activeCount & 1)) {
2485 if (nextSegment->tiny(nextAngle)) {
2486 unsortable = true;
2487 return NULL;
2488 }
2489 foundAngle = nextAngle;
2490 foundDone = nextSegment->done(nextAngle);
2491 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002492 }
2493 if (nextSegment->done()) {
2494 continue;
2495 }
2496 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2497 continue;
2498 }
2499 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2500 if (last) {
2501 *chase.append() = last;
2502#if DEBUG_WINDING
2503 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2504 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2505#endif
2506 }
2507 } while (++nextIndex != lastIndex);
2508 markDoneUnary(SkMin32(startIndex, endIndex));
2509 if (!foundAngle) {
2510 return NULL;
2511 }
2512 nextStart = foundAngle->start();
2513 nextEnd = foundAngle->end();
2514 nextSegment = foundAngle->segment();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002515 #if DEBUG_WINDING
2516 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2517 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2518 #endif
2519 return nextSegment;
2520 }
2521
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002522 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002523 const int startIndex = nextStart;
2524 const int endIndex = nextEnd;
2525 SkASSERT(startIndex != endIndex);
2526 int count = fTs.count();
2527 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2528 : startIndex > 0);
2529 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002530 int end = nextExactSpan(startIndex, step);
caryclark@google.com24bec792012-08-20 12:43:57 +00002531 SkASSERT(end >= 0);
2532 Span* endSpan = &fTs[end];
2533 Segment* other;
caryclark@google.com24bec792012-08-20 12:43:57 +00002534 if (isSimple(end)) {
2535 #if DEBUG_WINDING
2536 SkDebugf("%s simple\n", __FUNCTION__);
2537 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002538 int min = SkMin32(startIndex, endIndex);
2539 if (fTs[min].fDone) {
2540 return NULL;
2541 }
2542 markDone(min, 1);
caryclark@google.com24bec792012-08-20 12:43:57 +00002543 other = endSpan->fOther;
2544 nextStart = endSpan->fOtherIndex;
2545 double startT = other->fTs[nextStart].fT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002546 #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 +00002547 SkDEBUGCODE(bool firstLoop = true;)
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002548 if ((approximately_less_than_zero(startT) && step < 0)
2549 || (approximately_greater_than_one(startT) && step > 0)) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002550 step = -step;
2551 SkDEBUGCODE(firstLoop = false;)
2552 }
2553 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002554 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002555 nextEnd = nextStart;
2556 do {
2557 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002558 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002559 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002560 #if 01
caryclark@google.com24bec792012-08-20 12:43:57 +00002561 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2562 break;
2563 }
caryclark@google.com03f97062012-08-21 13:13:52 +00002564 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00002565 SkASSERT(firstLoop);
caryclark@google.com03f97062012-08-21 13:13:52 +00002566 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002567 SkDEBUGCODE(firstLoop = false;)
2568 step = -step;
2569 } while (true);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002570 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002571 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2572 return other;
2573 }
2574 SkTDArray<Angle> angles;
2575 SkASSERT(startIndex - endIndex != 0);
2576 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2577 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002578 buildAngles(end, angles, false);
caryclark@google.com24bec792012-08-20 12:43:57 +00002579 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002580 bool sortable = SortAngles(angles, sorted);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002581 if (!sortable) {
2582 unsortable = true;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002583 #if DEBUG_SORT
2584 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
2585 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002586 return NULL;
2587 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002588 int angleCount = angles.count();
2589 int firstIndex = findStartingEdge(sorted, startIndex, end);
2590 SkASSERT(firstIndex >= 0);
2591 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002592 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
caryclark@google.com24bec792012-08-20 12:43:57 +00002593 #endif
2594 SkASSERT(sorted[firstIndex]->segment() == this);
2595 int nextIndex = firstIndex + 1;
2596 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002597 const Angle* foundAngle = NULL;
2598 bool foundDone = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002599 Segment* nextSegment;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002600 int activeCount = 0;
caryclark@google.com24bec792012-08-20 12:43:57 +00002601 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002602 SkASSERT(nextIndex != firstIndex);
caryclark@google.com24bec792012-08-20 12:43:57 +00002603 if (nextIndex == angleCount) {
2604 nextIndex = 0;
2605 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002606 const Angle* nextAngle = sorted[nextIndex];
caryclark@google.com24bec792012-08-20 12:43:57 +00002607 nextSegment = nextAngle->segment();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002608 ++activeCount;
2609 if (!foundAngle || (foundDone && activeCount & 1)) {
2610 if (nextSegment->tiny(nextAngle)) {
2611 unsortable = true;
2612 return NULL;
2613 }
2614 foundAngle = nextAngle;
2615 foundDone = nextSegment->done(nextAngle);
2616 }
2617 if (nextSegment->done()) {
2618 continue;
caryclark@google.com24bec792012-08-20 12:43:57 +00002619 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002620 } while (++nextIndex != lastIndex);
2621 markDone(SkMin32(startIndex, endIndex), 1);
2622 if (!foundAngle) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002623 return NULL;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002624 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002625 nextStart = foundAngle->start();
2626 nextEnd = foundAngle->end();
2627 nextSegment = foundAngle->segment();
2628 #if DEBUG_WINDING
2629 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2630 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2631 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002632 return nextSegment;
2633 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002634
2635 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2636 int angleCount = sorted.count();
2637 int firstIndex = -1;
2638 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2639 const Angle* angle = sorted[angleIndex];
2640 if (angle->segment() == this && angle->start() == end &&
2641 angle->end() == start) {
2642 firstIndex = angleIndex;
2643 break;
2644 }
2645 }
2646 return firstIndex;
2647 }
2648
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002649 // FIXME: this is tricky code; needs its own unit test
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002650 // note that fOtherIndex isn't computed yet, so it can't be used here
caryclark@google.com4eeda372012-12-06 21:47:48 +00002651 void findTooCloseToCall() {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002652 int count = fTs.count();
2653 if (count < 3) { // require t=0, x, 1 at minimum
2654 return;
2655 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002656 int matchIndex = 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002657 int moCount;
2658 Span* match;
2659 Segment* mOther;
2660 do {
2661 match = &fTs[matchIndex];
2662 mOther = match->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002663 // FIXME: allow quads, cubics to be near coincident?
2664 if (mOther->fVerb == SkPath::kLine_Verb) {
2665 moCount = mOther->fTs.count();
2666 if (moCount >= 3) {
2667 break;
2668 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002669 }
2670 if (++matchIndex >= count) {
2671 return;
2672 }
2673 } while (true); // require t=0, x, 1 at minimum
caryclark@google.com15fa1382012-05-07 20:49:36 +00002674 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002675 const SkPoint* matchPt = &xyAtT(match);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002676 // look for a pair of nearby T values that map to the same (x,y) value
2677 // if found, see if the pair of other segments share a common point. If
2678 // so, the span from here to there is coincident.
caryclark@google.com15fa1382012-05-07 20:49:36 +00002679 for (int index = matchIndex + 1; index < count; ++index) {
2680 Span* test = &fTs[index];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002681 if (test->fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002682 continue;
2683 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002684 Segment* tOther = test->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002685 if (tOther->fVerb != SkPath::kLine_Verb) {
2686 continue; // FIXME: allow quads, cubics to be near coincident?
2687 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002688 int toCount = tOther->fTs.count();
2689 if (toCount < 3) { // require t=0, x, 1 at minimum
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002690 continue;
2691 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002692 const SkPoint* testPt = &xyAtT(test);
2693 if (*matchPt != *testPt) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002694 matchIndex = index;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002695 moCount = toCount;
2696 match = test;
2697 mOther = tOther;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002698 matchPt = testPt;
2699 continue;
2700 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002701 int moStart = -1;
2702 int moEnd = -1;
2703 double moStartT, moEndT;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002704 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002705 Span& moSpan = mOther->fTs[moIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002706 if (moSpan.fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002707 continue;
2708 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002709 if (moSpan.fOther == this) {
2710 if (moSpan.fOtherT == match->fT) {
2711 moStart = moIndex;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002712 moStartT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002713 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002714 continue;
2715 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002716 if (moSpan.fOther == tOther) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002717 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002718 moStart = -1;
2719 break;
2720 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002721 SkASSERT(moEnd == -1);
2722 moEnd = moIndex;
2723 moEndT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002724 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002725 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002726 if (moStart < 0 || moEnd < 0) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002727 continue;
2728 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002729 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002730 if (approximately_equal(moStartT, moEndT)) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002731 continue;
2732 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002733 int toStart = -1;
2734 int toEnd = -1;
2735 double toStartT, toEndT;
2736 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2737 Span& toSpan = tOther->fTs[toIndex];
caryclark@google.comc899ad92012-08-23 15:24:42 +00002738 if (toSpan.fDone) {
2739 continue;
2740 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002741 if (toSpan.fOther == this) {
2742 if (toSpan.fOtherT == test->fT) {
2743 toStart = toIndex;
2744 toStartT = toSpan.fT;
2745 }
2746 continue;
2747 }
2748 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002749 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002750 moStart = -1;
2751 break;
2752 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002753 SkASSERT(toEnd == -1);
2754 toEnd = toIndex;
2755 toEndT = toSpan.fT;
2756 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002757 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002758 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2759 if (toStart <= 0 || toEnd <= 0) {
2760 continue;
2761 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002762 if (approximately_equal(toStartT, toEndT)) {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002763 continue;
2764 }
2765 // test to see if the segment between there and here is linear
2766 if (!mOther->isLinear(moStart, moEnd)
2767 || !tOther->isLinear(toStart, toEnd)) {
2768 continue;
2769 }
caryclark@google.comc899ad92012-08-23 15:24:42 +00002770 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002771 if (flipped) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002772 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002773 } else {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002774 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002775 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002776 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002777 }
2778
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002779 // FIXME: either:
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002780 // a) mark spans with either end unsortable as done, or
2781 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2782 // when encountering an unsortable span
2783
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002784 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2785 // and use more concise logic like the old edge walker code?
2786 // FIXME: this needs to deal with coincident edges
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002787 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002788 // iterate through T intersections and return topmost
2789 // topmost tangent from y-min to first pt is closer to horizontal
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002790 SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002791 int firstT = -1;
caryclark@google.comd0a19eb2013-02-19 12:49:33 +00002792 /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002793 SkASSERT(firstT >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002794 // sort the edges to find the leftmost
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002795 int step = 1;
2796 int end = nextSpan(firstT, step);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002797 if (end == -1) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002798 step = -1;
2799 end = nextSpan(firstT, step);
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00002800 SkASSERT(end != -1);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002801 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002802 // if the topmost T is not on end, or is three-way or more, find left
2803 // look for left-ness from tLeft to firstT (matching y of other)
2804 SkTDArray<Angle> angles;
2805 SkASSERT(firstT - end != 0);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002806 addTwoAngles(end, firstT, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002807 buildAngles(firstT, angles, true);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002808 SkTDArray<Angle*> sorted;
caryclark@google.comf839c032012-10-26 21:03:50 +00002809 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002810 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002811 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002812 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002813 if (onlySortable && !sortable) {
2814 unsortable = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002815 return NULL;
2816 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002817 // skip edges that have already been processed
2818 firstT = -1;
2819 Segment* leftSegment;
2820 do {
2821 const Angle* angle = sorted[++firstT];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002822 SkASSERT(!onlySortable || !angle->unsortable());
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002823 leftSegment = angle->segment();
2824 tIndex = angle->end();
2825 endIndex = angle->start();
2826 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002827 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002828 bool bumpsUp = leftSegment->bumpsUp(tIndex, endIndex);
2829 SkPoint xyE = leftSegment->xyAtT(endIndex);
2830 SkPoint xyS = leftSegment->xyAtT(tIndex);
caryclark@google.com47d73da2013-02-17 01:41:25 +00002831 SkPoint dxyE = leftSegment->dxdy(endIndex);
2832 SkPoint dxyS = leftSegment->dxdy(tIndex);
2833 double cross = dxyE.cross(dxyS);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002834 bool bumpCheck = bumpsUp && xyE.fY < xyS.fY;
caryclark@google.com47d73da2013-02-17 01:41:25 +00002835 #if DEBUG_SWAP_TOP
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002836 SkDebugf("%s xyE=(%1.9g,%1.9g) xyS=(%1.9g,%1.9g)\n", __FUNCTION__,
2837 xyE.fX, xyE.fY, xyS.fX, xyS.fY);
2838 SkDebugf("%s dxyE=(%1.9g,%1.9g) dxyS=(%1.9g,%1.9g) cross=%1.9g bump=%s\n", __FUNCTION__,
2839 dxyE.fX, dxyE.fY, dxyS.fX, dxyS.fY, cross, bumpCheck ? "true" : "false");
caryclark@google.com47d73da2013-02-17 01:41:25 +00002840 #endif
caryclark@google.com5e0500f2013-02-20 12:51:37 +00002841 if ((cross > 0) ^ bumpCheck) {
2842 leftSegment->bumpsUp(tIndex, endIndex);
2843 SkDebugf("%s cross bump disagree\n", __FUNCTION__);
2844 }
2845 if (bumpCheck) {
caryclark@google.com47d73da2013-02-17 01:41:25 +00002846 #if DEBUG_SWAP_TOP
2847 SkDebugf("%s swap\n", __FUNCTION__);
2848 #endif
caryclark@google.com45a8fc62013-02-14 15:29:11 +00002849 SkTSwap(tIndex, endIndex);
2850 }
2851 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002852 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002853 return leftSegment;
2854 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002855
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002856 // FIXME: not crazy about this
2857 // when the intersections are performed, the other index is into an
2858 // incomplete array. as the array grows, the indices become incorrect
2859 // while the following fixes the indices up again, it isn't smart about
2860 // skipping segments whose indices are already correct
2861 // assuming we leave the code that wrote the index in the first place
2862 void fixOtherTIndex() {
2863 int iCount = fTs.count();
2864 for (int i = 0; i < iCount; ++i) {
2865 Span& iSpan = fTs[i];
2866 double oT = iSpan.fOtherT;
2867 Segment* other = iSpan.fOther;
2868 int oCount = other->fTs.count();
2869 for (int o = 0; o < oCount; ++o) {
2870 Span& oSpan = other->fTs[o];
2871 if (oT == oSpan.fT && this == oSpan.fOther) {
2872 iSpan.fOtherIndex = o;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002873 break;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002874 }
2875 }
2876 }
2877 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002878
caryclark@google.com4eeda372012-12-06 21:47:48 +00002879 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002880 fDoneSpans = 0;
2881 fOperand = operand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00002882 fXor = evenOdd;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002883 fPts = pts;
2884 fVerb = verb;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002885 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00002886
caryclark@google.com3586ece2012-12-27 18:46:58 +00002887 void initWinding(int start, int end) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002888 int local = spanSign(start, end);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002889 int oppLocal = oppSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002890 (void) markAndChaseWinding(start, end, local, oppLocal);
caryclark@google.com73ca6242013-01-17 21:02:47 +00002891 // OPTIMIZATION: the reverse mark and chase could skip the first marking
2892 (void) markAndChaseWinding(end, start, local, oppLocal);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002893 }
2894
caryclark@google.com3586ece2012-12-27 18:46:58 +00002895 void initWinding(int start, int end, int winding, int oppWinding) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002896 int local = spanSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002897 if (local * winding >= 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002898 winding += local;
2899 }
2900 int oppLocal = oppSign(start, end);
2901 if (oppLocal * oppWinding >= 0) {
2902 oppWinding += oppLocal;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002903 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002904 (void) markAndChaseWinding(start, end, winding, oppWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002905 }
2906
caryclark@google.com3586ece2012-12-27 18:46:58 +00002907/*
2908when we start with a vertical intersect, we try to use the dx to determine if the edge is to
2909the 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 +00002910sign or not. However, this isn't enough.
2911If 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 +00002912If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
2913from 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 +00002914the same winding is shared by both.
caryclark@google.com3586ece2012-12-27 18:46:58 +00002915*/
2916 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
2917 SkScalar hitOppDx) {
2918 SkASSERT(hitDx || !winding);
2919 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
2920 SkASSERT(dx);
2921 int windVal = windValue(SkMin32(start, end));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002922 #if DEBUG_WINDING_AT_T
2923 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
2924 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
2925 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002926 if (!winding) {
2927 winding = dx < 0 ? windVal : -windVal;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002928 } else if (winding * dx < 0) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00002929 int sideWind = winding + (dx < 0 ? windVal : -windVal);
2930 if (abs(winding) < abs(sideWind)) {
2931 winding = sideWind;
2932 }
2933 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002934 #if DEBUG_WINDING_AT_T
2935 SkDebugf(" winding=%d\n", winding);
2936 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002937 int oppLocal = oppSign(start, end);
2938 SkASSERT(hitOppDx || !oppWind || !oppLocal);
2939 int oppWindVal = oppValue(SkMin32(start, end));
2940 if (!oppWind) {
2941 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
2942 } else if (hitOppDx * dx >= 0) {
2943 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
2944 if (abs(oppWind) < abs(oppSideWind)) {
2945 oppWind = oppSideWind;
2946 }
2947 }
2948 (void) markAndChaseWinding(start, end, winding, oppWind);
2949 }
2950
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002951 bool intersected() const {
2952 return fTs.count() > 0;
2953 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002954
caryclark@google.com10227bf2012-12-28 22:10:41 +00002955 bool isCanceled(int tIndex) const {
2956 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
2957 }
2958
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002959 bool isConnected(int startIndex, int endIndex) const {
2960 return fTs[startIndex].fWindSum != SK_MinS32
2961 || fTs[endIndex].fWindSum != SK_MinS32;
2962 }
2963
caryclark@google.com235f56a2012-09-14 14:19:30 +00002964 bool isHorizontal() const {
2965 return fBounds.fTop == fBounds.fBottom;
2966 }
2967
caryclark@google.com15fa1382012-05-07 20:49:36 +00002968 bool isLinear(int start, int end) const {
2969 if (fVerb == SkPath::kLine_Verb) {
2970 return true;
2971 }
2972 if (fVerb == SkPath::kQuad_Verb) {
2973 SkPoint qPart[3];
2974 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
2975 return QuadIsLinear(qPart);
2976 } else {
2977 SkASSERT(fVerb == SkPath::kCubic_Verb);
2978 SkPoint cPart[4];
2979 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
2980 return CubicIsLinear(cPart);
2981 }
2982 }
caryclark@google.comb9738012012-07-03 19:53:30 +00002983
2984 // OPTIMIZE: successive calls could start were the last leaves off
2985 // or calls could specialize to walk forwards or backwards
2986 bool isMissing(double startT) const {
2987 size_t tCount = fTs.count();
2988 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002989 if (approximately_zero(startT - fTs[index].fT)) {
caryclark@google.comb9738012012-07-03 19:53:30 +00002990 return false;
2991 }
2992 }
2993 return true;
2994 }
2995
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002996 bool isSimple(int end) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002997 int count = fTs.count();
2998 if (count == 2) {
2999 return true;
3000 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003001 double t = fTs[end].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003002 if (approximately_less_than_zero(t)) {
3003 return !approximately_less_than_zero(fTs[1].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003004 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003005 if (approximately_greater_than_one(t)) {
3006 return !approximately_greater_than_one(fTs[count - 2].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003007 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003008 return false;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003009 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003010
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003011 bool isVertical() const {
3012 return fBounds.fLeft == fBounds.fRight;
3013 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003014
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003015 bool isVertical(int start, int end) const {
3016 return (*SegmentVertical[fVerb])(fPts, start, end);
3017 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003018
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003019 SkScalar leftMost(int start, int end) const {
3020 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
3021 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003022
caryclark@google.com495f8e42012-05-31 13:13:11 +00003023 // this span is excluded by the winding rule -- chase the ends
3024 // as long as they are unambiguous to mark connections as done
3025 // and give them the same winding value
caryclark@google.com59823f72012-08-09 18:17:47 +00003026 Span* markAndChaseDone(const Angle* angle, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003027 int index = angle->start();
3028 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003029 return markAndChaseDone(index, endIndex, winding);
3030 }
3031
caryclark@google.com31143cf2012-11-09 22:14:19 +00003032 Span* markAndChaseDone(int index, int endIndex, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003033 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003034 int min = SkMin32(index, endIndex);
3035 markDone(min, winding);
3036 Span* last;
3037 Segment* other = this;
3038 while ((other = other->nextChase(index, step, min, last))) {
3039 other->markDone(min, winding);
3040 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003041 return last;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003042 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003043
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003044 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
3045 int index = angle->start();
3046 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00003047 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003048 int min = SkMin32(index, endIndex);
3049 markDoneBinary(min, winding, oppWinding);
3050 Span* last;
3051 Segment* other = this;
3052 while ((other = other->nextChase(index, step, min, last))) {
3053 other->markDoneBinary(min, winding, oppWinding);
3054 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003055 return last;
3056 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003057
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003058 Span* markAndChaseDoneBinary(int index, int endIndex) {
3059 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003060 int min = SkMin32(index, endIndex);
3061 markDoneBinary(min);
3062 Span* last;
3063 Segment* other = this;
3064 while ((other = other->nextChase(index, step, min, last))) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003065 if (other->done()) {
3066 return NULL;
3067 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003068 other->markDoneBinary(min);
3069 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003070 return last;
3071 }
3072
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003073 Span* markAndChaseDoneUnary(int index, int endIndex) {
3074 int step = SkSign32(endIndex - index);
3075 int min = SkMin32(index, endIndex);
3076 markDoneUnary(min);
3077 Span* last;
3078 Segment* other = this;
3079 while ((other = other->nextChase(index, step, min, last))) {
3080 if (other->done()) {
3081 return NULL;
3082 }
3083 other->markDoneUnary(min);
3084 }
3085 return last;
3086 }
3087
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003088 Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
3089 int index = angle->start();
3090 int endIndex = angle->end();
3091 return markAndChaseDone(index, endIndex, winding);
3092 }
3093
caryclark@google.com4eeda372012-12-06 21:47:48 +00003094 Span* markAndChaseWinding(const Angle* angle, const int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003095 int index = angle->start();
3096 int endIndex = angle->end();
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003097 int step = SkSign32(endIndex - index);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003098 int min = SkMin32(index, endIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00003099 markWinding(min, winding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003100 Span* last;
3101 Segment* other = this;
3102 while ((other = other->nextChase(index, step, min, last))) {
3103 if (other->fTs[min].fWindSum != SK_MinS32) {
3104 SkASSERT(other->fTs[min].fWindSum == winding);
3105 return NULL;
3106 }
3107 other->markWinding(min, winding);
3108 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003109 return last;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003110 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003111
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003112 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003113 int min = SkMin32(index, endIndex);
3114 int step = SkSign32(endIndex - index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003115 markWinding(min, winding, oppWinding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003116 Span* last;
3117 Segment* other = this;
3118 while ((other = other->nextChase(index, step, min, last))) {
3119 if (other->fTs[min].fWindSum != SK_MinS32) {
3120 SkASSERT(other->fTs[min].fWindSum == winding);
3121 return NULL;
3122 }
3123 other->markWinding(min, winding, oppWinding);
3124 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003125 return last;
3126 }
3127
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003128 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
3129 int start = angle->start();
3130 int end = angle->end();
3131 return markAndChaseWinding(start, end, winding, oppWinding);
3132 }
3133
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003134 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
3135 SkASSERT(angle->segment() == this);
3136 if (useInnerWinding(maxWinding, sumWinding)) {
3137 maxWinding = sumWinding;
3138 }
3139 Span* last;
3140 if (activeAngle) {
3141 last = markAndChaseWinding(angle, maxWinding);
3142 } else {
3143 last = markAndChaseDoneUnary(angle, maxWinding);
3144 }
3145 return last;
3146 }
3147
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003148 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
3149 bool activeAngle, const Angle* angle) {
3150 SkASSERT(angle->segment() == this);
3151 if (useInnerWinding(maxWinding, sumWinding)) {
3152 maxWinding = sumWinding;
3153 }
3154 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
3155 oppMaxWinding = oppSumWinding;
3156 }
3157 Span* last;
3158 if (activeAngle) {
3159 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3160 } else {
3161 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
3162 }
3163 return last;
3164 }
3165
caryclark@google.com495f8e42012-05-31 13:13:11 +00003166 // FIXME: this should also mark spans with equal (x,y)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003167 // This may be called when the segment is already marked done. While this
3168 // wastes time, it shouldn't do any more than spin through the T spans.
rmistry@google.comd6176b02012-08-23 18:14:13 +00003169 // OPTIMIZATION: abort on first done found (assuming that this code is
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003170 // always called to mark segments done).
caryclark@google.com59823f72012-08-09 18:17:47 +00003171 void markDone(int index, int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003172 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003173 SkASSERT(winding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003174 double referenceT = fTs[index].fT;
3175 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003176 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3177 markOneDone(__FUNCTION__, lesser, winding);
3178 }
3179 do {
3180 markOneDone(__FUNCTION__, index, winding);
3181 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003182 }
3183
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003184 void markDoneBinary(int index, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003185 // SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003186 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003187 double referenceT = fTs[index].fT;
3188 int lesser = index;
3189 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003190 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003191 }
3192 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003193 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
3194 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3195 }
3196
3197 void markDoneBinary(int index) {
3198 double referenceT = fTs[index].fT;
3199 int lesser = index;
3200 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3201 markOneDoneBinary(__FUNCTION__, lesser);
3202 }
3203 do {
3204 markOneDoneBinary(__FUNCTION__, index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003205 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003206 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00003207
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003208 void markDoneUnary(int index, int winding) {
3209 // SkASSERT(!done());
3210 SkASSERT(winding);
3211 double referenceT = fTs[index].fT;
3212 int lesser = index;
3213 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3214 markOneDoneUnary(__FUNCTION__, lesser, winding);
3215 }
3216 do {
3217 markOneDoneUnary(__FUNCTION__, index, winding);
3218 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3219 }
3220
3221 void markDoneUnary(int index) {
3222 double referenceT = fTs[index].fT;
3223 int lesser = index;
3224 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3225 markOneDoneUnary(__FUNCTION__, lesser);
3226 }
3227 do {
3228 markOneDoneUnary(__FUNCTION__, index);
3229 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3230 }
3231
caryclark@google.com24bec792012-08-20 12:43:57 +00003232 void markOneDone(const char* funName, int tIndex, int winding) {
3233 Span* span = markOneWinding(funName, tIndex, winding);
3234 if (!span) {
3235 return;
3236 }
3237 span->fDone = true;
3238 fDoneSpans++;
3239 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003240
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003241 void markOneDoneBinary(const char* funName, int tIndex) {
3242 Span* span = verifyOneWinding(funName, tIndex);
3243 if (!span) {
3244 return;
3245 }
3246 span->fDone = true;
3247 fDoneSpans++;
3248 }
3249
3250 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003251 Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
3252 if (!span) {
3253 return;
3254 }
3255 span->fDone = true;
3256 fDoneSpans++;
3257 }
3258
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003259 void markOneDoneUnary(const char* funName, int tIndex) {
3260 Span* span = verifyOneWindingU(funName, tIndex);
3261 if (!span) {
3262 return;
3263 }
3264 span->fDone = true;
3265 fDoneSpans++;
3266 }
3267
3268 void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3269 Span* span = markOneWinding(funName, tIndex, winding);
3270 if (!span) {
3271 return;
3272 }
3273 span->fDone = true;
3274 fDoneSpans++;
3275 }
3276
caryclark@google.com24bec792012-08-20 12:43:57 +00003277 Span* markOneWinding(const char* funName, int tIndex, int winding) {
3278 Span& span = fTs[tIndex];
3279 if (span.fDone) {
3280 return NULL;
3281 }
3282 #if DEBUG_MARK_DONE
3283 debugShowNewWinding(funName, span, winding);
3284 #endif
3285 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com03f97062012-08-21 13:13:52 +00003286 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00003287 SkASSERT(abs(winding) <= gDebugMaxWindSum);
caryclark@google.com03f97062012-08-21 13:13:52 +00003288 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00003289 span.fWindSum = winding;
3290 return &span;
3291 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003292
caryclark@google.com31143cf2012-11-09 22:14:19 +00003293 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
3294 Span& span = fTs[tIndex];
3295 if (span.fDone) {
3296 return NULL;
3297 }
3298 #if DEBUG_MARK_DONE
3299 debugShowNewWinding(funName, span, winding, oppWinding);
3300 #endif
3301 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3302 #ifdef SK_DEBUG
3303 SkASSERT(abs(winding) <= gDebugMaxWindSum);
3304 #endif
3305 span.fWindSum = winding;
3306 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3307 #ifdef SK_DEBUG
3308 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
3309 #endif
3310 span.fOppSum = oppWinding;
3311 return &span;
3312 }
3313
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003314 bool bumpsUp(int tStart, int tEnd) const {
3315 SkPoint edge[4];
3316 (*SegmentSubDivide[fVerb])(fPts, fTs[tStart].fT, fTs[tEnd].fT, edge);
3317 switch (fVerb) {
3318 case SkPath::kLine_Verb:
3319 SkASSERT(0); // shouldn't call in for lines
3320 return true;
3321 case SkPath::kQuad_Verb:
3322 return approximately_greater(edge[0].fY, edge[1].fY)
3323 && approximately_lesser(edge[1].fY, edge[2].fY);
3324 case SkPath::kCubic_Verb:
3325 return (approximately_greater(edge[0].fY, edge[1].fY)
3326 && approximately_lesser(edge[1].fY, edge[3].fY))
3327 || (approximately_greater(edge[0].fY, edge[2].fY)
3328 && approximately_lesser(edge[2].fY, edge[3].fY));
3329 default:
3330 SkASSERT(0);
3331 return false;
3332 }
3333 }
3334
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003335 Span* verifyOneWinding(const char* funName, int tIndex) {
3336 Span& span = fTs[tIndex];
3337 if (span.fDone) {
3338 return NULL;
3339 }
3340 #if DEBUG_MARK_DONE
3341 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3342 #endif
3343 SkASSERT(span.fWindSum != SK_MinS32);
3344 SkASSERT(span.fOppSum != SK_MinS32);
3345 return &span;
3346 }
3347
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003348 Span* verifyOneWindingU(const char* funName, int tIndex) {
3349 Span& span = fTs[tIndex];
3350 if (span.fDone) {
3351 return NULL;
3352 }
3353 #if DEBUG_MARK_DONE
3354 debugShowNewWinding(funName, span, span.fWindSum);
3355 #endif
3356 SkASSERT(span.fWindSum != SK_MinS32);
3357 return &span;
3358 }
3359
caryclark@google.comf839c032012-10-26 21:03:50 +00003360 // note that just because a span has one end that is unsortable, that's
3361 // not enough to mark it done. The other end may be sortable, allowing the
3362 // span to be added.
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003363 // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003364 void markUnsortable(int start, int end) {
3365 Span* span = &fTs[start];
3366 if (start < end) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003367#if DEBUG_UNSORTABLE
3368 SkDebugf("%s start id=%d [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fID, start,
3369 xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003370#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003371 span->fUnsortableStart = true;
3372 } else {
3373 --span;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003374#if DEBUG_UNSORTABLE
3375 SkDebugf("%s end id=%d [%d] (%1.9g,%1.9g) next:(%1.9g,%1.9g)\n", __FUNCTION__, fID,
3376 start - 1, xAtT(start - 1), yAtT(start - 1), xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003377#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003378 span->fUnsortableEnd = true;
3379 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003380 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003381 return;
3382 }
3383 span->fDone = true;
3384 fDoneSpans++;
3385 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003386
caryclark@google.com59823f72012-08-09 18:17:47 +00003387 void markWinding(int index, int winding) {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003388 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003389 SkASSERT(winding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003390 double referenceT = fTs[index].fT;
3391 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003392 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3393 markOneWinding(__FUNCTION__, lesser, winding);
3394 }
3395 do {
3396 markOneWinding(__FUNCTION__, index, winding);
3397 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003398 }
3399
3400 void markWinding(int index, int winding, int oppWinding) {
3401 // SkASSERT(!done());
caryclark@google.com4eeda372012-12-06 21:47:48 +00003402 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003403 double referenceT = fTs[index].fT;
3404 int lesser = index;
3405 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3406 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003407 }
3408 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003409 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3410 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003411 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003412
caryclark@google.com2ddff932012-08-07 21:25:27 +00003413 void matchWindingValue(int tIndex, double t, bool borrowWind) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003414 int nextDoorWind = SK_MaxS32;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003415 int nextOppWind = SK_MaxS32;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003416 if (tIndex > 0) {
3417 const Span& below = fTs[tIndex - 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003418 if (approximately_negative(t - below.fT)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003419 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003420 nextOppWind = below.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003421 }
3422 }
3423 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3424 const Span& above = fTs[tIndex + 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003425 if (approximately_negative(above.fT - t)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003426 nextDoorWind = above.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003427 nextOppWind = above.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003428 }
3429 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003430 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3431 const Span& below = fTs[tIndex - 1];
3432 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003433 nextOppWind = below.fOppValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003434 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003435 if (nextDoorWind != SK_MaxS32) {
3436 Span& newSpan = fTs[tIndex];
3437 newSpan.fWindValue = nextDoorWind;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003438 newSpan.fOppValue = nextOppWind;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003439 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003440 newSpan.fDone = true;
3441 ++fDoneSpans;
3442 }
3443 }
3444 }
3445
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003446 bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3447 // find bounds
3448 Bounds bounds;
3449 bounds.setPoint(xyAtT(index));
3450 bounds.add(xyAtT(endIndex));
3451 SkScalar width = bounds.width();
3452 SkScalar height = bounds.height();
3453 if (width > height) {
3454 if (approximately_negative(width)) {
3455 unsortable = true; // edge is too small to resolve meaningfully
3456 }
3457 return false;
3458 } else {
3459 if (approximately_negative(height)) {
3460 unsortable = true; // edge is too small to resolve meaningfully
3461 }
3462 return true;
3463 }
3464 }
3465
caryclark@google.com9764cc62012-07-12 19:29:45 +00003466 // return span if when chasing, two or more radiating spans are not done
3467 // OPTIMIZATION: ? multiple spans is detected when there is only one valid
3468 // candidate and the remaining spans have windValue == 0 (canceled by
3469 // coincidence). The coincident edges could either be removed altogether,
3470 // or this code could be more complicated in detecting this case. Worth it?
3471 bool multipleSpans(int end) const {
3472 return end > 0 && end < fTs.count() - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00003473 }
3474
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003475 bool nextCandidate(int& start, int& end) const {
caryclark@google.com10227bf2012-12-28 22:10:41 +00003476 while (fTs[end].fDone) {
3477 if (fTs[end].fT == 1) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003478 return false;
3479 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00003480 ++end;
3481 }
3482 start = end;
3483 end = nextExactSpan(start, 1);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003484 return true;
3485 }
3486
caryclark@google.com4eeda372012-12-06 21:47:48 +00003487 Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
3488 int end = nextExactSpan(index, step);
3489 SkASSERT(end >= 0);
3490 if (multipleSpans(end)) {
3491 last = &fTs[end];
3492 return NULL;
3493 }
3494 const Span& endSpan = fTs[end];
3495 Segment* other = endSpan.fOther;
3496 index = endSpan.fOtherIndex;
caryclark@google.comaa358312013-01-29 20:28:49 +00003497 SkASSERT(index >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003498 int otherEnd = other->nextExactSpan(index, step);
caryclark@google.comaa358312013-01-29 20:28:49 +00003499 SkASSERT(otherEnd >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003500 min = SkMin32(index, otherEnd);
3501 return other;
3502 }
3503
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003504 // This has callers for two different situations: one establishes the end
3505 // of the current span, and one establishes the beginning of the next span
3506 // (thus the name). When this is looking for the end of the current span,
3507 // coincidence is found when the beginning Ts contain -step and the end
3508 // contains step. When it is looking for the beginning of the next, the
3509 // first Ts found can be ignored and the last Ts should contain -step.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003510 // OPTIMIZATION: probably should split into two functions
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003511 int nextSpan(int from, int step) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003512 const Span& fromSpan = fTs[from];
caryclark@google.com495f8e42012-05-31 13:13:11 +00003513 int count = fTs.count();
3514 int to = from;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003515 while (step > 0 ? ++to < count : --to >= 0) {
3516 const Span& span = fTs[to];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003517 if (approximately_zero(span.fT - fromSpan.fT)) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003518 continue;
3519 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003520 return to;
3521 }
3522 return -1;
3523 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +00003524
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003525 // FIXME
3526 // this returns at any difference in T, vs. a preset minimum. It may be
3527 // that all callers to nextSpan should use this instead.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003528 // OPTIMIZATION splitting this into separate loops for up/down steps
3529 // would allow using precisely_negative instead of precisely_zero
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003530 int nextExactSpan(int from, int step) const {
3531 const Span& fromSpan = fTs[from];
3532 int count = fTs.count();
3533 int to = from;
3534 while (step > 0 ? ++to < count : --to >= 0) {
3535 const Span& span = fTs[to];
caryclark@google.coma461ff02012-10-11 12:54:23 +00003536 if (precisely_zero(span.fT - fromSpan.fT)) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003537 continue;
3538 }
3539 return to;
3540 }
3541 return -1;
3542 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003543
caryclark@google.com235f56a2012-09-14 14:19:30 +00003544 bool operand() const {
3545 return fOperand;
3546 }
3547
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003548 int oppSign(const Angle* angle) const {
3549 SkASSERT(angle->segment() == this);
3550 return oppSign(angle->start(), angle->end());
3551 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003552
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003553 int oppSign(int startIndex, int endIndex) const {
3554 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3555 : fTs[endIndex].fOppValue;
3556#if DEBUG_WIND_BUMP
3557 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3558#endif
3559 return result;
3560 }
3561
caryclark@google.com31143cf2012-11-09 22:14:19 +00003562 int oppSum(int tIndex) const {
3563 return fTs[tIndex].fOppSum;
3564 }
3565
3566 int oppSum(const Angle* angle) const {
3567 int lesser = SkMin32(angle->start(), angle->end());
3568 return fTs[lesser].fOppSum;
caryclark@google.com235f56a2012-09-14 14:19:30 +00003569 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003570
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003571 int oppValue(int tIndex) const {
3572 return fTs[tIndex].fOppValue;
3573 }
3574
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003575 int oppValue(const Angle* angle) const {
3576 int lesser = SkMin32(angle->start(), angle->end());
3577 return fTs[lesser].fOppValue;
3578 }
3579
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003580 const SkPoint* pts() const {
3581 return fPts;
3582 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003583
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003584 void reset() {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003585 init(NULL, (SkPath::Verb) -1, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003586 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3587 fTs.reset();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003588 }
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +00003589
caryclark@google.com4eeda372012-12-06 21:47:48 +00003590 void setOppXor(bool isOppXor) {
3591 fOppXor = isOppXor;
3592 }
3593
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003594 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3595 int deltaSum = spanSign(index, endIndex);
3596 maxWinding = sumWinding;
3597 sumWinding = sumWinding -= deltaSum;
3598 }
3599
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003600 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3601 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3602 int deltaSum = spanSign(index, endIndex);
3603 int oppDeltaSum = oppSign(index, endIndex);
3604 if (operand()) {
3605 maxWinding = sumSuWinding;
3606 sumWinding = sumSuWinding -= deltaSum;
3607 oppMaxWinding = sumMiWinding;
3608 oppSumWinding = sumMiWinding -= oppDeltaSum;
3609 } else {
3610 maxWinding = sumMiWinding;
3611 sumWinding = sumMiWinding -= deltaSum;
3612 oppMaxWinding = sumSuWinding;
3613 oppSumWinding = sumSuWinding -= oppDeltaSum;
3614 }
3615 }
3616
caryclark@google.comf839c032012-10-26 21:03:50 +00003617 // This marks all spans unsortable so that this info is available for early
3618 // exclusion in find top and others. This could be optimized to only mark
3619 // adjacent spans that unsortable. However, this makes it difficult to later
3620 // determine starting points for edge detection in find top and the like.
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003621 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
caryclark@google.comf839c032012-10-26 21:03:50 +00003622 bool sortable = true;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003623 int angleCount = angles.count();
3624 int angleIndex;
3625 angleList.setReserve(angleCount);
3626 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003627 Angle& angle = angles[angleIndex];
caryclark@google.comf839c032012-10-26 21:03:50 +00003628 *angleList.append() = &angle;
3629 sortable &= !angle.unsortable();
3630 }
3631 if (sortable) {
3632 QSort<Angle>(angleList.begin(), angleList.end() - 1);
3633 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3634 if (angles[angleIndex].unsortable()) {
3635 sortable = false;
3636 break;
3637 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003638 }
3639 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003640 if (!sortable) {
3641 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3642 Angle& angle = angles[angleIndex];
3643 angle.segment()->markUnsortable(angle.start(), angle.end());
3644 }
3645 }
3646 return sortable;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003647 }
3648
caryclark@google.com1577e8f2012-05-22 17:01:14 +00003649 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003650 const Span& span(int tIndex) const {
3651 return fTs[tIndex];
3652 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003653
caryclark@google.com235f56a2012-09-14 14:19:30 +00003654 int spanSign(const Angle* angle) const {
3655 SkASSERT(angle->segment() == this);
3656 return spanSign(angle->start(), angle->end());
3657 }
3658
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003659 int spanSign(int startIndex, int endIndex) const {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003660 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3661 : fTs[endIndex].fWindValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003662#if DEBUG_WIND_BUMP
3663 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3664#endif
3665 return result;
3666 }
3667
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003668 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003669 double t(int tIndex) const {
3670 return fTs[tIndex].fT;
3671 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003672
caryclark@google.com10227bf2012-12-28 22:10:41 +00003673 double tAtMid(int start, int end, double mid) const {
3674 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
3675 }
3676
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003677 bool tiny(const Angle* angle) const {
3678 int start = angle->start();
3679 int end = angle->end();
caryclark@google.comf839c032012-10-26 21:03:50 +00003680 const Span& mSpan = fTs[SkMin32(start, end)];
3681 return mSpan.fTiny;
3682 }
3683
caryclark@google.com18063442012-07-25 12:05:18 +00003684 static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3685 double start) {
3686 int outCount = outsideTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003687 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
caryclark@google.com18063442012-07-25 12:05:18 +00003688 *outsideTs.append() = end;
3689 *outsideTs.append() = start;
3690 }
3691 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003692
caryclark@google.com24bec792012-08-20 12:43:57 +00003693 void undoneSpan(int& start, int& end) {
3694 size_t tCount = fTs.count();
3695 size_t index;
3696 for (index = 0; index < tCount; ++index) {
3697 if (!fTs[index].fDone) {
3698 break;
3699 }
3700 }
3701 SkASSERT(index < tCount - 1);
3702 start = index;
3703 double startT = fTs[index].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003704 while (approximately_negative(fTs[++index].fT - startT))
caryclark@google.com24bec792012-08-20 12:43:57 +00003705 SkASSERT(index < tCount);
3706 SkASSERT(index < tCount);
3707 end = index;
3708 }
caryclark@google.com18063442012-07-25 12:05:18 +00003709
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003710 bool unsortable(int index) const {
3711 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3712 }
3713
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003714 void updatePts(const SkPoint pts[]) {
3715 fPts = pts;
3716 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003717
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003718 int updateOppWinding(int index, int endIndex) const {
3719 int lesser = SkMin32(index, endIndex);
3720 int oppWinding = oppSum(lesser);
3721 int oppSpanWinding = oppSign(index, endIndex);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003722 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)
3723 && oppWinding != SK_MaxS32) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003724 oppWinding -= oppSpanWinding;
3725 }
3726 return oppWinding;
3727 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003728
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003729 int updateOppWinding(const Angle* angle) const {
3730 int startIndex = angle->start();
3731 int endIndex = angle->end();
3732 return updateOppWinding(endIndex, startIndex);
3733 }
3734
3735 int updateOppWindingReverse(const Angle* angle) const {
3736 int startIndex = angle->start();
3737 int endIndex = angle->end();
3738 return updateOppWinding(startIndex, endIndex);
3739 }
3740
3741 int updateWinding(int index, int endIndex) const {
3742 int lesser = SkMin32(index, endIndex);
3743 int winding = windSum(lesser);
3744 int spanWinding = spanSign(index, endIndex);
caryclark@google.com5e0500f2013-02-20 12:51:37 +00003745 if (winding && useInnerWinding(winding - spanWinding, winding) && winding != SK_MaxS32) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003746 winding -= spanWinding;
3747 }
3748 return winding;
3749 }
3750
3751 int updateWinding(const Angle* angle) const {
3752 int startIndex = angle->start();
3753 int endIndex = angle->end();
3754 return updateWinding(endIndex, startIndex);
3755 }
3756
3757 int updateWindingReverse(const Angle* angle) const {
3758 int startIndex = angle->start();
3759 int endIndex = angle->end();
3760 return updateWinding(startIndex, endIndex);
3761 }
3762
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003763 SkPath::Verb verb() const {
3764 return fVerb;
3765 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003766
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003767 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003768 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3769 return SK_MinS32;
3770 }
3771 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3772 SkASSERT(winding != SK_MinS32);
3773 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003774 #if DEBUG_WINDING_AT_T
3775 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003776 #endif
3777 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark@google.com3586ece2012-12-27 18:46:58 +00003778 dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003779 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3780 dx = fPts[2].fX - fPts[1].fX - dx;
3781 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003782 if (dx == 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003783 #if DEBUG_WINDING_AT_T
3784 SkDebugf(" dx=0 winding=SK_MinS32\n");
3785 #endif
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003786 return SK_MinS32;
3787 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003788 if (winding * dx > 0) { // if same signs, result is negative
3789 winding += dx > 0 ? -windVal : windVal;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003790 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003791 #if DEBUG_WINDING_AT_T
3792 SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding);
3793 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003794 return winding;
3795 }
3796
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003797 int windSum(int tIndex) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003798 return fTs[tIndex].fWindSum;
3799 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003800
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003801 int windSum(const Angle* angle) const {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003802 int start = angle->start();
3803 int end = angle->end();
3804 int index = SkMin32(start, end);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003805 return windSum(index);
caryclark@google.com495f8e42012-05-31 13:13:11 +00003806 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003807
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003808 int windValue(int tIndex) const {
3809 return fTs[tIndex].fWindValue;
3810 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003811
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003812 int windValue(const Angle* angle) const {
3813 int start = angle->start();
3814 int end = angle->end();
3815 int index = SkMin32(start, end);
3816 return windValue(index);
3817 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00003818
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003819 int windValueAt(double t) const {
3820 int count = fTs.count();
3821 for (int index = 0; index < count; ++index) {
3822 if (fTs[index].fT == t) {
3823 return fTs[index].fWindValue;
3824 }
3825 }
3826 SkASSERT(0);
3827 return 0;
3828 }
3829
caryclark@google.com3586ece2012-12-27 18:46:58 +00003830 SkScalar xAtT(int index) const {
3831 return xAtT(&fTs[index]);
3832 }
3833
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003834 SkScalar xAtT(const Span* span) const {
3835 return xyAtT(span).fX;
3836 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003837
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003838 const SkPoint& xyAtT(int index) const {
3839 return xyAtT(&fTs[index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003840 }
3841
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003842 const SkPoint& xyAtT(const Span* span) const {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003843 if (SkScalarIsNaN(span->fPt.fX)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003844 if (span->fT == 0) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003845 span->fPt = fPts[0];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003846 } else if (span->fT == 1) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003847 span->fPt = fPts[fVerb];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003848 } else {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003849 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003850 }
3851 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00003852 return span->fPt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003853 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003854
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003855 // used only by right angle winding finding
caryclark@google.com10227bf2012-12-28 22:10:41 +00003856 void xyAtT(double mid, SkPoint& pt) const {
3857 (*SegmentXYAtT[fVerb])(fPts, mid, &pt);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003858 }
3859
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003860 SkScalar yAtT(int index) const {
3861 return yAtT(&fTs[index]);
3862 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003863
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003864 SkScalar yAtT(const Span* span) const {
3865 return xyAtT(span).fY;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003866 }
3867
caryclark@google.com4eeda372012-12-06 21:47:48 +00003868 void zeroCoincidentOpp(Span* oTest, int index) {
3869 Span* const test = &fTs[index];
3870 Span* end = test;
3871 do {
3872 end->fOppValue = 0;
3873 end = &fTs[++index];
3874 } while (approximately_negative(end->fT - test->fT));
3875 }
3876
3877 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
3878 Span* const oTest = &fTs[oIndex];
3879 Span* oEnd = oTest;
3880 const double startT = test->fT;
3881 const double oStartT = oTest->fT;
3882 double otherTMatch = (test->fT - startT) * tRatio + oStartT;
3883 while (!approximately_negative(oEndT - oEnd->fT)
3884 && approximately_negative(oEnd->fT - otherTMatch)) {
3885 oEnd->fOppValue = 0;
3886 oEnd = &fTs[++oIndex];
3887 }
3888 }
3889
3890 void zeroSpan(Span* span) {
3891 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
caryclark@google.com6ec15262012-11-16 20:16:50 +00003892 span->fWindValue = 0;
caryclark@google.com729e1c42012-11-21 21:36:34 +00003893 span->fOppValue = 0;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003894 SkASSERT(!span->fDone);
3895 span->fDone = true;
3896 ++fDoneSpans;
caryclark@google.com6ec15262012-11-16 20:16:50 +00003897 }
3898
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003899#if DEBUG_DUMP
3900 void dump() const {
3901 const char className[] = "Segment";
3902 const int tab = 4;
3903 for (int i = 0; i < fTs.count(); ++i) {
3904 SkPoint out;
3905 (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
3906 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003907 " otherT=%1.9g windSum=%d\n",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003908 tab + sizeof(className), className, fID,
3909 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003910 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003911 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00003912 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003913 tab + sizeof(className), className, fID,
caryclark@google.com15fa1382012-05-07 20:49:36 +00003914 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003915 }
3916#endif
3917
caryclark@google.com47580692012-07-23 12:14:49 +00003918#if DEBUG_CONCIDENT
caryclark@google.comaa358312013-01-29 20:28:49 +00003919 // SkASSERT if pair has not already been added
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003920 void debugAddTPair(double t, const Segment& other, double otherT) const {
caryclark@google.comcc905052012-07-25 20:59:42 +00003921 for (int i = 0; i < fTs.count(); ++i) {
3922 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
3923 return;
3924 }
3925 }
3926 SkASSERT(0);
3927 }
3928#endif
3929
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003930#if DEBUG_DUMP
3931 int debugID() const {
3932 return fID;
3933 }
3934#endif
3935
caryclark@google.com24bec792012-08-20 12:43:57 +00003936#if DEBUG_WINDING
3937 void debugShowSums() const {
3938 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
3939 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
3940 for (int i = 0; i < fTs.count(); ++i) {
3941 const Span& span = fTs[i];
3942 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
3943 if (span.fWindSum == SK_MinS32) {
3944 SkDebugf("?");
3945 } else {
3946 SkDebugf("%d", span.fWindSum);
3947 }
3948 SkDebugf("]");
3949 }
3950 SkDebugf("\n");
3951 }
3952#endif
3953
caryclark@google.comcc905052012-07-25 20:59:42 +00003954#if DEBUG_CONCIDENT
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003955 void debugShowTs() const {
caryclark@google.com24bec792012-08-20 12:43:57 +00003956 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003957 int lastWind = -1;
3958 int lastOpp = -1;
3959 double lastT = -1;
3960 int i;
3961 for (i = 0; i < fTs.count(); ++i) {
3962 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
3963 || lastOpp != fTs[i].fOppValue;
3964 if (change && lastWind >= 0) {
3965 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3966 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3967 }
3968 if (change) {
3969 SkDebugf(" [o=%d", fTs[i].fOther->fID);
3970 lastWind = fTs[i].fWindValue;
3971 lastOpp = fTs[i].fOppValue;
3972 lastT = fTs[i].fT;
3973 } else {
3974 SkDebugf(",%d", fTs[i].fOther->fID);
3975 }
3976 }
3977 if (i <= 0) {
3978 return;
3979 }
3980 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3981 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3982 if (fOperand) {
3983 SkDebugf(" operand");
3984 }
3985 if (done()) {
3986 SkDebugf(" done");
caryclark@google.com47580692012-07-23 12:14:49 +00003987 }
3988 SkDebugf("\n");
3989 }
3990#endif
3991
caryclark@google.com027de222012-07-12 12:52:50 +00003992#if DEBUG_ACTIVE_SPANS
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003993 void debugShowActiveSpans() const {
caryclark@google.com027de222012-07-12 12:52:50 +00003994 if (done()) {
3995 return;
3996 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003997#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3998 int lastId = -1;
3999 double lastT = -1;
4000#endif
caryclark@google.com027de222012-07-12 12:52:50 +00004001 for (int i = 0; i < fTs.count(); ++i) {
4002 if (fTs[i].fDone) {
4003 continue;
4004 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004005#if DEBUG_ACTIVE_SPANS_SHORT_FORM
4006 if (lastId == fID && lastT == fTs[i].fT) {
4007 continue;
4008 }
4009 lastId = fID;
4010 lastT = fTs[i].fT;
4011#endif
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004012 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com027de222012-07-12 12:52:50 +00004013 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4014 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4015 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4016 }
4017 const Span* span = &fTs[i];
rmistry@google.comd6176b02012-08-23 18:14:13 +00004018 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
caryclark@google.com0c803d02012-08-06 11:15:47 +00004019 xAtT(span), yAtT(span));
caryclark@google.com47d73da2013-02-17 01:41:25 +00004020 int iEnd = i + 1;
4021 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) {
4022 ++iEnd;
4023 }
4024 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT);
caryclark@google.com027de222012-07-12 12:52:50 +00004025 const Segment* other = fTs[i].fOther;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004026 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
4027 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
4028 if (fTs[i].fWindSum == SK_MinS32) {
4029 SkDebugf("?");
4030 } else {
4031 SkDebugf("%d", fTs[i].fWindSum);
4032 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00004033 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
caryclark@google.com027de222012-07-12 12:52:50 +00004034 }
4035 }
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +00004036
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004037 // This isn't useful yet -- but leaving it in for now in case i think of something
4038 // to use it for
4039 void validateActiveSpans() const {
4040 if (done()) {
4041 return;
4042 }
4043 int tCount = fTs.count();
4044 for (int index = 0; index < tCount; ++index) {
4045 if (fTs[index].fDone) {
4046 continue;
4047 }
4048 // count number of connections which are not done
4049 int first = index;
4050 double baseT = fTs[index].fT;
4051 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
4052 --first;
4053 }
4054 int last = index;
4055 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
4056 ++last;
4057 }
4058 int connections = 0;
4059 connections += first > 0 && !fTs[first - 1].fDone;
4060 for (int test = first; test <= last; ++test) {
4061 connections += !fTs[test].fDone;
4062 const Segment* other = fTs[test].fOther;
4063 int oIndex = fTs[test].fOtherIndex;
4064 connections += !other->fTs[oIndex].fDone;
4065 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
4066 }
4067 // SkASSERT(!(connections & 1));
4068 }
4069 }
caryclark@google.com027de222012-07-12 12:52:50 +00004070#endif
4071
caryclark@google.com0c803d02012-08-06 11:15:47 +00004072#if DEBUG_MARK_DONE
4073 void debugShowNewWinding(const char* fun, const Span& span, int winding) {
4074 const SkPoint& pt = xyAtT(&span);
4075 SkDebugf("%s id=%d", fun, fID);
4076 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4077 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4078 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4079 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004080 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4081 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4082 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d windSum=",
4083 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, winding);
caryclark@google.com0c803d02012-08-06 11:15:47 +00004084 if (span.fWindSum == SK_MinS32) {
4085 SkDebugf("?");
4086 } else {
4087 SkDebugf("%d", span.fWindSum);
4088 }
4089 SkDebugf(" windValue=%d\n", span.fWindValue);
4090 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004091
4092 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
4093 const SkPoint& pt = xyAtT(&span);
4094 SkDebugf("%s id=%d", fun, fID);
4095 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
4096 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
4097 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
4098 }
4099 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
4100 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
4101 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=",
4102 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
4103 winding, oppWinding);
4104 if (span.fOppSum == SK_MinS32) {
4105 SkDebugf("?");
4106 } else {
4107 SkDebugf("%d", span.fOppSum);
4108 }
4109 SkDebugf(" windSum=");
4110 if (span.fWindSum == SK_MinS32) {
4111 SkDebugf("?");
4112 } else {
4113 SkDebugf("%d", span.fWindSum);
4114 }
4115 SkDebugf(" windValue=%d\n", span.fWindValue);
4116 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00004117#endif
4118
caryclark@google.com47580692012-07-23 12:14:49 +00004119#if DEBUG_SORT
caryclark@google.com03f97062012-08-21 13:13:52 +00004120 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
caryclark@google.com31143cf2012-11-09 22:14:19 +00004121 const int contourWinding, const int oppContourWinding) const {
caryclark@google.comafe56de2012-07-24 18:11:03 +00004122 SkASSERT(angles[first]->segment() == this);
caryclark@google.com200c2112012-08-03 15:05:04 +00004123 SkASSERT(angles.count() > 1);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004124 int lastSum = contourWinding;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004125 int oppLastSum = oppContourWinding;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004126 const Angle* firstAngle = angles[first];
4127 int windSum = lastSum - spanSign(firstAngle);
4128 int oppoSign = oppSign(firstAngle);
4129 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004130 SkDebugf("%s %s contourWinding=%d oppContourWinding=%d sign=%d\n", fun, __FUNCTION__,
4131 contourWinding, oppContourWinding, spanSign(angles[first]));
caryclark@google.comafe56de2012-07-24 18:11:03 +00004132 int index = first;
4133 bool firstTime = true;
caryclark@google.com47580692012-07-23 12:14:49 +00004134 do {
4135 const Angle& angle = *angles[index];
4136 const Segment& segment = *angle.segment();
4137 int start = angle.start();
4138 int end = angle.end();
4139 const Span& sSpan = segment.fTs[start];
4140 const Span& eSpan = segment.fTs[end];
4141 const Span& mSpan = segment.fTs[SkMin32(start, end)];
caryclark@google.com31143cf2012-11-09 22:14:19 +00004142 bool opp = segment.fOperand ^ fOperand;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004143 if (!firstTime) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004144 oppoSign = segment.oppSign(&angle);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004145 if (opp) {
4146 oppLastSum = oppWindSum;
4147 oppWindSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004148 if (oppoSign) {
4149 lastSum = windSum;
4150 windSum -= oppoSign;
4151 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004152 } else {
4153 lastSum = windSum;
4154 windSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004155 if (oppoSign) {
4156 oppLastSum = oppWindSum;
4157 oppWindSum -= oppoSign;
4158 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004159 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004160 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004161 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 +00004162 " sign=%d windValue=%d windSum=",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004163 __FUNCTION__, index, angle.unsortable() ? "*** UNSORTABLE *** " : "",
caryclark@google.comc91dfe42012-10-16 12:06:27 +00004164 segment.fID, kLVerbStr[segment.fVerb],
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004165 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
4166 segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(),
4167 mSpan.fWindValue);
skia.committer@gmail.comd454ec12013-02-21 07:15:03 +00004168 start here;
caryclark@google.com5e0500f2013-02-20 12:51:37 +00004169 // create an inline to replace this conditional
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004170 if (mSpan.fWindSum == SK_MinS32) {
4171 SkDebugf("?");
4172 } else {
4173 SkDebugf("%d", mSpan.fWindSum);
4174 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004175 int last, wind;
4176 if (opp) {
4177 last = oppLastSum;
4178 wind = oppWindSum;
4179 } else {
4180 last = lastSum;
4181 wind = windSum;
4182 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004183 if (!oppoSign) {
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00004184 SkDebugf(" %d->%d (max=%d)", last, wind,
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004185 useInnerWinding(last, wind) ? wind : last);
4186 } else {
4187 SkDebugf(" %d->%d (%d->%d)", last, wind, opp ? lastSum : oppLastSum,
4188 opp ? windSum : oppWindSum);
4189 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004190 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004191#if false && DEBUG_ANGLE
caryclark@google.comc899ad92012-08-23 15:24:42 +00004192 angle.debugShow(segment.xyAtT(&sSpan));
4193#endif
caryclark@google.com47580692012-07-23 12:14:49 +00004194 ++index;
4195 if (index == angles.count()) {
4196 index = 0;
4197 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004198 if (firstTime) {
4199 firstTime = false;
4200 }
caryclark@google.com47580692012-07-23 12:14:49 +00004201 } while (index != first);
4202 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00004203
4204 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
4205 const Angle* firstAngle = angles[first];
4206 const Segment* segment = firstAngle->segment();
4207 int winding = segment->updateWinding(firstAngle);
4208 int oppWinding = segment->updateOppWinding(firstAngle);
4209 debugShowSort(fun, angles, first, winding, oppWinding);
4210 }
4211
caryclark@google.com47580692012-07-23 12:14:49 +00004212#endif
4213
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004214#if DEBUG_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004215 static char as_digit(int value) {
4216 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
4217 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004218#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004219
caryclark@google.com729e1c42012-11-21 21:36:34 +00004220#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004221 int debugShowWindingValues(int slotCount, int ofInterest) const {
4222 if (!(1 << fID & ofInterest)) {
4223 return 0;
4224 }
4225 int sum = 0;
4226 SkTDArray<char> slots;
4227 slots.setCount(slotCount * 2);
4228 memset(slots.begin(), ' ', slotCount * 2);
4229 for (int i = 0; i < fTs.count(); ++i) {
4230 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
4231 // continue;
4232 // }
4233 sum += fTs[i].fWindValue;
4234 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
4235 sum += fTs[i].fOppValue;
4236 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
4237 }
4238 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
4239 slots.begin() + slotCount);
4240 return sum;
4241 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004242#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004243
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004244private:
4245 const SkPoint* fPts;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004246 Bounds fBounds;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004247 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
caryclark@google.com4eeda372012-12-06 21:47:48 +00004248 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
caryclark@google.com24bec792012-08-20 12:43:57 +00004249 int fDoneSpans; // quick check that segment is finished
caryclark@google.com4eeda372012-12-06 21:47:48 +00004250 // OPTIMIZATION: force the following to be byte-sized
4251 SkPath::Verb fVerb;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004252 bool fOperand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004253 bool fXor; // set if original contour had even-odd fill
4254 bool fOppXor; // set if opposite operand had even-odd fill
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004255#if DEBUG_DUMP
4256 int fID;
4257#endif
4258};
4259
caryclark@google.comb9738012012-07-03 19:53:30 +00004260class Contour;
4261
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004262struct Coincidence {
caryclark@google.comb9738012012-07-03 19:53:30 +00004263 Contour* fContours[2];
4264 int fSegments[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004265 double fTs[2][2];
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004266 SkPoint fPts[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004267};
4268
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004269class Contour {
4270public:
4271 Contour() {
4272 reset();
4273#if DEBUG_DUMP
4274 fID = ++gContourID;
4275#endif
4276 }
4277
4278 bool operator<(const Contour& rh) const {
4279 return fBounds.fTop == rh.fBounds.fTop
4280 ? fBounds.fLeft < rh.fBounds.fLeft
4281 : fBounds.fTop < rh.fBounds.fTop;
4282 }
4283
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004284 void addCoincident(int index, Contour* other, int otherIndex,
4285 const Intersections& ts, bool swap) {
4286 Coincidence& coincidence = *fCoincidences.append();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004287 coincidence.fContours[0] = this; // FIXME: no need to store
caryclark@google.comb9738012012-07-03 19:53:30 +00004288 coincidence.fContours[1] = other;
4289 coincidence.fSegments[0] = index;
4290 coincidence.fSegments[1] = otherIndex;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004291 coincidence.fTs[swap][0] = ts.fT[0][0];
4292 coincidence.fTs[swap][1] = ts.fT[0][1];
4293 coincidence.fTs[!swap][0] = ts.fT[1][0];
4294 coincidence.fTs[!swap][1] = ts.fT[1][1];
4295 coincidence.fPts[0] = ts.fPt[0].asSkPoint();
4296 coincidence.fPts[1] = ts.fPt[1].asSkPoint();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004297 }
4298
4299 void addCross(const Contour* crosser) {
4300#ifdef DEBUG_CROSS
4301 for (int index = 0; index < fCrosses.count(); ++index) {
4302 SkASSERT(fCrosses[index] != crosser);
4303 }
4304#endif
4305 *fCrosses.append() = crosser;
4306 }
4307
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004308 void addCubic(const SkPoint pts[4]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004309 fSegments.push_back().addCubic(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004310 fContainsCurves = true;
4311 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004312
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004313 int addLine(const SkPoint pts[2]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004314 fSegments.push_back().addLine(pts, fOperand, fXor);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004315 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004316 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004317
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004318 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
4319 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
4320 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004321
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004322 int addQuad(const SkPoint pts[3]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004323 fSegments.push_back().addQuad(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004324 fContainsCurves = true;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004325 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004326 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004327
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004328 int addT(int segIndex, double newT, Contour* other, int otherIndex, const SkPoint& pt) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004329 containsIntercepts();
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004330 return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex], pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004331 }
4332
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004333 int addUnsortableT(int segIndex, double newT, Contour* other, int otherIndex, bool start,
4334 const SkPoint& pt) {
4335 return fSegments[segIndex].addUnsortableT(newT, &other->fSegments[otherIndex], start, pt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00004336 }
4337
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004338 const Bounds& bounds() const {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004339 return fBounds;
4340 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004341
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004342 void complete() {
4343 setBounds();
4344 fContainsIntercepts = false;
4345 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004346
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004347 void containsIntercepts() {
4348 fContainsIntercepts = true;
4349 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004350
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004351 bool crosses(const Contour* crosser) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004352 for (int index = 0; index < fCrosses.count(); ++index) {
4353 if (fCrosses[index] == crosser) {
4354 return true;
4355 }
4356 }
4357 return false;
4358 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004359
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004360 bool done() const {
4361 return fDone;
4362 }
4363
caryclark@google.comf839c032012-10-26 21:03:50 +00004364 const SkPoint& end() const {
4365 const Segment& segment = fSegments.back();
4366 return segment.pts()[segment.verb()];
4367 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004368
caryclark@google.com4eeda372012-12-06 21:47:48 +00004369 void findTooCloseToCall() {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004370 int segmentCount = fSegments.count();
4371 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004372 fSegments[sIndex].findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004373 }
4374 }
4375
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004376 void fixOtherTIndex() {
4377 int segmentCount = fSegments.count();
4378 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4379 fSegments[sIndex].fixOtherTIndex();
4380 }
4381 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004382
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004383 Segment* nonVerticalSegment(int& start, int& end) {
4384 int segmentCount = fSortedSegments.count();
4385 SkASSERT(segmentCount > 0);
4386 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4387 Segment* testSegment = fSortedSegments[sortedIndex];
4388 if (testSegment->done()) {
4389 continue;
4390 }
4391 start = end = 0;
4392 while (testSegment->nextCandidate(start, end)) {
4393 if (!testSegment->isVertical(start, end)) {
4394 return testSegment;
4395 }
4396 }
4397 }
4398 return NULL;
4399 }
4400
caryclark@google.com31143cf2012-11-09 22:14:19 +00004401 bool operand() const {
4402 return fOperand;
4403 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004404
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004405 void reset() {
4406 fSegments.reset();
4407 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004408 fContainsCurves = fContainsIntercepts = fDone = false;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004409 }
caryclark@google.comb9738012012-07-03 19:53:30 +00004410
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004411 void resolveCoincidence(SkTDArray<Contour*>& contourList) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004412 int count = fCoincidences.count();
4413 for (int index = 0; index < count; ++index) {
4414 Coincidence& coincidence = fCoincidences[index];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004415 SkASSERT(coincidence.fContours[0] == this);
caryclark@google.comb9738012012-07-03 19:53:30 +00004416 int thisIndex = coincidence.fSegments[0];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004417 Segment& thisOne = fSegments[thisIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004418 Contour* otherContour = coincidence.fContours[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004419 int otherIndex = coincidence.fSegments[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004420 Segment& other = otherContour->fSegments[otherIndex];
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004421 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004422 continue;
4423 }
caryclark@google.com47580692012-07-23 12:14:49 +00004424 #if DEBUG_CONCIDENT
4425 thisOne.debugShowTs();
4426 other.debugShowTs();
4427 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004428 double startT = coincidence.fTs[0][0];
4429 double endT = coincidence.fTs[0][1];
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004430 bool cancelers = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004431 if (startT > endT) {
4432 SkTSwap<double>(startT, endT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004433 cancelers ^= true; // FIXME: just assign true
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004434 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004435 SkASSERT(!approximately_negative(endT - startT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004436 double oStartT = coincidence.fTs[1][0];
4437 double oEndT = coincidence.fTs[1][1];
4438 if (oStartT > oEndT) {
4439 SkTSwap<double>(oStartT, oEndT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004440 cancelers ^= true;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004441 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004442 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00004443 bool opp = fOperand ^ otherContour->fOperand;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004444 if (cancelers && !opp) {
4445 // make sure startT and endT have t entries
caryclark@google.com2ddff932012-08-07 21:25:27 +00004446 if (startT > 0 || oEndT < 1
4447 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004448 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004449 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00004450 if (oStartT > 0 || endT < 1
4451 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004452 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004453 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004454 if (!thisOne.done() && !other.done()) {
4455 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4456 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004457 } else {
caryclark@google.com200c2112012-08-03 15:05:04 +00004458 if (startT > 0 || oStartT > 0
4459 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004460 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004461 }
caryclark@google.com200c2112012-08-03 15:05:04 +00004462 if (endT < 1 || oEndT < 1
4463 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004464 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.comb9738012012-07-03 19:53:30 +00004465 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004466 if (!thisOne.done() && !other.done()) {
4467 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4468 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004469 }
caryclark@google.com47580692012-07-23 12:14:49 +00004470 #if DEBUG_CONCIDENT
4471 thisOne.debugShowTs();
4472 other.debugShowTs();
4473 #endif
caryclark@google.com729e1c42012-11-21 21:36:34 +00004474 #if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004475 debugShowWindingValues(contourList);
4476 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004477 }
4478 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004479
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004480 // first pass, add missing T values
4481 // second pass, determine winding values of overlaps
4482 void addCoincidentPoints() {
4483 int count = fCoincidences.count();
4484 for (int index = 0; index < count; ++index) {
4485 Coincidence& coincidence = fCoincidences[index];
4486 SkASSERT(coincidence.fContours[0] == this);
4487 int thisIndex = coincidence.fSegments[0];
4488 Segment& thisOne = fSegments[thisIndex];
4489 Contour* otherContour = coincidence.fContours[1];
4490 int otherIndex = coincidence.fSegments[1];
4491 Segment& other = otherContour->fSegments[otherIndex];
4492 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
4493 // OPTIMIZATION: remove from array
4494 continue;
4495 }
4496 #if DEBUG_CONCIDENT
4497 thisOne.debugShowTs();
4498 other.debugShowTs();
4499 #endif
4500 double startT = coincidence.fTs[0][0];
4501 double endT = coincidence.fTs[0][1];
4502 bool cancelers;
4503 if ((cancelers = startT > endT)) {
4504 SkTSwap<double>(startT, endT);
4505 }
4506 SkASSERT(!approximately_negative(endT - startT));
4507 double oStartT = coincidence.fTs[1][0];
4508 double oEndT = coincidence.fTs[1][1];
4509 if (oStartT > oEndT) {
4510 SkTSwap<double>(oStartT, oEndT);
4511 cancelers ^= true;
4512 }
4513 SkASSERT(!approximately_negative(oEndT - oStartT));
4514 bool opp = fOperand ^ otherContour->fOperand;
4515 if (cancelers && !opp) {
4516 // make sure startT and endT have t entries
4517 if (startT > 0 || oEndT < 1
4518 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004519 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004520 }
4521 if (oStartT > 0 || endT < 1
4522 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004523 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004524 }
4525 } else {
4526 if (startT > 0 || oStartT > 0
4527 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004528 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004529 }
4530 if (endT < 1 || oEndT < 1
4531 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004532 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004533 }
4534 }
4535 #if DEBUG_CONCIDENT
4536 thisOne.debugShowTs();
4537 other.debugShowTs();
4538 #endif
4539 }
4540 }
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00004541
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004542 void calcCoincidentWinding() {
4543 int count = fCoincidences.count();
4544 for (int index = 0; index < count; ++index) {
4545 Coincidence& coincidence = fCoincidences[index];
4546 SkASSERT(coincidence.fContours[0] == this);
4547 int thisIndex = coincidence.fSegments[0];
4548 Segment& thisOne = fSegments[thisIndex];
4549 if (thisOne.done()) {
4550 continue;
4551 }
4552 Contour* otherContour = coincidence.fContours[1];
4553 int otherIndex = coincidence.fSegments[1];
4554 Segment& other = otherContour->fSegments[otherIndex];
4555 if (other.done()) {
4556 continue;
4557 }
4558 double startT = coincidence.fTs[0][0];
4559 double endT = coincidence.fTs[0][1];
4560 bool cancelers;
4561 if ((cancelers = startT > endT)) {
4562 SkTSwap<double>(startT, endT);
4563 }
4564 SkASSERT(!approximately_negative(endT - startT));
4565 double oStartT = coincidence.fTs[1][0];
4566 double oEndT = coincidence.fTs[1][1];
4567 if (oStartT > oEndT) {
4568 SkTSwap<double>(oStartT, oEndT);
4569 cancelers ^= true;
4570 }
4571 SkASSERT(!approximately_negative(oEndT - oStartT));
4572 bool opp = fOperand ^ otherContour->fOperand;
4573 if (cancelers && !opp) {
4574 // make sure startT and endT have t entries
4575 if (!thisOne.done() && !other.done()) {
4576 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4577 }
4578 } else {
4579 if (!thisOne.done() && !other.done()) {
4580 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4581 }
4582 }
4583 #if DEBUG_CONCIDENT
4584 thisOne.debugShowTs();
4585 other.debugShowTs();
4586 #endif
4587 }
4588 }
4589
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004590 SkTArray<Segment>& segments() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004591 return fSegments;
4592 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004593
caryclark@google.com235f56a2012-09-14 14:19:30 +00004594 void setOperand(bool isOp) {
4595 fOperand = isOp;
4596 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00004597
caryclark@google.com4eeda372012-12-06 21:47:48 +00004598 void setOppXor(bool isOppXor) {
4599 fOppXor = isOppXor;
4600 int segmentCount = fSegments.count();
4601 for (int test = 0; test < segmentCount; ++test) {
4602 fSegments[test].setOppXor(isOppXor);
4603 }
4604 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004605
caryclark@google.com235f56a2012-09-14 14:19:30 +00004606 void setXor(bool isXor) {
4607 fXor = isXor;
4608 }
4609
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004610 void sortSegments() {
4611 int segmentCount = fSegments.count();
4612 fSortedSegments.setReserve(segmentCount);
4613 for (int test = 0; test < segmentCount; ++test) {
4614 *fSortedSegments.append() = &fSegments[test];
4615 }
4616 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4617 fFirstSorted = 0;
4618 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004619
caryclark@google.comf839c032012-10-26 21:03:50 +00004620 const SkPoint& start() const {
4621 return fSegments.front().pts()[0];
4622 }
4623
4624 void toPath(PathWrapper& path) const {
4625 int segmentCount = fSegments.count();
4626 const SkPoint& pt = fSegments.front().pts()[0];
4627 path.deferredMove(pt);
4628 for (int test = 0; test < segmentCount; ++test) {
4629 fSegments[test].addCurveTo(0, 1, path, true);
4630 }
4631 path.close();
4632 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004633
caryclark@google.comf839c032012-10-26 21:03:50 +00004634 void toPartialBackward(PathWrapper& path) const {
4635 int segmentCount = fSegments.count();
4636 for (int test = segmentCount - 1; test >= 0; --test) {
4637 fSegments[test].addCurveTo(1, 0, path, true);
4638 }
4639 }
4640
4641 void toPartialForward(PathWrapper& path) const {
4642 int segmentCount = fSegments.count();
4643 for (int test = 0; test < segmentCount; ++test) {
4644 fSegments[test].addCurveTo(0, 1, path, true);
4645 }
4646 }
4647
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004648 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004649 int segmentCount = fSortedSegments.count();
4650 SkASSERT(segmentCount > 0);
caryclark@google.comf839c032012-10-26 21:03:50 +00004651 int sortedIndex = fFirstSorted;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004652 fDone = true; // may be cleared below
caryclark@google.comf839c032012-10-26 21:03:50 +00004653 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4654 Segment* testSegment = fSortedSegments[sortedIndex];
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004655 if (testSegment->done()) {
caryclark@google.comf839c032012-10-26 21:03:50 +00004656 if (sortedIndex == fFirstSorted) {
4657 ++fFirstSorted;
4658 }
4659 continue;
4660 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004661 fDone = false;
caryclark@google.com45a8fc62013-02-14 15:29:11 +00004662 SkPoint testXY = testSegment->activeLeftTop(true, NULL);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004663 if (topStart) {
4664 if (testXY.fY < topLeft.fY) {
4665 continue;
4666 }
4667 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4668 continue;
4669 }
4670 if (bestXY.fY < testXY.fY) {
4671 continue;
4672 }
4673 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4674 continue;
4675 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004676 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004677 topStart = testSegment;
caryclark@google.comf839c032012-10-26 21:03:50 +00004678 bestXY = testXY;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004679 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004680 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004681
caryclark@google.com24bec792012-08-20 12:43:57 +00004682 Segment* undoneSegment(int& start, int& end) {
4683 int segmentCount = fSegments.count();
4684 for (int test = 0; test < segmentCount; ++test) {
4685 Segment* testSegment = &fSegments[test];
4686 if (testSegment->done()) {
4687 continue;
4688 }
4689 testSegment->undoneSpan(start, end);
4690 return testSegment;
4691 }
4692 return NULL;
4693 }
4694
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004695 int updateSegment(int index, const SkPoint* pts) {
4696 Segment& segment = fSegments[index];
4697 segment.updatePts(pts);
4698 return segment.verb() + 1;
4699 }
4700
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004701#if DEBUG_TEST
4702 SkTArray<Segment>& debugSegments() {
4703 return fSegments;
4704 }
4705#endif
4706
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004707#if DEBUG_DUMP
4708 void dump() {
4709 int i;
4710 const char className[] = "Contour";
4711 const int tab = 4;
4712 SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4713 for (i = 0; i < fSegments.count(); ++i) {
4714 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4715 className, i);
4716 fSegments[i].dump();
4717 }
4718 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4719 tab + sizeof(className), className,
4720 fBounds.fLeft, fBounds.fTop,
4721 fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004722 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4723 className, fContainsIntercepts);
4724 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4725 className, fContainsCurves);
4726 }
4727#endif
4728
caryclark@google.com027de222012-07-12 12:52:50 +00004729#if DEBUG_ACTIVE_SPANS
4730 void debugShowActiveSpans() {
4731 for (int index = 0; index < fSegments.count(); ++index) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004732 fSegments[index].debugShowActiveSpans();
caryclark@google.com027de222012-07-12 12:52:50 +00004733 }
4734 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004735
4736 void validateActiveSpans() {
4737 for (int index = 0; index < fSegments.count(); ++index) {
4738 fSegments[index].validateActiveSpans();
4739 }
4740 }
caryclark@google.com027de222012-07-12 12:52:50 +00004741#endif
4742
caryclark@google.com729e1c42012-11-21 21:36:34 +00004743#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004744 int debugShowWindingValues(int totalSegments, int ofInterest) {
4745 int count = fSegments.count();
4746 int sum = 0;
4747 for (int index = 0; index < count; ++index) {
4748 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4749 }
4750 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4751 return sum;
4752 }
4753
4754 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4755 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4756 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4757 int ofInterest = 1 << 5 | 1 << 8;
4758 int total = 0;
4759 int index;
4760 for (index = 0; index < contourList.count(); ++index) {
4761 total += contourList[index]->segments().count();
4762 }
4763 int sum = 0;
4764 for (index = 0; index < contourList.count(); ++index) {
4765 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4766 }
4767 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4768 }
4769#endif
4770
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004771protected:
4772 void setBounds() {
4773 int count = fSegments.count();
4774 if (count == 0) {
4775 SkDebugf("%s empty contour\n", __FUNCTION__);
4776 SkASSERT(0);
4777 // FIXME: delete empty contour?
4778 return;
4779 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004780 fBounds = fSegments.front().bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004781 for (int index = 1; index < count; ++index) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004782 fBounds.add(fSegments[index].bounds());
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004783 }
4784 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004785
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004786private:
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004787 SkTArray<Segment> fSegments;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004788 SkTDArray<Segment*> fSortedSegments;
4789 int fFirstSorted;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004790 SkTDArray<Coincidence> fCoincidences;
4791 SkTDArray<const Contour*> fCrosses;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004792 Bounds fBounds;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004793 bool fContainsIntercepts;
4794 bool fContainsCurves;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004795 bool fDone;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004796 bool fOperand; // true for the second argument to a binary operator
4797 bool fXor;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004798 bool fOppXor;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004799#if DEBUG_DUMP
4800 int fID;
4801#endif
4802};
4803
4804class EdgeBuilder {
4805public:
4806
caryclark@google.comf839c032012-10-26 21:03:50 +00004807EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
4808 : fPath(path.nativePath())
4809 , fContours(contours)
4810{
4811 init();
4812}
4813
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004814EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
caryclark@google.com235f56a2012-09-14 14:19:30 +00004815 : fPath(&path)
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004816 , fContours(contours)
4817{
caryclark@google.comf839c032012-10-26 21:03:50 +00004818 init();
4819}
4820
4821void init() {
4822 fCurrentContour = NULL;
4823 fOperand = false;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004824 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004825#if DEBUG_DUMP
4826 gContourID = 0;
4827 gSegmentID = 0;
4828#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00004829 fSecondHalf = preFetch();
4830}
4831
4832void addOperand(const SkPath& path) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00004833 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
4834 fPathVerbs.pop();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004835 fPath = &path;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004836 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004837 preFetch();
4838}
4839
4840void finish() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004841 walk();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004842 complete();
4843 if (fCurrentContour && !fCurrentContour->segments().count()) {
4844 fContours.pop_back();
4845 }
4846 // correct pointers in contours since fReducePts may have moved as it grew
4847 int cIndex = 0;
4848 int extraCount = fExtra.count();
4849 SkASSERT(extraCount == 0 || fExtra[0] == -1);
4850 int eIndex = 0;
4851 int rIndex = 0;
4852 while (++eIndex < extraCount) {
4853 int offset = fExtra[eIndex];
4854 if (offset < 0) {
4855 ++cIndex;
4856 continue;
4857 }
4858 fCurrentContour = &fContours[cIndex];
4859 rIndex += fCurrentContour->updateSegment(offset - 1,
4860 &fReducePts[rIndex]);
4861 }
4862 fExtra.reset(); // we're done with this
4863}
4864
4865ShapeOpMask xorMask() const {
caryclark@google.com729e1c42012-11-21 21:36:34 +00004866 return fXorMask[fOperand];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004867}
4868
4869protected:
4870
4871void complete() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004872 if (fCurrentContour && fCurrentContour->segments().count()) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004873 fCurrentContour->complete();
4874 fCurrentContour = NULL;
4875 }
4876}
4877
caryclark@google.com235f56a2012-09-14 14:19:30 +00004878// FIXME:remove once we can access path pts directly
4879int preFetch() {
4880 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004881 SkPoint pts[4];
4882 SkPath::Verb verb;
4883 do {
4884 verb = iter.next(pts);
4885 *fPathVerbs.append() = verb;
4886 if (verb == SkPath::kMove_Verb) {
4887 *fPathPts.append() = pts[0];
4888 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
4889 fPathPts.append(verb, &pts[1]);
4890 }
4891 } while (verb != SkPath::kDone_Verb);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004892 return fPathVerbs.count() - 1;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004893}
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004894
caryclark@google.com235f56a2012-09-14 14:19:30 +00004895void walk() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004896 SkPath::Verb reducedVerb;
4897 uint8_t* verbPtr = fPathVerbs.begin();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004898 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004899 const SkPoint* pointsPtr = fPathPts.begin();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004900 const SkPoint* finalCurveStart = NULL;
4901 const SkPoint* finalCurveEnd = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004902 SkPath::Verb verb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004903 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
4904 switch (verb) {
4905 case SkPath::kMove_Verb:
4906 complete();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004907 if (!fCurrentContour) {
4908 fCurrentContour = fContours.push_back_n(1);
caryclark@google.com235f56a2012-09-14 14:19:30 +00004909 fCurrentContour->setOperand(fOperand);
caryclark@google.com729e1c42012-11-21 21:36:34 +00004910 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004911 *fExtra.append() = -1; // start new contour
4912 }
caryclark@google.com59823f72012-08-09 18:17:47 +00004913 finalCurveEnd = pointsPtr++;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004914 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004915 case SkPath::kLine_Verb:
4916 // skip degenerate points
4917 if (pointsPtr[-1].fX != pointsPtr[0].fX
4918 || pointsPtr[-1].fY != pointsPtr[0].fY) {
4919 fCurrentContour->addLine(&pointsPtr[-1]);
4920 }
4921 break;
4922 case SkPath::kQuad_Verb:
rmistry@google.comd6176b02012-08-23 18:14:13 +00004923
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004924 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
4925 if (reducedVerb == 0) {
4926 break; // skip degenerate points
4927 }
4928 if (reducedVerb == 1) {
rmistry@google.comd6176b02012-08-23 18:14:13 +00004929 *fExtra.append() =
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004930 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004931 break;
4932 }
4933 fCurrentContour->addQuad(&pointsPtr[-1]);
4934 break;
4935 case SkPath::kCubic_Verb:
4936 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
4937 if (reducedVerb == 0) {
4938 break; // skip degenerate points
4939 }
4940 if (reducedVerb == 1) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004941 *fExtra.append() =
4942 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004943 break;
4944 }
4945 if (reducedVerb == 2) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004946 *fExtra.append() =
4947 fCurrentContour->addQuad(fReducePts.end() - 3);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004948 break;
4949 }
4950 fCurrentContour->addCubic(&pointsPtr[-1]);
4951 break;
4952 case SkPath::kClose_Verb:
4953 SkASSERT(fCurrentContour);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004954 if (finalCurveStart && finalCurveEnd
4955 && *finalCurveStart != *finalCurveEnd) {
4956 *fReducePts.append() = *finalCurveStart;
4957 *fReducePts.append() = *finalCurveEnd;
4958 *fExtra.append() =
4959 fCurrentContour->addLine(fReducePts.end() - 2);
4960 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004961 complete();
caryclark@google.com31143cf2012-11-09 22:14:19 +00004962 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004963 default:
4964 SkDEBUGFAIL("bad verb");
4965 return;
4966 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004967 finalCurveStart = &pointsPtr[verb - 1];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004968 pointsPtr += verb;
4969 SkASSERT(fCurrentContour);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004970 nextVerb:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004971 if (verbPtr == endOfFirstHalf) {
4972 fOperand = true;
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004973 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004974 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004975}
4976
4977private:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004978 const SkPath* fPath;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004979 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004980 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004981 Contour* fCurrentContour;
4982 SkTArray<Contour>& fContours;
4983 SkTDArray<SkPoint> fReducePts; // segments created on the fly
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004984 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
caryclark@google.com729e1c42012-11-21 21:36:34 +00004985 ShapeOpMask fXorMask[2];
caryclark@google.com235f56a2012-09-14 14:19:30 +00004986 int fSecondHalf;
4987 bool fOperand;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004988};
4989
4990class Work {
4991public:
4992 enum SegmentType {
4993 kHorizontalLine_Segment = -1,
4994 kVerticalLine_Segment = 0,
4995 kLine_Segment = SkPath::kLine_Verb,
4996 kQuad_Segment = SkPath::kQuad_Verb,
4997 kCubic_Segment = SkPath::kCubic_Verb,
4998 };
rmistry@google.comd6176b02012-08-23 18:14:13 +00004999
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005000 void addCoincident(Work& other, const Intersections& ts, bool swap) {
5001 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
5002 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005003
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005004 // FIXME: does it make sense to write otherIndex now if we're going to
5005 // fix it up later?
5006 void addOtherT(int index, double otherT, int otherIndex) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005007 fContour->addOtherT(fIndex, index, otherT, otherIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005008 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005009
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005010 // Avoid collapsing t values that are close to the same since
5011 // we walk ts to describe consecutive intersections. Since a pair of ts can
5012 // be nearly equal, any problems caused by this should be taken care
5013 // of later.
5014 // On the edge or out of range values are negative; add 2 to get end
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005015 int addT(double newT, const Work& other, const SkPoint& pt) {
5016 return fContour->addT(fIndex, newT, other.fContour, other.fIndex, pt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005017 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005018
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005019 int addUnsortableT(double newT, const Work& other, bool start, const SkPoint& pt) {
5020 return fContour->addUnsortableT(fIndex, newT, other.fContour, other.fIndex, start, pt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005021 }
5022
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005023 bool advance() {
5024 return ++fIndex < fLast;
5025 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005026
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005027 SkScalar bottom() const {
5028 return bounds().fBottom;
5029 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005030
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005031 const Bounds& bounds() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005032 return fContour->segments()[fIndex].bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005033 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00005034
caryclark@google.com73ca6242013-01-17 21:02:47 +00005035#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005036 const SkPoint* cubic() const {
5037 return fCubic;
5038 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005039#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005040
5041 void init(Contour* contour) {
5042 fContour = contour;
5043 fIndex = 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005044 fLast = contour->segments().count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005045 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00005046
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00005047 bool isAdjacent(const Work& next) {
5048 return fContour == next.fContour && fIndex + 1 == next.fIndex;
5049 }
5050
5051 bool isFirstLast(const Work& next) {
5052 return fContour == next.fContour && fIndex == 0
5053 && next.fIndex == fLast - 1;
5054 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005055
5056 SkScalar left() const {
5057 return bounds().fLeft;
5058 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005059
caryclark@google.com73ca6242013-01-17 21:02:47 +00005060#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005061 void promoteToCubic() {
5062 fCubic[0] = pts()[0];
5063 fCubic[2] = pts()[1];
5064 fCubic[3] = pts()[2];
5065 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
5066 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
5067 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
5068 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
5069 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005070#endif
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005071
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005072 const SkPoint* pts() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005073 return fContour->segments()[fIndex].pts();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005074 }
5075
5076 SkScalar right() const {
5077 return bounds().fRight;
5078 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005079
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005080 ptrdiff_t segmentIndex() const {
5081 return fIndex;
5082 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005083
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005084 SegmentType segmentType() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005085 const Segment& segment = fContour->segments()[fIndex];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005086 SegmentType type = (SegmentType) segment.verb();
5087 if (type != kLine_Segment) {
5088 return type;
5089 }
5090 if (segment.isHorizontal()) {
5091 return kHorizontalLine_Segment;
5092 }
5093 if (segment.isVertical()) {
5094 return kVerticalLine_Segment;
5095 }
5096 return kLine_Segment;
5097 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005098
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005099 bool startAfter(const Work& after) {
5100 fIndex = after.fIndex;
5101 return advance();
5102 }
5103
5104 SkScalar top() const {
5105 return bounds().fTop;
5106 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005107
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005108 SkPath::Verb verb() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005109 return fContour->segments()[fIndex].verb();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005110 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005111
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005112 SkScalar x() const {
5113 return bounds().fLeft;
5114 }
5115
5116 bool xFlipped() const {
5117 return x() != pts()[0].fX;
5118 }
5119
5120 SkScalar y() const {
5121 return bounds().fTop;
5122 }
5123
5124 bool yFlipped() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005125 return y() != pts()[0].fY;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005126 }
5127
5128protected:
5129 Contour* fContour;
caryclark@google.com73ca6242013-01-17 21:02:47 +00005130#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005131 SkPoint fCubic[4];
caryclark@google.com73ca6242013-01-17 21:02:47 +00005132#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005133 int fIndex;
5134 int fLast;
5135};
5136
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005137#if DEBUG_ADD_INTERSECTING_TS
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005138static void debugShowLineIntersection(int pts, const Work& wt, const Work& wn,
5139 const Intersections& i) {
5140 SkASSERT(i.used() == pts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005141 if (!pts) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005142 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n",
5143 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
5144 wt.pts()[1].fX, wt.pts()[1].fY, wn.pts()[0].fX, wn.pts()[0].fY,
5145 wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005146 return;
5147 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00005148 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 +00005149 __FUNCTION__,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005150 i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY,
5151 wt.pts()[1].fX, wt.pts()[1].fY, i.fPt[0].x, i.fPt[0].y);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005152 if (pts == 2) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005153 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 +00005154 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005155 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g)", i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY,
5156 wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005157 if (pts == 2) {
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005158 SkDebugf(" wnTs[1]=%1.9g", i.fT[1][1]);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005159 }
5160 SkDebugf("\n");
5161}
5162
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005163static void debugShowQuadLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005164 const Work& wn, const Intersections& i) {
5165 SkASSERT(i.used() == pts);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005166 if (!pts) {
5167 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
caryclark@google.com0b7da432012-10-31 19:00:20 +00005168 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005169 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
5170 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005171 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005172 return;
5173 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005174 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)", __FUNCTION__,
5175 i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY,
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005176 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005177 i.fPt[0].x, i.fPt[0].y);
5178 for (int index = 1; index < pts; ++index) {
5179 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index],
5180 i.fPt[index].x, i.fPt[index].y);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005181 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005182 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g)", i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY,
5183 wn.pts()[1].fX, wn.pts()[1].fY);
5184 for (int index = 1; index < pts; ++index) {
5185 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005186 }
5187 SkDebugf("\n");
5188}
5189
caryclark@google.coma461ff02012-10-11 12:54:23 +00005190static void debugShowQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005191 const Work& wn, const Intersections& i) {
5192 SkASSERT(i.used() == pts);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005193 if (!pts) {
5194 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5195 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5196 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
skia.committer@gmail.com5b6f9162012-10-12 02:01:15 +00005197 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.coma461ff02012-10-11 12:54:23 +00005198 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005199 wn.pts()[2].fX, wn.pts()[2].fY );
caryclark@google.coma461ff02012-10-11 12:54:23 +00005200 return;
5201 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005202 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)", __FUNCTION__,
5203 i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY,
caryclark@google.coma461ff02012-10-11 12:54:23 +00005204 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005205 i.fPt[0].x, i.fPt[0].y);
5206 for (int index = 1; index < pts; ++index) {
5207 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
5208 i.fPt[index].y);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005209 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005210 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)",
5211 i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY,
5212 wn.pts()[1].fX, wn.pts()[1].fY, wn.pts()[2].fX, wn.pts()[2].fY);
5213 for (int index = 1; index < pts; ++index) {
5214 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005215 }
caryclark@google.comb9738012012-07-03 19:53:30 +00005216 SkDebugf("\n");
5217}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005218
5219static void debugShowCubicLineIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005220 const Work& wn, const Intersections& i) {
5221 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005222 if (!pts) {
5223 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5224 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
5225 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5226 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5227 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
5228 return;
5229 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005230 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)",
5231 __FUNCTION__,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005232 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 +00005233 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005234 i.fPt[0].x, i.fPt[0].y);
5235 for (int index = 1; index < pts; ++index) {
5236 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
5237 i.fPt[index].y);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005238 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005239 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g)",
5240 i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
5241 for (int index = 1; index < pts; ++index) {
5242 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005243 }
5244 SkDebugf("\n");
5245}
5246
caryclark@google.com73ca6242013-01-17 21:02:47 +00005247// FIXME: show more than two intersection points
5248static void debugShowCubicQuadIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005249 const Work& wn, const Intersections& i) {
5250 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005251 if (!pts) {
5252 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5253 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5254 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5255 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5256 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5257 wn.pts()[2].fX, wn.pts()[2].fY );
5258 return;
5259 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005260 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)",
5261 __FUNCTION__,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005262 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 +00005263 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005264 i.fPt[0].x, i.fPt[0].y);
5265 for (int index = 1; index < pts; ++index) {
5266 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
5267 i.fPt[index].y);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005268 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005269 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)",
5270 i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5271 wn.pts()[2].fX, wn.pts()[2].fY);
5272 for (int index = 1; index < pts; ++index) {
5273 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005274 }
5275 SkDebugf("\n");
5276}
5277
5278// FIXME: show more than two intersection points
5279static void debugShowCubicIntersection(int pts, const Work& wt,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005280 const Work& wn, const Intersections& i) {
5281 SkASSERT(i.used() == pts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005282 if (!pts) {
5283 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5284 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5285 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5286 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5287 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5288 wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY );
5289 return;
5290 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00005291 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)",
5292 __FUNCTION__,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005293 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 +00005294 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005295 i.fPt[0].x, i.fPt[0].y);
5296 for (int index = 1; index < pts; ++index) {
5297 SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
5298 i.fPt[index].y);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005299 }
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005300 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)",
5301 i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5302 wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY);
5303 for (int index = 1; index < pts; ++index) {
5304 SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[0][index]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005305 }
5306 SkDebugf("\n");
5307}
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005308
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005309#else
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005310static void debugShowLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005311}
caryclark@google.coma461ff02012-10-11 12:54:23 +00005312
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005313static void debugShowQuadLineIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005314}
5315
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005316static void debugShowQuadIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005317}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005318
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005319static void debugShowCubicLineIntersection(int , const Work& , const Work& ,
5320 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005321}
5322
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005323static void debugShowCubicQuadIntersection(int , const Work& , const Work& ,
5324 const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005325}
5326
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005327static void debugShowCubicIntersection(int , const Work& , const Work& , const Intersections& ) {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005328}
5329#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005330
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005331static bool addIntersectTs(Contour* test, Contour* next) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005332
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005333 if (test != next) {
5334 if (test->bounds().fBottom < next->bounds().fTop) {
5335 return false;
5336 }
5337 if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5338 return true;
5339 }
5340 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005341 Work wt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005342 wt.init(test);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005343 bool foundCommonContour = test == next;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005344 do {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005345 Work wn;
5346 wn.init(next);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005347 if (test == next && !wn.startAfter(wt)) {
5348 continue;
5349 }
5350 do {
5351 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5352 continue;
5353 }
5354 int pts;
5355 Intersections ts;
5356 bool swap = false;
5357 switch (wt.segmentType()) {
5358 case Work::kHorizontalLine_Segment:
5359 swap = true;
5360 switch (wn.segmentType()) {
5361 case Work::kHorizontalLine_Segment:
5362 case Work::kVerticalLine_Segment:
5363 case Work::kLine_Segment: {
5364 pts = HLineIntersect(wn.pts(), wt.left(),
5365 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005366 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005367 break;
5368 }
5369 case Work::kQuad_Segment: {
5370 pts = HQuadIntersect(wn.pts(), wt.left(),
5371 wt.right(), wt.y(), wt.xFlipped(), ts);
5372 break;
5373 }
5374 case Work::kCubic_Segment: {
5375 pts = HCubicIntersect(wn.pts(), wt.left(),
5376 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005377 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005378 break;
5379 }
5380 default:
5381 SkASSERT(0);
5382 }
5383 break;
5384 case Work::kVerticalLine_Segment:
5385 swap = true;
5386 switch (wn.segmentType()) {
5387 case Work::kHorizontalLine_Segment:
5388 case Work::kVerticalLine_Segment:
5389 case Work::kLine_Segment: {
5390 pts = VLineIntersect(wn.pts(), wt.top(),
5391 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005392 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005393 break;
5394 }
5395 case Work::kQuad_Segment: {
5396 pts = VQuadIntersect(wn.pts(), wt.top(),
5397 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5398 break;
5399 }
5400 case Work::kCubic_Segment: {
5401 pts = VCubicIntersect(wn.pts(), wt.top(),
5402 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005403 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005404 break;
5405 }
5406 default:
5407 SkASSERT(0);
5408 }
5409 break;
5410 case Work::kLine_Segment:
5411 switch (wn.segmentType()) {
5412 case Work::kHorizontalLine_Segment:
5413 pts = HLineIntersect(wt.pts(), wn.left(),
5414 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005415 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005416 break;
5417 case Work::kVerticalLine_Segment:
5418 pts = VLineIntersect(wt.pts(), wn.top(),
5419 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005420 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005421 break;
5422 case Work::kLine_Segment: {
5423 pts = LineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005424 debugShowLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005425 break;
5426 }
5427 case Work::kQuad_Segment: {
5428 swap = true;
5429 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005430 debugShowQuadLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005431 break;
5432 }
5433 case Work::kCubic_Segment: {
5434 swap = true;
5435 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005436 debugShowCubicLineIntersection(pts, wn, wt, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005437 break;
5438 }
5439 default:
5440 SkASSERT(0);
5441 }
5442 break;
5443 case Work::kQuad_Segment:
5444 switch (wn.segmentType()) {
5445 case Work::kHorizontalLine_Segment:
5446 pts = HQuadIntersect(wt.pts(), wn.left(),
5447 wn.right(), wn.y(), wn.xFlipped(), ts);
5448 break;
5449 case Work::kVerticalLine_Segment:
5450 pts = VQuadIntersect(wt.pts(), wn.top(),
5451 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5452 break;
5453 case Work::kLine_Segment: {
5454 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005455 debugShowQuadLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005456 break;
5457 }
5458 case Work::kQuad_Segment: {
5459 pts = QuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005460 debugShowQuadIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005461 break;
5462 }
5463 case Work::kCubic_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005464 #if APPROXIMATE_CUBICS
5465 swap = true;
5466 pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005467 debugShowCubicQuadIntersection(pts, wn, wt, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005468 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005469 wt.promoteToCubic();
5470 pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005471 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005472 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005473 break;
5474 }
5475 default:
5476 SkASSERT(0);
5477 }
5478 break;
5479 case Work::kCubic_Segment:
5480 switch (wn.segmentType()) {
5481 case Work::kHorizontalLine_Segment:
5482 pts = HCubicIntersect(wt.pts(), wn.left(),
5483 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005484 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005485 break;
5486 case Work::kVerticalLine_Segment:
5487 pts = VCubicIntersect(wt.pts(), wn.top(),
5488 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005489 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005490 break;
5491 case Work::kLine_Segment: {
5492 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005493 debugShowCubicLineIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005494 break;
5495 }
5496 case Work::kQuad_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005497 #if APPROXIMATE_CUBICS
5498 pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005499 debugShowCubicQuadIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005500 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005501 wn.promoteToCubic();
5502 pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005503 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005504 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005505 break;
5506 }
5507 case Work::kCubic_Segment: {
5508 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005509 debugShowCubicIntersection(pts, wt, wn, ts);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005510 break;
5511 }
5512 default:
5513 SkASSERT(0);
5514 }
5515 break;
5516 default:
5517 SkASSERT(0);
5518 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005519 if (!foundCommonContour && pts > 0) {
5520 test->addCross(next);
5521 next->addCross(test);
5522 foundCommonContour = true;
5523 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005524 // in addition to recording T values, record matching segment
caryclark@google.com73ca6242013-01-17 21:02:47 +00005525 if (ts.unsortable()) {
5526 bool start = true;
5527 for (int pt = 0; pt < ts.used(); ++pt) {
5528 // FIXME: if unsortable, the other points to the original. This logic is
5529 // untested downstream.
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005530 SkPoint point = ts.fPt[pt].asSkPoint();
5531 int testTAt = wt.addUnsortableT(ts.fT[swap][pt], wt, start, point);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005532 wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005533 testTAt = wn.addUnsortableT(ts.fT[!swap][pt], wn, start ^ ts.fFlip, point);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005534 wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt);
5535 start ^= true;
5536 }
5537 continue;
5538 }
caryclark@google.com32546db2012-08-31 20:55:07 +00005539 if (pts == 2) {
5540 if (wn.segmentType() <= Work::kLine_Segment
5541 && wt.segmentType() <= Work::kLine_Segment) {
5542 wt.addCoincident(wn, ts, swap);
5543 continue;
5544 }
caryclark@google.combeda3892013-02-07 13:13:41 +00005545 if (wn.segmentType() >= Work::kQuad_Segment
5546 && wt.segmentType() >= Work::kQuad_Segment
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005547 && ts.fIsCoincident[0]) {
5548 SkASSERT(ts.coincidentUsed() == 2);
caryclark@google.com32546db2012-08-31 20:55:07 +00005549 wt.addCoincident(wn, ts, swap);
5550 continue;
5551 }
5552
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00005553 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00005554 for (int pt = 0; pt < pts; ++pt) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005555 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5556 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
caryclark@google.com45a8fc62013-02-14 15:29:11 +00005557 SkPoint point = ts.fPt[pt].asSkPoint();
5558 int testTAt = wt.addT(ts.fT[swap][pt], wn, point);
5559 int nextTAt = wn.addT(ts.fT[!swap][pt], wt, point);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005560 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
5561 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005562 }
5563 } while (wn.advance());
5564 } while (wt.advance());
5565 return true;
5566}
5567
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005568// resolve any coincident pairs found while intersecting, and
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005569// see if coincidence is formed by clipping non-concident segments
caryclark@google.com4eeda372012-12-06 21:47:48 +00005570static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005571 int contourCount = contourList.count();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005572#if ONE_PASS_COINCIDENCE_CHECK
caryclark@google.comf25edfe2012-06-01 18:20:10 +00005573 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005574 Contour* contour = contourList[cIndex];
caryclark@google.com7ba591e2012-11-20 14:21:54 +00005575 contour->resolveCoincidence(contourList);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005576 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005577#else
5578 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5579 Contour* contour = contourList[cIndex];
5580 contour->addCoincidentPoints();
5581 }
5582 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5583 Contour* contour = contourList[cIndex];
5584 contour->calcCoincidentWinding();
5585 }
5586#endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005587 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5588 Contour* contour = contourList[cIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00005589 contour->findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005590 }
5591}
5592
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005593static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005594 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005595 SkPoint basePt;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005596 double tAtMid = current->tAtMid(index, endIndex, mid);
5597 current->xyAtT(tAtMid, basePt);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005598 int contourCount = contourList.count();
5599 SkScalar bestY = SK_ScalarMin;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005600 Segment* bestSeg = NULL;
5601 int bestTIndex;
5602 bool bestOpp;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005603 bool hitSomething = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005604 for (int cTest = 0; cTest < contourCount; ++cTest) {
5605 Contour* contour = contourList[cTest];
5606 bool testOpp = contour->operand() ^ current->operand() ^ opp;
5607 if (basePt.fY < contour->bounds().fTop) {
5608 continue;
5609 }
5610 if (bestY > contour->bounds().fBottom) {
5611 continue;
5612 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005613 int segmentCount = contour->segments().count();
5614 for (int test = 0; test < segmentCount; ++test) {
5615 Segment* testSeg = &contour->segments()[test];
5616 SkScalar testY = bestY;
5617 double testHit;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005618 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
5619 testOpp, testSeg == current);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005620 if (testTIndex < 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005621 if (testTIndex == SK_MinS32) {
5622 hitSomething = true;
5623 bestSeg = NULL;
5624 goto abortContours; // vertical encountered, return and try different point
5625 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005626 continue;
5627 }
5628 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005629 double baseT = current->t(index);
5630 double endT = current->t(endIndex);
5631 double newMid = (testHit - baseT) / (endT - baseT);
5632#if DEBUG_WINDING
5633 SkPoint midXY, newXY;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005634 double midT = current->tAtMid(index, endIndex, mid);
5635 current->xyAtT(midT, midXY);
5636 double newMidT = current->tAtMid(index, endIndex, newMid);
5637 current->xyAtT(newMidT, newXY);
caryclark@google.com3586ece2012-12-27 18:46:58 +00005638 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
5639 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
5640 current->debugID(), mid, newMid,
5641 baseT, current->xAtT(index), current->yAtT(index),
5642 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
5643 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
5644 endT, current->xAtT(endIndex), current->yAtT(endIndex));
5645#endif
5646 mid = newMid * 2; // calling loop with divide by 2 before continuing
5647 return SK_MinS32;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005648 }
5649 bestSeg = testSeg;
5650 bestHit = testHit;
5651 bestOpp = testOpp;
5652 bestTIndex = testTIndex;
5653 bestY = testY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005654 }
5655 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005656abortContours:
caryclark@google.com10227bf2012-12-28 22:10:41 +00005657 int result;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005658 if (!bestSeg) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00005659 result = hitSomething ? SK_MinS32 : 0;
5660 } else {
5661 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
5662 current = bestSeg;
5663 index = bestTIndex;
5664 endIndex = bestSeg->nextSpan(bestTIndex, 1);
5665 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
5666 tryAgain = true;
5667 return 0;
5668 }
5669 result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
5670 SkASSERT(bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005671 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005672 double baseT = current->t(index);
5673 double endT = current->t(endIndex);
5674 bestHit = baseT + mid * (endT - baseT);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005675 return result;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005676}
5677
caryclark@google.com24bec792012-08-20 12:43:57 +00005678static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
5679 int contourCount = contourList.count();
5680 Segment* result;
5681 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5682 Contour* contour = contourList[cIndex];
5683 result = contour->undoneSegment(start, end);
5684 if (result) {
5685 return result;
5686 }
5687 }
5688 return NULL;
5689}
5690
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005691#define OLD_FIND_CHASE 1
caryclark@google.com24bec792012-08-20 12:43:57 +00005692
caryclark@google.com31143cf2012-11-09 22:14:19 +00005693static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005694 while (chase.count()) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005695 Span* span;
5696 chase.pop(&span);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005697 const Span& backPtr = span->fOther->span(span->fOtherIndex);
5698 Segment* segment = backPtr.fOther;
5699 tIndex = backPtr.fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005700 SkTDArray<Angle> angles;
5701 int done = 0;
5702 if (segment->activeAngle(tIndex, done, angles)) {
5703 Angle* last = angles.end() - 1;
5704 tIndex = last->start();
5705 endIndex = last->end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005706 #if TRY_ROTATE
5707 *chase.insert(0) = span;
5708 #else
5709 *chase.append() = span;
5710 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005711 return last->segment();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005712 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005713 if (done == angles.count()) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00005714 continue;
5715 }
5716 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005717 bool sortable = Segment::SortAngles(angles, sorted);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005718 int angleCount = sorted.count();
caryclark@google.com03f97062012-08-21 13:13:52 +00005719#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005720 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00005721#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005722 if (!sortable) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005723 continue;
5724 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005725 // find first angle, initialize winding to computed fWindSum
5726 int firstIndex = -1;
5727 const Angle* angle;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005728#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005729 int winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005730 do {
5731 angle = sorted[++firstIndex];
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005732 segment = angle->segment();
5733 winding = segment->windSum(angle);
5734 } while (winding == SK_MinS32);
5735 int spanWinding = segment->spanSign(angle->start(), angle->end());
5736 #if DEBUG_WINDING
caryclark@google.com31143cf2012-11-09 22:14:19 +00005737 SkDebugf("%s winding=%d spanWinding=%d\n",
5738 __FUNCTION__, winding, spanWinding);
caryclark@google.com47580692012-07-23 12:14:49 +00005739 #endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005740 // turn span winding into contour winding
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005741 if (spanWinding * winding < 0) {
5742 winding += spanWinding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005743 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005744 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005745 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005746 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005747 // we care about first sign and whether wind sum indicates this
5748 // edge is inside or outside. Maybe need to pass span winding
5749 // or first winding or something into this function?
5750 // advance to first undone angle, then return it and winding
5751 // (to set whether edges are active or not)
5752 int nextIndex = firstIndex + 1;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005753 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005754 angle = sorted[firstIndex];
caryclark@google.com2ddff932012-08-07 21:25:27 +00005755 winding -= angle->segment()->spanSign(angle);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005756#else
5757 do {
5758 angle = sorted[++firstIndex];
5759 segment = angle->segment();
5760 } while (segment->windSum(angle) == SK_MinS32);
5761 #if DEBUG_SORT
5762 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5763 #endif
5764 int sumWinding = segment->updateWindingReverse(angle);
5765 int nextIndex = firstIndex + 1;
5766 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5767 Segment* first = NULL;
5768#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005769 do {
5770 SkASSERT(nextIndex != firstIndex);
5771 if (nextIndex == angleCount) {
5772 nextIndex = 0;
5773 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005774 angle = sorted[nextIndex];
caryclark@google.com9764cc62012-07-12 19:29:45 +00005775 segment = angle->segment();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005776#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005777 int maxWinding = winding;
caryclark@google.com2ddff932012-08-07 21:25:27 +00005778 winding -= segment->spanSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005779 #if DEBUG_SORT
caryclark@google.com2ddff932012-08-07 21:25:27 +00005780 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
5781 segment->debugID(), maxWinding, winding, angle->sign());
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005782 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005783 tIndex = angle->start();
5784 endIndex = angle->end();
5785 int lesser = SkMin32(tIndex, endIndex);
5786 const Span& nextSpan = segment->span(lesser);
5787 if (!nextSpan.fDone) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005788#if 1
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005789 // FIXME: this be wrong? assign startWinding if edge is in
caryclark@google.com9764cc62012-07-12 19:29:45 +00005790 // same direction. If the direction is opposite, winding to
5791 // assign is flipped sign or +/- 1?
caryclark@google.com59823f72012-08-09 18:17:47 +00005792 if (useInnerWinding(maxWinding, winding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005793 maxWinding = winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005794 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005795 segment->markAndChaseWinding(angle, maxWinding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005796#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005797 break;
5798 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005799#else
5800 int start = angle->start();
5801 int end = angle->end();
5802 int maxWinding;
5803 segment->setUpWinding(start, end, maxWinding, sumWinding);
5804 if (!segment->done(angle)) {
5805 if (!first) {
5806 first = segment;
5807 tIndex = start;
5808 endIndex = end;
5809 }
5810 (void) segment->markAngle(maxWinding, sumWinding, true, angle);
5811 }
5812#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005813 } while (++nextIndex != lastIndex);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005814 #if TRY_ROTATE
5815 *chase.insert(0) = span;
5816 #else
5817 *chase.append() = span;
5818 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005819 return segment;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005820 }
5821 return NULL;
5822}
5823
caryclark@google.com027de222012-07-12 12:52:50 +00005824#if DEBUG_ACTIVE_SPANS
5825static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005826 int index;
5827 for (index = 0; index < contourList.count(); ++ index) {
caryclark@google.com027de222012-07-12 12:52:50 +00005828 contourList[index]->debugShowActiveSpans();
5829 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005830 for (index = 0; index < contourList.count(); ++ index) {
5831 contourList[index]->validateActiveSpans();
5832 }
caryclark@google.com027de222012-07-12 12:52:50 +00005833}
5834#endif
5835
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005836static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005837 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005838 Segment* result;
5839 do {
caryclark@google.comf839c032012-10-26 21:03:50 +00005840 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005841 int contourCount = contourList.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00005842 Segment* topStart = NULL;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005843 done = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00005844 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5845 Contour* contour = contourList[cIndex];
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005846 if (contour->done()) {
5847 continue;
5848 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005849 const Bounds& bounds = contour->bounds();
5850 if (bounds.fBottom < topLeft.fY) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005851 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005852 continue;
5853 }
5854 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005855 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005856 continue;
5857 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005858 contour->topSortableSegment(topLeft, bestXY, topStart);
5859 if (!contour->done()) {
5860 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005861 }
5862 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005863 if (!topStart) {
5864 return NULL;
5865 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005866 topLeft = bestXY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005867 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005868 } while (!result);
5869 return result;
5870}
caryclark@google.com31143cf2012-11-09 22:14:19 +00005871
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005872static int rightAngleWinding(SkTDArray<Contour*>& contourList,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005873 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005874 bool opp) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005875 double test = 0.9;
5876 int contourWinding;
5877 do {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005878 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
5879 tryAgain, test, opp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005880 if (contourWinding != SK_MinS32 || tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005881 return contourWinding;
5882 }
5883 test /= 2;
5884 } while (!approximately_negative(test));
5885 SkASSERT(0); // should be OK to comment out, but interested when this hits
5886 return contourWinding;
5887}
5888
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005889static void skipVertical(SkTDArray<Contour*>& contourList,
5890 Segment*& current, int& index, int& endIndex) {
5891 if (!current->isVertical(index, endIndex)) {
5892 return;
5893 }
5894 int contourCount = contourList.count();
5895 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5896 Contour* contour = contourList[cIndex];
5897 if (contour->done()) {
5898 continue;
5899 }
5900 current = contour->nonVerticalSegment(index, endIndex);
5901 if (current) {
5902 return;
5903 }
5904 }
5905}
5906
caryclark@google.com3586ece2012-12-27 18:46:58 +00005907static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005908 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
5909 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
5910 true);
5911 if (!current) {
5912 return NULL;
5913 }
5914 if (firstContour) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005915 current->initWinding(index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005916 firstContour = false;
5917 return current;
5918 }
5919 int minIndex = SkMin32(index, endIndex);
5920 int sumWinding = current->windSum(minIndex);
5921 if (sumWinding != SK_MinS32) {
5922 return current;
5923 }
5924 sumWinding = current->computeSum(index, endIndex, binary);
5925 if (sumWinding != SK_MinS32) {
5926 return current;
5927 }
5928 int contourWinding;
5929 int oppContourWinding = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005930 // the simple upward projection of the unresolved points hit unsortable angles
5931 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005932 bool tryAgain;
5933 double tHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005934 SkScalar hitDx = 0;
5935 SkScalar hitOppDx = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005936 do {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005937 // if current is vertical, find another candidate which is not
5938 // if only remaining candidates are vertical, then they can be marked done
caryclark@google.com10227bf2012-12-28 22:10:41 +00005939 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005940 skipVertical(contourList, current, index, endIndex);
caryclark@google.com10227bf2012-12-28 22:10:41 +00005941 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005942 tryAgain = false;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005943 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005944 tryAgain, false);
5945 if (tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005946 continue;
5947 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005948 if (!binary) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005949 break;
5950 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005951 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005952 tryAgain, true);
5953 } while (tryAgain);
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00005954
caryclark@google.com3586ece2012-12-27 18:46:58 +00005955 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005956 return current;
5957}
5958
5959// rewrite that abandons keeping local track of winding
caryclark@google.com3586ece2012-12-27 18:46:58 +00005960static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005961 bool firstContour = true;
5962 bool unsortable = false;
5963 bool topUnsortable = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005964 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
5965 do {
5966 int index, endIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005967 bool topDone;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005968 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005969 topUnsortable, topDone, false);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005970 if (!current) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005971 if (topUnsortable || !topDone) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005972 topUnsortable = false;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005973 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005974 topLeft.fX = topLeft.fY = SK_ScalarMin;
5975 continue;
5976 }
5977 break;
5978 }
5979 SkTDArray<Span*> chaseArray;
5980 do {
5981 if (current->activeWinding(index, endIndex)) {
5982 do {
5983 #if DEBUG_ACTIVE_SPANS
5984 if (!unsortable && current->done()) {
5985 debugShowActiveSpans(contourList);
5986 }
5987 #endif
5988 SkASSERT(unsortable || !current->done());
5989 int nextStart = index;
5990 int nextEnd = endIndex;
5991 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
5992 unsortable);
5993 if (!next) {
5994 if (!unsortable && simple.hasMove()
5995 && current->verb() != SkPath::kLine_Verb
5996 && !simple.isClosed()) {
5997 current->addCurveTo(index, endIndex, simple, true);
5998 SkASSERT(simple.isClosed());
5999 }
6000 break;
6001 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006002 #if DEBUG_FLOW
6003 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6004 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
6005 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
6006 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006007 current->addCurveTo(index, endIndex, simple, true);
6008 current = next;
6009 index = nextStart;
6010 endIndex = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006011 } while (!simple.isClosed() && (!unsortable
caryclark@google.com10227bf2012-12-28 22:10:41 +00006012 || !current->done(SkMin32(index, endIndex))));
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006013 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
6014 SkASSERT(unsortable);
6015 int min = SkMin32(index, endIndex);
6016 if (!current->done(min)) {
6017 current->addCurveTo(index, endIndex, simple, true);
6018 current->markDoneUnary(min);
6019 }
6020 }
6021 simple.close();
6022 } else {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00006023 Span* last = current->markAndChaseDoneUnary(index, endIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00006024 if (last) {
6025 *chaseArray.append() = last;
6026 }
6027 }
6028 current = findChase(chaseArray, index, endIndex);
6029 #if DEBUG_ACTIVE_SPANS
6030 debugShowActiveSpans(contourList);
6031 #endif
6032 if (!current) {
6033 break;
6034 }
6035 } while (true);
6036 } while (true);
6037 return simple.someAssemblyRequired();
6038}
6039
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006040// returns true if all edges were processed
caryclark@google.comf839c032012-10-26 21:03:50 +00006041static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006042 Segment* current;
6043 int start, end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006044 bool unsortable = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006045 bool closable = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00006046 while ((current = findUndone(contourList, start, end))) {
caryclark@google.com24bec792012-08-20 12:43:57 +00006047 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006048 #if DEBUG_ACTIVE_SPANS
6049 if (!unsortable && current->done()) {
6050 debugShowActiveSpans(contourList);
6051 }
6052 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006053 SkASSERT(unsortable || !current->done());
caryclark@google.com24bec792012-08-20 12:43:57 +00006054 int nextStart = start;
6055 int nextEnd = end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006056 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
caryclark@google.com24bec792012-08-20 12:43:57 +00006057 if (!next) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006058 if (!unsortable && simple.hasMove()
caryclark@google.comf839c032012-10-26 21:03:50 +00006059 && current->verb() != SkPath::kLine_Verb
6060 && !simple.isClosed()) {
6061 current->addCurveTo(start, end, simple, true);
6062 SkASSERT(simple.isClosed());
caryclark@google.comc899ad92012-08-23 15:24:42 +00006063 }
caryclark@google.com24bec792012-08-20 12:43:57 +00006064 break;
6065 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006066 #if DEBUG_FLOW
6067 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
6068 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
6069 current->xyAtT(end).fX, current->xyAtT(end).fY);
6070 #endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006071 current->addCurveTo(start, end, simple, true);
caryclark@google.com24bec792012-08-20 12:43:57 +00006072 current = next;
6073 start = nextStart;
6074 end = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00006075 } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006076 if (!simple.isClosed()) {
6077 SkASSERT(unsortable);
6078 int min = SkMin32(start, end);
6079 if (!current->done(min)) {
6080 current->addCurveTo(start, end, simple, true);
6081 current->markDone(min, 1);
6082 }
6083 closable = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00006084 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006085 simple.close();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00006086 #if DEBUG_ACTIVE_SPANS
6087 debugShowActiveSpans(contourList);
6088 #endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00006089 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006090 return closable;
caryclark@google.com24bec792012-08-20 12:43:57 +00006091}
6092
caryclark@google.comb45a1b42012-05-18 20:50:33 +00006093static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
6094 int contourCount = contourList.count();
6095 for (int cTest = 0; cTest < contourCount; ++cTest) {
6096 Contour* contour = contourList[cTest];
6097 contour->fixOtherTIndex();
6098 }
6099}
6100
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006101static void sortSegments(SkTDArray<Contour*>& contourList) {
6102 int contourCount = contourList.count();
6103 for (int cTest = 0; cTest < contourCount; ++cTest) {
6104 Contour* contour = contourList[cTest];
6105 contour->sortSegments();
6106 }
6107}
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006108
caryclark@google.com4eeda372012-12-06 21:47:48 +00006109static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
6110 bool evenOdd, bool oppEvenOdd) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006111 int count = contours.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006112 if (count == 0) {
6113 return;
6114 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006115 for (int index = 0; index < count; ++index) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00006116 Contour& contour = contours[index];
6117 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
6118 *list.append() = &contour;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006119 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006120 QSort<Contour>(list.begin(), list.end() - 1);
6121}
6122
caryclark@google.comf839c032012-10-26 21:03:50 +00006123static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006124 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006125}
6126
caryclark@google.com10227bf2012-12-28 22:10:41 +00006127static bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
6128 return distances[one] < distances[two];
6129}
caryclark@google.comf839c032012-10-26 21:03:50 +00006130 /*
6131 check start and end of each contour
6132 if not the same, record them
6133 match them up
6134 connect closest
6135 reassemble contour pieces into new path
6136 */
6137static void assemble(const PathWrapper& path, PathWrapper& simple) {
6138#if DEBUG_PATH_CONSTRUCTION
6139 SkDebugf("%s\n", __FUNCTION__);
6140#endif
6141 SkTArray<Contour> contours;
6142 EdgeBuilder builder(path, contours);
6143 builder.finish();
6144 int count = contours.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006145 int outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006146 SkTDArray<int> runs; // indices of partial contours
caryclark@google.com0b7da432012-10-31 19:00:20 +00006147 for (outer = 0; outer < count; ++outer) {
6148 const Contour& eContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006149 const SkPoint& eStart = eContour.start();
6150 const SkPoint& eEnd = eContour.end();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006151#if DEBUG_ASSEMBLE
6152 SkDebugf("%s contour", __FUNCTION__);
6153 if (!approximatelyEqual(eStart, eEnd)) {
6154 SkDebugf("[%d]", runs.count());
6155 } else {
6156 SkDebugf(" ");
6157 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006158 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006159 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
6160#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006161 if (approximatelyEqual(eStart, eEnd)) {
6162 eContour.toPath(simple);
6163 continue;
6164 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006165 *runs.append() = outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006166 }
6167 count = runs.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006168 if (count == 0) {
6169 return;
6170 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006171 SkTDArray<int> sLink, eLink;
6172 sLink.setCount(count);
6173 eLink.setCount(count);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006174 int rIndex, iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006175 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006176 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006177 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006178 SkTDArray<double> distances;
6179 const int ends = count * 2; // all starts and ends
6180 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
6181 distances.setCount(entries);
6182 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
6183 outer = runs[rIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006184 const Contour& oContour = contours[outer];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006185 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
6186 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
6187 * ends - rIndex - 1;
6188 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
6189 int inner = runs[iIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006190 const Contour& iContour = contours[inner];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006191 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
6192 double dx = iPt.fX - oPt.fX;
6193 double dy = iPt.fY - oPt.fY;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006194 double dist = dx * dx + dy * dy;
caryclark@google.com10227bf2012-12-28 22:10:41 +00006195 distances[row + iIndex] = dist; // oStart distance from iStart
6196 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006197 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006198 SkTDArray<int> sortedDist;
6199 sortedDist.setCount(entries);
6200 for (rIndex = 0; rIndex < entries; ++rIndex) {
6201 sortedDist[rIndex] = rIndex;
6202 }
6203 QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
6204 int remaining = count; // number of start/end pairs
6205 for (rIndex = 0; rIndex < entries; ++rIndex) {
6206 int pair = sortedDist[rIndex];
6207 int row = pair / ends;
6208 int col = pair - row * ends;
6209 int thingOne = row < col ? row : ends - row - 2;
6210 int ndxOne = thingOne >> 1;
6211 bool endOne = thingOne & 1;
6212 int* linkOne = endOne ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006213 if (linkOne[ndxOne] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006214 continue;
6215 }
6216 int thingTwo = row < col ? col : ends - row + col - 1;
6217 int ndxTwo = thingTwo >> 1;
6218 bool endTwo = thingTwo & 1;
6219 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006220 if (linkTwo[ndxTwo] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006221 continue;
6222 }
6223 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
6224 bool flip = endOne == endTwo;
6225 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
6226 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
6227 if (!--remaining) {
6228 break;
6229 }
6230 }
6231 SkASSERT(!remaining);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006232#if DEBUG_ASSEMBLE
6233 for (rIndex = 0; rIndex < count; ++rIndex) {
6234 int s = sLink[rIndex];
6235 int e = eLink[rIndex];
6236 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
6237 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
caryclark@google.comf839c032012-10-26 21:03:50 +00006238 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006239#endif
6240 rIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00006241 do {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006242 bool forward = true;
6243 bool first = true;
6244 int sIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006245 SkASSERT(sIndex != SK_MaxS32);
6246 sLink[rIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006247 int eIndex;
6248 if (sIndex < 0) {
6249 eIndex = sLink[~sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006250 sLink[~sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006251 } else {
6252 eIndex = eLink[sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006253 eLink[sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006254 }
caryclark@google.comaa358312013-01-29 20:28:49 +00006255 SkASSERT(eIndex != SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006256#if DEBUG_ASSEMBLE
6257 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006258 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
6259 eIndex < 0 ? ~eIndex : eIndex);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006260#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006261 do {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006262 outer = runs[rIndex];
6263 const Contour& contour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006264 if (first) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006265 first = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006266 const SkPoint* startPtr = &contour.start();
caryclark@google.comf839c032012-10-26 21:03:50 +00006267 simple.deferredMove(startPtr[0]);
6268 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006269 if (forward) {
6270 contour.toPartialForward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006271 } else {
6272 contour.toPartialBackward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006273 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006274#if DEBUG_ASSEMBLE
6275 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006276 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006277 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
6278#endif
6279 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006280 simple.close();
caryclark@google.comf839c032012-10-26 21:03:50 +00006281 break;
6282 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006283 if (forward) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006284 eIndex = eLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006285 SkASSERT(eIndex != SK_MaxS32);
6286 eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006287 if (eIndex >= 0) {
6288 SkASSERT(sLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006289 sLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006290 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006291 SkASSERT(eLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006292 eLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006293 }
6294 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006295 eIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006296 SkASSERT(eIndex != SK_MaxS32);
6297 sLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006298 if (eIndex >= 0) {
6299 SkASSERT(eLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006300 eLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006301 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006302 SkASSERT(sLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006303 sLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006304 }
6305 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006306 rIndex = eIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006307 if (rIndex < 0) {
6308 forward ^= 1;
6309 rIndex = ~rIndex;
6310 }
6311 } while (true);
6312 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006313 if (sLink[rIndex] != SK_MaxS32) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006314 break;
6315 }
6316 }
6317 } while (rIndex < count);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006318#if DEBUG_ASSEMBLE
6319 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006320 SkASSERT(sLink[rIndex] == SK_MaxS32);
6321 SkASSERT(eLink[rIndex] == SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006322 }
6323#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006324}
6325
6326void simplifyx(const SkPath& path, SkPath& result) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006327 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
caryclark@google.comf839c032012-10-26 21:03:50 +00006328 result.reset();
6329 result.setFillType(SkPath::kEvenOdd_FillType);
6330 PathWrapper simple(result);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006331
6332 // turn path into list of segments
6333 SkTArray<Contour> contours;
6334 // FIXME: add self-intersecting cubics' T values to segment
6335 EdgeBuilder builder(path, contours);
caryclark@google.com235f56a2012-09-14 14:19:30 +00006336 builder.finish();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006337 SkTDArray<Contour*> contourList;
caryclark@google.com4eeda372012-12-06 21:47:48 +00006338 makeContourList(contours, contourList, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006339 Contour** currentPtr = contourList.begin();
6340 if (!currentPtr) {
6341 return;
6342 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006343 Contour** listEnd = contourList.end();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006344 // find all intersections between segments
6345 do {
6346 Contour** nextPtr = currentPtr;
6347 Contour* current = *currentPtr++;
6348 Contour* next;
6349 do {
6350 next = *nextPtr++;
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00006351 } while (addIntersectTs(current, next) && nextPtr != listEnd);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006352 } while (currentPtr != listEnd);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006353 // eat through coincident edges
caryclark@google.com4eeda372012-12-06 21:47:48 +00006354 coincidenceCheck(contourList, 0);
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00006355 fixOtherTIndex(contourList);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006356 sortSegments(contourList);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006357#if DEBUG_ACTIVE_SPANS
6358 debugShowActiveSpans(contourList);
6359#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006360 // construct closed contours
caryclark@google.com3586ece2012-12-27 18:46:58 +00006361 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00006362 : !bridgeXor(contourList, simple))
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006363 { // if some edges could not be resolved, assemble remaining fragments
caryclark@google.comf839c032012-10-26 21:03:50 +00006364 SkPath temp;
6365 temp.setFillType(SkPath::kEvenOdd_FillType);
6366 PathWrapper assembled(temp);
6367 assemble(simple, assembled);
6368 result = *assembled.nativePath();
caryclark@google.com24bec792012-08-20 12:43:57 +00006369 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006370}