blob: ad3767a33e55cdb68065c737e27e5dbe705ec50a [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.com73ca6242013-01-17 21:02:47 +000034#define FORCE_RELEASE 0 // set force release to 1 for multiple thread -- no debugging
caryclark@google.comfa0588f2012-04-26 21:01:06 +000035
caryclark@google.com31143cf2012-11-09 22:14:19 +000036#if FORCE_RELEASE || defined SK_RELEASE
caryclark@google.com47580692012-07-23 12:14:49 +000037
38const bool gRunTestsInOneThread = false;
39
40#define DEBUG_ACTIVE_SPANS 0
caryclark@google.com4eeda372012-12-06 21:47:48 +000041#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000042#define DEBUG_ADD_INTERSECTING_TS 0
caryclark@google.com47580692012-07-23 12:14:49 +000043#define DEBUG_ADD_T_PAIR 0
caryclark@google.comc899ad92012-08-23 15:24:42 +000044#define DEBUG_ANGLE 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000045#define DEBUG_ASSEMBLE 0
caryclark@google.com47580692012-07-23 12:14:49 +000046#define DEBUG_CONCIDENT 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000047#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000048#define DEBUG_FLOW 0
caryclark@google.com8dcf1142012-07-02 20:27:02 +000049#define DEBUG_MARK_DONE 0
caryclark@google.comf839c032012-10-26 21:03:50 +000050#define DEBUG_PATH_CONSTRUCTION 0
caryclark@google.com729e1c42012-11-21 21:36:34 +000051#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000052#define DEBUG_SORT 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000053#define DEBUG_UNSORTABLE 0
caryclark@google.comafe56de2012-07-24 18:11:03 +000054#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000055#define DEBUG_WINDING 0
caryclark@google.com8f9f4682013-01-03 21:18:16 +000056#define DEBUG_WINDING_AT_T 0
caryclark@google.comfa0588f2012-04-26 21:01:06 +000057
58#else
59
caryclark@google.com47580692012-07-23 12:14:49 +000060const bool gRunTestsInOneThread = true;
caryclark@google.comfa0588f2012-04-26 21:01:06 +000061
caryclark@google.comc91dfe42012-10-16 12:06:27 +000062#define DEBUG_ACTIVE_SPANS 1
caryclark@google.com4eeda372012-12-06 21:47:48 +000063#define DEBUG_ACTIVE_SPANS_SHORT_FORM 1
caryclark@google.com6aea33f2012-10-09 14:11:58 +000064#define DEBUG_ADD_INTERSECTING_TS 1
65#define DEBUG_ADD_T_PAIR 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000066#define DEBUG_ANGLE 1
caryclark@google.come7bd5f42012-12-13 19:47:53 +000067#define DEBUG_ASSEMBLE 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000068#define DEBUG_CONCIDENT 1
caryclark@google.com534aa5b2012-08-02 20:08:21 +000069#define DEBUG_CROSS 0
caryclark@google.come7bd5f42012-12-13 19:47:53 +000070#define DEBUG_FLOW 1
caryclark@google.com3350c3c2012-08-24 15:24:36 +000071#define DEBUG_MARK_DONE 1
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000072#define DEBUG_PATH_CONSTRUCTION 1
caryclark@google.com729e1c42012-11-21 21:36:34 +000073#define DEBUG_SHOW_WINDING 0
caryclark@google.com47580692012-07-23 12:14:49 +000074#define DEBUG_SORT 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000075#define DEBUG_UNSORTABLE 1
caryclark@google.comafe56de2012-07-24 18:11:03 +000076#define DEBUG_WIND_BUMP 0
caryclark@google.com47580692012-07-23 12:14:49 +000077#define DEBUG_WINDING 1
caryclark@google.com8f9f4682013-01-03 21:18:16 +000078#define DEBUG_WINDING_AT_T 1
caryclark@google.comfa0588f2012-04-26 21:01:06 +000079
80#endif
81
caryclark@google.com6aea33f2012-10-09 14:11:58 +000082#define DEBUG_DUMP (DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | DEBUG_PATH_CONSTRUCTION)
caryclark@google.com027de222012-07-12 12:52:50 +000083
caryclark@google.comfa0588f2012-04-26 21:01:06 +000084#if DEBUG_DUMP
85static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
caryclark@google.com65f9f0a2012-05-23 18:09:25 +000086// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
caryclark@google.comfa0588f2012-04-26 21:01:06 +000087static int gContourID;
88static int gSegmentID;
89#endif
90
caryclark@google.com8dcf1142012-07-02 20:27:02 +000091#ifndef DEBUG_TEST
92#define DEBUG_TEST 0
93#endif
94
caryclark@google.com32546db2012-08-31 20:55:07 +000095#define MAKE_CONST_LINE(line, pts) \
96 const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}
97#define MAKE_CONST_QUAD(quad, pts) \
98 const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
99 {pts[2].fX, pts[2].fY}}
100#define MAKE_CONST_CUBIC(cubic, pts) \
101 const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \
102 {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}}
103
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000104static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
105 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000106 MAKE_CONST_LINE(aLine, a);
107 MAKE_CONST_LINE(bLine, b);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000108 return intersect(aLine, bLine, intersections.fT[0], intersections.fT[1]);
109}
110
111static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
112 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000113 MAKE_CONST_QUAD(aQuad, a);
114 MAKE_CONST_LINE(bLine, b);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000115 return intersect(aQuad, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000116}
117
caryclark@google.com32546db2012-08-31 20:55:07 +0000118static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000119 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000120 MAKE_CONST_CUBIC(aCubic, a);
121 MAKE_CONST_LINE(bLine, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000122 return intersect(aCubic, bLine, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000123}
124
125static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
126 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000127 MAKE_CONST_QUAD(aQuad, a);
128 MAKE_CONST_QUAD(bQuad, b);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000129#define TRY_QUARTIC_SOLUTION 1
130#if TRY_QUARTIC_SOLUTION
131 intersect2(aQuad, bQuad, intersections);
132#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000133 intersect(aQuad, bQuad, intersections);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000134#endif
caryclark@google.com32546db2012-08-31 20:55:07 +0000135 return intersections.fUsed ? intersections.fUsed : intersections.fCoincidentUsed;
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000136}
137
caryclark@google.com73ca6242013-01-17 21:02:47 +0000138#if APPROXIMATE_CUBICS
139static int CubicQuadIntersect(const SkPoint a[4], const SkPoint b[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000140 Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000141 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000142 MAKE_CONST_QUAD(bQuad, b);
143 return intersect(aCubic, bQuad, intersections);
144}
145#endif
146
147static int CubicIntersect(const SkPoint a[4], const SkPoint b[4], Intersections& intersections) {
148 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com32546db2012-08-31 20:55:07 +0000149 MAKE_CONST_CUBIC(bCubic, b);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000150#if APPROXIMATE_CUBICS
151 intersect2(aCubic, bCubic, intersections);
152#else
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000153 intersect(aCubic, bCubic, intersections);
caryclark@google.com73ca6242013-01-17 21:02:47 +0000154#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000155 return intersections.fUsed;
156}
157
158static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
159 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000160 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000161 return horizontalIntersect(aLine, left, right, y, flipped, intersections);
162}
163
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000164static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
165 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000166 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000167 return horizontalIntersect(aQuad, left, right, y, flipped, intersections);
168}
169
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000170static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
171 SkScalar y, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000172 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000173 return horizontalIntersect(aCubic, left, right, y, flipped, intersections);
174}
175
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000176static int (* const HSegmentIntersect[])(const SkPoint [], SkScalar ,
177 SkScalar , SkScalar , bool , Intersections& ) = {
178 NULL,
179 HLineIntersect,
180 HQuadIntersect,
181 HCubicIntersect
182};
183
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000184static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom,
185 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000186 MAKE_CONST_LINE(aLine, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000187 return verticalIntersect(aLine, top, bottom, x, flipped, intersections);
188}
189
190static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom,
191 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000192 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000193 return verticalIntersect(aQuad, top, bottom, x, flipped, intersections);
194}
195
196static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom,
197 SkScalar x, bool flipped, Intersections& intersections) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000198 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000199 return verticalIntersect(aCubic, top, bottom, x, flipped, intersections);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000200}
201
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000202static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar ,
203 SkScalar , SkScalar , bool , Intersections& ) = {
204 NULL,
205 VLineIntersect,
206 VQuadIntersect,
207 VCubicIntersect
208};
209
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000210static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000211 MAKE_CONST_LINE(line, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000212 double x, y;
213 xy_at_t(line, t, x, y);
214 out->fX = SkDoubleToScalar(x);
215 out->fY = SkDoubleToScalar(y);
216}
217
218static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000219 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000220 double x, y;
221 xy_at_t(quad, t, x, y);
222 out->fX = SkDoubleToScalar(x);
223 out->fY = SkDoubleToScalar(y);
224}
225
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000226static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
227 MAKE_CONST_QUAD(quad, a);
228 xy_at_t(quad, t, out->x, out->y);
229}
230
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000231static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000232 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000233 double x, y;
234 xy_at_t(cubic, t, x, y);
235 out->fX = SkDoubleToScalar(x);
236 out->fY = SkDoubleToScalar(y);
237}
238
239static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = {
240 NULL,
241 LineXYAtT,
242 QuadXYAtT,
243 CubicXYAtT
244};
245
246static SkScalar LineXAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000247 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000248 double x;
249 xy_at_t(aLine, t, x, *(double*) 0);
250 return SkDoubleToScalar(x);
251}
252
253static SkScalar QuadXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000254 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000255 double x;
256 xy_at_t(quad, t, x, *(double*) 0);
257 return SkDoubleToScalar(x);
258}
259
260static SkScalar CubicXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000261 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000262 double x;
263 xy_at_t(cubic, t, x, *(double*) 0);
264 return SkDoubleToScalar(x);
265}
266
267static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = {
268 NULL,
269 LineXAtT,
270 QuadXAtT,
271 CubicXAtT
272};
273
274static SkScalar LineYAtT(const SkPoint a[2], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000275 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000276 double y;
277 xy_at_t(aLine, t, *(double*) 0, y);
278 return SkDoubleToScalar(y);
279}
280
281static SkScalar QuadYAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000282 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000283 double y;
284 xy_at_t(quad, t, *(double*) 0, y);
285 return SkDoubleToScalar(y);
286}
287
288static SkScalar CubicYAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000289 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000290 double y;
291 xy_at_t(cubic, t, *(double*) 0, y);
292 return SkDoubleToScalar(y);
293}
294
295static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = {
296 NULL,
297 LineYAtT,
298 QuadYAtT,
299 CubicYAtT
300};
301
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000302static SkScalar LineDXAtT(const SkPoint a[2], double ) {
303 return a[1].fX - a[0].fX;
304}
305
306static SkScalar QuadDXAtT(const SkPoint a[3], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000307 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000308 double x = dx_at_t(quad, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000309 return SkDoubleToScalar(x);
310}
311
312static SkScalar CubicDXAtT(const SkPoint a[4], double t) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000313 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000314 double x = dx_at_t(cubic, t);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000315 return SkDoubleToScalar(x);
316}
317
318static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = {
319 NULL,
320 LineDXAtT,
321 QuadDXAtT,
322 CubicDXAtT
323};
324
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000325static SkScalar LineDYAtT(const SkPoint a[2], double ) {
326 return a[1].fY - a[0].fY;
327}
328
329static SkScalar QuadDYAtT(const SkPoint a[3], double t) {
330 MAKE_CONST_QUAD(quad, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000331 double y = dy_at_t(quad, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000332 return SkDoubleToScalar(y);
333}
334
335static SkScalar CubicDYAtT(const SkPoint a[4], double t) {
336 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000337 double y = dy_at_t(cubic, t);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000338 return SkDoubleToScalar(y);
339}
340
341static SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = {
342 NULL,
343 LineDYAtT,
344 QuadDYAtT,
345 CubicDYAtT
346};
347
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000348static void LineSubDivide(const SkPoint a[2], double startT, double endT,
349 SkPoint sub[2]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000350 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000351 _Line dst;
352 sub_divide(aLine, startT, endT, dst);
353 sub[0].fX = SkDoubleToScalar(dst[0].x);
354 sub[0].fY = SkDoubleToScalar(dst[0].y);
355 sub[1].fX = SkDoubleToScalar(dst[1].x);
356 sub[1].fY = SkDoubleToScalar(dst[1].y);
357}
358
359static void QuadSubDivide(const SkPoint a[3], double startT, double endT,
360 SkPoint sub[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000361 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000362 Quadratic dst;
363 sub_divide(aQuad, startT, endT, dst);
364 sub[0].fX = SkDoubleToScalar(dst[0].x);
365 sub[0].fY = SkDoubleToScalar(dst[0].y);
366 sub[1].fX = SkDoubleToScalar(dst[1].x);
367 sub[1].fY = SkDoubleToScalar(dst[1].y);
368 sub[2].fX = SkDoubleToScalar(dst[2].x);
369 sub[2].fY = SkDoubleToScalar(dst[2].y);
370}
371
372static void CubicSubDivide(const SkPoint a[4], double startT, double endT,
373 SkPoint sub[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000374 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000375 Cubic dst;
376 sub_divide(aCubic, startT, endT, dst);
377 sub[0].fX = SkDoubleToScalar(dst[0].x);
378 sub[0].fY = SkDoubleToScalar(dst[0].y);
379 sub[1].fX = SkDoubleToScalar(dst[1].x);
380 sub[1].fY = SkDoubleToScalar(dst[1].y);
381 sub[2].fX = SkDoubleToScalar(dst[2].x);
382 sub[2].fY = SkDoubleToScalar(dst[2].y);
383 sub[3].fX = SkDoubleToScalar(dst[3].x);
384 sub[3].fY = SkDoubleToScalar(dst[3].y);
385}
386
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000387static void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
388 SkPoint []) = {
389 NULL,
390 LineSubDivide,
391 QuadSubDivide,
392 CubicSubDivide
393};
394
caryclark@google.comaa358312013-01-29 20:28:49 +0000395static void LineSubDivideHD(const SkPoint a[2], double startT, double endT, _Line& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000396 MAKE_CONST_LINE(aLine, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000397 sub_divide(aLine, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000398}
399
caryclark@google.comaa358312013-01-29 20:28:49 +0000400static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT, Quadratic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000401 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000402 sub_divide(aQuad, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000403}
404
caryclark@google.comaa358312013-01-29 20:28:49 +0000405static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT, Cubic& dst) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000406 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000407 sub_divide(aCubic, startT, endT, dst);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000408}
409
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000410#if DEBUG_UNUSED
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000411static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
412 SkRect& bounds) {
413 SkPoint dst[3];
414 QuadSubDivide(a, startT, endT, dst);
415 bounds.fLeft = bounds.fRight = dst[0].fX;
416 bounds.fTop = bounds.fBottom = dst[0].fY;
417 for (int index = 1; index < 3; ++index) {
418 bounds.growToInclude(dst[index].fX, dst[index].fY);
419 }
420}
421
422static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
423 SkRect& bounds) {
424 SkPoint dst[4];
425 CubicSubDivide(a, startT, endT, dst);
426 bounds.fLeft = bounds.fRight = dst[0].fX;
427 bounds.fTop = bounds.fBottom = dst[0].fY;
428 for (int index = 1; index < 4; ++index) {
429 bounds.growToInclude(dst[index].fX, dst[index].fY);
430 }
431}
caryclark@google.com65f9f0a2012-05-23 18:09:25 +0000432#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000433
caryclark@google.com15fa1382012-05-07 20:49:36 +0000434static SkPath::Verb QuadReduceOrder(const SkPoint a[3],
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000435 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000436 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000437 Quadratic dst;
438 int order = reduceOrder(aQuad, dst);
caryclark@google.com24bec792012-08-20 12:43:57 +0000439 if (order == 2) { // quad became line
440 for (int index = 0; index < order; ++index) {
441 SkPoint* pt = reducePts.append();
442 pt->fX = SkDoubleToScalar(dst[index].x);
443 pt->fY = SkDoubleToScalar(dst[index].y);
444 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000445 }
446 return (SkPath::Verb) (order - 1);
447}
448
449static SkPath::Verb CubicReduceOrder(const SkPoint a[4],
450 SkTDArray<SkPoint>& reducePts) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000451 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000452 Cubic dst;
453 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed);
caryclark@google.com24bec792012-08-20 12:43:57 +0000454 if (order == 2 || order == 3) { // cubic became line or quad
455 for (int index = 0; index < order; ++index) {
456 SkPoint* pt = reducePts.append();
457 pt->fX = SkDoubleToScalar(dst[index].x);
458 pt->fY = SkDoubleToScalar(dst[index].y);
459 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000460 }
461 return (SkPath::Verb) (order - 1);
462}
463
caryclark@google.com15fa1382012-05-07 20:49:36 +0000464static bool QuadIsLinear(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000465 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000466 return isLinear(aQuad, 0, 2);
467}
468
469static bool CubicIsLinear(const SkPoint a[4]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000470 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.com15fa1382012-05-07 20:49:36 +0000471 return isLinear(aCubic, 0, 3);
472}
473
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000474static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000475 MAKE_CONST_LINE(aLine, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000476 double x[2];
477 xy_at_t(aLine, startT, x[0], *(double*) 0);
caryclark@google.com495f8e42012-05-31 13:13:11 +0000478 xy_at_t(aLine, endT, x[1], *(double*) 0);
479 return SkMinScalar((float) x[0], (float) x[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000480}
481
482static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000483 MAKE_CONST_QUAD(aQuad, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000484 return (float) leftMostT(aQuad, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000485}
486
487static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000488 MAKE_CONST_CUBIC(aCubic, a);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000489 return (float) leftMostT(aCubic, startT, endT);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000490}
491
492static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
493 NULL,
494 LineLeftMost,
495 QuadLeftMost,
496 CubicLeftMost
497};
498
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000499#if 0 // currently unused
caryclark@google.com235f56a2012-09-14 14:19:30 +0000500static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
501 Intersections& intersections) {
502 MAKE_CONST_QUAD(aQuad, a);
503 MAKE_CONST_LINE(bLine, b);
504 return intersectRay(aQuad, bLine, intersections);
505}
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000506#endif
507
508static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine,
509 Intersections& intersections) {
510 MAKE_CONST_QUAD(aQuad, a);
511 return intersectRay(aQuad, bLine, intersections);
512}
caryclark@google.com235f56a2012-09-14 14:19:30 +0000513
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000514static bool LineVertical(const SkPoint a[2], double startT, double endT) {
515 MAKE_CONST_LINE(aLine, a);
516 double x[2];
517 xy_at_t(aLine, startT, x[0], *(double*) 0);
518 xy_at_t(aLine, endT, x[1], *(double*) 0);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000519 return AlmostEqualUlps((float) x[0], (float) x[1]);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000520}
521
522static bool QuadVertical(const SkPoint a[3], double startT, double endT) {
523 SkPoint dst[3];
524 QuadSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000525 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000526}
527
528static bool CubicVertical(const SkPoint a[4], double startT, double endT) {
529 SkPoint dst[4];
530 CubicSubDivide(a, startT, endT, dst);
caryclark@google.com6d0032a2013-01-04 19:41:13 +0000531 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX)
532 && AlmostEqualUlps(dst[2].fX, dst[3].fX);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000533}
534
535static bool (* const SegmentVertical[])(const SkPoint [], double , double) = {
536 NULL,
537 LineVertical,
538 QuadVertical,
539 CubicVertical
540};
541
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000542class Segment;
543
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000544struct Span {
545 Segment* fOther;
546 mutable SkPoint fPt; // lazily computed as needed
547 double fT;
548 double fOtherT; // value at fOther[fOtherIndex].fT
549 int fOtherIndex; // can't be used during intersection
caryclark@google.com31143cf2012-11-09 22:14:19 +0000550 int fWindSum; // accumulated from contours surrounding this one.
551 int fOppSum; // for binary operators: the opposite winding sum
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000552 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
caryclark@google.com57cff8d2012-11-14 21:14:56 +0000553 int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000554 bool fDone; // if set, this span to next higher T has been processed
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000555 bool fUnsortableStart; // set when start is part of an unsortable pair
556 bool fUnsortableEnd; // set when end is part of an unsortable pair
caryclark@google.comf839c032012-10-26 21:03:50 +0000557 bool fTiny; // if set, span may still be considered once for edge following
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000558};
559
caryclark@google.com15fa1382012-05-07 20:49:36 +0000560// sorting angles
561// given angles of {dx dy ddx ddy dddx dddy} sort them
562class Angle {
563public:
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000564 // FIXME: this is bogus for quads and cubics
565 // if the quads and cubics' line from end pt to ctrl pt are coincident,
566 // there's no obvious way to determine the curve ordering from the
567 // derivatives alone. In particular, if one quadratic's coincident tangent
568 // is longer than the other curve, the final control point can place the
569 // longer curve on either side of the shorter one.
570 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
571 // may provide some help, but nothing has been figured out yet.
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000572
caryclark@google.com32546db2012-08-31 20:55:07 +0000573 /*(
574 for quads and cubics, set up a parameterized line (e.g. LineParameters )
575 for points [0] to [1]. See if point [2] is on that line, or on one side
576 or the other. If it both quads' end points are on the same side, choose
577 the shorter tangent. If the tangents are equal, choose the better second
578 tangent angle
skia.committer@gmail.com4f55d392012-09-01 02:00:58 +0000579
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000580 maybe I could set up LineParameters lazily
caryclark@google.com32546db2012-08-31 20:55:07 +0000581 */
caryclark@google.com15fa1382012-05-07 20:49:36 +0000582 bool operator<(const Angle& rh) const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000583 double y = dy();
584 double ry = rh.dy();
585 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
586 return y < 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000587 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000588 double x = dx();
589 double rx = rh.dx();
590 if (y == 0 && ry == 0 && x * rx < 0) {
591 return x < rx;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000592 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000593 double x_ry = x * ry;
594 double rx_y = rx * y;
595 double cmp = x_ry - rx_y;
caryclark@google.comc899ad92012-08-23 15:24:42 +0000596 if (!approximately_zero(cmp)) {
caryclark@google.com15fa1382012-05-07 20:49:36 +0000597 return cmp < 0;
598 }
caryclark@google.comd1688742012-09-18 20:08:37 +0000599 if (approximately_zero(x_ry) && approximately_zero(rx_y)
600 && !approximately_zero_squared(cmp)) {
601 return cmp < 0;
602 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000603 // at this point, the initial tangent line is coincident
caryclark@google.com31143cf2012-11-09 22:14:19 +0000604 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
605 || !approximately_zero(rh.fSide))) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000606 // FIXME: running demo will trigger this assertion
607 // (don't know if commenting out will trigger further assertion or not)
608 // commenting it out allows demo to run in release, though
609 // SkASSERT(fSide != rh.fSide);
610 return fSide < rh.fSide;
611 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000612 // see if either curve can be lengthened and try the tangent compare again
613 if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
614 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
615 Angle longer = *this;
616 Angle rhLonger = rh;
617 if (longer.lengthen() | rhLonger.lengthen()) {
618 return longer < rhLonger;
619 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000620 #if 0
caryclark@google.coma461ff02012-10-11 12:54:23 +0000621 // what if we extend in the other direction?
622 longer = *this;
623 rhLonger = rh;
624 if (longer.reverseLengthen() | rhLonger.reverseLengthen()) {
625 return longer < rhLonger;
626 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000627 #endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000628 }
caryclark@google.com185c7c42012-10-19 18:26:24 +0000629 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
caryclark@google.com31143cf2012-11-09 22:14:19 +0000630 || (rh.fVerb == SkPath::kLine_Verb
631 && approximately_zero(rx) && approximately_zero(ry))) {
caryclark@google.com185c7c42012-10-19 18:26:24 +0000632 // See general unsortable comment below. This case can happen when
633 // one line has a non-zero change in t but no change in x and y.
634 fUnsortable = true;
635 rh.fUnsortable = true;
636 return this < &rh; // even with no solution, return a stable sort
637 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000638 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
639 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
640 fUnsortable = true;
641 rh.fUnsortable = true;
642 return this < &rh; // even with no solution, return a stable sort
643 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000644 SkASSERT(fVerb == SkPath::kQuad_Verb); // worry about cubics later
645 SkASSERT(rh.fVerb == SkPath::kQuad_Verb);
skia.committer@gmail.comc1ad0222012-09-19 02:01:47 +0000646 // FIXME: until I can think of something better, project a ray from the
caryclark@google.comd1688742012-09-18 20:08:37 +0000647 // end of the shorter tangent to midway between the end points
648 // through both curves and use the resulting angle to sort
caryclark@google.com235f56a2012-09-14 14:19:30 +0000649 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
650 double len = fTangent1.normalSquared();
651 double rlen = rh.fTangent1.normalSquared();
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000652 _Line ray;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000653 Intersections i, ri;
caryclark@google.comd1688742012-09-18 20:08:37 +0000654 int roots, rroots;
655 bool flip = false;
656 do {
657 const Quadratic& q = (len < rlen) ^ flip ? fQ : rh.fQ;
658 double midX = (q[0].x + q[2].x) / 2;
659 double midY = (q[0].y + q[2].y) / 2;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000660 ray[0] = q[1];
661 ray[1].x = midX;
662 ray[1].y = midY;
caryclark@google.comd1688742012-09-18 20:08:37 +0000663 SkASSERT(ray[0] != ray[1]);
664 roots = QuadRayIntersect(fPts, ray, i);
665 rroots = QuadRayIntersect(rh.fPts, ray, ri);
666 } while ((roots == 0 || rroots == 0) && (flip ^= true));
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000667 if (roots == 0 || rroots == 0) {
668 // FIXME: we don't have a solution in this case. The interim solution
669 // is to mark the edges as unsortable, exclude them from this and
670 // future computations, and allow the returned path to be fragmented
671 fUnsortable = true;
672 rh.fUnsortable = true;
673 return this < &rh; // even with no solution, return a stable sort
674 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000675 _Point loc;
676 double best = SK_ScalarInfinity;
677 double dx, dy, dist;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000678 int index;
679 for (index = 0; index < roots; ++index) {
680 QuadXYAtT(fPts, i.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000681 dx = loc.x - ray[0].x;
682 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000683 dist = dx * dx + dy * dy;
684 if (best > dist) {
685 best = dist;
686 }
687 }
688 for (index = 0; index < rroots; ++index) {
689 QuadXYAtT(rh.fPts, ri.fT[0][index], &loc);
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000690 dx = loc.x - ray[0].x;
691 dy = loc.y - ray[0].y;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000692 dist = dx * dx + dy * dy;
693 if (best > dist) {
694 return fSide < 0;
695 }
696 }
697 return fSide > 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000698 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000699
caryclark@google.com47580692012-07-23 12:14:49 +0000700 double dx() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000701 return fTangent1.dx();
caryclark@google.com47580692012-07-23 12:14:49 +0000702 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000703
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000704 double dy() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000705 return fTangent1.dy();
caryclark@google.com7db7c6b2012-07-27 21:22:25 +0000706 }
707
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000708 int end() const {
709 return fEnd;
710 }
711
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000712 bool isHorizontal() const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000713 return dy() == 0 && fVerb == SkPath::kLine_Verb;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000714 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000715
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000716 bool lengthen() {
717 int newEnd = fEnd;
718 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
719 fEnd = newEnd;
720 setSpans();
721 return true;
722 }
723 return false;
724 }
725
caryclark@google.coma461ff02012-10-11 12:54:23 +0000726 bool reverseLengthen() {
727 if (fReversed) {
728 return false;
729 }
730 int newEnd = fStart;
731 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
732 fEnd = newEnd;
733 fReversed = true;
734 setSpans();
735 return true;
736 }
737 return false;
738 }
739
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000740 void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000741 int start, int end, const SkTDArray<Span>& spans) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000742 fSegment = segment;
743 fStart = start;
744 fEnd = end;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000745 fPts = orig;
746 fVerb = verb;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000747 fSpans = &spans;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000748 fReversed = false;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000749 fUnsortable = false;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000750 setSpans();
751 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000752
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000753
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000754 void setSpans() {
755 double startT = (*fSpans)[fStart].fT;
756 double endT = (*fSpans)[fEnd].fT;
757 switch (fVerb) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000758 case SkPath::kLine_Verb:
759 _Line l;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000760 LineSubDivideHD(fPts, startT, endT, l);
caryclark@google.com32546db2012-08-31 20:55:07 +0000761 // OPTIMIZATION: for pure line compares, we never need fTangent1.c
762 fTangent1.lineEndPoints(l);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000763 fSide = 0;
caryclark@google.com32546db2012-08-31 20:55:07 +0000764 break;
765 case SkPath::kQuad_Verb:
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000766 QuadSubDivideHD(fPts, startT, endT, fQ);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000767 fTangent1.quadEndPoints(fQ, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000768 #if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
769 if (dx() == 0 && dy() == 0) {
770 SkDebugf("*** %s quad is line\n");
771 fTangent1.quadEndPoints(fQ);
772 }
773 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +0000774 fSide = -fTangent1.pointDistance(fQ[2]); // not normalized -- compare sign only
caryclark@google.com32546db2012-08-31 20:55:07 +0000775 break;
776 case SkPath::kCubic_Verb:
777 Cubic c;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000778 CubicSubDivideHD(fPts, startT, endT, c);
caryclark@google.com32546db2012-08-31 20:55:07 +0000779 fTangent1.cubicEndPoints(c, 0, 1);
caryclark@google.comaa358312013-01-29 20:28:49 +0000780 if (dx() == 0 && dy() == 0) {
781 fTangent1.cubicEndPoints(c, 0, 2);
782 #if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
783 if (dx() == 0 && dy() == 0) {
784 SkDebugf("*** %s cubic is line\n");
785 fTangent1.cubicEndPoints(c, 0, 3);
786 }
787 #endif
788 }
caryclark@google.com235f56a2012-09-14 14:19:30 +0000789 fSide = -fTangent1.pointDistance(c[2]); // not normalized -- compare sign only
caryclark@google.com32546db2012-08-31 20:55:07 +0000790 break;
caryclark@google.com235f56a2012-09-14 14:19:30 +0000791 default:
792 SkASSERT(0);
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000793 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +0000794 fUnsortable = dx() == 0 && dy() == 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000795 if (fUnsortable) {
796 return;
797 }
798 SkASSERT(fStart != fEnd);
799 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
800 for (int index = fStart; index != fEnd; index += step) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000801#if 1
802 const Span& thisSpan = (*fSpans)[index];
803 const Span& nextSpan = (*fSpans)[index + step];
804 if (thisSpan.fTiny || thisSpan.fT == nextSpan.fT) {
805 continue;
caryclark@google.comf839c032012-10-26 21:03:50 +0000806 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000807 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
808#if DEBUG_UNSORTABLE
809 if (fUnsortable) {
810 SkPoint iPt, ePt;
811 (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt);
812 (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt);
813 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
814 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
815 }
816#endif
817 return;
818#else
819 if ((*fSpans)[index].fUnsortableStart) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000820 fUnsortable = true;
821 return;
822 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000823#endif
caryclark@google.comf839c032012-10-26 21:03:50 +0000824 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +0000825#if 1
826#if DEBUG_UNSORTABLE
827 SkPoint iPt, ePt;
828 (*SegmentXYAtT[fVerb])(fPts, startT, &iPt);
829 (*SegmentXYAtT[fVerb])(fPts, endT, &ePt);
830 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
831 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
832#endif
833 fUnsortable = true;
834#endif
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000835 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +0000836
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000837 Segment* segment() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000838 return const_cast<Segment*>(fSegment);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000839 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000840
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000841 int sign() const {
caryclark@google.com495f8e42012-05-31 13:13:11 +0000842 return SkSign32(fStart - fEnd);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000843 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000844
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000845 const SkTDArray<Span>* spans() const {
846 return fSpans;
847 }
848
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000849 int start() const {
850 return fStart;
caryclark@google.com15fa1382012-05-07 20:49:36 +0000851 }
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +0000852
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000853 bool unsortable() const {
854 return fUnsortable;
855 }
caryclark@google.com15fa1382012-05-07 20:49:36 +0000856
caryclark@google.comc899ad92012-08-23 15:24:42 +0000857#if DEBUG_ANGLE
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000858 const SkPoint* pts() const {
859 return fPts;
860 }
861
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000862 SkPath::Verb verb() const {
863 return fVerb;
864 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +0000865
caryclark@google.comc899ad92012-08-23 15:24:42 +0000866 void debugShow(const SkPoint& a) const {
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000867 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
caryclark@google.comc899ad92012-08-23 15:24:42 +0000868 }
869#endif
870
caryclark@google.com15fa1382012-05-07 20:49:36 +0000871private:
caryclark@google.com235f56a2012-09-14 14:19:30 +0000872 const SkPoint* fPts;
873 Quadratic fQ;
874 SkPath::Verb fVerb;
875 double fSide;
876 LineParameters fTangent1;
caryclark@google.com6aea33f2012-10-09 14:11:58 +0000877 const SkTDArray<Span>* fSpans;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000878 const Segment* fSegment;
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000879 int fStart;
880 int fEnd;
caryclark@google.coma461ff02012-10-11 12:54:23 +0000881 bool fReversed;
caryclark@google.comc91dfe42012-10-16 12:06:27 +0000882 mutable bool fUnsortable; // this alone is editable by the less than operator
caryclark@google.com15fa1382012-05-07 20:49:36 +0000883};
884
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000885// Bounds, unlike Rect, does not consider a line to be empty.
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000886struct Bounds : public SkRect {
887 static bool Intersects(const Bounds& a, const Bounds& b) {
888 return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
889 a.fTop <= b.fBottom && b.fTop <= a.fBottom;
890 }
891
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000892 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
893 if (left < fLeft) {
894 fLeft = left;
895 }
896 if (top < fTop) {
897 fTop = top;
898 }
899 if (right > fRight) {
900 fRight = right;
901 }
902 if (bottom > fBottom) {
903 fBottom = bottom;
904 }
905 }
906
907 void add(const Bounds& toAdd) {
908 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
909 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000910
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000911 void add(const SkPoint& pt) {
912 if (pt.fX < fLeft) fLeft = pt.fX;
913 if (pt.fY < fTop) fTop = pt.fY;
914 if (pt.fX > fRight) fRight = pt.fX;
915 if (pt.fY > fBottom) fBottom = pt.fY;
916 }
917
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000918 bool isEmpty() {
919 return fLeft > fRight || fTop > fBottom
caryclark@google.com235f56a2012-09-14 14:19:30 +0000920 || (fLeft == fRight && fTop == fBottom)
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000921 || isnan(fLeft) || isnan(fRight)
922 || isnan(fTop) || isnan(fBottom);
923 }
924
925 void setCubicBounds(const SkPoint a[4]) {
926 _Rect dRect;
caryclark@google.com32546db2012-08-31 20:55:07 +0000927 MAKE_CONST_CUBIC(cubic, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000928 dRect.setBounds(cubic);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000929 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
930 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000931 }
932
933 void setQuadBounds(const SkPoint a[3]) {
caryclark@google.com32546db2012-08-31 20:55:07 +0000934 MAKE_CONST_QUAD(quad, a);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000935 _Rect dRect;
936 dRect.setBounds(quad);
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000937 set((float) dRect.left, (float) dRect.top, (float) dRect.right,
938 (float) dRect.bottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000939 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000940
941 void setPoint(const SkPoint& pt) {
942 fLeft = fRight = pt.fX;
943 fTop = fBottom = pt.fY;
944 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000945};
946
caryclark@google.com7ba591e2012-11-20 14:21:54 +0000947// OPTIMIZATION: does the following also work, and is it any faster?
948// return outerWinding * innerWinding > 0
949// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
caryclark@google.com2ddff932012-08-07 21:25:27 +0000950static bool useInnerWinding(int outerWinding, int innerWinding) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000951 // SkASSERT(outerWinding != innerWinding);
caryclark@google.com2ddff932012-08-07 21:25:27 +0000952 int absOut = abs(outerWinding);
953 int absIn = abs(innerWinding);
954 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
955 if (outerWinding * innerWinding < 0) {
956#if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +0000957 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
caryclark@google.com2ddff932012-08-07 21:25:27 +0000958 outerWinding, innerWinding, result ? "true" : "false");
959#endif
960 }
961 return result;
962}
963
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000964#define F (false) // discard the edge
965#define T (true) // keep the edge
966
caryclark@google.comd0deb4f2012-12-17 13:58:08 +0000967static const bool gUnaryActiveEdge[2][2] = {
968// from=0 from=1
969// to=0,1 to=0,1
970 {F, T}, {T, F},
971};
972
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000973static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = {
974// miFrom=0 miFrom=1
975// miTo=0 miTo=1 miTo=0 miTo=1
976// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
977// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
978 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
979 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
980 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
981 {{{{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 +0000982};
983
caryclark@google.com9f3e9a52012-12-10 12:50:53 +0000984#undef F
985#undef T
caryclark@google.com235f56a2012-09-14 14:19:30 +0000986
caryclark@google.comf839c032012-10-26 21:03:50 +0000987// wrap path to keep track of whether the contour is initialized and non-empty
988class PathWrapper {
989public:
990 PathWrapper(SkPath& path)
991 : fPathPtr(&path)
caryclark@google.comd0deb4f2012-12-17 13:58:08 +0000992 , fCloses(0)
993 , fMoves(0)
caryclark@google.comf839c032012-10-26 21:03:50 +0000994 {
995 init();
996 }
997
998 void close() {
999 if (!fHasMove) {
1000 return;
1001 }
1002 bool callClose = isClosed();
1003 lineTo();
1004 if (fEmpty) {
1005 return;
1006 }
1007 if (callClose) {
1008 #if DEBUG_PATH_CONSTRUCTION
1009 SkDebugf("path.close();\n");
1010 #endif
1011 fPathPtr->close();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001012 fCloses++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001013 }
1014 init();
1015 }
1016
1017 void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
1018 lineTo();
1019 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001020 fDefer[1] = pt3;
1021 nudge();
1022 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001023#if DEBUG_PATH_CONSTRUCTION
1024 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001025 pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001026#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001027 fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001028 fEmpty = false;
1029 }
1030
1031 void deferredLine(const SkPoint& pt) {
1032 if (pt == fDefer[1]) {
1033 return;
1034 }
1035 if (changedSlopes(pt)) {
1036 lineTo();
1037 fDefer[0] = fDefer[1];
1038 }
1039 fDefer[1] = pt;
1040 }
1041
1042 void deferredMove(const SkPoint& pt) {
1043 fMoved = true;
1044 fHasMove = true;
1045 fEmpty = true;
1046 fDefer[0] = fDefer[1] = pt;
1047 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001048
caryclark@google.comf839c032012-10-26 21:03:50 +00001049 void deferredMoveLine(const SkPoint& pt) {
1050 if (!fHasMove) {
1051 deferredMove(pt);
1052 }
1053 deferredLine(pt);
1054 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001055
caryclark@google.comf839c032012-10-26 21:03:50 +00001056 bool hasMove() const {
1057 return fHasMove;
1058 }
1059
1060 void init() {
1061 fEmpty = true;
1062 fHasMove = false;
1063 fMoved = false;
1064 }
1065
1066 bool isClosed() const {
1067 return !fEmpty && fFirstPt == fDefer[1];
1068 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001069
caryclark@google.comf839c032012-10-26 21:03:50 +00001070 void lineTo() {
1071 if (fDefer[0] == fDefer[1]) {
1072 return;
1073 }
1074 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001075 nudge();
caryclark@google.comf839c032012-10-26 21:03:50 +00001076 fEmpty = false;
1077#if DEBUG_PATH_CONSTRUCTION
1078 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
1079#endif
1080 fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
1081 fDefer[0] = fDefer[1];
1082 }
1083
1084 const SkPath* nativePath() const {
1085 return fPathPtr;
1086 }
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +00001087
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001088 void nudge() {
1089 if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX)
1090 || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) {
1091 return;
1092 }
1093 fDefer[1] = fFirstPt;
1094 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001095
1096 void quadTo(const SkPoint& pt1, const SkPoint& pt2) {
1097 lineTo();
1098 moveTo();
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001099 fDefer[1] = pt2;
1100 nudge();
1101 fDefer[0] = fDefer[1];
caryclark@google.comf839c032012-10-26 21:03:50 +00001102#if DEBUG_PATH_CONSTRUCTION
1103 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001104 pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001105#endif
caryclark@google.com85ec74c2013-01-28 19:25:51 +00001106 fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
caryclark@google.comf839c032012-10-26 21:03:50 +00001107 fEmpty = false;
1108 }
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00001109
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001110 bool someAssemblyRequired() const {
1111 return fCloses < fMoves;
1112 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001113
1114protected:
1115 bool changedSlopes(const SkPoint& pt) const {
1116 if (fDefer[0] == fDefer[1]) {
1117 return false;
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001118 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001119 SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
1120 SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
1121 SkScalar lineDx = pt.fX - fDefer[1].fX;
1122 SkScalar lineDy = pt.fY - fDefer[1].fY;
1123 return deferDx * lineDy != deferDy * lineDx;
1124 }
1125
1126 void moveTo() {
1127 if (!fMoved) {
1128 return;
1129 }
1130 fFirstPt = fDefer[0];
1131#if DEBUG_PATH_CONSTRUCTION
1132 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
1133#endif
1134 fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
1135 fMoved = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001136 fMoves++;
caryclark@google.comf839c032012-10-26 21:03:50 +00001137 }
1138
1139private:
1140 SkPath* fPathPtr;
1141 SkPoint fDefer[2];
1142 SkPoint fFirstPt;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001143 int fCloses;
1144 int fMoves;
caryclark@google.comf839c032012-10-26 21:03:50 +00001145 bool fEmpty;
1146 bool fHasMove;
1147 bool fMoved;
1148};
1149
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001150class Segment {
1151public:
1152 Segment() {
1153#if DEBUG_DUMP
1154 fID = ++gSegmentID;
1155#endif
1156 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00001157
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001158 bool operator<(const Segment& rh) const {
1159 return fBounds.fTop < rh.fBounds.fTop;
1160 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001161
caryclark@google.com4eeda372012-12-06 21:47:48 +00001162 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001163 if (activeAngleInner(index, done, angles)) {
1164 return true;
1165 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001166 int lesser = index;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001167 while (--lesser >= 0 && equalPoints(index, lesser)) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001168 if (activeAngleOther(lesser, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001169 return true;
1170 }
1171 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001172 lesser = index;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001173 do {
caryclark@google.com9764cc62012-07-12 19:29:45 +00001174 if (activeAngleOther(index, done, angles)) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001175 return true;
1176 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001177 } while (++index < fTs.count() && equalPoints(index, lesser));
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001178 return false;
1179 }
1180
caryclark@google.com4eeda372012-12-06 21:47:48 +00001181 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001182 Span* span = &fTs[index];
1183 Segment* other = span->fOther;
1184 int oIndex = span->fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001185 return other->activeAngleInner(oIndex, done, angles);
1186 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001187
caryclark@google.com4eeda372012-12-06 21:47:48 +00001188 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001189 int next = nextExactSpan(index, 1);
caryclark@google.com9764cc62012-07-12 19:29:45 +00001190 if (next > 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001191 Span& upSpan = fTs[index];
1192 if (upSpan.fWindValue || upSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001193 addAngle(angles, index, next);
caryclark@google.comf839c032012-10-26 21:03:50 +00001194 if (upSpan.fDone || upSpan.fUnsortableEnd) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001195 done++;
1196 } else if (upSpan.fWindSum != SK_MinS32) {
1197 return true;
1198 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001199 } else if (!upSpan.fDone) {
1200 upSpan.fDone = true;
1201 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001202 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001203 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00001204 int prev = nextExactSpan(index, -1);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001205 // edge leading into junction
caryclark@google.com9764cc62012-07-12 19:29:45 +00001206 if (prev >= 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001207 Span& downSpan = fTs[prev];
1208 if (downSpan.fWindValue || downSpan.fOppValue) {
caryclark@google.com210acaf2012-07-12 21:05:13 +00001209 addAngle(angles, index, prev);
1210 if (downSpan.fDone) {
1211 done++;
1212 } else if (downSpan.fWindSum != SK_MinS32) {
1213 return true;
1214 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001215 } else if (!downSpan.fDone) {
1216 downSpan.fDone = true;
1217 fDoneSpans++;
caryclark@google.com9764cc62012-07-12 19:29:45 +00001218 }
1219 }
1220 return false;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00001221 }
1222
caryclark@google.comf839c032012-10-26 21:03:50 +00001223 void activeLeftTop(SkPoint& result) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001224 SkASSERT(!done());
1225 int count = fTs.count();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001226 result.fX = result.fY = SK_ScalarMax;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001227 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00001228 bool lastUnsortable = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001229 for (int index = 0; index < count; ++index) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001230 const Span& span = fTs[index];
1231 if (span.fUnsortableStart | lastUnsortable) {
1232 goto next;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001233 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001234 if (!span.fDone | !lastDone) {
1235 const SkPoint& xy = xyAtT(index);
1236 if (result.fY < xy.fY) {
1237 goto next;
1238 }
1239 if (result.fY == xy.fY && result.fX < xy.fX) {
1240 goto next;
1241 }
1242 result = xy;
1243 }
1244 next:
1245 lastDone = span.fDone;
1246 lastUnsortable = span.fUnsortableEnd;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001247 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001248 }
1249
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001250 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
1251 int sumMiWinding = updateWinding(endIndex, index);
1252 int sumSuWinding = updateOppWinding(endIndex, index);
1253 if (fOperand) {
1254 SkTSwap<int>(sumMiWinding, sumSuWinding);
1255 }
1256 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1257 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding,
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001258 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001259 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00001260
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001261 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op,
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00001262 int& sumMiWinding, int& sumSuWinding,
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001263 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
1264 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1265 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001266 bool miFrom;
1267 bool miTo;
1268 bool suFrom;
1269 bool suTo;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001270 if (operand()) {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001271 miFrom = (oppMaxWinding & xorMiMask) != 0;
1272 miTo = (oppSumWinding & xorMiMask) != 0;
1273 suFrom = (maxWinding & xorSuMask) != 0;
1274 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001275 } else {
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001276 miFrom = (maxWinding & xorMiMask) != 0;
1277 miTo = (sumWinding & xorMiMask) != 0;
1278 suFrom = (oppMaxWinding & xorSuMask) != 0;
1279 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001280 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00001281 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
1282 SkASSERT(result != -1);
1283 return result;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001284 }
1285
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00001286 bool activeWinding(int index, int endIndex) {
1287 int sumWinding = updateWinding(endIndex, index);
1288 int maxWinding;
1289 return activeWinding(index, endIndex, maxWinding, sumWinding);
1290 }
1291
1292 bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
1293 setUpWinding(index, endIndex, maxWinding, sumWinding);
1294 bool from = maxWinding != 0;
1295 bool to = sumWinding != 0;
1296 bool result = gUnaryActiveEdge[from][to];
1297 SkASSERT(result != -1);
1298 return result;
1299 }
1300
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001301 void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001302 SkASSERT(start != end);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001303 Angle* angle = angles.append();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001304#if DEBUG_ANGLE
caryclark@google.com31143cf2012-11-09 22:14:19 +00001305 if (angles.count() > 1 && !fTs[start].fTiny) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001306 SkPoint angle0Pt, newPt;
1307 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
1308 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
1309 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
caryclark@google.com6d0032a2013-01-04 19:41:13 +00001310 SkASSERT(AlmostEqualUlps(angle0Pt.fX, newPt.fX));
1311 SkASSERT(AlmostEqualUlps(angle0Pt.fY, newPt.fY));
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001312 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001313#endif
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001314 angle->set(fPts, fVerb, this, start, end, fTs);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001315 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001316
caryclark@google.com2ddff932012-08-07 21:25:27 +00001317 void addCancelOutsides(double tStart, double oStart, Segment& other,
caryclark@google.comcc905052012-07-25 20:59:42 +00001318 double oEnd) {
1319 int tIndex = -1;
1320 int tCount = fTs.count();
1321 int oIndex = -1;
1322 int oCount = other.fTs.count();
caryclark@google.comcc905052012-07-25 20:59:42 +00001323 do {
1324 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001325 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001326 int tIndexStart = tIndex;
1327 do {
1328 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001329 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount);
caryclark@google.comcc905052012-07-25 20:59:42 +00001330 int oIndexStart = oIndex;
1331 double nextT;
1332 do {
1333 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001334 } while (nextT < 1 && approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001335 double oNextT;
1336 do {
1337 oNextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001338 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001339 // at this point, spans before and after are at:
1340 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
1341 // if tIndexStart == 0, no prior span
1342 // if nextT == 1, no following span
rmistry@google.comd6176b02012-08-23 18:14:13 +00001343
caryclark@google.comcc905052012-07-25 20:59:42 +00001344 // advance the span with zero winding
1345 // if the following span exists (not past the end, non-zero winding)
1346 // connect the two edges
1347 if (!fTs[tIndexStart].fWindValue) {
1348 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
1349 #if DEBUG_CONCIDENT
1350 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1351 __FUNCTION__, fID, other.fID, tIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001352 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
1353 xyAtT(tIndexStart).fY);
caryclark@google.comcc905052012-07-25 20:59:42 +00001354 #endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001355 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001356 }
1357 if (nextT < 1 && fTs[tIndex].fWindValue) {
1358 #if DEBUG_CONCIDENT
1359 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1360 __FUNCTION__, fID, other.fID, tIndex,
1361 fTs[tIndex].fT, xyAtT(tIndex).fX,
1362 xyAtT(tIndex).fY);
1363 #endif
caryclark@google.com2ddff932012-08-07 21:25:27 +00001364 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001365 }
1366 } else {
1367 SkASSERT(!other.fTs[oIndexStart].fWindValue);
1368 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
1369 #if DEBUG_CONCIDENT
1370 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1371 __FUNCTION__, fID, other.fID, oIndexStart - 1,
caryclark@google.com27c449a2012-07-27 18:26:38 +00001372 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
1373 other.xyAtT(oIndexStart).fY);
1374 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
caryclark@google.comcc905052012-07-25 20:59:42 +00001375 #endif
caryclark@google.comcc905052012-07-25 20:59:42 +00001376 }
1377 if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
1378 #if DEBUG_CONCIDENT
1379 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
1380 __FUNCTION__, fID, other.fID, oIndex,
1381 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
1382 other.xyAtT(oIndex).fY);
1383 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
1384 #endif
1385 }
1386 }
1387 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001388
caryclark@google.comcc905052012-07-25 20:59:42 +00001389 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
1390 double oEnd) {
1391 // walk this to outsideTs[0]
1392 // walk other to outsideTs[1]
1393 // if either is > 0, add a pointer to the other, copying adjacent winding
1394 int tIndex = -1;
1395 int oIndex = -1;
1396 double tStart = outsideTs[0];
1397 double oStart = outsideTs[1];
1398 do {
1399 ++tIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001400 } while (!approximately_negative(tStart - fTs[tIndex].fT));
caryclark@google.comcc905052012-07-25 20:59:42 +00001401 do {
1402 ++oIndex;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001403 } while (!approximately_negative(oStart - other.fTs[oIndex].fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001404 if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001405 addTPair(tStart, other, oStart, false);
caryclark@google.comcc905052012-07-25 20:59:42 +00001406 }
1407 tStart = fTs[tIndex].fT;
1408 oStart = other.fTs[oIndex].fT;
1409 do {
1410 double nextT;
1411 do {
1412 nextT = fTs[++tIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001413 } while (approximately_negative(nextT - tStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001414 tStart = nextT;
1415 do {
1416 nextT = other.fTs[++oIndex].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001417 } while (approximately_negative(nextT - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001418 oStart = nextT;
caryclark@google.com4eeda372012-12-06 21:47:48 +00001419 if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001420 break;
1421 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00001422 addTPair(tStart, other, oStart, false);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001423 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
caryclark@google.comcc905052012-07-25 20:59:42 +00001424 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001425
caryclark@google.com4eeda372012-12-06 21:47:48 +00001426 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
1427 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001428 fBounds.setCubicBounds(pts);
1429 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00001430
caryclark@google.comf839c032012-10-26 21:03:50 +00001431 /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001432 SkPoint edge[4];
caryclark@google.comf839c032012-10-26 21:03:50 +00001433 const SkPoint* ePtr;
1434 int lastT = fTs.count() - 1;
1435 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
1436 ePtr = fPts;
1437 } else {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001438 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end)
caryclark@google.comf839c032012-10-26 21:03:50 +00001439 (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
1440 ePtr = edge;
1441 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001442 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001443 bool reverse = ePtr == fPts && start != 0;
1444 if (reverse) {
1445 path.deferredMoveLine(ePtr[fVerb]);
1446 switch (fVerb) {
1447 case SkPath::kLine_Verb:
1448 path.deferredLine(ePtr[0]);
1449 break;
1450 case SkPath::kQuad_Verb:
1451 path.quadTo(ePtr[1], ePtr[0]);
1452 break;
1453 case SkPath::kCubic_Verb:
1454 path.cubicTo(ePtr[2], ePtr[1], ePtr[0]);
1455 break;
1456 default:
1457 SkASSERT(0);
1458 }
1459 // return ePtr[0];
1460 } else {
1461 path.deferredMoveLine(ePtr[0]);
1462 switch (fVerb) {
1463 case SkPath::kLine_Verb:
1464 path.deferredLine(ePtr[1]);
1465 break;
1466 case SkPath::kQuad_Verb:
1467 path.quadTo(ePtr[1], ePtr[2]);
1468 break;
1469 case SkPath::kCubic_Verb:
1470 path.cubicTo(ePtr[1], ePtr[2], ePtr[3]);
1471 break;
1472 default:
1473 SkASSERT(0);
1474 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001475 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001476 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001477 // return ePtr[fVerb];
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001478 }
1479
caryclark@google.com4eeda372012-12-06 21:47:48 +00001480 void addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
1481 init(pts, SkPath::kLine_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001482 fBounds.set(pts, 2);
1483 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001484
caryclark@google.comf839c032012-10-26 21:03:50 +00001485#if 0
1486 const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001487 const SkPoint& pt = xyAtT(tIndex);
1488 if (active) {
caryclark@google.comf839c032012-10-26 21:03:50 +00001489 path.deferredMove(pt);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001490 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00001491 return pt;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001492 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001493#endif
caryclark@google.com1577e8f2012-05-22 17:01:14 +00001494
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001495 // add 2 to edge or out of range values to get T extremes
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001496 void addOtherT(int index, double otherT, int otherIndex) {
1497 Span& span = fTs[index];
caryclark@google.comf839c032012-10-26 21:03:50 +00001498 #if PIN_ADD_T
caryclark@google.com185c7c42012-10-19 18:26:24 +00001499 if (precisely_less_than_zero(otherT)) {
1500 otherT = 0;
1501 } else if (precisely_greater_than_one(otherT)) {
1502 otherT = 1;
1503 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001504 #endif
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001505 span.fOtherT = otherT;
1506 span.fOtherIndex = otherIndex;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001507 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001508
caryclark@google.com4eeda372012-12-06 21:47:48 +00001509 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
1510 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001511 fBounds.setQuadBounds(pts);
1512 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001513
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001514 // Defer all coincident edge processing until
1515 // after normal intersections have been computed
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001516
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001517// no need to be tricky; insert in normal T order
1518// resolve overlapping ts when considering coincidence later
1519
1520 // add non-coincident intersection. Resulting edges are sorted in T.
1521 int addT(double newT, Segment* other) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001522 // FIXME: in the pathological case where there is a ton of intercepts,
1523 // binary search?
1524 int insertedAt = -1;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001525 size_t tCount = fTs.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00001526 #if PIN_ADD_T
caryclark@google.comc899ad92012-08-23 15:24:42 +00001527 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect)
caryclark@google.com185c7c42012-10-19 18:26:24 +00001528 if (precisely_less_than_zero(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001529 newT = 0;
caryclark@google.com185c7c42012-10-19 18:26:24 +00001530 } else if (precisely_greater_than_one(newT)) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00001531 newT = 1;
1532 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001533 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001534 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00001535 // OPTIMIZATION: if there are three or more identical Ts, then
1536 // the fourth and following could be further insertion-sorted so
1537 // that all the edges are clockwise or counterclockwise.
1538 // This could later limit segment tests to the two adjacent
1539 // neighbors, although it doesn't help with determining which
1540 // circular direction to go in.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001541 if (newT < fTs[index].fT) {
1542 insertedAt = index;
1543 break;
caryclark@google.com15fa1382012-05-07 20:49:36 +00001544 }
1545 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001546 Span* span;
1547 if (insertedAt >= 0) {
1548 span = fTs.insert(insertedAt);
1549 } else {
1550 insertedAt = tCount;
1551 span = fTs.append();
1552 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001553 span->fT = newT;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001554 span->fOther = other;
caryclark@google.com27c449a2012-07-27 18:26:38 +00001555 span->fPt.fX = SK_ScalarNaN;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001556 span->fWindSum = SK_MinS32;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001557 span->fOppSum = SK_MinS32;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001558 span->fWindValue = 1;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001559 span->fOppValue = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00001560 span->fTiny = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001561 if ((span->fDone = newT == 1)) {
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00001562 ++fDoneSpans;
rmistry@google.comd6176b02012-08-23 18:14:13 +00001563 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001564 span->fUnsortableStart = false;
1565 span->fUnsortableEnd = false;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001566 int less = -1;
1567 while (&span[less + 1] - fTs.begin() > 0 && !span[less].fDone
1568 && !precisely_negative(newT - span[less].fT)
1569 // && approximately_negative(newT - span[less].fT)
1570 && xyAtT(&span[less]) == xyAtT(span)) {
1571 span[less].fTiny = true;
1572 span[less].fDone = true;
1573 if (approximately_negative(newT - span[less].fT)) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00001574 if (approximately_greater_than_one(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001575 span[less].fUnsortableStart = true;
1576 span[less - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001577 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001578 if (approximately_less_than_zero(span[less].fT)) {
1579 span[less + 1].fUnsortableStart = true;
1580 span[less].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001581 }
1582 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001583 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001584 --less;
caryclark@google.comf839c032012-10-26 21:03:50 +00001585 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001586 int more = 1;
1587 while (fTs.end() - &span[more - 1] > 1 && !span[more - 1].fDone
1588 && !precisely_negative(span[more].fT - newT)
1589 // && approximately_negative(span[more].fT - newT)
1590 && xyAtT(&span[more]) == xyAtT(span)) {
1591 span[more - 1].fTiny = true;
1592 span[more - 1].fDone = true;
1593 if (approximately_negative(span[more].fT - newT)) {
1594 if (approximately_greater_than_one(span[more].fT)) {
1595 span[more + 1].fUnsortableStart = true;
1596 span[more].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001597 }
1598 if (approximately_less_than_zero(newT)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001599 span[more].fUnsortableStart = true;
1600 span[more - 1].fUnsortableEnd = true;
caryclark@google.com0b7da432012-10-31 19:00:20 +00001601 }
1602 }
caryclark@google.comf839c032012-10-26 21:03:50 +00001603 ++fDoneSpans;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00001604 ++more;
caryclark@google.comf839c032012-10-26 21:03:50 +00001605 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00001606 return insertedAt;
1607 }
1608
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001609 // set spans from start to end to decrement by one
1610 // note this walks other backwards
1611 // FIMXE: there's probably an edge case that can be constructed where
1612 // two span in one segment are separated by float epsilon on one span but
1613 // not the other, if one segment is very small. For this
1614 // case the counts asserted below may or may not be enough to separate the
caryclark@google.com2ddff932012-08-07 21:25:27 +00001615 // spans. Even if the counts work out, what if the spans aren't correctly
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001616 // sorted? It feels better in such a case to match the span's other span
1617 // pointer since both coincident segments must contain the same spans.
1618 void addTCancel(double startT, double endT, Segment& other,
1619 double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001620 SkASSERT(!approximately_negative(endT - startT));
1621 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00001622 bool binary = fOperand != other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001623 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001624 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001625 ++index;
1626 }
caryclark@google.comb9738012012-07-03 19:53:30 +00001627 int oIndex = other.fTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001628 while (approximately_positive(other.fTs[--oIndex].fT - oEndT))
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001629 ;
caryclark@google.com59823f72012-08-09 18:17:47 +00001630 double tRatio = (oEndT - oStartT) / (endT - startT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001631 Span* test = &fTs[index];
1632 Span* oTest = &other.fTs[oIndex];
caryclark@google.com18063442012-07-25 12:05:18 +00001633 SkTDArray<double> outsideTs;
1634 SkTDArray<double> oOutsideTs;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001635 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001636 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
caryclark@google.comcc905052012-07-25 20:59:42 +00001637 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.com200c2112012-08-03 15:05:04 +00001638 double testT = test->fT;
1639 double oTestT = oTest->fT;
1640 Span* span = test;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001641 do {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001642 if (decrement) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00001643 decrementSpan(span);
caryclark@google.com200c2112012-08-03 15:05:04 +00001644 } else if (track && span->fT < 1 && oTestT < 1) {
1645 TrackOutside(outsideTs, span->fT, oTestT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001646 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001647 span = &fTs[++index];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001648 } while (approximately_negative(span->fT - testT));
caryclark@google.com200c2112012-08-03 15:05:04 +00001649 Span* oSpan = oTest;
caryclark@google.com59823f72012-08-09 18:17:47 +00001650 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
1651 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
1652 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001653 while (approximately_negative(otherTMatchStart - oSpan->fT)
1654 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
caryclark@google.com03f97062012-08-21 13:13:52 +00001655 #ifdef SK_DEBUG
caryclark@google.com59823f72012-08-09 18:17:47 +00001656 SkASSERT(originalWindValue == oSpan->fWindValue);
caryclark@google.com03f97062012-08-21 13:13:52 +00001657 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001658 if (decrement) {
caryclark@google.com200c2112012-08-03 15:05:04 +00001659 other.decrementSpan(oSpan);
1660 } else if (track && oSpan->fT < 1 && testT < 1) {
1661 TrackOutside(oOutsideTs, oSpan->fT, testT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001662 }
1663 if (!oIndex) {
1664 break;
1665 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001666 oSpan = &other.fTs[--oIndex];
rmistry@google.comd6176b02012-08-23 18:14:13 +00001667 }
caryclark@google.com200c2112012-08-03 15:05:04 +00001668 test = span;
1669 oTest = oSpan;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001670 } while (!approximately_negative(endT - test->fT));
1671 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
caryclark@google.com18063442012-07-25 12:05:18 +00001672 // FIXME: determine if canceled edges need outside ts added
caryclark@google.comcc905052012-07-25 20:59:42 +00001673 if (!done() && outsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001674 double tStart = outsideTs[0];
1675 double oStart = outsideTs[1];
1676 addCancelOutsides(tStart, oStart, other, oEndT);
1677 int count = outsideTs.count();
1678 if (count > 2) {
1679 double tStart = outsideTs[count - 2];
1680 double oStart = outsideTs[count - 1];
1681 addCancelOutsides(tStart, oStart, other, oEndT);
1682 }
caryclark@google.com18063442012-07-25 12:05:18 +00001683 }
caryclark@google.comcc905052012-07-25 20:59:42 +00001684 if (!other.done() && oOutsideTs.count()) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00001685 double tStart = oOutsideTs[0];
1686 double oStart = oOutsideTs[1];
1687 other.addCancelOutsides(tStart, oStart, *this, endT);
caryclark@google.com18063442012-07-25 12:05:18 +00001688 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001689 }
skia.committer@gmail.com15dd3002013-01-18 07:07:28 +00001690
caryclark@google.com73ca6242013-01-17 21:02:47 +00001691 int addUnsortableT(double newT, Segment* other, bool start) {
1692 int result = addT(newT, other);
1693 Span* span = &fTs[result];
1694 if (start) {
1695 if (result > 0) {
1696 span[result - 1].fUnsortableEnd = true;
1697 }
1698 span[result].fUnsortableStart = true;
1699 } else {
1700 span[result].fUnsortableEnd = true;
1701 if (result + 1 < fTs.count()) {
1702 span[result + 1].fUnsortableStart = true;
1703 }
1704 }
1705 return result;
1706 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00001707
caryclark@google.com4eeda372012-12-06 21:47:48 +00001708 int bumpCoincidentThis(const Span* oTest, bool opp, int index,
1709 SkTDArray<double>& outsideTs) {
1710 int oWindValue = oTest->fWindValue;
1711 int oOppValue = oTest->fOppValue;
1712 if (opp) {
1713 SkTSwap<int>(oWindValue, oOppValue);
1714 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001715 Span* const test = &fTs[index];
1716 Span* end = test;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001717 const double oStartT = oTest->fT;
1718 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001719 if (bumpSpan(end, oWindValue, oOppValue)) {
1720 TrackOutside(outsideTs, end->fT, oStartT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001721 }
1722 end = &fTs[++index];
1723 } while (approximately_negative(end->fT - test->fT));
1724 return index;
1725 }
1726
1727 // because of the order in which coincidences are resolved, this and other
1728 // may not have the same intermediate points. Compute the corresponding
1729 // intermediate T values (using this as the master, other as the follower)
1730 // and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com4eeda372012-12-06 21:47:48 +00001731 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex,
1732 SkTDArray<double>& oOutsideTs) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001733 Span* const oTest = &fTs[oIndex];
1734 Span* oEnd = oTest;
1735 const double startT = test->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001736 const double oStartT = oTest->fT;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001737 while (!approximately_negative(oEndT - oEnd->fT)
caryclark@google.com4eeda372012-12-06 21:47:48 +00001738 && approximately_negative(oEnd->fT - oStartT)) {
1739 zeroSpan(oEnd);
1740 TrackOutside(oOutsideTs, oEnd->fT, startT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001741 oEnd = &fTs[++oIndex];
1742 }
1743 return oIndex;
1744 }
1745
1746 // FIXME: need to test this case:
1747 // contourA has two segments that are coincident
1748 // contourB has two segments that are coincident in the same place
1749 // each ends up with +2/0 pairs for winding count
1750 // since logic below doesn't transfer count (only increments/decrements) can this be
1751 // resolved to +4/0 ?
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001752
1753 // set spans from start to end to increment the greater by one and decrement
1754 // the lesser
caryclark@google.com4eeda372012-12-06 21:47:48 +00001755 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001756 SkASSERT(!approximately_negative(endT - startT));
1757 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001758 bool opp = fOperand ^ other.fOperand;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001759 int index = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001760 while (!approximately_negative(startT - fTs[index].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001761 ++index;
1762 }
1763 int oIndex = 0;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001764 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001765 ++oIndex;
1766 }
1767 Span* test = &fTs[index];
1768 Span* oTest = &other.fTs[oIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001769 SkTDArray<double> outsideTs;
1770 SkTDArray<double> oOutsideTs;
1771 do {
caryclark@google.com4eeda372012-12-06 21:47:48 +00001772 // if either span has an opposite value and the operands don't match, resolve first
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001773 // SkASSERT(!test->fDone || !oTest->fDone);
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001774 if (test->fDone || oTest->fDone) {
1775 index = advanceCoincidentThis(oTest, opp, index);
1776 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex);
1777 } else {
1778 index = bumpCoincidentThis(oTest, opp, index, outsideTs);
1779 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs);
1780 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00001781 test = &fTs[index];
1782 oTest = &other.fTs[oIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001783 } while (!approximately_negative(endT - test->fT));
1784 SkASSERT(approximately_negative(oTest->fT - oEndT));
1785 SkASSERT(approximately_negative(oEndT - oTest->fT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00001786 if (!done() && outsideTs.count()) {
1787 addCoinOutsides(outsideTs, other, oEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001788 }
1789 if (!other.done() && oOutsideTs.count()) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001790 other.addCoinOutsides(oOutsideTs, *this, endT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001791 }
1792 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001793
caryclark@google.comcc905052012-07-25 20:59:42 +00001794 // FIXME: this doesn't prevent the same span from being added twice
caryclark@google.comaa358312013-01-29 20:28:49 +00001795 // fix in caller, SkASSERT here?
caryclark@google.com2ddff932012-08-07 21:25:27 +00001796 void addTPair(double t, Segment& other, double otherT, bool borrowWind) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001797 int tCount = fTs.count();
1798 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1799 const Span& span = fTs[tIndex];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00001800 if (!approximately_negative(span.fT - t)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001801 break;
1802 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00001803 if (approximately_negative(span.fT - t) && span.fOther == &other
1804 && approximately_equal(span.fOtherT, otherT)) {
caryclark@google.comcc905052012-07-25 20:59:42 +00001805#if DEBUG_ADD_T_PAIR
1806 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1807 __FUNCTION__, fID, t, other.fID, otherT);
1808#endif
1809 return;
1810 }
1811 }
caryclark@google.com47580692012-07-23 12:14:49 +00001812#if DEBUG_ADD_T_PAIR
1813 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1814 __FUNCTION__, fID, t, other.fID, otherT);
1815#endif
caryclark@google.comb9738012012-07-03 19:53:30 +00001816 int insertedAt = addT(t, &other);
1817 int otherInsertedAt = other.addT(otherT, this);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001818 addOtherT(insertedAt, otherT, otherInsertedAt);
caryclark@google.comb9738012012-07-03 19:53:30 +00001819 other.addOtherT(otherInsertedAt, t, insertedAt);
caryclark@google.com2ddff932012-08-07 21:25:27 +00001820 matchWindingValue(insertedAt, t, borrowWind);
1821 other.matchWindingValue(otherInsertedAt, otherT, borrowWind);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001822 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001823
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001824 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001825 // add edge leading into junction
caryclark@google.com4eeda372012-12-06 21:47:48 +00001826 int min = SkMin32(end, start);
1827 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001828 addAngle(angles, end, start);
1829 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001830 // add edge leading away from junction
caryclark@google.com495f8e42012-05-31 13:13:11 +00001831 int step = SkSign32(end - start);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001832 int tIndex = nextExactSpan(end, step);
caryclark@google.com4eeda372012-12-06 21:47:48 +00001833 min = SkMin32(end, tIndex);
1834 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001835 addAngle(angles, end, tIndex);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001836 }
1837 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001838
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001839 int advanceCoincidentThis(const Span* oTest, bool opp, int index) {
1840 Span* const test = &fTs[index];
1841 Span* end = test;
1842 do {
1843 end = &fTs[++index];
1844 } while (approximately_negative(end->fT - test->fT));
1845 return index;
1846 }
1847
1848 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) {
1849 Span* const oTest = &fTs[oIndex];
1850 Span* oEnd = oTest;
1851 const double oStartT = oTest->fT;
1852 while (!approximately_negative(oEndT - oEnd->fT)
1853 && approximately_negative(oEnd->fT - oStartT)) {
1854 oEnd = &fTs[++oIndex];
1855 }
1856 return oIndex;
1857 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00001858
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00001859 bool betweenTs(int lesser, double testT, int greater) {
1860 if (lesser > greater) {
1861 SkTSwap<int>(lesser, greater);
1862 }
1863 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
1864 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00001865
caryclark@google.comfa0588f2012-04-26 21:01:06 +00001866 const Bounds& bounds() const {
1867 return fBounds;
1868 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00001869
caryclark@google.com31143cf2012-11-09 22:14:19 +00001870 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001871 double referenceT = fTs[index].fT;
1872 int lesser = index;
caryclark@google.com31143cf2012-11-09 22:14:19 +00001873 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
1874 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00001875 buildAnglesInner(lesser, angles);
1876 }
1877 do {
1878 buildAnglesInner(index, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001879 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
1880 && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comb45a1b42012-05-18 20:50:33 +00001881 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001882
1883 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
1884 Span* span = &fTs[index];
1885 Segment* other = span->fOther;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001886 // if there is only one live crossing, and no coincidence, continue
1887 // in the same direction
1888 // if there is coincidence, the only choice may be to reverse direction
1889 // find edge on either side of intersection
1890 int oIndex = span->fOtherIndex;
1891 // if done == -1, prior span has already been processed
1892 int step = 1;
caryclark@google.coma461ff02012-10-11 12:54:23 +00001893 int next = other->nextExactSpan(oIndex, step);
caryclark@google.coma461ff02012-10-11 12:54:23 +00001894 if (next < 0) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001895 step = -step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00001896 next = other->nextExactSpan(oIndex, step);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001897 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00001898 // add candidate into and away from junction
1899 other->addTwoAngles(next, oIndex, angles);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00001900 }
1901
caryclark@google.com7fce0de2012-11-29 14:31:50 +00001902 int computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001903 SkTDArray<Angle> angles;
1904 addTwoAngles(startIndex, endIndex, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00001905 buildAngles(endIndex, angles, false);
caryclark@google.comd1688742012-09-18 20:08:37 +00001906 // OPTIMIZATION: check all angles to see if any have computed wind sum
1907 // before sorting (early exit if none)
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001908 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001909 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00001910#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00001911 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00001912#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00001913 if (!sortable) {
1914 return SK_MinS32;
1915 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001916 int angleCount = angles.count();
1917 const Angle* angle;
1918 const Segment* base;
1919 int winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001920 int oWinding;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001921 int firstIndex = 0;
1922 do {
1923 angle = sorted[firstIndex];
1924 base = angle->segment();
1925 winding = base->windSum(angle);
1926 if (winding != SK_MinS32) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001927 oWinding = base->oppSum(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001928 break;
1929 }
1930 if (++firstIndex == angleCount) {
1931 return SK_MinS32;
1932 }
1933 } while (true);
1934 // turn winding into contourWinding
caryclark@google.com2ddff932012-08-07 21:25:27 +00001935 int spanWinding = base->spanSign(angle);
1936 bool inner = useInnerWinding(winding + spanWinding, winding);
1937 #if DEBUG_WINDING
caryclark@google.com24bec792012-08-20 12:43:57 +00001938 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
caryclark@google.com59823f72012-08-09 18:17:47 +00001939 spanWinding, winding, angle->sign(), inner,
caryclark@google.com2ddff932012-08-07 21:25:27 +00001940 inner ? winding + spanWinding : winding);
1941 #endif
1942 if (inner) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001943 winding += spanWinding;
1944 }
1945 #if DEBUG_SORT
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001946 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001947 #endif
1948 int nextIndex = firstIndex + 1;
1949 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com2ddff932012-08-07 21:25:27 +00001950 winding -= base->spanSign(angle);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001951 oWinding -= base->oppSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001952 do {
1953 if (nextIndex == angleCount) {
1954 nextIndex = 0;
1955 }
1956 angle = sorted[nextIndex];
1957 Segment* segment = angle->segment();
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001958 bool opp = base->fOperand ^ segment->fOperand;
1959 int maxWinding, oMaxWinding;
1960 int spanSign = segment->spanSign(angle);
1961 int oppoSign = segment->oppSign(angle);
1962 if (opp) {
1963 oMaxWinding = oWinding;
1964 oWinding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00001965 maxWinding = winding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001966 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001967 winding -= oppoSign;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001968 }
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001969 } else {
1970 maxWinding = winding;
1971 winding -= spanSign;
caryclark@google.com729e1c42012-11-21 21:36:34 +00001972 oMaxWinding = oWinding;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001973 if (oppoSign) {
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001974 oWinding -= oppoSign;
1975 }
1976 }
1977 if (segment->windSum(angle) == SK_MinS32) {
1978 if (opp) {
1979 if (useInnerWinding(oMaxWinding, oWinding)) {
1980 oMaxWinding = oWinding;
1981 }
1982 if (oppoSign && useInnerWinding(maxWinding, winding)) {
1983 maxWinding = winding;
1984 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00001985 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001986 } else {
1987 if (useInnerWinding(maxWinding, winding)) {
1988 maxWinding = winding;
1989 }
1990 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
1991 oMaxWinding = oWinding;
1992 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00001993 (void) segment->markAndChaseWinding(angle, maxWinding,
1994 binary ? oMaxWinding : 0);
caryclark@google.com7ba591e2012-11-20 14:21:54 +00001995 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00001996 }
1997 } while (++nextIndex != lastIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00001998 int minIndex = SkMin32(startIndex, endIndex);
caryclark@google.com6ec15262012-11-16 20:16:50 +00001999 return windSum(minIndex);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00002000 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002001
caryclark@google.com3586ece2012-12-27 18:46:58 +00002002 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
caryclark@google.com10227bf2012-12-28 22:10:41 +00002003 double mid, bool opp, bool current) const {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002004 SkScalar bottom = fBounds.fBottom;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002005 int bestTIndex = -1;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002006 if (bottom <= bestY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002007 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002008 }
2009 SkScalar top = fBounds.fTop;
2010 if (top >= basePt.fY) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002011 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002012 }
2013 if (fBounds.fLeft > basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002014 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002015 }
2016 if (fBounds.fRight < basePt.fX) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002017 return bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002018 }
2019 if (fBounds.fLeft == fBounds.fRight) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002020 // if vertical, and directly above test point, wait for another one
caryclark@google.com6d0032a2013-01-04 19:41:13 +00002021 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002022 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002023 // intersect ray starting at basePt with edge
2024 Intersections intersections;
2025 // OPTIMIZE: use specialty function that intersects ray with curve,
2026 // returning t values only for curve (we don't care about t on ray)
2027 int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
2028 if (pts == 0 || (current && pts == 1)) {
2029 return bestTIndex;
2030 }
2031 if (current) {
2032 SkASSERT(pts > 1);
2033 int closestIdx = 0;
2034 double closest = fabs(intersections.fT[0][0] - mid);
2035 for (int idx = 1; idx < pts; ++idx) {
2036 double test = fabs(intersections.fT[0][idx] - mid);
2037 if (closest > test) {
2038 closestIdx = idx;
2039 closest = test;
2040 }
2041 }
2042 if (closestIdx < pts - 1) {
2043 intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
2044 }
2045 --pts;
2046 }
2047 double bestT = -1;
2048 for (int index = 0; index < pts; ++index) {
2049 double foundT = intersections.fT[0][index];
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002050 if (approximately_less_than_zero(foundT)
2051 || approximately_greater_than_one(foundT)) {
2052 continue;
2053 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002054 SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
2055 if (approximately_negative(testY - bestY)
2056 || approximately_negative(basePt.fY - testY)) {
caryclark@google.com47580692012-07-23 12:14:49 +00002057 continue;
2058 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002059 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002060 return SK_MinS32; // if the intersection is edge on, wait for another one
caryclark@google.com10227bf2012-12-28 22:10:41 +00002061 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002062 if (fVerb > SkPath::kLine_Verb) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002063 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
2064 if (approximately_zero(dx)) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002065 return SK_MinS32; // hit vertical, wait for another one
caryclark@google.com3586ece2012-12-27 18:46:58 +00002066 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00002067 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002068 bestY = testY;
2069 bestT = foundT;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002070 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002071 if (bestT < 0) {
2072 return bestTIndex;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002073 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002074 SkASSERT(bestT >= 0);
2075 SkASSERT(bestT <= 1);
2076 int start;
2077 int end = 0;
2078 do {
2079 start = end;
2080 end = nextSpan(start, 1);
2081 } while (fTs[end].fT < bestT);
2082 // FIXME: see next candidate for a better pattern to find the next start/end pair
2083 while (start + 1 < end && fTs[start].fDone) {
2084 ++start;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002085 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002086 if (!isCanceled(start)) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00002087 hitT = bestT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002088 bestTIndex = start;
caryclark@google.com10227bf2012-12-28 22:10:41 +00002089 hitSomething = true;
caryclark@google.com3586ece2012-12-27 18:46:58 +00002090 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00002091 return bestTIndex;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002092 }
caryclark@google.com18063442012-07-25 12:05:18 +00002093
caryclark@google.com4eeda372012-12-06 21:47:48 +00002094 void decrementSpan(Span* span) {
caryclark@google.com18063442012-07-25 12:05:18 +00002095 SkASSERT(span->fWindValue > 0);
2096 if (--(span->fWindValue) == 0) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002097 if (!span->fOppValue && !span->fDone) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002098 span->fDone = true;
2099 ++fDoneSpans;
2100 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002101 }
2102 }
2103
2104 bool bumpSpan(Span* span, int windDelta, int oppDelta) {
2105 SkASSERT(!span->fDone);
2106 span->fWindValue += windDelta;
2107 SkASSERT(span->fWindValue >= 0);
2108 span->fOppValue += oppDelta;
2109 SkASSERT(span->fOppValue >= 0);
2110 if (fXor) {
2111 span->fWindValue &= 1;
2112 }
2113 if (fOppXor) {
2114 span->fOppValue &= 1;
2115 }
2116 if (!span->fWindValue && !span->fOppValue) {
2117 span->fDone = true;
2118 ++fDoneSpans;
caryclark@google.com18063442012-07-25 12:05:18 +00002119 return true;
2120 }
2121 return false;
2122 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002123
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002124 // OPTIMIZE
2125 // when the edges are initially walked, they don't automatically get the prior and next
2126 // 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 +00002127 // and would additionally remove the need for similar checks in condition edges. It would
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00002128 // also allow intersection code to assume end of segment intersections (maybe?)
2129 bool complete() const {
2130 int count = fTs.count();
2131 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
2132 }
caryclark@google.com18063442012-07-25 12:05:18 +00002133
caryclark@google.com15fa1382012-05-07 20:49:36 +00002134 bool done() const {
caryclark@google.comaf46cff2012-05-22 21:12:00 +00002135 SkASSERT(fDoneSpans <= fTs.count());
2136 return fDoneSpans == fTs.count();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002137 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00002138
caryclark@google.comf839c032012-10-26 21:03:50 +00002139 bool done(int min) const {
2140 return fTs[min].fDone;
2141 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002142
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002143 bool done(const Angle* angle) const {
2144 return done(SkMin32(angle->start(), angle->end()));
caryclark@google.com47580692012-07-23 12:14:49 +00002145 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00002146
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002147 bool equalPoints(int greaterTIndex, int lesserTIndex) {
2148 SkASSERT(greaterTIndex >= lesserTIndex);
2149 double greaterT = fTs[greaterTIndex].fT;
2150 double lesserT = fTs[lesserTIndex].fT;
2151 if (greaterT == lesserT) {
2152 return true;
2153 }
2154 if (!approximately_negative(greaterT - lesserT)) {
2155 return false;
2156 }
2157 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
2158 }
2159
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002160 /*
2161 The M and S variable name parts stand for the operators.
2162 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2163 Su stands for Subtrahend
2164 The Opp variable name part designates that the value is for the Opposite operator.
2165 Opposite values result from combining coincident spans.
2166 */
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002167
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002168 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2169 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002170 const int startIndex = nextStart;
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002171 const int endIndex = nextEnd;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002172 SkASSERT(startIndex != endIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002173 const int count = fTs.count();
2174 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2175 const int step = SkSign32(endIndex - startIndex);
2176 const int end = nextExactSpan(startIndex, step);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002177 SkASSERT(end >= 0);
2178 Span* endSpan = &fTs[end];
2179 Segment* other;
2180 if (isSimple(end)) {
2181 // mark the smaller of startIndex, endIndex done, and all adjacent
2182 // spans with the same T value (but not 'other' spans)
2183 #if DEBUG_WINDING
2184 SkDebugf("%s simple\n", __FUNCTION__);
2185 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002186 int min = SkMin32(startIndex, endIndex);
2187 if (fTs[min].fDone) {
2188 return NULL;
2189 }
2190 markDoneBinary(min);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002191 other = endSpan->fOther;
2192 nextStart = endSpan->fOtherIndex;
2193 double startT = other->fTs[nextStart].fT;
2194 nextEnd = nextStart;
2195 do {
2196 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002197 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002198 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002199 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2200 return other;
2201 }
2202 // more than one viable candidate -- measure angles to find best
2203 SkTDArray<Angle> angles;
2204 SkASSERT(startIndex - endIndex != 0);
2205 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2206 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002207 buildAngles(end, angles, true);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002208 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002209 bool sortable = SortAngles(angles, sorted);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002210 int angleCount = angles.count();
2211 int firstIndex = findStartingEdge(sorted, startIndex, end);
2212 SkASSERT(firstIndex >= 0);
2213 #if DEBUG_SORT
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002214 debugShowSort(__FUNCTION__, sorted, firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002215 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002216 if (!sortable) {
2217 unsortable = true;
2218 return NULL;
2219 }
caryclark@google.com235f56a2012-09-14 14:19:30 +00002220 SkASSERT(sorted[firstIndex]->segment() == this);
2221 #if DEBUG_WINDING
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002222 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2223 sorted[firstIndex]->sign());
caryclark@google.com235f56a2012-09-14 14:19:30 +00002224 #endif
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002225 int sumMiWinding = updateWinding(endIndex, startIndex);
2226 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2227 if (operand()) {
2228 SkTSwap<int>(sumMiWinding, sumSuWinding);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002229 }
2230 int nextIndex = firstIndex + 1;
2231 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2232 const Angle* foundAngle = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002233 bool foundDone = false;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002234 // iterate through the angle, and compute everyone's winding
caryclark@google.com235f56a2012-09-14 14:19:30 +00002235 Segment* nextSegment;
caryclark@google.com235f56a2012-09-14 14:19:30 +00002236 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002237 SkASSERT(nextIndex != firstIndex);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002238 if (nextIndex == angleCount) {
2239 nextIndex = 0;
2240 }
2241 const Angle* nextAngle = sorted[nextIndex];
2242 nextSegment = nextAngle->segment();
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002243 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
2244 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2245 nextAngle->end(), op, sumMiWinding, sumSuWinding,
2246 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
2247 if (activeAngle && (!foundAngle || foundDone)) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002248 foundAngle = nextAngle;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002249 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
caryclark@google.com235f56a2012-09-14 14:19:30 +00002250 }
2251 if (nextSegment->done()) {
2252 continue;
2253 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002254 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2255 continue;
2256 }
2257 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
2258 oppSumWinding, activeAngle, nextAngle);
2259 if (last) {
2260 *chase.append() = last;
2261#if DEBUG_WINDING
2262 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2263 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2264#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002265 }
2266 } while (++nextIndex != lastIndex);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002267 markDoneBinary(SkMin32(startIndex, endIndex));
caryclark@google.com235f56a2012-09-14 14:19:30 +00002268 if (!foundAngle) {
2269 return NULL;
2270 }
2271 nextStart = foundAngle->start();
2272 nextEnd = foundAngle->end();
2273 nextSegment = foundAngle->segment();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00002274
caryclark@google.com235f56a2012-09-14 14:19:30 +00002275 #if DEBUG_WINDING
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002276 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2277 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002278 #endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00002279 return nextSegment;
2280 }
caryclark@google.com47580692012-07-23 12:14:49 +00002281
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002282 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd,
2283 bool& unsortable) {
2284 const int startIndex = nextStart;
2285 const int endIndex = nextEnd;
2286 SkASSERT(startIndex != endIndex);
2287 const int count = fTs.count();
2288 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2289 const int step = SkSign32(endIndex - startIndex);
2290 const int end = nextExactSpan(startIndex, step);
2291 SkASSERT(end >= 0);
2292 Span* endSpan = &fTs[end];
2293 Segment* other;
2294 if (isSimple(end)) {
2295 // mark the smaller of startIndex, endIndex done, and all adjacent
2296 // spans with the same T value (but not 'other' spans)
2297 #if DEBUG_WINDING
2298 SkDebugf("%s simple\n", __FUNCTION__);
2299 #endif
2300 int min = SkMin32(startIndex, endIndex);
2301 if (fTs[min].fDone) {
2302 return NULL;
2303 }
2304 markDoneUnary(min);
2305 other = endSpan->fOther;
2306 nextStart = endSpan->fOtherIndex;
2307 double startT = other->fTs[nextStart].fT;
2308 nextEnd = nextStart;
2309 do {
2310 nextEnd += step;
2311 }
2312 while (precisely_zero(startT - other->fTs[nextEnd].fT));
2313 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2314 return other;
2315 }
2316 // more than one viable candidate -- measure angles to find best
2317 SkTDArray<Angle> angles;
2318 SkASSERT(startIndex - endIndex != 0);
2319 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2320 addTwoAngles(startIndex, end, angles);
2321 buildAngles(end, angles, true);
2322 SkTDArray<Angle*> sorted;
2323 bool sortable = SortAngles(angles, sorted);
2324 int angleCount = angles.count();
2325 int firstIndex = findStartingEdge(sorted, startIndex, end);
2326 SkASSERT(firstIndex >= 0);
2327 #if DEBUG_SORT
2328 debugShowSort(__FUNCTION__, sorted, firstIndex);
2329 #endif
2330 if (!sortable) {
2331 unsortable = true;
2332 return NULL;
2333 }
2334 SkASSERT(sorted[firstIndex]->segment() == this);
2335 #if DEBUG_WINDING
2336 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2337 sorted[firstIndex]->sign());
2338 #endif
2339 int sumWinding = updateWinding(endIndex, startIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002340 int nextIndex = firstIndex + 1;
2341 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2342 const Angle* foundAngle = NULL;
2343 bool foundDone = false;
2344 // iterate through the angle, and compute everyone's winding
2345 Segment* nextSegment;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002346 int activeCount = 0;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002347 do {
2348 SkASSERT(nextIndex != firstIndex);
2349 if (nextIndex == angleCount) {
2350 nextIndex = 0;
2351 }
2352 const Angle* nextAngle = sorted[nextIndex];
2353 nextSegment = nextAngle->segment();
2354 int maxWinding;
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +00002355 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002356 maxWinding, sumWinding);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002357 if (activeAngle) {
2358 ++activeCount;
2359 if (!foundAngle || (foundDone && activeCount & 1)) {
2360 if (nextSegment->tiny(nextAngle)) {
2361 unsortable = true;
2362 return NULL;
2363 }
2364 foundAngle = nextAngle;
2365 foundDone = nextSegment->done(nextAngle);
2366 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002367 }
2368 if (nextSegment->done()) {
2369 continue;
2370 }
2371 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
2372 continue;
2373 }
2374 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
2375 if (last) {
2376 *chase.append() = last;
2377#if DEBUG_WINDING
2378 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
2379 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2380#endif
2381 }
2382 } while (++nextIndex != lastIndex);
2383 markDoneUnary(SkMin32(startIndex, endIndex));
2384 if (!foundAngle) {
2385 return NULL;
2386 }
2387 nextStart = foundAngle->start();
2388 nextEnd = foundAngle->end();
2389 nextSegment = foundAngle->segment();
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002390 #if DEBUG_WINDING
2391 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2392 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2393 #endif
2394 return nextSegment;
2395 }
2396
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002397 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002398 const int startIndex = nextStart;
2399 const int endIndex = nextEnd;
2400 SkASSERT(startIndex != endIndex);
2401 int count = fTs.count();
2402 SkASSERT(startIndex < endIndex ? startIndex < count - 1
2403 : startIndex > 0);
2404 int step = SkSign32(endIndex - startIndex);
caryclark@google.coma461ff02012-10-11 12:54:23 +00002405 int end = nextExactSpan(startIndex, step);
caryclark@google.com24bec792012-08-20 12:43:57 +00002406 SkASSERT(end >= 0);
2407 Span* endSpan = &fTs[end];
2408 Segment* other;
caryclark@google.com24bec792012-08-20 12:43:57 +00002409 if (isSimple(end)) {
2410 #if DEBUG_WINDING
2411 SkDebugf("%s simple\n", __FUNCTION__);
2412 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002413 int min = SkMin32(startIndex, endIndex);
2414 if (fTs[min].fDone) {
2415 return NULL;
2416 }
2417 markDone(min, 1);
caryclark@google.com24bec792012-08-20 12:43:57 +00002418 other = endSpan->fOther;
2419 nextStart = endSpan->fOtherIndex;
2420 double startT = other->fTs[nextStart].fT;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002421 #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 +00002422 SkDEBUGCODE(bool firstLoop = true;)
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002423 if ((approximately_less_than_zero(startT) && step < 0)
2424 || (approximately_greater_than_one(startT) && step > 0)) {
caryclark@google.com24bec792012-08-20 12:43:57 +00002425 step = -step;
2426 SkDEBUGCODE(firstLoop = false;)
2427 }
2428 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002429 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002430 nextEnd = nextStart;
2431 do {
2432 nextEnd += step;
caryclark@google.coma461ff02012-10-11 12:54:23 +00002433 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00002434 while (precisely_zero(startT - other->fTs[nextEnd].fT));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002435 #if 01
caryclark@google.com24bec792012-08-20 12:43:57 +00002436 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
2437 break;
2438 }
caryclark@google.com03f97062012-08-21 13:13:52 +00002439 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00002440 SkASSERT(firstLoop);
caryclark@google.com03f97062012-08-21 13:13:52 +00002441 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002442 SkDEBUGCODE(firstLoop = false;)
2443 step = -step;
2444 } while (true);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002445 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002446 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
2447 return other;
2448 }
2449 SkTDArray<Angle> angles;
2450 SkASSERT(startIndex - endIndex != 0);
2451 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2452 addTwoAngles(startIndex, end, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002453 buildAngles(end, angles, false);
caryclark@google.com24bec792012-08-20 12:43:57 +00002454 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002455 bool sortable = SortAngles(angles, sorted);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002456 if (!sortable) {
2457 unsortable = true;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002458 #if DEBUG_SORT
2459 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
2460 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002461 return NULL;
2462 }
caryclark@google.com24bec792012-08-20 12:43:57 +00002463 int angleCount = angles.count();
2464 int firstIndex = findStartingEdge(sorted, startIndex, end);
2465 SkASSERT(firstIndex >= 0);
2466 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002467 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
caryclark@google.com24bec792012-08-20 12:43:57 +00002468 #endif
2469 SkASSERT(sorted[firstIndex]->segment() == this);
2470 int nextIndex = firstIndex + 1;
2471 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002472 const Angle* foundAngle = NULL;
2473 bool foundDone = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00002474 Segment* nextSegment;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002475 int activeCount = 0;
caryclark@google.com24bec792012-08-20 12:43:57 +00002476 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002477 SkASSERT(nextIndex != firstIndex);
caryclark@google.com24bec792012-08-20 12:43:57 +00002478 if (nextIndex == angleCount) {
2479 nextIndex = 0;
2480 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002481 const Angle* nextAngle = sorted[nextIndex];
caryclark@google.com24bec792012-08-20 12:43:57 +00002482 nextSegment = nextAngle->segment();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002483 ++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 }
2492 if (nextSegment->done()) {
2493 continue;
caryclark@google.com24bec792012-08-20 12:43:57 +00002494 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002495 } while (++nextIndex != lastIndex);
2496 markDone(SkMin32(startIndex, endIndex), 1);
2497 if (!foundAngle) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002498 return NULL;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002499 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002500 nextStart = foundAngle->start();
2501 nextEnd = foundAngle->end();
2502 nextSegment = foundAngle->segment();
2503 #if DEBUG_WINDING
2504 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2505 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd);
2506 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00002507 return nextSegment;
2508 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002509
2510 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
2511 int angleCount = sorted.count();
2512 int firstIndex = -1;
2513 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2514 const Angle* angle = sorted[angleIndex];
2515 if (angle->segment() == this && angle->start() == end &&
2516 angle->end() == start) {
2517 firstIndex = angleIndex;
2518 break;
2519 }
2520 }
2521 return firstIndex;
2522 }
2523
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002524 // FIXME: this is tricky code; needs its own unit test
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002525 // note that fOtherIndex isn't computed yet, so it can't be used here
caryclark@google.com4eeda372012-12-06 21:47:48 +00002526 void findTooCloseToCall() {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002527 int count = fTs.count();
2528 if (count < 3) { // require t=0, x, 1 at minimum
2529 return;
2530 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002531 int matchIndex = 0;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002532 int moCount;
2533 Span* match;
2534 Segment* mOther;
2535 do {
2536 match = &fTs[matchIndex];
2537 mOther = match->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002538 // FIXME: allow quads, cubics to be near coincident?
2539 if (mOther->fVerb == SkPath::kLine_Verb) {
2540 moCount = mOther->fTs.count();
2541 if (moCount >= 3) {
2542 break;
2543 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002544 }
2545 if (++matchIndex >= count) {
2546 return;
2547 }
2548 } while (true); // require t=0, x, 1 at minimum
caryclark@google.com15fa1382012-05-07 20:49:36 +00002549 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002550 const SkPoint* matchPt = &xyAtT(match);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002551 // look for a pair of nearby T values that map to the same (x,y) value
2552 // if found, see if the pair of other segments share a common point. If
2553 // so, the span from here to there is coincident.
caryclark@google.com15fa1382012-05-07 20:49:36 +00002554 for (int index = matchIndex + 1; index < count; ++index) {
2555 Span* test = &fTs[index];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002556 if (test->fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002557 continue;
2558 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002559 Segment* tOther = test->fOther;
caryclark@google.comc899ad92012-08-23 15:24:42 +00002560 if (tOther->fVerb != SkPath::kLine_Verb) {
2561 continue; // FIXME: allow quads, cubics to be near coincident?
2562 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002563 int toCount = tOther->fTs.count();
2564 if (toCount < 3) { // require t=0, x, 1 at minimum
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002565 continue;
2566 }
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002567 const SkPoint* testPt = &xyAtT(test);
2568 if (*matchPt != *testPt) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002569 matchIndex = index;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002570 moCount = toCount;
2571 match = test;
2572 mOther = tOther;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002573 matchPt = testPt;
2574 continue;
2575 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002576 int moStart = -1;
2577 int moEnd = -1;
2578 double moStartT, moEndT;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002579 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002580 Span& moSpan = mOther->fTs[moIndex];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002581 if (moSpan.fDone) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002582 continue;
2583 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00002584 if (moSpan.fOther == this) {
2585 if (moSpan.fOtherT == match->fT) {
2586 moStart = moIndex;
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002587 moStartT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002588 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002589 continue;
2590 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002591 if (moSpan.fOther == tOther) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002592 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002593 moStart = -1;
2594 break;
2595 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002596 SkASSERT(moEnd == -1);
2597 moEnd = moIndex;
2598 moEndT = moSpan.fT;
caryclark@google.com15fa1382012-05-07 20:49:36 +00002599 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002600 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002601 if (moStart < 0 || moEnd < 0) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002602 continue;
2603 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002604 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002605 if (approximately_equal(moStartT, moEndT)) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002606 continue;
2607 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002608 int toStart = -1;
2609 int toEnd = -1;
2610 double toStartT, toEndT;
2611 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
2612 Span& toSpan = tOther->fTs[toIndex];
caryclark@google.comc899ad92012-08-23 15:24:42 +00002613 if (toSpan.fDone) {
2614 continue;
2615 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002616 if (toSpan.fOther == this) {
2617 if (toSpan.fOtherT == test->fT) {
2618 toStart = toIndex;
2619 toStartT = toSpan.fT;
2620 }
2621 continue;
2622 }
2623 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002624 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
caryclark@google.comc899ad92012-08-23 15:24:42 +00002625 moStart = -1;
2626 break;
2627 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002628 SkASSERT(toEnd == -1);
2629 toEnd = toIndex;
2630 toEndT = toSpan.fT;
2631 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002632 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002633 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
2634 if (toStart <= 0 || toEnd <= 0) {
2635 continue;
2636 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002637 if (approximately_equal(toStartT, toEndT)) {
caryclark@google.com1577e8f2012-05-22 17:01:14 +00002638 continue;
2639 }
2640 // test to see if the segment between there and here is linear
2641 if (!mOther->isLinear(moStart, moEnd)
2642 || !tOther->isLinear(toStart, toEnd)) {
2643 continue;
2644 }
caryclark@google.comc899ad92012-08-23 15:24:42 +00002645 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002646 if (flipped) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002647 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002648 } else {
caryclark@google.com4eeda372012-12-06 21:47:48 +00002649 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002650 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002651 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002652 }
2653
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002654 // start here;
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00002655 // either:
caryclark@google.comc91dfe42012-10-16 12:06:27 +00002656 // a) mark spans with either end unsortable as done, or
2657 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2658 // when encountering an unsortable span
2659
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002660 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2661 // and use more concise logic like the old edge walker code?
2662 // FIXME: this needs to deal with coincident edges
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002663 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002664 // iterate through T intersections and return topmost
2665 // topmost tangent from y-min to first pt is closer to horizontal
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002666 SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002667 int firstT = -1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002668 SkPoint topPt;
2669 topPt.fY = SK_ScalarMax;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002670 int count = fTs.count();
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002671 // see if either end is not done since we want smaller Y of the pair
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002672 bool lastDone = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002673 bool lastUnsortable = false;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002674 for (int index = 0; index < count; ++index) {
caryclark@google.com15fa1382012-05-07 20:49:36 +00002675 const Span& span = fTs[index];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002676 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00002677 goto next;
2678 }
2679 if (!span.fDone | !lastDone) {
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002680 const SkPoint& intercept = xyAtT(&span);
2681 if (topPt.fY > intercept.fY || (topPt.fY == intercept.fY
2682 && topPt.fX > intercept.fX)) {
2683 topPt = intercept;
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002684 firstT = index;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002685 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002686 }
caryclark@google.comf839c032012-10-26 21:03:50 +00002687 next:
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002688 lastDone = span.fDone;
caryclark@google.comf839c032012-10-26 21:03:50 +00002689 lastUnsortable = span.fUnsortableEnd;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002690 }
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00002691 SkASSERT(firstT >= 0);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002692 // sort the edges to find the leftmost
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002693 int step = 1;
2694 int end = nextSpan(firstT, step);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002695 if (end == -1) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002696 step = -1;
2697 end = nextSpan(firstT, step);
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00002698 SkASSERT(end != -1);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002699 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002700 // if the topmost T is not on end, or is three-way or more, find left
2701 // look for left-ness from tLeft to firstT (matching y of other)
2702 SkTDArray<Angle> angles;
2703 SkASSERT(firstT - end != 0);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002704 addTwoAngles(end, firstT, angles);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002705 buildAngles(firstT, angles, true);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002706 SkTDArray<Angle*> sorted;
caryclark@google.comf839c032012-10-26 21:03:50 +00002707 bool sortable = SortAngles(angles, sorted);
caryclark@google.com03f97062012-08-21 13:13:52 +00002708 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00002709 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00002710 #endif
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002711 if (onlySortable && !sortable) {
2712 unsortable = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00002713 return NULL;
2714 }
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002715 // skip edges that have already been processed
2716 firstT = -1;
2717 Segment* leftSegment;
2718 do {
2719 const Angle* angle = sorted[++firstT];
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002720 SkASSERT(!onlySortable || !angle->unsortable());
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00002721 leftSegment = angle->segment();
2722 tIndex = angle->end();
2723 endIndex = angle->start();
2724 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002725 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002726 return leftSegment;
2727 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002728
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002729 // FIXME: not crazy about this
2730 // when the intersections are performed, the other index is into an
2731 // incomplete array. as the array grows, the indices become incorrect
2732 // while the following fixes the indices up again, it isn't smart about
2733 // skipping segments whose indices are already correct
2734 // assuming we leave the code that wrote the index in the first place
2735 void fixOtherTIndex() {
2736 int iCount = fTs.count();
2737 for (int i = 0; i < iCount; ++i) {
2738 Span& iSpan = fTs[i];
2739 double oT = iSpan.fOtherT;
2740 Segment* other = iSpan.fOther;
2741 int oCount = other->fTs.count();
2742 for (int o = 0; o < oCount; ++o) {
2743 Span& oSpan = other->fTs[o];
2744 if (oT == oSpan.fT && this == oSpan.fOther) {
2745 iSpan.fOtherIndex = o;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002746 break;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002747 }
2748 }
2749 }
2750 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002751
caryclark@google.com4eeda372012-12-06 21:47:48 +00002752 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
caryclark@google.com235f56a2012-09-14 14:19:30 +00002753 fDoneSpans = 0;
2754 fOperand = operand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00002755 fXor = evenOdd;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002756 fPts = pts;
2757 fVerb = verb;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00002758 }
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00002759
caryclark@google.com3586ece2012-12-27 18:46:58 +00002760 void initWinding(int start, int end) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002761 int local = spanSign(start, end);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002762 int oppLocal = oppSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002763 (void) markAndChaseWinding(start, end, local, oppLocal);
caryclark@google.com73ca6242013-01-17 21:02:47 +00002764 // OPTIMIZATION: the reverse mark and chase could skip the first marking
2765 (void) markAndChaseWinding(end, start, local, oppLocal);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002766 }
2767
caryclark@google.com3586ece2012-12-27 18:46:58 +00002768 void initWinding(int start, int end, int winding, int oppWinding) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002769 int local = spanSign(start, end);
caryclark@google.com3586ece2012-12-27 18:46:58 +00002770 if (local * winding >= 0) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002771 winding += local;
2772 }
2773 int oppLocal = oppSign(start, end);
2774 if (oppLocal * oppWinding >= 0) {
2775 oppWinding += oppLocal;
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002776 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002777 (void) markAndChaseWinding(start, end, winding, oppWinding);
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002778 }
2779
caryclark@google.com3586ece2012-12-27 18:46:58 +00002780/*
2781when we start with a vertical intersect, we try to use the dx to determine if the edge is to
2782the 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 +00002783sign or not. However, this isn't enough.
2784If 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 +00002785If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
2786from 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 +00002787the same winding is shared by both.
caryclark@google.com3586ece2012-12-27 18:46:58 +00002788*/
2789 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
2790 SkScalar hitOppDx) {
2791 SkASSERT(hitDx || !winding);
2792 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
2793 SkASSERT(dx);
2794 int windVal = windValue(SkMin32(start, end));
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002795 #if DEBUG_WINDING_AT_T
2796 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
2797 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
2798 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002799 if (!winding) {
2800 winding = dx < 0 ? windVal : -windVal;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002801 } else if (winding * dx < 0) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00002802 int sideWind = winding + (dx < 0 ? windVal : -windVal);
2803 if (abs(winding) < abs(sideWind)) {
2804 winding = sideWind;
2805 }
2806 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00002807 #if DEBUG_WINDING_AT_T
2808 SkDebugf(" winding=%d\n", winding);
2809 #endif
caryclark@google.com3586ece2012-12-27 18:46:58 +00002810 int oppLocal = oppSign(start, end);
2811 SkASSERT(hitOppDx || !oppWind || !oppLocal);
2812 int oppWindVal = oppValue(SkMin32(start, end));
2813 if (!oppWind) {
2814 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
2815 } else if (hitOppDx * dx >= 0) {
2816 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
2817 if (abs(oppWind) < abs(oppSideWind)) {
2818 oppWind = oppSideWind;
2819 }
2820 }
2821 (void) markAndChaseWinding(start, end, winding, oppWind);
2822 }
2823
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002824 bool intersected() const {
2825 return fTs.count() > 0;
2826 }
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002827
caryclark@google.com10227bf2012-12-28 22:10:41 +00002828 bool isCanceled(int tIndex) const {
2829 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
2830 }
2831
caryclark@google.com7db7c6b2012-07-27 21:22:25 +00002832 bool isConnected(int startIndex, int endIndex) const {
2833 return fTs[startIndex].fWindSum != SK_MinS32
2834 || fTs[endIndex].fWindSum != SK_MinS32;
2835 }
2836
caryclark@google.com235f56a2012-09-14 14:19:30 +00002837 bool isHorizontal() const {
2838 return fBounds.fTop == fBounds.fBottom;
2839 }
2840
caryclark@google.com15fa1382012-05-07 20:49:36 +00002841 bool isLinear(int start, int end) const {
2842 if (fVerb == SkPath::kLine_Verb) {
2843 return true;
2844 }
2845 if (fVerb == SkPath::kQuad_Verb) {
2846 SkPoint qPart[3];
2847 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart);
2848 return QuadIsLinear(qPart);
2849 } else {
2850 SkASSERT(fVerb == SkPath::kCubic_Verb);
2851 SkPoint cPart[4];
2852 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart);
2853 return CubicIsLinear(cPart);
2854 }
2855 }
caryclark@google.comb9738012012-07-03 19:53:30 +00002856
2857 // OPTIMIZE: successive calls could start were the last leaves off
2858 // or calls could specialize to walk forwards or backwards
2859 bool isMissing(double startT) const {
2860 size_t tCount = fTs.count();
2861 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002862 if (approximately_zero(startT - fTs[index].fT)) {
caryclark@google.comb9738012012-07-03 19:53:30 +00002863 return false;
2864 }
2865 }
2866 return true;
2867 }
2868
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002869 bool isSimple(int end) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002870 int count = fTs.count();
2871 if (count == 2) {
2872 return true;
2873 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002874 double t = fTs[end].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002875 if (approximately_less_than_zero(t)) {
2876 return !approximately_less_than_zero(fTs[1].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002877 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00002878 if (approximately_greater_than_one(t)) {
2879 return !approximately_greater_than_one(fTs[count - 2].fT);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002880 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002881 return false;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00002882 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002883
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002884 bool isVertical() const {
2885 return fBounds.fLeft == fBounds.fRight;
2886 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00002887
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002888 bool isVertical(int start, int end) const {
2889 return (*SegmentVertical[fVerb])(fPts, start, end);
2890 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00002891
caryclark@google.comfa0588f2012-04-26 21:01:06 +00002892 SkScalar leftMost(int start, int end) const {
2893 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
2894 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002895
caryclark@google.com495f8e42012-05-31 13:13:11 +00002896 // this span is excluded by the winding rule -- chase the ends
2897 // as long as they are unambiguous to mark connections as done
2898 // and give them the same winding value
caryclark@google.com59823f72012-08-09 18:17:47 +00002899 Span* markAndChaseDone(const Angle* angle, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002900 int index = angle->start();
2901 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00002902 return markAndChaseDone(index, endIndex, winding);
2903 }
2904
caryclark@google.com31143cf2012-11-09 22:14:19 +00002905 Span* markAndChaseDone(int index, int endIndex, int winding) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00002906 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002907 int min = SkMin32(index, endIndex);
2908 markDone(min, winding);
2909 Span* last;
2910 Segment* other = this;
2911 while ((other = other->nextChase(index, step, min, last))) {
2912 other->markDone(min, winding);
2913 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002914 return last;
caryclark@google.com495f8e42012-05-31 13:13:11 +00002915 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00002916
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002917 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) {
2918 int index = angle->start();
2919 int endIndex = angle->end();
caryclark@google.com31143cf2012-11-09 22:14:19 +00002920 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002921 int min = SkMin32(index, endIndex);
2922 markDoneBinary(min, winding, oppWinding);
2923 Span* last;
2924 Segment* other = this;
2925 while ((other = other->nextChase(index, step, min, last))) {
2926 other->markDoneBinary(min, winding, oppWinding);
2927 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002928 return last;
2929 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002930
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002931 Span* markAndChaseDoneBinary(int index, int endIndex) {
2932 int step = SkSign32(endIndex - index);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002933 int min = SkMin32(index, endIndex);
2934 markDoneBinary(min);
2935 Span* last;
2936 Segment* other = this;
2937 while ((other = other->nextChase(index, step, min, last))) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00002938 if (other->done()) {
2939 return NULL;
2940 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00002941 other->markDoneBinary(min);
2942 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00002943 return last;
2944 }
2945
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00002946 Span* markAndChaseDoneUnary(int index, int endIndex) {
2947 int step = SkSign32(endIndex - index);
2948 int min = SkMin32(index, endIndex);
2949 markDoneUnary(min);
2950 Span* last;
2951 Segment* other = this;
2952 while ((other = other->nextChase(index, step, min, last))) {
2953 if (other->done()) {
2954 return NULL;
2955 }
2956 other->markDoneUnary(min);
2957 }
2958 return last;
2959 }
2960
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00002961 Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
2962 int index = angle->start();
2963 int endIndex = angle->end();
2964 return markAndChaseDone(index, endIndex, winding);
2965 }
2966
caryclark@google.com4eeda372012-12-06 21:47:48 +00002967 Span* markAndChaseWinding(const Angle* angle, const int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002968 int index = angle->start();
2969 int endIndex = angle->end();
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00002970 int step = SkSign32(endIndex - index);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002971 int min = SkMin32(index, endIndex);
caryclark@google.com59823f72012-08-09 18:17:47 +00002972 markWinding(min, winding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002973 Span* last;
2974 Segment* other = this;
2975 while ((other = other->nextChase(index, step, min, last))) {
2976 if (other->fTs[min].fWindSum != SK_MinS32) {
2977 SkASSERT(other->fTs[min].fWindSum == winding);
2978 return NULL;
2979 }
2980 other->markWinding(min, winding);
2981 }
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00002982 return last;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00002983 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00002984
caryclark@google.com7fce0de2012-11-29 14:31:50 +00002985 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00002986 int min = SkMin32(index, endIndex);
2987 int step = SkSign32(endIndex - index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00002988 markWinding(min, winding, oppWinding);
caryclark@google.com4eeda372012-12-06 21:47:48 +00002989 Span* last;
2990 Segment* other = this;
2991 while ((other = other->nextChase(index, step, min, last))) {
2992 if (other->fTs[min].fWindSum != SK_MinS32) {
2993 SkASSERT(other->fTs[min].fWindSum == winding);
2994 return NULL;
2995 }
2996 other->markWinding(min, winding, oppWinding);
2997 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00002998 return last;
2999 }
3000
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003001 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
3002 int start = angle->start();
3003 int end = angle->end();
3004 return markAndChaseWinding(start, end, winding, oppWinding);
3005 }
3006
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003007 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) {
3008 SkASSERT(angle->segment() == this);
3009 if (useInnerWinding(maxWinding, sumWinding)) {
3010 maxWinding = sumWinding;
3011 }
3012 Span* last;
3013 if (activeAngle) {
3014 last = markAndChaseWinding(angle, maxWinding);
3015 } else {
3016 last = markAndChaseDoneUnary(angle, maxWinding);
3017 }
3018 return last;
3019 }
3020
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003021 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
3022 bool activeAngle, const Angle* angle) {
3023 SkASSERT(angle->segment() == this);
3024 if (useInnerWinding(maxWinding, sumWinding)) {
3025 maxWinding = sumWinding;
3026 }
3027 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) {
3028 oppMaxWinding = oppSumWinding;
3029 }
3030 Span* last;
3031 if (activeAngle) {
3032 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3033 } else {
3034 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
3035 }
3036 return last;
3037 }
3038
caryclark@google.com495f8e42012-05-31 13:13:11 +00003039 // FIXME: this should also mark spans with equal (x,y)
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003040 // This may be called when the segment is already marked done. While this
3041 // wastes time, it shouldn't do any more than spin through the T spans.
rmistry@google.comd6176b02012-08-23 18:14:13 +00003042 // OPTIMIZATION: abort on first done found (assuming that this code is
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003043 // always called to mark segments done).
caryclark@google.com59823f72012-08-09 18:17:47 +00003044 void markDone(int index, int winding) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003045 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003046 SkASSERT(winding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003047 double referenceT = fTs[index].fT;
3048 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003049 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3050 markOneDone(__FUNCTION__, lesser, winding);
3051 }
3052 do {
3053 markOneDone(__FUNCTION__, index, winding);
3054 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003055 }
3056
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003057 void markDoneBinary(int index, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003058 // SkASSERT(!done());
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003059 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003060 double referenceT = fTs[index].fT;
3061 int lesser = index;
3062 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003063 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003064 }
3065 do {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003066 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
3067 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3068 }
3069
3070 void markDoneBinary(int index) {
3071 double referenceT = fTs[index].fT;
3072 int lesser = index;
3073 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3074 markOneDoneBinary(__FUNCTION__, lesser);
3075 }
3076 do {
3077 markOneDoneBinary(__FUNCTION__, index);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003078 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003079 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00003080
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003081 void markDoneUnary(int index, int winding) {
3082 // SkASSERT(!done());
3083 SkASSERT(winding);
3084 double referenceT = fTs[index].fT;
3085 int lesser = index;
3086 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3087 markOneDoneUnary(__FUNCTION__, lesser, winding);
3088 }
3089 do {
3090 markOneDoneUnary(__FUNCTION__, index, winding);
3091 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3092 }
3093
3094 void markDoneUnary(int index) {
3095 double referenceT = fTs[index].fT;
3096 int lesser = index;
3097 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3098 markOneDoneUnary(__FUNCTION__, lesser);
3099 }
3100 do {
3101 markOneDoneUnary(__FUNCTION__, index);
3102 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3103 }
3104
caryclark@google.com24bec792012-08-20 12:43:57 +00003105 void markOneDone(const char* funName, int tIndex, int winding) {
3106 Span* span = markOneWinding(funName, tIndex, winding);
3107 if (!span) {
3108 return;
3109 }
3110 span->fDone = true;
3111 fDoneSpans++;
3112 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003113
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003114 void markOneDoneBinary(const char* funName, int tIndex) {
3115 Span* span = verifyOneWinding(funName, tIndex);
3116 if (!span) {
3117 return;
3118 }
3119 span->fDone = true;
3120 fDoneSpans++;
3121 }
3122
3123 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003124 Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
3125 if (!span) {
3126 return;
3127 }
3128 span->fDone = true;
3129 fDoneSpans++;
3130 }
3131
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003132 void markOneDoneUnary(const char* funName, int tIndex) {
3133 Span* span = verifyOneWindingU(funName, tIndex);
3134 if (!span) {
3135 return;
3136 }
3137 span->fDone = true;
3138 fDoneSpans++;
3139 }
3140
3141 void markOneDoneUnary(const char* funName, int tIndex, int winding) {
3142 Span* span = markOneWinding(funName, tIndex, winding);
3143 if (!span) {
3144 return;
3145 }
3146 span->fDone = true;
3147 fDoneSpans++;
3148 }
3149
caryclark@google.com24bec792012-08-20 12:43:57 +00003150 Span* markOneWinding(const char* funName, int tIndex, int winding) {
3151 Span& span = fTs[tIndex];
3152 if (span.fDone) {
3153 return NULL;
3154 }
3155 #if DEBUG_MARK_DONE
3156 debugShowNewWinding(funName, span, winding);
3157 #endif
3158 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com03f97062012-08-21 13:13:52 +00003159 #ifdef SK_DEBUG
caryclark@google.com24bec792012-08-20 12:43:57 +00003160 SkASSERT(abs(winding) <= gDebugMaxWindSum);
caryclark@google.com03f97062012-08-21 13:13:52 +00003161 #endif
caryclark@google.com24bec792012-08-20 12:43:57 +00003162 span.fWindSum = winding;
3163 return &span;
3164 }
skia.committer@gmail.com24c29d92012-10-20 02:01:23 +00003165
caryclark@google.com31143cf2012-11-09 22:14:19 +00003166 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
3167 Span& span = fTs[tIndex];
3168 if (span.fDone) {
3169 return NULL;
3170 }
3171 #if DEBUG_MARK_DONE
3172 debugShowNewWinding(funName, span, winding, oppWinding);
3173 #endif
3174 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3175 #ifdef SK_DEBUG
3176 SkASSERT(abs(winding) <= gDebugMaxWindSum);
3177 #endif
3178 span.fWindSum = winding;
3179 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3180 #ifdef SK_DEBUG
3181 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
3182 #endif
3183 span.fOppSum = oppWinding;
3184 return &span;
3185 }
3186
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003187 Span* verifyOneWinding(const char* funName, int tIndex) {
3188 Span& span = fTs[tIndex];
3189 if (span.fDone) {
3190 return NULL;
3191 }
3192 #if DEBUG_MARK_DONE
3193 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3194 #endif
3195 SkASSERT(span.fWindSum != SK_MinS32);
3196 SkASSERT(span.fOppSum != SK_MinS32);
3197 return &span;
3198 }
3199
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003200 Span* verifyOneWindingU(const char* funName, int tIndex) {
3201 Span& span = fTs[tIndex];
3202 if (span.fDone) {
3203 return NULL;
3204 }
3205 #if DEBUG_MARK_DONE
3206 debugShowNewWinding(funName, span, span.fWindSum);
3207 #endif
3208 SkASSERT(span.fWindSum != SK_MinS32);
3209 return &span;
3210 }
3211
caryclark@google.comf839c032012-10-26 21:03:50 +00003212 // note that just because a span has one end that is unsortable, that's
3213 // not enough to mark it done. The other end may be sortable, allowing the
3214 // span to be added.
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003215 // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003216 void markUnsortable(int start, int end) {
3217 Span* span = &fTs[start];
3218 if (start < end) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003219#if DEBUG_UNSORTABLE
3220 SkDebugf("%s start id=%d [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fID, start,
3221 xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003222#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003223 span->fUnsortableStart = true;
3224 } else {
3225 --span;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003226#if DEBUG_UNSORTABLE
3227 SkDebugf("%s end id=%d [%d] (%1.9g,%1.9g) next:(%1.9g,%1.9g)\n", __FUNCTION__, fID,
3228 start - 1, xAtT(start - 1), yAtT(start - 1), xAtT(start), yAtT(start));
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00003229#endif
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003230 span->fUnsortableEnd = true;
3231 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003232 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003233 return;
3234 }
3235 span->fDone = true;
3236 fDoneSpans++;
3237 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003238
caryclark@google.com59823f72012-08-09 18:17:47 +00003239 void markWinding(int index, int winding) {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003240 // SkASSERT(!done());
caryclark@google.com24bec792012-08-20 12:43:57 +00003241 SkASSERT(winding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003242 double referenceT = fTs[index].fT;
3243 int lesser = index;
caryclark@google.coma461ff02012-10-11 12:54:23 +00003244 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3245 markOneWinding(__FUNCTION__, lesser, winding);
3246 }
3247 do {
3248 markOneWinding(__FUNCTION__, index, winding);
3249 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com31143cf2012-11-09 22:14:19 +00003250 }
3251
3252 void markWinding(int index, int winding, int oppWinding) {
3253 // SkASSERT(!done());
caryclark@google.com4eeda372012-12-06 21:47:48 +00003254 SkASSERT(winding || oppWinding);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003255 double referenceT = fTs[index].fT;
3256 int lesser = index;
3257 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3258 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003259 }
3260 do {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003261 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3262 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
caryclark@google.comaf46cff2012-05-22 21:12:00 +00003263 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003264
caryclark@google.com2ddff932012-08-07 21:25:27 +00003265 void matchWindingValue(int tIndex, double t, bool borrowWind) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003266 int nextDoorWind = SK_MaxS32;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003267 int nextOppWind = SK_MaxS32;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003268 if (tIndex > 0) {
3269 const Span& below = fTs[tIndex - 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003270 if (approximately_negative(t - below.fT)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003271 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003272 nextOppWind = below.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003273 }
3274 }
3275 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3276 const Span& above = fTs[tIndex + 1];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003277 if (approximately_negative(above.fT - t)) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003278 nextDoorWind = above.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003279 nextOppWind = above.fOppValue;
caryclark@google.com0c803d02012-08-06 11:15:47 +00003280 }
3281 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00003282 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3283 const Span& below = fTs[tIndex - 1];
3284 nextDoorWind = below.fWindValue;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003285 nextOppWind = below.fOppValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003286 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003287 if (nextDoorWind != SK_MaxS32) {
3288 Span& newSpan = fTs[tIndex];
3289 newSpan.fWindValue = nextDoorWind;
caryclark@google.com7ba591e2012-11-20 14:21:54 +00003290 newSpan.fOppValue = nextOppWind;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003291 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
caryclark@google.com0c803d02012-08-06 11:15:47 +00003292 newSpan.fDone = true;
3293 ++fDoneSpans;
3294 }
3295 }
3296 }
3297
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003298 bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
3299 // find bounds
3300 Bounds bounds;
3301 bounds.setPoint(xyAtT(index));
3302 bounds.add(xyAtT(endIndex));
3303 SkScalar width = bounds.width();
3304 SkScalar height = bounds.height();
3305 if (width > height) {
3306 if (approximately_negative(width)) {
3307 unsortable = true; // edge is too small to resolve meaningfully
3308 }
3309 return false;
3310 } else {
3311 if (approximately_negative(height)) {
3312 unsortable = true; // edge is too small to resolve meaningfully
3313 }
3314 return true;
3315 }
3316 }
3317
caryclark@google.com9764cc62012-07-12 19:29:45 +00003318 // return span if when chasing, two or more radiating spans are not done
3319 // OPTIMIZATION: ? multiple spans is detected when there is only one valid
3320 // candidate and the remaining spans have windValue == 0 (canceled by
3321 // coincidence). The coincident edges could either be removed altogether,
3322 // or this code could be more complicated in detecting this case. Worth it?
3323 bool multipleSpans(int end) const {
3324 return end > 0 && end < fTs.count() - 1;
caryclark@google.com88f7d0c2012-06-07 21:09:20 +00003325 }
3326
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003327 bool nextCandidate(int& start, int& end) const {
caryclark@google.com10227bf2012-12-28 22:10:41 +00003328 while (fTs[end].fDone) {
3329 if (fTs[end].fT == 1) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003330 return false;
3331 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00003332 ++end;
3333 }
3334 start = end;
3335 end = nextExactSpan(start, 1);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003336 return true;
3337 }
3338
caryclark@google.com4eeda372012-12-06 21:47:48 +00003339 Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
3340 int end = nextExactSpan(index, step);
3341 SkASSERT(end >= 0);
3342 if (multipleSpans(end)) {
3343 last = &fTs[end];
3344 return NULL;
3345 }
3346 const Span& endSpan = fTs[end];
3347 Segment* other = endSpan.fOther;
3348 index = endSpan.fOtherIndex;
caryclark@google.comaa358312013-01-29 20:28:49 +00003349 SkASSERT(index >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003350 int otherEnd = other->nextExactSpan(index, step);
caryclark@google.comaa358312013-01-29 20:28:49 +00003351 SkASSERT(otherEnd >= 0);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003352 min = SkMin32(index, otherEnd);
3353 return other;
3354 }
3355
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003356 // This has callers for two different situations: one establishes the end
3357 // of the current span, and one establishes the beginning of the next span
3358 // (thus the name). When this is looking for the end of the current span,
3359 // coincidence is found when the beginning Ts contain -step and the end
3360 // contains step. When it is looking for the beginning of the next, the
3361 // first Ts found can be ignored and the last Ts should contain -step.
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003362 // OPTIMIZATION: probably should split into two functions
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003363 int nextSpan(int from, int step) const {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003364 const Span& fromSpan = fTs[from];
caryclark@google.com495f8e42012-05-31 13:13:11 +00003365 int count = fTs.count();
3366 int to = from;
caryclark@google.com495f8e42012-05-31 13:13:11 +00003367 while (step > 0 ? ++to < count : --to >= 0) {
3368 const Span& span = fTs[to];
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003369 if (approximately_zero(span.fT - fromSpan.fT)) {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003370 continue;
3371 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003372 return to;
3373 }
3374 return -1;
3375 }
skia.committer@gmail.com439cb512012-10-10 02:01:30 +00003376
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003377 // FIXME
3378 // this returns at any difference in T, vs. a preset minimum. It may be
3379 // that all callers to nextSpan should use this instead.
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003380 // OPTIMIZATION splitting this into separate loops for up/down steps
3381 // would allow using precisely_negative instead of precisely_zero
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003382 int nextExactSpan(int from, int step) const {
3383 const Span& fromSpan = fTs[from];
3384 int count = fTs.count();
3385 int to = from;
3386 while (step > 0 ? ++to < count : --to >= 0) {
3387 const Span& span = fTs[to];
caryclark@google.coma461ff02012-10-11 12:54:23 +00003388 if (precisely_zero(span.fT - fromSpan.fT)) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003389 continue;
3390 }
3391 return to;
3392 }
3393 return -1;
3394 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003395
caryclark@google.com235f56a2012-09-14 14:19:30 +00003396 bool operand() const {
3397 return fOperand;
3398 }
3399
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003400 int oppSign(const Angle* angle) const {
3401 SkASSERT(angle->segment() == this);
3402 return oppSign(angle->start(), angle->end());
3403 }
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00003404
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003405 int oppSign(int startIndex, int endIndex) const {
3406 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue
3407 : fTs[endIndex].fOppValue;
3408#if DEBUG_WIND_BUMP
3409 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
3410#endif
3411 return result;
3412 }
3413
caryclark@google.com31143cf2012-11-09 22:14:19 +00003414 int oppSum(int tIndex) const {
3415 return fTs[tIndex].fOppSum;
3416 }
3417
3418 int oppSum(const Angle* angle) const {
3419 int lesser = SkMin32(angle->start(), angle->end());
3420 return fTs[lesser].fOppSum;
caryclark@google.com235f56a2012-09-14 14:19:30 +00003421 }
caryclark@google.com495f8e42012-05-31 13:13:11 +00003422
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003423 int oppValue(int tIndex) const {
3424 return fTs[tIndex].fOppValue;
3425 }
3426
caryclark@google.come7bd5f42012-12-13 19:47:53 +00003427 int oppValue(const Angle* angle) const {
3428 int lesser = SkMin32(angle->start(), angle->end());
3429 return fTs[lesser].fOppValue;
3430 }
3431
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003432 const SkPoint* pts() const {
3433 return fPts;
3434 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003435
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003436 void reset() {
caryclark@google.com4eeda372012-12-06 21:47:48 +00003437 init(NULL, (SkPath::Verb) -1, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003438 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
3439 fTs.reset();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003440 }
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +00003441
caryclark@google.com4eeda372012-12-06 21:47:48 +00003442 void setOppXor(bool isOppXor) {
3443 fOppXor = isOppXor;
3444 }
3445
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003446 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
3447 int deltaSum = spanSign(index, endIndex);
3448 maxWinding = sumWinding;
3449 sumWinding = sumWinding -= deltaSum;
3450 }
3451
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003452 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
3453 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) {
3454 int deltaSum = spanSign(index, endIndex);
3455 int oppDeltaSum = oppSign(index, endIndex);
3456 if (operand()) {
3457 maxWinding = sumSuWinding;
3458 sumWinding = sumSuWinding -= deltaSum;
3459 oppMaxWinding = sumMiWinding;
3460 oppSumWinding = sumMiWinding -= oppDeltaSum;
3461 } else {
3462 maxWinding = sumMiWinding;
3463 sumWinding = sumMiWinding -= deltaSum;
3464 oppMaxWinding = sumSuWinding;
3465 oppSumWinding = sumSuWinding -= oppDeltaSum;
3466 }
3467 }
3468
caryclark@google.comf839c032012-10-26 21:03:50 +00003469 // This marks all spans unsortable so that this info is available for early
3470 // exclusion in find top and others. This could be optimized to only mark
3471 // adjacent spans that unsortable. However, this makes it difficult to later
3472 // determine starting points for edge detection in find top and the like.
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003473 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
caryclark@google.comf839c032012-10-26 21:03:50 +00003474 bool sortable = true;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003475 int angleCount = angles.count();
3476 int angleIndex;
3477 angleList.setReserve(angleCount);
3478 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003479 Angle& angle = angles[angleIndex];
caryclark@google.comf839c032012-10-26 21:03:50 +00003480 *angleList.append() = &angle;
3481 sortable &= !angle.unsortable();
3482 }
3483 if (sortable) {
3484 QSort<Angle>(angleList.begin(), angleList.end() - 1);
3485 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3486 if (angles[angleIndex].unsortable()) {
3487 sortable = false;
3488 break;
3489 }
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003490 }
3491 }
caryclark@google.comf839c032012-10-26 21:03:50 +00003492 if (!sortable) {
3493 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
3494 Angle& angle = angles[angleIndex];
3495 angle.segment()->markUnsortable(angle.start(), angle.end());
3496 }
3497 }
3498 return sortable;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00003499 }
3500
caryclark@google.com1577e8f2012-05-22 17:01:14 +00003501 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003502 const Span& span(int tIndex) const {
3503 return fTs[tIndex];
3504 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003505
caryclark@google.com235f56a2012-09-14 14:19:30 +00003506 int spanSign(const Angle* angle) const {
3507 SkASSERT(angle->segment() == this);
3508 return spanSign(angle->start(), angle->end());
3509 }
3510
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003511 int spanSign(int startIndex, int endIndex) const {
caryclark@google.com31143cf2012-11-09 22:14:19 +00003512 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
3513 : fTs[endIndex].fWindValue;
caryclark@google.com2ddff932012-08-07 21:25:27 +00003514#if DEBUG_WIND_BUMP
3515 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
3516#endif
3517 return result;
3518 }
3519
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003520 // OPTIMIZATION: mark as debugging only if used solely by tests
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003521 double t(int tIndex) const {
3522 return fTs[tIndex].fT;
3523 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003524
caryclark@google.com10227bf2012-12-28 22:10:41 +00003525 double tAtMid(int start, int end, double mid) const {
3526 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
3527 }
3528
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003529 bool tiny(const Angle* angle) const {
3530 int start = angle->start();
3531 int end = angle->end();
caryclark@google.comf839c032012-10-26 21:03:50 +00003532 const Span& mSpan = fTs[SkMin32(start, end)];
3533 return mSpan.fTiny;
3534 }
3535
caryclark@google.com18063442012-07-25 12:05:18 +00003536 static void TrackOutside(SkTDArray<double>& outsideTs, double end,
3537 double start) {
3538 int outCount = outsideTs.count();
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003539 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) {
caryclark@google.com18063442012-07-25 12:05:18 +00003540 *outsideTs.append() = end;
3541 *outsideTs.append() = start;
3542 }
3543 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00003544
caryclark@google.com24bec792012-08-20 12:43:57 +00003545 void undoneSpan(int& start, int& end) {
3546 size_t tCount = fTs.count();
3547 size_t index;
3548 for (index = 0; index < tCount; ++index) {
3549 if (!fTs[index].fDone) {
3550 break;
3551 }
3552 }
3553 SkASSERT(index < tCount - 1);
3554 start = index;
3555 double startT = fTs[index].fT;
caryclark@google.com3350c3c2012-08-24 15:24:36 +00003556 while (approximately_negative(fTs[++index].fT - startT))
caryclark@google.com24bec792012-08-20 12:43:57 +00003557 SkASSERT(index < tCount);
3558 SkASSERT(index < tCount);
3559 end = index;
3560 }
caryclark@google.com18063442012-07-25 12:05:18 +00003561
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003562 bool unsortable(int index) const {
3563 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
3564 }
3565
caryclark@google.comb45a1b42012-05-18 20:50:33 +00003566 void updatePts(const SkPoint pts[]) {
3567 fPts = pts;
3568 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003569
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003570 int updateOppWinding(int index, int endIndex) const {
3571 int lesser = SkMin32(index, endIndex);
3572 int oppWinding = oppSum(lesser);
3573 int oppSpanWinding = oppSign(index, endIndex);
3574 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)) {
3575 oppWinding -= oppSpanWinding;
3576 }
3577 return oppWinding;
3578 }
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +00003579
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003580 int updateOppWinding(const Angle* angle) const {
3581 int startIndex = angle->start();
3582 int endIndex = angle->end();
3583 return updateOppWinding(endIndex, startIndex);
3584 }
3585
3586 int updateOppWindingReverse(const Angle* angle) const {
3587 int startIndex = angle->start();
3588 int endIndex = angle->end();
3589 return updateOppWinding(startIndex, endIndex);
3590 }
3591
3592 int updateWinding(int index, int endIndex) const {
3593 int lesser = SkMin32(index, endIndex);
3594 int winding = windSum(lesser);
3595 int spanWinding = spanSign(index, endIndex);
caryclark@google.com9f3e9a52012-12-10 12:50:53 +00003596 if (winding && useInnerWinding(winding - spanWinding, winding)) {
caryclark@google.com7fce0de2012-11-29 14:31:50 +00003597 winding -= spanWinding;
3598 }
3599 return winding;
3600 }
3601
3602 int updateWinding(const Angle* angle) const {
3603 int startIndex = angle->start();
3604 int endIndex = angle->end();
3605 return updateWinding(endIndex, startIndex);
3606 }
3607
3608 int updateWindingReverse(const Angle* angle) const {
3609 int startIndex = angle->start();
3610 int endIndex = angle->end();
3611 return updateWinding(startIndex, endIndex);
3612 }
3613
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003614 SkPath::Verb verb() const {
3615 return fVerb;
3616 }
skia.committer@gmail.comb89a03c2012-12-22 02:02:33 +00003617
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00003618 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003619 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3620 return SK_MinS32;
3621 }
3622 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3623 SkASSERT(winding != SK_MinS32);
3624 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003625 #if DEBUG_WINDING_AT_T
3626 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003627 #endif
3628 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark@google.com3586ece2012-12-27 18:46:58 +00003629 dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003630 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
3631 dx = fPts[2].fX - fPts[1].fX - dx;
3632 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003633 if (dx == 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003634 #if DEBUG_WINDING_AT_T
3635 SkDebugf(" dx=0 winding=SK_MinS32\n");
3636 #endif
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003637 return SK_MinS32;
3638 }
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003639 if (winding * dx > 0) { // if same signs, result is negative
3640 winding += dx > 0 ? -windVal : windVal;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003641 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003642 #if DEBUG_WINDING_AT_T
3643 SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding);
3644 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00003645 return winding;
3646 }
3647
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003648 int windSum(int tIndex) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003649 return fTs[tIndex].fWindSum;
3650 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003651
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003652 int windSum(const Angle* angle) const {
caryclark@google.com495f8e42012-05-31 13:13:11 +00003653 int start = angle->start();
3654 int end = angle->end();
3655 int index = SkMin32(start, end);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00003656 return windSum(index);
caryclark@google.com495f8e42012-05-31 13:13:11 +00003657 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003658
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003659 int windValue(int tIndex) const {
3660 return fTs[tIndex].fWindValue;
3661 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003662
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003663 int windValue(const Angle* angle) const {
3664 int start = angle->start();
3665 int end = angle->end();
3666 int index = SkMin32(start, end);
3667 return windValue(index);
3668 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00003669
caryclark@google.com8f9f4682013-01-03 21:18:16 +00003670 int windValueAt(double t) const {
3671 int count = fTs.count();
3672 for (int index = 0; index < count; ++index) {
3673 if (fTs[index].fT == t) {
3674 return fTs[index].fWindValue;
3675 }
3676 }
3677 SkASSERT(0);
3678 return 0;
3679 }
3680
caryclark@google.com3586ece2012-12-27 18:46:58 +00003681 SkScalar xAtT(int index) const {
3682 return xAtT(&fTs[index]);
3683 }
3684
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003685 SkScalar xAtT(const Span* span) const {
3686 return xyAtT(span).fX;
3687 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00003688
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003689 const SkPoint& xyAtT(int index) const {
3690 return xyAtT(&fTs[index]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003691 }
3692
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003693 const SkPoint& xyAtT(const Span* span) const {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003694 if (SkScalarIsNaN(span->fPt.fX)) {
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003695 if (span->fT == 0) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003696 span->fPt = fPts[0];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003697 } else if (span->fT == 1) {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003698 span->fPt = fPts[fVerb];
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003699 } else {
caryclark@google.com27c449a2012-07-27 18:26:38 +00003700 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00003701 }
3702 }
caryclark@google.com27c449a2012-07-27 18:26:38 +00003703 return span->fPt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003704 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00003705
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003706 // used only by right angle winding finding
caryclark@google.com10227bf2012-12-28 22:10:41 +00003707 void xyAtT(double mid, SkPoint& pt) const {
3708 (*SegmentXYAtT[fVerb])(fPts, mid, &pt);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00003709 }
3710
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003711 SkScalar yAtT(int index) const {
3712 return yAtT(&fTs[index]);
3713 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003714
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003715 SkScalar yAtT(const Span* span) const {
3716 return xyAtT(span).fY;
caryclark@google.coma833b5c2012-04-30 19:38:50 +00003717 }
3718
caryclark@google.com4eeda372012-12-06 21:47:48 +00003719 void zeroCoincidentOpp(Span* oTest, int index) {
3720 Span* const test = &fTs[index];
3721 Span* end = test;
3722 do {
3723 end->fOppValue = 0;
3724 end = &fTs[++index];
3725 } while (approximately_negative(end->fT - test->fT));
3726 }
3727
3728 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) {
3729 Span* const oTest = &fTs[oIndex];
3730 Span* oEnd = oTest;
3731 const double startT = test->fT;
3732 const double oStartT = oTest->fT;
3733 double otherTMatch = (test->fT - startT) * tRatio + oStartT;
3734 while (!approximately_negative(oEndT - oEnd->fT)
3735 && approximately_negative(oEnd->fT - otherTMatch)) {
3736 oEnd->fOppValue = 0;
3737 oEnd = &fTs[++oIndex];
3738 }
3739 }
3740
3741 void zeroSpan(Span* span) {
3742 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
caryclark@google.com6ec15262012-11-16 20:16:50 +00003743 span->fWindValue = 0;
caryclark@google.com729e1c42012-11-21 21:36:34 +00003744 span->fOppValue = 0;
caryclark@google.com4eeda372012-12-06 21:47:48 +00003745 SkASSERT(!span->fDone);
3746 span->fDone = true;
3747 ++fDoneSpans;
caryclark@google.com6ec15262012-11-16 20:16:50 +00003748 }
3749
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003750#if DEBUG_DUMP
3751 void dump() const {
3752 const char className[] = "Segment";
3753 const int tab = 4;
3754 for (int i = 0; i < fTs.count(); ++i) {
3755 SkPoint out;
3756 (*SegmentXYAtT[fVerb])(fPts, t(i), &out);
3757 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003758 " otherT=%1.9g windSum=%d\n",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003759 tab + sizeof(className), className, fID,
3760 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY,
caryclark@google.com8dcf1142012-07-02 20:27:02 +00003761 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003762 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00003763 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003764 tab + sizeof(className), className, fID,
caryclark@google.com15fa1382012-05-07 20:49:36 +00003765 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00003766 }
3767#endif
3768
caryclark@google.com47580692012-07-23 12:14:49 +00003769#if DEBUG_CONCIDENT
caryclark@google.comaa358312013-01-29 20:28:49 +00003770 // SkASSERT if pair has not already been added
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003771 void debugAddTPair(double t, const Segment& other, double otherT) const {
caryclark@google.comcc905052012-07-25 20:59:42 +00003772 for (int i = 0; i < fTs.count(); ++i) {
3773 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
3774 return;
3775 }
3776 }
3777 SkASSERT(0);
3778 }
3779#endif
3780
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003781#if DEBUG_DUMP
3782 int debugID() const {
3783 return fID;
3784 }
3785#endif
3786
caryclark@google.com24bec792012-08-20 12:43:57 +00003787#if DEBUG_WINDING
3788 void debugShowSums() const {
3789 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
3790 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
3791 for (int i = 0; i < fTs.count(); ++i) {
3792 const Span& span = fTs[i];
3793 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
3794 if (span.fWindSum == SK_MinS32) {
3795 SkDebugf("?");
3796 } else {
3797 SkDebugf("%d", span.fWindSum);
3798 }
3799 SkDebugf("]");
3800 }
3801 SkDebugf("\n");
3802 }
3803#endif
3804
caryclark@google.comcc905052012-07-25 20:59:42 +00003805#if DEBUG_CONCIDENT
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003806 void debugShowTs() const {
caryclark@google.com24bec792012-08-20 12:43:57 +00003807 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com4eeda372012-12-06 21:47:48 +00003808 int lastWind = -1;
3809 int lastOpp = -1;
3810 double lastT = -1;
3811 int i;
3812 for (i = 0; i < fTs.count(); ++i) {
3813 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
3814 || lastOpp != fTs[i].fOppValue;
3815 if (change && lastWind >= 0) {
3816 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3817 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3818 }
3819 if (change) {
3820 SkDebugf(" [o=%d", fTs[i].fOther->fID);
3821 lastWind = fTs[i].fWindValue;
3822 lastOpp = fTs[i].fOppValue;
3823 lastT = fTs[i].fT;
3824 } else {
3825 SkDebugf(",%d", fTs[i].fOther->fID);
3826 }
3827 }
3828 if (i <= 0) {
3829 return;
3830 }
3831 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3832 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3833 if (fOperand) {
3834 SkDebugf(" operand");
3835 }
3836 if (done()) {
3837 SkDebugf(" done");
caryclark@google.com47580692012-07-23 12:14:49 +00003838 }
3839 SkDebugf("\n");
3840 }
3841#endif
3842
caryclark@google.com027de222012-07-12 12:52:50 +00003843#if DEBUG_ACTIVE_SPANS
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003844 void debugShowActiveSpans() const {
caryclark@google.com027de222012-07-12 12:52:50 +00003845 if (done()) {
3846 return;
3847 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003848#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3849 int lastId = -1;
3850 double lastT = -1;
3851#endif
caryclark@google.com027de222012-07-12 12:52:50 +00003852 for (int i = 0; i < fTs.count(); ++i) {
3853 if (fTs[i].fDone) {
3854 continue;
3855 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003856#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3857 if (lastId == fID && lastT == fTs[i].fT) {
3858 continue;
3859 }
3860 lastId = fID;
3861 lastT = fTs[i].fT;
3862#endif
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003863 SkDebugf("%s id=%d", __FUNCTION__, fID);
caryclark@google.com027de222012-07-12 12:52:50 +00003864 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3865 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3866 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3867 }
3868 const Span* span = &fTs[i];
rmistry@google.comd6176b02012-08-23 18:14:13 +00003869 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT,
caryclark@google.com0c803d02012-08-06 11:15:47 +00003870 xAtT(span), yAtT(span));
caryclark@google.com027de222012-07-12 12:52:50 +00003871 const Segment* other = fTs[i].fOther;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003872 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
3873 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
3874 if (fTs[i].fWindSum == SK_MinS32) {
3875 SkDebugf("?");
3876 } else {
3877 SkDebugf("%d", fTs[i].fWindSum);
3878 }
caryclark@google.com4eeda372012-12-06 21:47:48 +00003879 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
caryclark@google.com027de222012-07-12 12:52:50 +00003880 }
3881 }
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +00003882
caryclark@google.com6aea33f2012-10-09 14:11:58 +00003883 // This isn't useful yet -- but leaving it in for now in case i think of something
3884 // to use it for
3885 void validateActiveSpans() const {
3886 if (done()) {
3887 return;
3888 }
3889 int tCount = fTs.count();
3890 for (int index = 0; index < tCount; ++index) {
3891 if (fTs[index].fDone) {
3892 continue;
3893 }
3894 // count number of connections which are not done
3895 int first = index;
3896 double baseT = fTs[index].fT;
3897 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
3898 --first;
3899 }
3900 int last = index;
3901 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
3902 ++last;
3903 }
3904 int connections = 0;
3905 connections += first > 0 && !fTs[first - 1].fDone;
3906 for (int test = first; test <= last; ++test) {
3907 connections += !fTs[test].fDone;
3908 const Segment* other = fTs[test].fOther;
3909 int oIndex = fTs[test].fOtherIndex;
3910 connections += !other->fTs[oIndex].fDone;
3911 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
3912 }
3913 // SkASSERT(!(connections & 1));
3914 }
3915 }
caryclark@google.com027de222012-07-12 12:52:50 +00003916#endif
3917
caryclark@google.com0c803d02012-08-06 11:15:47 +00003918#if DEBUG_MARK_DONE
3919 void debugShowNewWinding(const char* fun, const Span& span, int winding) {
3920 const SkPoint& pt = xyAtT(&span);
3921 SkDebugf("%s id=%d", fun, fID);
3922 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3923 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3924 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3925 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00003926 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3927 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3928 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d windSum=",
3929 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, winding);
caryclark@google.com0c803d02012-08-06 11:15:47 +00003930 if (span.fWindSum == SK_MinS32) {
3931 SkDebugf("?");
3932 } else {
3933 SkDebugf("%d", span.fWindSum);
3934 }
3935 SkDebugf(" windValue=%d\n", span.fWindValue);
3936 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003937
3938 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
3939 const SkPoint& pt = xyAtT(&span);
3940 SkDebugf("%s id=%d", fun, fID);
3941 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
3942 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
3943 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3944 }
3945 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3946 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3947 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=",
3948 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
3949 winding, oppWinding);
3950 if (span.fOppSum == SK_MinS32) {
3951 SkDebugf("?");
3952 } else {
3953 SkDebugf("%d", span.fOppSum);
3954 }
3955 SkDebugf(" windSum=");
3956 if (span.fWindSum == SK_MinS32) {
3957 SkDebugf("?");
3958 } else {
3959 SkDebugf("%d", span.fWindSum);
3960 }
3961 SkDebugf(" windValue=%d\n", span.fWindValue);
3962 }
caryclark@google.com0c803d02012-08-06 11:15:47 +00003963#endif
3964
caryclark@google.com47580692012-07-23 12:14:49 +00003965#if DEBUG_SORT
caryclark@google.com03f97062012-08-21 13:13:52 +00003966 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
caryclark@google.com31143cf2012-11-09 22:14:19 +00003967 const int contourWinding, const int oppContourWinding) const {
caryclark@google.comafe56de2012-07-24 18:11:03 +00003968 SkASSERT(angles[first]->segment() == this);
caryclark@google.com200c2112012-08-03 15:05:04 +00003969 SkASSERT(angles.count() > 1);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003970 int lastSum = contourWinding;
caryclark@google.com31143cf2012-11-09 22:14:19 +00003971 int oppLastSum = oppContourWinding;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003972 const Angle* firstAngle = angles[first];
3973 int windSum = lastSum - spanSign(firstAngle);
3974 int oppoSign = oppSign(firstAngle);
3975 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.com31143cf2012-11-09 22:14:19 +00003976 SkDebugf("%s %s contourWinding=%d oppContourWinding=%d sign=%d\n", fun, __FUNCTION__,
3977 contourWinding, oppContourWinding, spanSign(angles[first]));
caryclark@google.comafe56de2012-07-24 18:11:03 +00003978 int index = first;
3979 bool firstTime = true;
caryclark@google.com47580692012-07-23 12:14:49 +00003980 do {
3981 const Angle& angle = *angles[index];
3982 const Segment& segment = *angle.segment();
3983 int start = angle.start();
3984 int end = angle.end();
3985 const Span& sSpan = segment.fTs[start];
3986 const Span& eSpan = segment.fTs[end];
3987 const Span& mSpan = segment.fTs[SkMin32(start, end)];
caryclark@google.com31143cf2012-11-09 22:14:19 +00003988 bool opp = segment.fOperand ^ fOperand;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00003989 if (!firstTime) {
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003990 oppoSign = segment.oppSign(&angle);
caryclark@google.com31143cf2012-11-09 22:14:19 +00003991 if (opp) {
3992 oppLastSum = oppWindSum;
3993 oppWindSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00003994 if (oppoSign) {
3995 lastSum = windSum;
3996 windSum -= oppoSign;
3997 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00003998 } else {
3999 lastSum = windSum;
4000 windSum -= segment.spanSign(&angle);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004001 if (oppoSign) {
4002 oppLastSum = oppWindSum;
4003 oppWindSum -= oppoSign;
4004 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004005 }
caryclark@google.comafe56de2012-07-24 18:11:03 +00004006 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004007 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 +00004008 " sign=%d windValue=%d windSum=",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004009 __FUNCTION__, index, angle.unsortable() ? "*** UNSORTABLE *** " : "",
caryclark@google.comc91dfe42012-10-16 12:06:27 +00004010 segment.fID, kLVerbStr[segment.fVerb],
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004011 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
4012 segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(),
4013 mSpan.fWindValue);
4014 if (mSpan.fWindSum == SK_MinS32) {
4015 SkDebugf("?");
4016 } else {
4017 SkDebugf("%d", mSpan.fWindSum);
4018 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004019 int last, wind;
4020 if (opp) {
4021 last = oppLastSum;
4022 wind = oppWindSum;
4023 } else {
4024 last = lastSum;
4025 wind = windSum;
4026 }
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004027 if (!oppoSign) {
skia.committer@gmail.comb3b6a602012-11-15 02:01:17 +00004028 SkDebugf(" %d->%d (max=%d)", last, wind,
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004029 useInnerWinding(last, wind) ? wind : last);
4030 } else {
4031 SkDebugf(" %d->%d (%d->%d)", last, wind, opp ? lastSum : oppLastSum,
4032 opp ? windSum : oppWindSum);
4033 }
caryclark@google.com31143cf2012-11-09 22:14:19 +00004034 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004035#if false && DEBUG_ANGLE
caryclark@google.comc899ad92012-08-23 15:24:42 +00004036 angle.debugShow(segment.xyAtT(&sSpan));
4037#endif
caryclark@google.com47580692012-07-23 12:14:49 +00004038 ++index;
4039 if (index == angles.count()) {
4040 index = 0;
4041 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004042 if (firstTime) {
4043 firstTime = false;
4044 }
caryclark@google.com47580692012-07-23 12:14:49 +00004045 } while (index != first);
4046 }
caryclark@google.com7fce0de2012-11-29 14:31:50 +00004047
4048 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) {
4049 const Angle* firstAngle = angles[first];
4050 const Segment* segment = firstAngle->segment();
4051 int winding = segment->updateWinding(firstAngle);
4052 int oppWinding = segment->updateOppWinding(firstAngle);
4053 debugShowSort(fun, angles, first, winding, oppWinding);
4054 }
4055
caryclark@google.com47580692012-07-23 12:14:49 +00004056#endif
4057
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004058#if DEBUG_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004059 static char as_digit(int value) {
4060 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
4061 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004062#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004063
caryclark@google.com729e1c42012-11-21 21:36:34 +00004064#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004065 int debugShowWindingValues(int slotCount, int ofInterest) const {
4066 if (!(1 << fID & ofInterest)) {
4067 return 0;
4068 }
4069 int sum = 0;
4070 SkTDArray<char> slots;
4071 slots.setCount(slotCount * 2);
4072 memset(slots.begin(), ' ', slotCount * 2);
4073 for (int i = 0; i < fTs.count(); ++i) {
4074 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
4075 // continue;
4076 // }
4077 sum += fTs[i].fWindValue;
4078 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
4079 sum += fTs[i].fOppValue;
4080 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
4081 }
4082 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
4083 slots.begin() + slotCount);
4084 return sum;
4085 }
caryclark@google.com729e1c42012-11-21 21:36:34 +00004086#endif
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004087
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004088private:
4089 const SkPoint* fPts;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004090 Bounds fBounds;
caryclark@google.com15fa1382012-05-07 20:49:36 +00004091 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
caryclark@google.com4eeda372012-12-06 21:47:48 +00004092 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
caryclark@google.com24bec792012-08-20 12:43:57 +00004093 int fDoneSpans; // quick check that segment is finished
caryclark@google.com4eeda372012-12-06 21:47:48 +00004094 // OPTIMIZATION: force the following to be byte-sized
4095 SkPath::Verb fVerb;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004096 bool fOperand;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004097 bool fXor; // set if original contour had even-odd fill
4098 bool fOppXor; // set if opposite operand had even-odd fill
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004099#if DEBUG_DUMP
4100 int fID;
4101#endif
4102};
4103
caryclark@google.comb9738012012-07-03 19:53:30 +00004104class Contour;
4105
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004106struct Coincidence {
caryclark@google.comb9738012012-07-03 19:53:30 +00004107 Contour* fContours[2];
4108 int fSegments[2];
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004109 double fTs[2][2];
4110};
4111
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004112class Contour {
4113public:
4114 Contour() {
4115 reset();
4116#if DEBUG_DUMP
4117 fID = ++gContourID;
4118#endif
4119 }
4120
4121 bool operator<(const Contour& rh) const {
4122 return fBounds.fTop == rh.fBounds.fTop
4123 ? fBounds.fLeft < rh.fBounds.fLeft
4124 : fBounds.fTop < rh.fBounds.fTop;
4125 }
4126
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004127 void addCoincident(int index, Contour* other, int otherIndex,
4128 const Intersections& ts, bool swap) {
4129 Coincidence& coincidence = *fCoincidences.append();
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004130 coincidence.fContours[0] = this; // FIXME: no need to store
caryclark@google.comb9738012012-07-03 19:53:30 +00004131 coincidence.fContours[1] = other;
4132 coincidence.fSegments[0] = index;
4133 coincidence.fSegments[1] = otherIndex;
caryclark@google.com32546db2012-08-31 20:55:07 +00004134 if (fSegments[index].verb() == SkPath::kLine_Verb &&
4135 other->fSegments[otherIndex].verb() == SkPath::kLine_Verb) {
4136 // FIXME: coincident lines use legacy Ts instead of coincident Ts
4137 coincidence.fTs[swap][0] = ts.fT[0][0];
4138 coincidence.fTs[swap][1] = ts.fT[0][1];
4139 coincidence.fTs[!swap][0] = ts.fT[1][0];
4140 coincidence.fTs[!swap][1] = ts.fT[1][1];
4141 } else if (fSegments[index].verb() == SkPath::kQuad_Verb &&
4142 other->fSegments[otherIndex].verb() == SkPath::kQuad_Verb) {
4143 coincidence.fTs[swap][0] = ts.fCoincidentT[0][0];
4144 coincidence.fTs[swap][1] = ts.fCoincidentT[0][1];
4145 coincidence.fTs[!swap][0] = ts.fCoincidentT[1][0];
4146 coincidence.fTs[!swap][1] = ts.fCoincidentT[1][1];
4147 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004148 }
4149
4150 void addCross(const Contour* crosser) {
4151#ifdef DEBUG_CROSS
4152 for (int index = 0; index < fCrosses.count(); ++index) {
4153 SkASSERT(fCrosses[index] != crosser);
4154 }
4155#endif
4156 *fCrosses.append() = crosser;
4157 }
4158
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004159 void addCubic(const SkPoint pts[4]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004160 fSegments.push_back().addCubic(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004161 fContainsCurves = true;
4162 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004163
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004164 int addLine(const SkPoint pts[2]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004165 fSegments.push_back().addLine(pts, fOperand, fXor);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004166 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004167 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004168
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004169 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
4170 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
4171 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004172
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004173 int addQuad(const SkPoint pts[3]) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004174 fSegments.push_back().addQuad(pts, fOperand, fXor);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004175 fContainsCurves = true;
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004176 return fSegments.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004177 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004178
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004179 int addT(int segIndex, double newT, Contour* other, int otherIndex) {
4180 containsIntercepts();
4181 return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex]);
4182 }
4183
caryclark@google.com73ca6242013-01-17 21:02:47 +00004184 int addUnsortableT(int segIndex, double newT, Contour* other, int otherIndex, bool start) {
4185 return fSegments[segIndex].addUnsortableT(newT, &other->fSegments[otherIndex], start);
4186 }
4187
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004188 const Bounds& bounds() const {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004189 return fBounds;
4190 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004191
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004192 void complete() {
4193 setBounds();
4194 fContainsIntercepts = false;
4195 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004196
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004197 void containsIntercepts() {
4198 fContainsIntercepts = true;
4199 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004200
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004201 bool crosses(const Contour* crosser) const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004202 for (int index = 0; index < fCrosses.count(); ++index) {
4203 if (fCrosses[index] == crosser) {
4204 return true;
4205 }
4206 }
4207 return false;
4208 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004209
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004210 bool done() const {
4211 return fDone;
4212 }
4213
caryclark@google.comf839c032012-10-26 21:03:50 +00004214 const SkPoint& end() const {
4215 const Segment& segment = fSegments.back();
4216 return segment.pts()[segment.verb()];
4217 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004218
caryclark@google.com4eeda372012-12-06 21:47:48 +00004219 void findTooCloseToCall() {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004220 int segmentCount = fSegments.count();
4221 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004222 fSegments[sIndex].findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004223 }
4224 }
4225
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004226 void fixOtherTIndex() {
4227 int segmentCount = fSegments.count();
4228 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
4229 fSegments[sIndex].fixOtherTIndex();
4230 }
4231 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +00004232
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004233 Segment* nonVerticalSegment(int& start, int& end) {
4234 int segmentCount = fSortedSegments.count();
4235 SkASSERT(segmentCount > 0);
4236 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
4237 Segment* testSegment = fSortedSegments[sortedIndex];
4238 if (testSegment->done()) {
4239 continue;
4240 }
4241 start = end = 0;
4242 while (testSegment->nextCandidate(start, end)) {
4243 if (!testSegment->isVertical(start, end)) {
4244 return testSegment;
4245 }
4246 }
4247 }
4248 return NULL;
4249 }
4250
caryclark@google.com31143cf2012-11-09 22:14:19 +00004251 bool operand() const {
4252 return fOperand;
4253 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004254
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004255 void reset() {
4256 fSegments.reset();
4257 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004258 fContainsCurves = fContainsIntercepts = fDone = false;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004259 }
caryclark@google.comb9738012012-07-03 19:53:30 +00004260
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004261 void resolveCoincidence(SkTDArray<Contour*>& contourList) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004262 int count = fCoincidences.count();
4263 for (int index = 0; index < count; ++index) {
4264 Coincidence& coincidence = fCoincidences[index];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004265 SkASSERT(coincidence.fContours[0] == this);
caryclark@google.comb9738012012-07-03 19:53:30 +00004266 int thisIndex = coincidence.fSegments[0];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004267 Segment& thisOne = fSegments[thisIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00004268 Contour* otherContour = coincidence.fContours[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004269 int otherIndex = coincidence.fSegments[1];
caryclark@google.comb9738012012-07-03 19:53:30 +00004270 Segment& other = otherContour->fSegments[otherIndex];
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004271 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00004272 continue;
4273 }
caryclark@google.com47580692012-07-23 12:14:49 +00004274 #if DEBUG_CONCIDENT
4275 thisOne.debugShowTs();
4276 other.debugShowTs();
4277 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004278 double startT = coincidence.fTs[0][0];
4279 double endT = coincidence.fTs[0][1];
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004280 bool cancelers = false;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004281 if (startT > endT) {
4282 SkTSwap<double>(startT, endT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004283 cancelers ^= true; // FIXME: just assign true
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004284 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004285 SkASSERT(!approximately_negative(endT - startT));
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004286 double oStartT = coincidence.fTs[1][0];
4287 double oEndT = coincidence.fTs[1][1];
4288 if (oStartT > oEndT) {
4289 SkTSwap<double>(oStartT, oEndT);
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004290 cancelers ^= true;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004291 }
caryclark@google.com3350c3c2012-08-24 15:24:36 +00004292 SkASSERT(!approximately_negative(oEndT - oStartT));
caryclark@google.com4eeda372012-12-06 21:47:48 +00004293 bool opp = fOperand ^ otherContour->fOperand;
caryclark@google.com57cff8d2012-11-14 21:14:56 +00004294 if (cancelers && !opp) {
4295 // make sure startT and endT have t entries
caryclark@google.com2ddff932012-08-07 21:25:27 +00004296 if (startT > 0 || oEndT < 1
4297 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
4298 thisOne.addTPair(startT, other, oEndT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004299 }
caryclark@google.com2ddff932012-08-07 21:25:27 +00004300 if (oStartT > 0 || endT < 1
4301 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
4302 other.addTPair(oStartT, thisOne, endT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004303 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004304 if (!thisOne.done() && !other.done()) {
4305 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4306 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004307 } else {
caryclark@google.com200c2112012-08-03 15:05:04 +00004308 if (startT > 0 || oStartT > 0
4309 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00004310 thisOne.addTPair(startT, other, oStartT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004311 }
caryclark@google.com200c2112012-08-03 15:05:04 +00004312 if (endT < 1 || oEndT < 1
4313 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
caryclark@google.com2ddff932012-08-07 21:25:27 +00004314 other.addTPair(oEndT, thisOne, endT, true);
caryclark@google.comb9738012012-07-03 19:53:30 +00004315 }
caryclark@google.com0d3d09e2012-12-10 14:50:04 +00004316 if (!thisOne.done() && !other.done()) {
4317 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4318 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004319 }
caryclark@google.com47580692012-07-23 12:14:49 +00004320 #if DEBUG_CONCIDENT
4321 thisOne.debugShowTs();
4322 other.debugShowTs();
4323 #endif
caryclark@google.com729e1c42012-11-21 21:36:34 +00004324 #if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004325 debugShowWindingValues(contourList);
4326 #endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004327 }
4328 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004329
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004330 // first pass, add missing T values
4331 // second pass, determine winding values of overlaps
4332 void addCoincidentPoints() {
4333 int count = fCoincidences.count();
4334 for (int index = 0; index < count; ++index) {
4335 Coincidence& coincidence = fCoincidences[index];
4336 SkASSERT(coincidence.fContours[0] == this);
4337 int thisIndex = coincidence.fSegments[0];
4338 Segment& thisOne = fSegments[thisIndex];
4339 Contour* otherContour = coincidence.fContours[1];
4340 int otherIndex = coincidence.fSegments[1];
4341 Segment& other = otherContour->fSegments[otherIndex];
4342 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
4343 // OPTIMIZATION: remove from array
4344 continue;
4345 }
4346 #if DEBUG_CONCIDENT
4347 thisOne.debugShowTs();
4348 other.debugShowTs();
4349 #endif
4350 double startT = coincidence.fTs[0][0];
4351 double endT = coincidence.fTs[0][1];
4352 bool cancelers;
4353 if ((cancelers = startT > endT)) {
4354 SkTSwap<double>(startT, endT);
4355 }
4356 SkASSERT(!approximately_negative(endT - startT));
4357 double oStartT = coincidence.fTs[1][0];
4358 double oEndT = coincidence.fTs[1][1];
4359 if (oStartT > oEndT) {
4360 SkTSwap<double>(oStartT, oEndT);
4361 cancelers ^= true;
4362 }
4363 SkASSERT(!approximately_negative(oEndT - oStartT));
4364 bool opp = fOperand ^ otherContour->fOperand;
4365 if (cancelers && !opp) {
4366 // make sure startT and endT have t entries
4367 if (startT > 0 || oEndT < 1
4368 || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
4369 thisOne.addTPair(startT, other, oEndT, true);
4370 }
4371 if (oStartT > 0 || endT < 1
4372 || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
4373 other.addTPair(oStartT, thisOne, endT, true);
4374 }
4375 } else {
4376 if (startT > 0 || oStartT > 0
4377 || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
4378 thisOne.addTPair(startT, other, oStartT, true);
4379 }
4380 if (endT < 1 || oEndT < 1
4381 || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
4382 other.addTPair(oEndT, thisOne, endT, true);
4383 }
4384 }
4385 #if DEBUG_CONCIDENT
4386 thisOne.debugShowTs();
4387 other.debugShowTs();
4388 #endif
4389 }
4390 }
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00004391
caryclark@google.com8f9f4682013-01-03 21:18:16 +00004392 void calcCoincidentWinding() {
4393 int count = fCoincidences.count();
4394 for (int index = 0; index < count; ++index) {
4395 Coincidence& coincidence = fCoincidences[index];
4396 SkASSERT(coincidence.fContours[0] == this);
4397 int thisIndex = coincidence.fSegments[0];
4398 Segment& thisOne = fSegments[thisIndex];
4399 if (thisOne.done()) {
4400 continue;
4401 }
4402 Contour* otherContour = coincidence.fContours[1];
4403 int otherIndex = coincidence.fSegments[1];
4404 Segment& other = otherContour->fSegments[otherIndex];
4405 if (other.done()) {
4406 continue;
4407 }
4408 double startT = coincidence.fTs[0][0];
4409 double endT = coincidence.fTs[0][1];
4410 bool cancelers;
4411 if ((cancelers = startT > endT)) {
4412 SkTSwap<double>(startT, endT);
4413 }
4414 SkASSERT(!approximately_negative(endT - startT));
4415 double oStartT = coincidence.fTs[1][0];
4416 double oEndT = coincidence.fTs[1][1];
4417 if (oStartT > oEndT) {
4418 SkTSwap<double>(oStartT, oEndT);
4419 cancelers ^= true;
4420 }
4421 SkASSERT(!approximately_negative(oEndT - oStartT));
4422 bool opp = fOperand ^ otherContour->fOperand;
4423 if (cancelers && !opp) {
4424 // make sure startT and endT have t entries
4425 if (!thisOne.done() && !other.done()) {
4426 thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
4427 }
4428 } else {
4429 if (!thisOne.done() && !other.done()) {
4430 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
4431 }
4432 }
4433 #if DEBUG_CONCIDENT
4434 thisOne.debugShowTs();
4435 other.debugShowTs();
4436 #endif
4437 }
4438 }
4439
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004440 SkTArray<Segment>& segments() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004441 return fSegments;
4442 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004443
caryclark@google.com235f56a2012-09-14 14:19:30 +00004444 void setOperand(bool isOp) {
4445 fOperand = isOp;
4446 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +00004447
caryclark@google.com4eeda372012-12-06 21:47:48 +00004448 void setOppXor(bool isOppXor) {
4449 fOppXor = isOppXor;
4450 int segmentCount = fSegments.count();
4451 for (int test = 0; test < segmentCount; ++test) {
4452 fSegments[test].setOppXor(isOppXor);
4453 }
4454 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004455
caryclark@google.com235f56a2012-09-14 14:19:30 +00004456 void setXor(bool isXor) {
4457 fXor = isXor;
4458 }
4459
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004460 void sortSegments() {
4461 int segmentCount = fSegments.count();
4462 fSortedSegments.setReserve(segmentCount);
4463 for (int test = 0; test < segmentCount; ++test) {
4464 *fSortedSegments.append() = &fSegments[test];
4465 }
4466 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
4467 fFirstSorted = 0;
4468 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004469
caryclark@google.comf839c032012-10-26 21:03:50 +00004470 const SkPoint& start() const {
4471 return fSegments.front().pts()[0];
4472 }
4473
4474 void toPath(PathWrapper& path) const {
4475 int segmentCount = fSegments.count();
4476 const SkPoint& pt = fSegments.front().pts()[0];
4477 path.deferredMove(pt);
4478 for (int test = 0; test < segmentCount; ++test) {
4479 fSegments[test].addCurveTo(0, 1, path, true);
4480 }
4481 path.close();
4482 }
skia.committer@gmail.com549c93e2012-10-27 02:01:15 +00004483
caryclark@google.comf839c032012-10-26 21:03:50 +00004484 void toPartialBackward(PathWrapper& path) const {
4485 int segmentCount = fSegments.count();
4486 for (int test = segmentCount - 1; test >= 0; --test) {
4487 fSegments[test].addCurveTo(1, 0, path, true);
4488 }
4489 }
4490
4491 void toPartialForward(PathWrapper& path) const {
4492 int segmentCount = fSegments.count();
4493 for (int test = 0; test < segmentCount; ++test) {
4494 fSegments[test].addCurveTo(0, 1, path, true);
4495 }
4496 }
4497
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004498 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004499 int segmentCount = fSortedSegments.count();
4500 SkASSERT(segmentCount > 0);
caryclark@google.comf839c032012-10-26 21:03:50 +00004501 int sortedIndex = fFirstSorted;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004502 fDone = true; // may be cleared below
caryclark@google.comf839c032012-10-26 21:03:50 +00004503 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
4504 Segment* testSegment = fSortedSegments[sortedIndex];
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004505 if (testSegment->done()) {
caryclark@google.comf839c032012-10-26 21:03:50 +00004506 if (sortedIndex == fFirstSorted) {
4507 ++fFirstSorted;
4508 }
4509 continue;
4510 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004511 fDone = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00004512 SkPoint testXY;
4513 testSegment->activeLeftTop(testXY);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004514 if (topStart) {
4515 if (testXY.fY < topLeft.fY) {
4516 continue;
4517 }
4518 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
4519 continue;
4520 }
4521 if (bestXY.fY < testXY.fY) {
4522 continue;
4523 }
4524 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
4525 continue;
4526 }
caryclark@google.comf839c032012-10-26 21:03:50 +00004527 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004528 topStart = testSegment;
caryclark@google.comf839c032012-10-26 21:03:50 +00004529 bestXY = testXY;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004530 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004531 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004532
caryclark@google.com24bec792012-08-20 12:43:57 +00004533 Segment* undoneSegment(int& start, int& end) {
4534 int segmentCount = fSegments.count();
4535 for (int test = 0; test < segmentCount; ++test) {
4536 Segment* testSegment = &fSegments[test];
4537 if (testSegment->done()) {
4538 continue;
4539 }
4540 testSegment->undoneSpan(start, end);
4541 return testSegment;
4542 }
4543 return NULL;
4544 }
4545
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004546 int updateSegment(int index, const SkPoint* pts) {
4547 Segment& segment = fSegments[index];
4548 segment.updatePts(pts);
4549 return segment.verb() + 1;
4550 }
4551
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004552#if DEBUG_TEST
4553 SkTArray<Segment>& debugSegments() {
4554 return fSegments;
4555 }
4556#endif
4557
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004558#if DEBUG_DUMP
4559 void dump() {
4560 int i;
4561 const char className[] = "Contour";
4562 const int tab = 4;
4563 SkDebugf("%s %p (contour=%d)\n", className, this, fID);
4564 for (i = 0; i < fSegments.count(); ++i) {
4565 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className),
4566 className, i);
4567 fSegments[i].dump();
4568 }
4569 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n",
4570 tab + sizeof(className), className,
4571 fBounds.fLeft, fBounds.fTop,
4572 fBounds.fRight, fBounds.fBottom);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004573 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
4574 className, fContainsIntercepts);
4575 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className),
4576 className, fContainsCurves);
4577 }
4578#endif
4579
caryclark@google.com027de222012-07-12 12:52:50 +00004580#if DEBUG_ACTIVE_SPANS
4581 void debugShowActiveSpans() {
4582 for (int index = 0; index < fSegments.count(); ++index) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00004583 fSegments[index].debugShowActiveSpans();
caryclark@google.com027de222012-07-12 12:52:50 +00004584 }
4585 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00004586
4587 void validateActiveSpans() {
4588 for (int index = 0; index < fSegments.count(); ++index) {
4589 fSegments[index].validateActiveSpans();
4590 }
4591 }
caryclark@google.com027de222012-07-12 12:52:50 +00004592#endif
4593
caryclark@google.com729e1c42012-11-21 21:36:34 +00004594#if DEBUG_SHOW_WINDING
caryclark@google.com7ba591e2012-11-20 14:21:54 +00004595 int debugShowWindingValues(int totalSegments, int ofInterest) {
4596 int count = fSegments.count();
4597 int sum = 0;
4598 for (int index = 0; index < count; ++index) {
4599 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
4600 }
4601 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
4602 return sum;
4603 }
4604
4605 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) {
4606 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
4607 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
4608 int ofInterest = 1 << 5 | 1 << 8;
4609 int total = 0;
4610 int index;
4611 for (index = 0; index < contourList.count(); ++index) {
4612 total += contourList[index]->segments().count();
4613 }
4614 int sum = 0;
4615 for (index = 0; index < contourList.count(); ++index) {
4616 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
4617 }
4618 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
4619 }
4620#endif
4621
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004622protected:
4623 void setBounds() {
4624 int count = fSegments.count();
4625 if (count == 0) {
4626 SkDebugf("%s empty contour\n", __FUNCTION__);
4627 SkASSERT(0);
4628 // FIXME: delete empty contour?
4629 return;
4630 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004631 fBounds = fSegments.front().bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004632 for (int index = 1; index < count; ++index) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004633 fBounds.add(fSegments[index].bounds());
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004634 }
4635 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004636
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004637private:
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004638 SkTArray<Segment> fSegments;
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004639 SkTDArray<Segment*> fSortedSegments;
4640 int fFirstSorted;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004641 SkTDArray<Coincidence> fCoincidences;
4642 SkTDArray<const Contour*> fCrosses;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004643 Bounds fBounds;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004644 bool fContainsIntercepts;
4645 bool fContainsCurves;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00004646 bool fDone;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004647 bool fOperand; // true for the second argument to a binary operator
4648 bool fXor;
caryclark@google.com4eeda372012-12-06 21:47:48 +00004649 bool fOppXor;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004650#if DEBUG_DUMP
4651 int fID;
4652#endif
4653};
4654
4655class EdgeBuilder {
4656public:
4657
caryclark@google.comf839c032012-10-26 21:03:50 +00004658EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours)
4659 : fPath(path.nativePath())
4660 , fContours(contours)
4661{
4662 init();
4663}
4664
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004665EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
caryclark@google.com235f56a2012-09-14 14:19:30 +00004666 : fPath(&path)
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004667 , fContours(contours)
4668{
caryclark@google.comf839c032012-10-26 21:03:50 +00004669 init();
4670}
4671
4672void init() {
4673 fCurrentContour = NULL;
4674 fOperand = false;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004675 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004676#if DEBUG_DUMP
4677 gContourID = 0;
4678 gSegmentID = 0;
4679#endif
caryclark@google.com235f56a2012-09-14 14:19:30 +00004680 fSecondHalf = preFetch();
4681}
4682
4683void addOperand(const SkPath& path) {
caryclark@google.com31143cf2012-11-09 22:14:19 +00004684 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
4685 fPathVerbs.pop();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004686 fPath = &path;
caryclark@google.com729e1c42012-11-21 21:36:34 +00004687 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004688 preFetch();
4689}
4690
4691void finish() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004692 walk();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004693 complete();
4694 if (fCurrentContour && !fCurrentContour->segments().count()) {
4695 fContours.pop_back();
4696 }
4697 // correct pointers in contours since fReducePts may have moved as it grew
4698 int cIndex = 0;
4699 int extraCount = fExtra.count();
4700 SkASSERT(extraCount == 0 || fExtra[0] == -1);
4701 int eIndex = 0;
4702 int rIndex = 0;
4703 while (++eIndex < extraCount) {
4704 int offset = fExtra[eIndex];
4705 if (offset < 0) {
4706 ++cIndex;
4707 continue;
4708 }
4709 fCurrentContour = &fContours[cIndex];
4710 rIndex += fCurrentContour->updateSegment(offset - 1,
4711 &fReducePts[rIndex]);
4712 }
4713 fExtra.reset(); // we're done with this
4714}
4715
4716ShapeOpMask xorMask() const {
caryclark@google.com729e1c42012-11-21 21:36:34 +00004717 return fXorMask[fOperand];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004718}
4719
4720protected:
4721
4722void complete() {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004723 if (fCurrentContour && fCurrentContour->segments().count()) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004724 fCurrentContour->complete();
4725 fCurrentContour = NULL;
4726 }
4727}
4728
caryclark@google.com235f56a2012-09-14 14:19:30 +00004729// FIXME:remove once we can access path pts directly
4730int preFetch() {
4731 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004732 SkPoint pts[4];
4733 SkPath::Verb verb;
4734 do {
4735 verb = iter.next(pts);
4736 *fPathVerbs.append() = verb;
4737 if (verb == SkPath::kMove_Verb) {
4738 *fPathPts.append() = pts[0];
4739 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
4740 fPathPts.append(verb, &pts[1]);
4741 }
4742 } while (verb != SkPath::kDone_Verb);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004743 return fPathVerbs.count() - 1;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004744}
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004745
caryclark@google.com235f56a2012-09-14 14:19:30 +00004746void walk() {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004747 SkPath::Verb reducedVerb;
4748 uint8_t* verbPtr = fPathVerbs.begin();
caryclark@google.com235f56a2012-09-14 14:19:30 +00004749 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004750 const SkPoint* pointsPtr = fPathPts.begin();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004751 const SkPoint* finalCurveStart = NULL;
4752 const SkPoint* finalCurveEnd = NULL;
caryclark@google.com235f56a2012-09-14 14:19:30 +00004753 SkPath::Verb verb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004754 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
4755 switch (verb) {
4756 case SkPath::kMove_Verb:
4757 complete();
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004758 if (!fCurrentContour) {
4759 fCurrentContour = fContours.push_back_n(1);
caryclark@google.com235f56a2012-09-14 14:19:30 +00004760 fCurrentContour->setOperand(fOperand);
caryclark@google.com729e1c42012-11-21 21:36:34 +00004761 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004762 *fExtra.append() = -1; // start new contour
4763 }
caryclark@google.com59823f72012-08-09 18:17:47 +00004764 finalCurveEnd = pointsPtr++;
caryclark@google.com31143cf2012-11-09 22:14:19 +00004765 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004766 case SkPath::kLine_Verb:
4767 // skip degenerate points
4768 if (pointsPtr[-1].fX != pointsPtr[0].fX
4769 || pointsPtr[-1].fY != pointsPtr[0].fY) {
4770 fCurrentContour->addLine(&pointsPtr[-1]);
4771 }
4772 break;
4773 case SkPath::kQuad_Verb:
rmistry@google.comd6176b02012-08-23 18:14:13 +00004774
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004775 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
4776 if (reducedVerb == 0) {
4777 break; // skip degenerate points
4778 }
4779 if (reducedVerb == 1) {
rmistry@google.comd6176b02012-08-23 18:14:13 +00004780 *fExtra.append() =
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004781 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004782 break;
4783 }
4784 fCurrentContour->addQuad(&pointsPtr[-1]);
4785 break;
4786 case SkPath::kCubic_Verb:
4787 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts);
4788 if (reducedVerb == 0) {
4789 break; // skip degenerate points
4790 }
4791 if (reducedVerb == 1) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004792 *fExtra.append() =
4793 fCurrentContour->addLine(fReducePts.end() - 2);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004794 break;
4795 }
4796 if (reducedVerb == 2) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004797 *fExtra.append() =
4798 fCurrentContour->addQuad(fReducePts.end() - 3);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004799 break;
4800 }
4801 fCurrentContour->addCubic(&pointsPtr[-1]);
4802 break;
4803 case SkPath::kClose_Verb:
4804 SkASSERT(fCurrentContour);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004805 if (finalCurveStart && finalCurveEnd
4806 && *finalCurveStart != *finalCurveEnd) {
4807 *fReducePts.append() = *finalCurveStart;
4808 *fReducePts.append() = *finalCurveEnd;
4809 *fExtra.append() =
4810 fCurrentContour->addLine(fReducePts.end() - 2);
4811 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004812 complete();
caryclark@google.com31143cf2012-11-09 22:14:19 +00004813 goto nextVerb;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004814 default:
4815 SkDEBUGFAIL("bad verb");
4816 return;
4817 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004818 finalCurveStart = &pointsPtr[verb - 1];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004819 pointsPtr += verb;
4820 SkASSERT(fCurrentContour);
caryclark@google.com31143cf2012-11-09 22:14:19 +00004821 nextVerb:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004822 if (verbPtr == endOfFirstHalf) {
4823 fOperand = true;
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +00004824 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004825 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004826}
4827
4828private:
caryclark@google.com235f56a2012-09-14 14:19:30 +00004829 const SkPath* fPath;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004830 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004831 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004832 Contour* fCurrentContour;
4833 SkTArray<Contour>& fContours;
4834 SkTDArray<SkPoint> fReducePts; // segments created on the fly
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004835 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
caryclark@google.com729e1c42012-11-21 21:36:34 +00004836 ShapeOpMask fXorMask[2];
caryclark@google.com235f56a2012-09-14 14:19:30 +00004837 int fSecondHalf;
4838 bool fOperand;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004839};
4840
4841class Work {
4842public:
4843 enum SegmentType {
4844 kHorizontalLine_Segment = -1,
4845 kVerticalLine_Segment = 0,
4846 kLine_Segment = SkPath::kLine_Verb,
4847 kQuad_Segment = SkPath::kQuad_Verb,
4848 kCubic_Segment = SkPath::kCubic_Verb,
4849 };
rmistry@google.comd6176b02012-08-23 18:14:13 +00004850
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004851 void addCoincident(Work& other, const Intersections& ts, bool swap) {
4852 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
4853 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004854
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004855 // FIXME: does it make sense to write otherIndex now if we're going to
4856 // fix it up later?
4857 void addOtherT(int index, double otherT, int otherIndex) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004858 fContour->addOtherT(fIndex, index, otherT, otherIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004859 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004860
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004861 // Avoid collapsing t values that are close to the same since
4862 // we walk ts to describe consecutive intersections. Since a pair of ts can
4863 // be nearly equal, any problems caused by this should be taken care
4864 // of later.
4865 // On the edge or out of range values are negative; add 2 to get end
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004866 int addT(double newT, const Work& other) {
4867 return fContour->addT(fIndex, newT, other.fContour, other.fIndex);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004868 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004869
caryclark@google.com73ca6242013-01-17 21:02:47 +00004870 int addUnsortableT(double newT, const Work& other, bool start) {
4871 return fContour->addUnsortableT(fIndex, newT, other.fContour, other.fIndex, start);
4872 }
4873
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004874 bool advance() {
4875 return ++fIndex < fLast;
4876 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004877
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004878 SkScalar bottom() const {
4879 return bounds().fBottom;
4880 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004881
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004882 const Bounds& bounds() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004883 return fContour->segments()[fIndex].bounds();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004884 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004885
caryclark@google.com73ca6242013-01-17 21:02:47 +00004886#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004887 const SkPoint* cubic() const {
4888 return fCubic;
4889 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00004890#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004891
4892 void init(Contour* contour) {
4893 fContour = contour;
4894 fIndex = 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004895 fLast = contour->segments().count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004896 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00004897
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00004898 bool isAdjacent(const Work& next) {
4899 return fContour == next.fContour && fIndex + 1 == next.fIndex;
4900 }
4901
4902 bool isFirstLast(const Work& next) {
4903 return fContour == next.fContour && fIndex == 0
4904 && next.fIndex == fLast - 1;
4905 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004906
4907 SkScalar left() const {
4908 return bounds().fLeft;
4909 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004910
caryclark@google.com73ca6242013-01-17 21:02:47 +00004911#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004912 void promoteToCubic() {
4913 fCubic[0] = pts()[0];
4914 fCubic[2] = pts()[1];
4915 fCubic[3] = pts()[2];
4916 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3;
4917 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3;
4918 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3;
4919 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3;
4920 }
caryclark@google.com73ca6242013-01-17 21:02:47 +00004921#endif
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004922
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004923 const SkPoint* pts() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004924 return fContour->segments()[fIndex].pts();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004925 }
4926
4927 SkScalar right() const {
4928 return bounds().fRight;
4929 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004930
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004931 ptrdiff_t segmentIndex() const {
4932 return fIndex;
4933 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004934
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004935 SegmentType segmentType() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004936 const Segment& segment = fContour->segments()[fIndex];
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004937 SegmentType type = (SegmentType) segment.verb();
4938 if (type != kLine_Segment) {
4939 return type;
4940 }
4941 if (segment.isHorizontal()) {
4942 return kHorizontalLine_Segment;
4943 }
4944 if (segment.isVertical()) {
4945 return kVerticalLine_Segment;
4946 }
4947 return kLine_Segment;
4948 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004949
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004950 bool startAfter(const Work& after) {
4951 fIndex = after.fIndex;
4952 return advance();
4953 }
4954
4955 SkScalar top() const {
4956 return bounds().fTop;
4957 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004958
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004959 SkPath::Verb verb() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004960 return fContour->segments()[fIndex].verb();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004961 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00004962
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004963 SkScalar x() const {
4964 return bounds().fLeft;
4965 }
4966
4967 bool xFlipped() const {
4968 return x() != pts()[0].fX;
4969 }
4970
4971 SkScalar y() const {
4972 return bounds().fTop;
4973 }
4974
4975 bool yFlipped() const {
caryclark@google.com8dcf1142012-07-02 20:27:02 +00004976 return y() != pts()[0].fY;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004977 }
4978
4979protected:
4980 Contour* fContour;
caryclark@google.com73ca6242013-01-17 21:02:47 +00004981#if !APPROXIMATE_CUBICS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004982 SkPoint fCubic[4];
caryclark@google.com73ca6242013-01-17 21:02:47 +00004983#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004984 int fIndex;
4985 int fLast;
4986};
4987
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00004988#if DEBUG_ADD_INTERSECTING_TS
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004989static void debugShowLineIntersection(int pts, const Work& wt,
4990 const Work& wn, const double wtTs[2], const double wnTs[2]) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00004991 return;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004992 if (!pts) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00004993 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n",
4994 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
4995 wt.pts()[1].fX, wt.pts()[1].fY, wn.pts()[0].fX, wn.pts()[0].fY,
4996 wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004997 return;
4998 }
4999 SkPoint wtOutPt, wnOutPt;
5000 LineXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5001 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005002 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 +00005003 __FUNCTION__,
5004 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5005 wt.pts()[1].fX, wt.pts()[1].fY, wtOutPt.fX, wtOutPt.fY);
5006 if (pts == 2) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005007 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005008 }
caryclark@google.coma461ff02012-10-11 12:54:23 +00005009 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005010 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5011 wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
5012 if (pts == 2) {
caryclark@google.coma461ff02012-10-11 12:54:23 +00005013 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
5014 }
5015 SkDebugf("\n");
5016}
5017
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005018static void debugShowQuadLineIntersection(int pts, const Work& wt,
5019 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5020 if (!pts) {
5021 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
caryclark@google.com0b7da432012-10-31 19:00:20 +00005022 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005023 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
5024 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005025 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005026 return;
5027 }
5028 SkPoint wtOutPt, wnOutPt;
5029 QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5030 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5031 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5032 __FUNCTION__,
5033 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5034 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
5035 wtOutPt.fX, wtOutPt.fY);
5036 if (pts == 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005037 QuadXYAtT(wt.pts(), wtTs[1], &wtOutPt);
5038 SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", wtTs[1], wtOutPt.fX, wtOutPt.fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005039 }
5040 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5041 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5042 wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
5043 if (pts == 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005044 LineXYAtT(wn.pts(), wnTs[1], &wnOutPt);
5045 SkDebugf(" wnTs[1]=%1.9g (%1.9g,%1.9g)", wnTs[1], wnOutPt.fX, wnOutPt.fY);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005046 }
5047 SkDebugf("\n");
5048}
5049
caryclark@google.com73ca6242013-01-17 21:02:47 +00005050// FIXME: show more than two intersection points
caryclark@google.coma461ff02012-10-11 12:54:23 +00005051static void debugShowQuadIntersection(int pts, const Work& wt,
5052 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5053 if (!pts) {
5054 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5055 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5056 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
skia.committer@gmail.com5b6f9162012-10-12 02:01:15 +00005057 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
caryclark@google.coma461ff02012-10-11 12:54:23 +00005058 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005059 wn.pts()[2].fX, wn.pts()[2].fY );
caryclark@google.coma461ff02012-10-11 12:54:23 +00005060 return;
5061 }
5062 SkPoint wtOutPt, wnOutPt;
5063 QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5064 QuadXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5065 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5066 __FUNCTION__,
5067 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
5068 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
5069 wtOutPt.fX, wtOutPt.fY);
5070 if (pts == 2) {
5071 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
5072 }
5073 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5074 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
5075 wn.pts()[1].fX, wn.pts()[1].fY, wn.pts()[2].fX, wn.pts()[2].fY,
5076 wnOutPt.fX, wnOutPt.fY);
5077 if (pts == 2) {
5078 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005079 }
caryclark@google.comb9738012012-07-03 19:53:30 +00005080 SkDebugf("\n");
5081}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005082
5083static void debugShowCubicLineIntersection(int pts, const Work& wt,
5084 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5085 if (!pts) {
5086 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5087 " (%1.9g,%1.9g %1.9g,%1.9g)\n",
5088 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5089 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5090 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
5091 return;
5092 }
5093 SkPoint wtOutPt, wnOutPt;
5094 CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5095 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5096 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)",
5097 __FUNCTION__,
5098 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5099 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5100 wtOutPt.fX, wtOutPt.fY);
5101 if (pts == 2) {
5102 CubicXYAtT(wt.pts(), wtTs[1], &wtOutPt);
5103 SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", wtTs[1], wtOutPt.fX, wtOutPt.fY);
5104 }
5105 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5106 wtTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5107 wnOutPt.fX, wnOutPt.fY);
5108 if (pts == 2) {
5109 LineXYAtT(wn.pts(), wnTs[1], &wnOutPt);
5110 SkDebugf(" wnTs[1]=%1.9g (%1.9g,%1.9g)", wnTs[1], wnOutPt.fX, wnOutPt.fY);
5111 }
5112 SkDebugf("\n");
5113}
5114
caryclark@google.com73ca6242013-01-17 21:02:47 +00005115// FIXME: show more than two intersection points
5116static void debugShowCubicQuadIntersection(int pts, const Work& wt,
5117 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5118 if (!pts) {
5119 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5120 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5121 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5122 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5123 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5124 wn.pts()[2].fX, wn.pts()[2].fY );
5125 return;
5126 }
5127 SkPoint wtOutPt, wnOutPt;
5128 CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005129 QuadXYAtT(wn.pts(), wnTs[0], &wnOutPt);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005130 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)",
5131 __FUNCTION__,
5132 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5133 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5134 wtOutPt.fX, wtOutPt.fY);
5135 if (pts == 2) {
5136 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
5137 }
5138 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5139 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5140 wn.pts()[2].fX, wn.pts()[2].fY,
5141 wnOutPt.fX, wnOutPt.fY);
5142 if (pts == 2) {
5143 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
5144 }
5145 SkDebugf("\n");
5146}
5147
5148// FIXME: show more than two intersection points
5149static void debugShowCubicIntersection(int pts, const Work& wt,
5150 const Work& wn, const double wtTs[2], const double wnTs[2]) {
5151 if (!pts) {
5152 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
5153 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
5154 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5155 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5156 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5157 wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY );
5158 return;
5159 }
5160 SkPoint wtOutPt, wnOutPt;
5161 CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
5162 CubicXYAtT(wn.pts(), wnTs[0], &wnOutPt);
5163 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)",
5164 __FUNCTION__,
5165 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
5166 wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
5167 wtOutPt.fX, wtOutPt.fY);
5168 if (pts == 2) {
5169 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
5170 }
5171 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
5172 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
5173 wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY,
5174 wnOutPt.fX, wnOutPt.fY);
5175 if (pts == 2) {
5176 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
5177 }
5178 SkDebugf("\n");
5179}
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005180
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005181#else
5182static void debugShowLineIntersection(int , const Work& ,
5183 const Work& , const double [2], const double [2]) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005184}
caryclark@google.coma461ff02012-10-11 12:54:23 +00005185
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005186static void debugShowQuadLineIntersection(int , const Work& ,
5187 const Work& , const double [2], const double [2]) {
5188}
5189
caryclark@google.coma461ff02012-10-11 12:54:23 +00005190static void debugShowQuadIntersection(int , const Work& ,
5191 const Work& , const double [2], const double [2]) {
5192}
caryclark@google.com73ca6242013-01-17 21:02:47 +00005193
5194static void debugShowCubicLineIntersection(int , const Work& ,
5195 const Work& , const double [2], const double [2]) {
5196}
5197
caryclark@google.com73ca6242013-01-17 21:02:47 +00005198static void debugShowCubicQuadIntersection(int , const Work& ,
5199 const Work& , const double [2], const double [2]) {
5200}
5201
5202static void debugShowCubicIntersection(int , const Work& ,
5203 const Work& , const double [2], const double [2]) {
5204}
5205#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005206
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00005207static bool addIntersectTs(Contour* test, Contour* next) {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005208
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005209 if (test != next) {
5210 if (test->bounds().fBottom < next->bounds().fTop) {
5211 return false;
5212 }
5213 if (!Bounds::Intersects(test->bounds(), next->bounds())) {
5214 return true;
5215 }
5216 }
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005217 Work wt;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005218 wt.init(test);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005219 bool foundCommonContour = test == next;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005220 do {
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005221 Work wn;
5222 wn.init(next);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005223 if (test == next && !wn.startAfter(wt)) {
5224 continue;
5225 }
5226 do {
5227 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) {
5228 continue;
5229 }
5230 int pts;
5231 Intersections ts;
5232 bool swap = false;
5233 switch (wt.segmentType()) {
5234 case Work::kHorizontalLine_Segment:
5235 swap = true;
5236 switch (wn.segmentType()) {
5237 case Work::kHorizontalLine_Segment:
5238 case Work::kVerticalLine_Segment:
5239 case Work::kLine_Segment: {
5240 pts = HLineIntersect(wn.pts(), wt.left(),
5241 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005242 debugShowLineIntersection(pts, wt, wn,
5243 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005244 break;
5245 }
5246 case Work::kQuad_Segment: {
5247 pts = HQuadIntersect(wn.pts(), wt.left(),
5248 wt.right(), wt.y(), wt.xFlipped(), ts);
5249 break;
5250 }
5251 case Work::kCubic_Segment: {
5252 pts = HCubicIntersect(wn.pts(), wt.left(),
5253 wt.right(), wt.y(), wt.xFlipped(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005254 debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005255 break;
5256 }
5257 default:
5258 SkASSERT(0);
5259 }
5260 break;
5261 case Work::kVerticalLine_Segment:
5262 swap = true;
5263 switch (wn.segmentType()) {
5264 case Work::kHorizontalLine_Segment:
5265 case Work::kVerticalLine_Segment:
5266 case Work::kLine_Segment: {
5267 pts = VLineIntersect(wn.pts(), wt.top(),
5268 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005269 debugShowLineIntersection(pts, wt, wn,
5270 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005271 break;
5272 }
5273 case Work::kQuad_Segment: {
5274 pts = VQuadIntersect(wn.pts(), wt.top(),
5275 wt.bottom(), wt.x(), wt.yFlipped(), ts);
5276 break;
5277 }
5278 case Work::kCubic_Segment: {
5279 pts = VCubicIntersect(wn.pts(), wt.top(),
5280 wt.bottom(), wt.x(), wt.yFlipped(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005281 debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005282 break;
5283 }
5284 default:
5285 SkASSERT(0);
5286 }
5287 break;
5288 case Work::kLine_Segment:
5289 switch (wn.segmentType()) {
5290 case Work::kHorizontalLine_Segment:
5291 pts = HLineIntersect(wt.pts(), wn.left(),
5292 wn.right(), wn.y(), wn.xFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005293 debugShowLineIntersection(pts, wt, wn,
5294 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005295 break;
5296 case Work::kVerticalLine_Segment:
5297 pts = VLineIntersect(wt.pts(), wn.top(),
5298 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005299 debugShowLineIntersection(pts, wt, wn,
5300 ts.fT[1], ts.fT[0]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005301 break;
5302 case Work::kLine_Segment: {
5303 pts = LineIntersect(wt.pts(), wn.pts(), ts);
5304 debugShowLineIntersection(pts, wt, wn,
5305 ts.fT[1], ts.fT[0]);
5306 break;
5307 }
5308 case Work::kQuad_Segment: {
5309 swap = true;
5310 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005311 debugShowQuadLineIntersection(pts, wn, wt,
5312 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005313 break;
5314 }
5315 case Work::kCubic_Segment: {
5316 swap = true;
5317 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005318 debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005319 break;
5320 }
5321 default:
5322 SkASSERT(0);
5323 }
5324 break;
5325 case Work::kQuad_Segment:
5326 switch (wn.segmentType()) {
5327 case Work::kHorizontalLine_Segment:
5328 pts = HQuadIntersect(wt.pts(), wn.left(),
5329 wn.right(), wn.y(), wn.xFlipped(), ts);
5330 break;
5331 case Work::kVerticalLine_Segment:
5332 pts = VQuadIntersect(wt.pts(), wn.top(),
5333 wn.bottom(), wn.x(), wn.yFlipped(), ts);
5334 break;
5335 case Work::kLine_Segment: {
5336 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005337 debugShowQuadLineIntersection(pts, wt, wn,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005338 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005339 break;
5340 }
5341 case Work::kQuad_Segment: {
5342 pts = QuadIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.coma461ff02012-10-11 12:54:23 +00005343 debugShowQuadIntersection(pts, wt, wn,
caryclark@google.com0b7da432012-10-31 19:00:20 +00005344 ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005345 break;
5346 }
5347 case Work::kCubic_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005348 #if APPROXIMATE_CUBICS
5349 swap = true;
5350 pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts);
5351 debugShowCubicQuadIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
5352 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005353 wt.promoteToCubic();
5354 pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005355 debugShowCubicIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005356 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005357 break;
5358 }
5359 default:
5360 SkASSERT(0);
5361 }
5362 break;
5363 case Work::kCubic_Segment:
5364 switch (wn.segmentType()) {
5365 case Work::kHorizontalLine_Segment:
5366 pts = HCubicIntersect(wt.pts(), wn.left(),
5367 wn.right(), wn.y(), wn.xFlipped(), ts);
5368 break;
5369 case Work::kVerticalLine_Segment:
5370 pts = VCubicIntersect(wt.pts(), wn.top(),
5371 wn.bottom(), wn.x(), wn.yFlipped(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005372 debugShowCubicLineIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005373 break;
5374 case Work::kLine_Segment: {
5375 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005376 debugShowCubicLineIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005377 break;
5378 }
5379 case Work::kQuad_Segment: {
caryclark@google.com73ca6242013-01-17 21:02:47 +00005380 #if APPROXIMATE_CUBICS
5381 pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts);
5382 debugShowCubicQuadIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
5383 #else
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005384 wn.promoteToCubic();
5385 pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
caryclark@google.com85ec74c2013-01-28 19:25:51 +00005386 debugShowCubicIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005387 #endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005388 break;
5389 }
5390 case Work::kCubic_Segment: {
5391 pts = CubicIntersect(wt.pts(), wn.pts(), ts);
caryclark@google.com73ca6242013-01-17 21:02:47 +00005392 debugShowCubicIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005393 break;
5394 }
5395 default:
5396 SkASSERT(0);
5397 }
5398 break;
5399 default:
5400 SkASSERT(0);
5401 }
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005402 if (!foundCommonContour && pts > 0) {
5403 test->addCross(next);
5404 next->addCross(test);
5405 foundCommonContour = true;
5406 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005407 // in addition to recording T values, record matching segment
caryclark@google.com73ca6242013-01-17 21:02:47 +00005408 if (ts.unsortable()) {
5409 bool start = true;
5410 for (int pt = 0; pt < ts.used(); ++pt) {
5411 // FIXME: if unsortable, the other points to the original. This logic is
5412 // untested downstream.
5413 int testTAt = wt.addUnsortableT(ts.fT[swap][pt], wt, start);
5414 wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt);
5415 testTAt = wn.addUnsortableT(ts.fT[!swap][pt], wn, start ^ ts.fFlip);
5416 wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt);
5417 start ^= true;
5418 }
5419 continue;
5420 }
caryclark@google.com32546db2012-08-31 20:55:07 +00005421 if (pts == 2) {
5422 if (wn.segmentType() <= Work::kLine_Segment
5423 && wt.segmentType() <= Work::kLine_Segment) {
5424 wt.addCoincident(wn, ts, swap);
5425 continue;
5426 }
5427 if (wn.segmentType() == Work::kQuad_Segment
5428 && wt.segmentType() == Work::kQuad_Segment
5429 && ts.coincidentUsed() == 2) {
5430 wt.addCoincident(wn, ts, swap);
5431 continue;
5432 }
5433
caryclark@google.coma3f05fa2012-06-01 17:44:28 +00005434 }
caryclark@google.com15fa1382012-05-07 20:49:36 +00005435 for (int pt = 0; pt < pts; ++pt) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005436 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
5437 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005438 int testTAt = wt.addT(ts.fT[swap][pt], wn);
5439 int nextTAt = wn.addT(ts.fT[!swap][pt], wt);
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005440 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
5441 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005442 }
5443 } while (wn.advance());
5444 } while (wt.advance());
5445 return true;
5446}
5447
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005448// resolve any coincident pairs found while intersecting, and
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005449// see if coincidence is formed by clipping non-concident segments
caryclark@google.com4eeda372012-12-06 21:47:48 +00005450static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005451 int contourCount = contourList.count();
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005452#if ONE_PASS_COINCIDENCE_CHECK
caryclark@google.comf25edfe2012-06-01 18:20:10 +00005453 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005454 Contour* contour = contourList[cIndex];
caryclark@google.com7ba591e2012-11-20 14:21:54 +00005455 contour->resolveCoincidence(contourList);
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005456 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005457#else
5458 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5459 Contour* contour = contourList[cIndex];
5460 contour->addCoincidentPoints();
5461 }
5462 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5463 Contour* contour = contourList[cIndex];
5464 contour->calcCoincidentWinding();
5465 }
5466#endif
caryclark@google.com8dcf1142012-07-02 20:27:02 +00005467 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5468 Contour* contour = contourList[cIndex];
caryclark@google.com4eeda372012-12-06 21:47:48 +00005469 contour->findTooCloseToCall();
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005470 }
5471}
5472
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005473static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005474 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005475 SkPoint basePt;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005476 double tAtMid = current->tAtMid(index, endIndex, mid);
5477 current->xyAtT(tAtMid, basePt);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005478 int contourCount = contourList.count();
5479 SkScalar bestY = SK_ScalarMin;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005480 Segment* bestSeg = NULL;
5481 int bestTIndex;
5482 bool bestOpp;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005483 bool hitSomething = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005484 for (int cTest = 0; cTest < contourCount; ++cTest) {
5485 Contour* contour = contourList[cTest];
5486 bool testOpp = contour->operand() ^ current->operand() ^ opp;
5487 if (basePt.fY < contour->bounds().fTop) {
5488 continue;
5489 }
5490 if (bestY > contour->bounds().fBottom) {
5491 continue;
5492 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005493 int segmentCount = contour->segments().count();
5494 for (int test = 0; test < segmentCount; ++test) {
5495 Segment* testSeg = &contour->segments()[test];
5496 SkScalar testY = bestY;
5497 double testHit;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005498 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
5499 testOpp, testSeg == current);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005500 if (testTIndex < 0) {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005501 if (testTIndex == SK_MinS32) {
5502 hitSomething = true;
5503 bestSeg = NULL;
5504 goto abortContours; // vertical encountered, return and try different point
5505 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005506 continue;
5507 }
5508 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005509 double baseT = current->t(index);
5510 double endT = current->t(endIndex);
5511 double newMid = (testHit - baseT) / (endT - baseT);
5512#if DEBUG_WINDING
5513 SkPoint midXY, newXY;
caryclark@google.com10227bf2012-12-28 22:10:41 +00005514 double midT = current->tAtMid(index, endIndex, mid);
5515 current->xyAtT(midT, midXY);
5516 double newMidT = current->tAtMid(index, endIndex, newMid);
5517 current->xyAtT(newMidT, newXY);
caryclark@google.com3586ece2012-12-27 18:46:58 +00005518 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
5519 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
5520 current->debugID(), mid, newMid,
5521 baseT, current->xAtT(index), current->yAtT(index),
5522 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
5523 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
5524 endT, current->xAtT(endIndex), current->yAtT(endIndex));
5525#endif
5526 mid = newMid * 2; // calling loop with divide by 2 before continuing
5527 return SK_MinS32;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005528 }
5529 bestSeg = testSeg;
5530 bestHit = testHit;
5531 bestOpp = testOpp;
5532 bestTIndex = testTIndex;
5533 bestY = testY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005534 }
5535 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005536abortContours:
caryclark@google.com10227bf2012-12-28 22:10:41 +00005537 int result;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005538 if (!bestSeg) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00005539 result = hitSomething ? SK_MinS32 : 0;
5540 } else {
5541 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
5542 current = bestSeg;
5543 index = bestTIndex;
5544 endIndex = bestSeg->nextSpan(bestTIndex, 1);
5545 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
5546 tryAgain = true;
5547 return 0;
5548 }
5549 result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
5550 SkASSERT(bestDx);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005551 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005552 double baseT = current->t(index);
5553 double endT = current->t(endIndex);
5554 bestHit = baseT + mid * (endT - baseT);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005555 return result;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005556}
5557
caryclark@google.com24bec792012-08-20 12:43:57 +00005558static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
5559 int contourCount = contourList.count();
5560 Segment* result;
5561 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5562 Contour* contour = contourList[cIndex];
5563 result = contour->undoneSegment(start, end);
5564 if (result) {
5565 return result;
5566 }
5567 }
5568 return NULL;
5569}
5570
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005571#define OLD_FIND_CHASE 1
caryclark@google.com24bec792012-08-20 12:43:57 +00005572
caryclark@google.com31143cf2012-11-09 22:14:19 +00005573static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005574 while (chase.count()) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00005575 Span* span;
5576 chase.pop(&span);
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005577 const Span& backPtr = span->fOther->span(span->fOtherIndex);
5578 Segment* segment = backPtr.fOther;
5579 tIndex = backPtr.fOtherIndex;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005580 SkTDArray<Angle> angles;
5581 int done = 0;
5582 if (segment->activeAngle(tIndex, done, angles)) {
5583 Angle* last = angles.end() - 1;
5584 tIndex = last->start();
5585 endIndex = last->end();
caryclark@google.com0b7da432012-10-31 19:00:20 +00005586 #if TRY_ROTATE
5587 *chase.insert(0) = span;
5588 #else
5589 *chase.append() = span;
5590 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005591 return last->segment();
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005592 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005593 if (done == angles.count()) {
caryclark@google.com9764cc62012-07-12 19:29:45 +00005594 continue;
5595 }
5596 SkTDArray<Angle*> sorted;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005597 bool sortable = Segment::SortAngles(angles, sorted);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005598 int angleCount = sorted.count();
caryclark@google.com03f97062012-08-21 13:13:52 +00005599#if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005600 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
caryclark@google.com03f97062012-08-21 13:13:52 +00005601#endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005602 if (!sortable) {
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005603 continue;
5604 }
caryclark@google.com9764cc62012-07-12 19:29:45 +00005605 // find first angle, initialize winding to computed fWindSum
5606 int firstIndex = -1;
5607 const Angle* angle;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005608#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005609 int winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005610 do {
5611 angle = sorted[++firstIndex];
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005612 segment = angle->segment();
5613 winding = segment->windSum(angle);
5614 } while (winding == SK_MinS32);
5615 int spanWinding = segment->spanSign(angle->start(), angle->end());
5616 #if DEBUG_WINDING
caryclark@google.com31143cf2012-11-09 22:14:19 +00005617 SkDebugf("%s winding=%d spanWinding=%d\n",
5618 __FUNCTION__, winding, spanWinding);
caryclark@google.com47580692012-07-23 12:14:49 +00005619 #endif
caryclark@google.com31143cf2012-11-09 22:14:19 +00005620 // turn span winding into contour winding
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005621 if (spanWinding * winding < 0) {
5622 winding += spanWinding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005623 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005624 #if DEBUG_SORT
caryclark@google.com31143cf2012-11-09 22:14:19 +00005625 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005626 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005627 // we care about first sign and whether wind sum indicates this
5628 // edge is inside or outside. Maybe need to pass span winding
5629 // or first winding or something into this function?
5630 // advance to first undone angle, then return it and winding
5631 // (to set whether edges are active or not)
5632 int nextIndex = firstIndex + 1;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005633 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005634 angle = sorted[firstIndex];
caryclark@google.com2ddff932012-08-07 21:25:27 +00005635 winding -= angle->segment()->spanSign(angle);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005636#else
5637 do {
5638 angle = sorted[++firstIndex];
5639 segment = angle->segment();
5640 } while (segment->windSum(angle) == SK_MinS32);
5641 #if DEBUG_SORT
5642 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
5643 #endif
5644 int sumWinding = segment->updateWindingReverse(angle);
5645 int nextIndex = firstIndex + 1;
5646 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
5647 Segment* first = NULL;
5648#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005649 do {
5650 SkASSERT(nextIndex != firstIndex);
5651 if (nextIndex == angleCount) {
5652 nextIndex = 0;
5653 }
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005654 angle = sorted[nextIndex];
caryclark@google.com9764cc62012-07-12 19:29:45 +00005655 segment = angle->segment();
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005656#if OLD_FIND_CHASE
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005657 int maxWinding = winding;
caryclark@google.com2ddff932012-08-07 21:25:27 +00005658 winding -= segment->spanSign(angle);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005659 #if DEBUG_SORT
caryclark@google.com2ddff932012-08-07 21:25:27 +00005660 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
5661 segment->debugID(), maxWinding, winding, angle->sign());
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005662 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005663 tIndex = angle->start();
5664 endIndex = angle->end();
5665 int lesser = SkMin32(tIndex, endIndex);
5666 const Span& nextSpan = segment->span(lesser);
5667 if (!nextSpan.fDone) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005668#if 1
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005669 // FIXME: this be wrong? assign startWinding if edge is in
caryclark@google.com9764cc62012-07-12 19:29:45 +00005670 // same direction. If the direction is opposite, winding to
5671 // assign is flipped sign or +/- 1?
caryclark@google.com59823f72012-08-09 18:17:47 +00005672 if (useInnerWinding(maxWinding, winding)) {
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005673 maxWinding = winding;
caryclark@google.com9764cc62012-07-12 19:29:45 +00005674 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005675 segment->markAndChaseWinding(angle, maxWinding, 0);
caryclark@google.com534aa5b2012-08-02 20:08:21 +00005676#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005677 break;
5678 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005679#else
5680 int start = angle->start();
5681 int end = angle->end();
5682 int maxWinding;
5683 segment->setUpWinding(start, end, maxWinding, sumWinding);
5684 if (!segment->done(angle)) {
5685 if (!first) {
5686 first = segment;
5687 tIndex = start;
5688 endIndex = end;
5689 }
5690 (void) segment->markAngle(maxWinding, sumWinding, true, angle);
5691 }
5692#endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005693 } while (++nextIndex != lastIndex);
caryclark@google.com0b7da432012-10-31 19:00:20 +00005694 #if TRY_ROTATE
5695 *chase.insert(0) = span;
5696 #else
5697 *chase.append() = span;
5698 #endif
caryclark@google.com9764cc62012-07-12 19:29:45 +00005699 return segment;
caryclark@google.comfa4a6e92012-07-11 17:52:32 +00005700 }
5701 return NULL;
5702}
5703
caryclark@google.com027de222012-07-12 12:52:50 +00005704#if DEBUG_ACTIVE_SPANS
5705static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005706 int index;
5707 for (index = 0; index < contourList.count(); ++ index) {
caryclark@google.com027de222012-07-12 12:52:50 +00005708 contourList[index]->debugShowActiveSpans();
5709 }
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005710 for (index = 0; index < contourList.count(); ++ index) {
5711 contourList[index]->validateActiveSpans();
5712 }
caryclark@google.com027de222012-07-12 12:52:50 +00005713}
5714#endif
5715
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005716static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005717 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005718 Segment* result;
5719 do {
caryclark@google.comf839c032012-10-26 21:03:50 +00005720 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005721 int contourCount = contourList.count();
caryclark@google.comf839c032012-10-26 21:03:50 +00005722 Segment* topStart = NULL;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005723 done = true;
caryclark@google.comf839c032012-10-26 21:03:50 +00005724 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5725 Contour* contour = contourList[cIndex];
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005726 if (contour->done()) {
5727 continue;
5728 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005729 const Bounds& bounds = contour->bounds();
5730 if (bounds.fBottom < topLeft.fY) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005731 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005732 continue;
5733 }
5734 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005735 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005736 continue;
5737 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005738 contour->topSortableSegment(topLeft, bestXY, topStart);
5739 if (!contour->done()) {
5740 done = false;
caryclark@google.comf839c032012-10-26 21:03:50 +00005741 }
5742 }
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005743 if (!topStart) {
5744 return NULL;
5745 }
caryclark@google.comf839c032012-10-26 21:03:50 +00005746 topLeft = bestXY;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005747 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005748 } while (!result);
5749 return result;
5750}
caryclark@google.com31143cf2012-11-09 22:14:19 +00005751
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005752static int rightAngleWinding(SkTDArray<Contour*>& contourList,
caryclark@google.com3586ece2012-12-27 18:46:58 +00005753 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005754 bool opp) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005755 double test = 0.9;
5756 int contourWinding;
5757 do {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005758 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
5759 tryAgain, test, opp);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005760 if (contourWinding != SK_MinS32 || tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005761 return contourWinding;
5762 }
5763 test /= 2;
5764 } while (!approximately_negative(test));
5765 SkASSERT(0); // should be OK to comment out, but interested when this hits
5766 return contourWinding;
5767}
5768
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005769static void skipVertical(SkTDArray<Contour*>& contourList,
5770 Segment*& current, int& index, int& endIndex) {
5771 if (!current->isVertical(index, endIndex)) {
5772 return;
5773 }
5774 int contourCount = contourList.count();
5775 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
5776 Contour* contour = contourList[cIndex];
5777 if (contour->done()) {
5778 continue;
5779 }
5780 current = contour->nonVerticalSegment(index, endIndex);
5781 if (current) {
5782 return;
5783 }
5784 }
5785}
5786
caryclark@google.com3586ece2012-12-27 18:46:58 +00005787static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005788 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
5789 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
5790 true);
5791 if (!current) {
5792 return NULL;
5793 }
5794 if (firstContour) {
caryclark@google.com3586ece2012-12-27 18:46:58 +00005795 current->initWinding(index, endIndex);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005796 firstContour = false;
5797 return current;
5798 }
5799 int minIndex = SkMin32(index, endIndex);
5800 int sumWinding = current->windSum(minIndex);
5801 if (sumWinding != SK_MinS32) {
5802 return current;
5803 }
5804 sumWinding = current->computeSum(index, endIndex, binary);
5805 if (sumWinding != SK_MinS32) {
5806 return current;
5807 }
5808 int contourWinding;
5809 int oppContourWinding = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005810 // the simple upward projection of the unresolved points hit unsortable angles
5811 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005812 bool tryAgain;
5813 double tHit;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005814 SkScalar hitDx = 0;
5815 SkScalar hitOppDx = 0;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005816 do {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005817 // if current is vertical, find another candidate which is not
5818 // if only remaining candidates are vertical, then they can be marked done
caryclark@google.com10227bf2012-12-28 22:10:41 +00005819 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005820 skipVertical(contourList, current, index, endIndex);
caryclark@google.com10227bf2012-12-28 22:10:41 +00005821 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005822 tryAgain = false;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005823 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005824 tryAgain, false);
5825 if (tryAgain) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005826 continue;
5827 }
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005828 if (!binary) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005829 break;
5830 }
caryclark@google.com3586ece2012-12-27 18:46:58 +00005831 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005832 tryAgain, true);
5833 } while (tryAgain);
skia.committer@gmail.com8d83d0d2012-12-28 02:01:18 +00005834
caryclark@google.com3586ece2012-12-27 18:46:58 +00005835 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005836 return current;
5837}
5838
5839// rewrite that abandons keeping local track of winding
caryclark@google.com3586ece2012-12-27 18:46:58 +00005840static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005841 bool firstContour = true;
5842 bool unsortable = false;
5843 bool topUnsortable = false;
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005844 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
5845 do {
5846 int index, endIndex;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005847 bool topDone;
caryclark@google.com3586ece2012-12-27 18:46:58 +00005848 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005849 topUnsortable, topDone, false);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005850 if (!current) {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005851 if (topUnsortable || !topDone) {
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005852 topUnsortable = false;
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005853 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005854 topLeft.fX = topLeft.fY = SK_ScalarMin;
5855 continue;
5856 }
5857 break;
5858 }
5859 SkTDArray<Span*> chaseArray;
5860 do {
5861 if (current->activeWinding(index, endIndex)) {
5862 do {
5863 #if DEBUG_ACTIVE_SPANS
5864 if (!unsortable && current->done()) {
5865 debugShowActiveSpans(contourList);
5866 }
5867 #endif
5868 SkASSERT(unsortable || !current->done());
5869 int nextStart = index;
5870 int nextEnd = endIndex;
5871 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd,
5872 unsortable);
5873 if (!next) {
5874 if (!unsortable && simple.hasMove()
5875 && current->verb() != SkPath::kLine_Verb
5876 && !simple.isClosed()) {
5877 current->addCurveTo(index, endIndex, simple, true);
5878 SkASSERT(simple.isClosed());
5879 }
5880 break;
5881 }
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005882 #if DEBUG_FLOW
5883 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
5884 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
5885 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
5886 #endif
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005887 current->addCurveTo(index, endIndex, simple, true);
5888 current = next;
5889 index = nextStart;
5890 endIndex = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005891 } while (!simple.isClosed() && (!unsortable
caryclark@google.com10227bf2012-12-28 22:10:41 +00005892 || !current->done(SkMin32(index, endIndex))));
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005893 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
5894 SkASSERT(unsortable);
5895 int min = SkMin32(index, endIndex);
5896 if (!current->done(min)) {
5897 current->addCurveTo(index, endIndex, simple, true);
5898 current->markDoneUnary(min);
5899 }
5900 }
5901 simple.close();
5902 } else {
caryclark@google.comdb0b3e02012-12-21 21:34:36 +00005903 Span* last = current->markAndChaseDoneUnary(index, endIndex);
caryclark@google.comd0deb4f2012-12-17 13:58:08 +00005904 if (last) {
5905 *chaseArray.append() = last;
5906 }
5907 }
5908 current = findChase(chaseArray, index, endIndex);
5909 #if DEBUG_ACTIVE_SPANS
5910 debugShowActiveSpans(contourList);
5911 #endif
5912 if (!current) {
5913 break;
5914 }
5915 } while (true);
5916 } while (true);
5917 return simple.someAssemblyRequired();
5918}
5919
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005920// returns true if all edges were processed
caryclark@google.comf839c032012-10-26 21:03:50 +00005921static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
caryclark@google.com24bec792012-08-20 12:43:57 +00005922 Segment* current;
5923 int start, end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005924 bool unsortable = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005925 bool closable = true;
caryclark@google.com24bec792012-08-20 12:43:57 +00005926 while ((current = findUndone(contourList, start, end))) {
caryclark@google.com24bec792012-08-20 12:43:57 +00005927 do {
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005928 #if DEBUG_ACTIVE_SPANS
5929 if (!unsortable && current->done()) {
5930 debugShowActiveSpans(contourList);
5931 }
5932 #endif
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005933 SkASSERT(unsortable || !current->done());
caryclark@google.com24bec792012-08-20 12:43:57 +00005934 int nextStart = start;
5935 int nextEnd = end;
caryclark@google.comc91dfe42012-10-16 12:06:27 +00005936 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable);
caryclark@google.com24bec792012-08-20 12:43:57 +00005937 if (!next) {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005938 if (!unsortable && simple.hasMove()
caryclark@google.comf839c032012-10-26 21:03:50 +00005939 && current->verb() != SkPath::kLine_Verb
5940 && !simple.isClosed()) {
5941 current->addCurveTo(start, end, simple, true);
5942 SkASSERT(simple.isClosed());
caryclark@google.comc899ad92012-08-23 15:24:42 +00005943 }
caryclark@google.com24bec792012-08-20 12:43:57 +00005944 break;
5945 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005946 #if DEBUG_FLOW
5947 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
5948 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
5949 current->xyAtT(end).fX, current->xyAtT(end).fY);
5950 #endif
caryclark@google.comf839c032012-10-26 21:03:50 +00005951 current->addCurveTo(start, end, simple, true);
caryclark@google.com24bec792012-08-20 12:43:57 +00005952 current = next;
5953 start = nextStart;
5954 end = nextEnd;
caryclark@google.com8f9f4682013-01-03 21:18:16 +00005955 } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005956 if (!simple.isClosed()) {
5957 SkASSERT(unsortable);
5958 int min = SkMin32(start, end);
5959 if (!current->done(min)) {
5960 current->addCurveTo(start, end, simple, true);
5961 current->markDone(min, 1);
5962 }
5963 closable = false;
caryclark@google.com24bec792012-08-20 12:43:57 +00005964 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005965 simple.close();
caryclark@google.com6aea33f2012-10-09 14:11:58 +00005966 #if DEBUG_ACTIVE_SPANS
5967 debugShowActiveSpans(contourList);
5968 #endif
rmistry@google.comd6176b02012-08-23 18:14:13 +00005969 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00005970 return closable;
caryclark@google.com24bec792012-08-20 12:43:57 +00005971}
5972
caryclark@google.comb45a1b42012-05-18 20:50:33 +00005973static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
5974 int contourCount = contourList.count();
5975 for (int cTest = 0; cTest < contourCount; ++cTest) {
5976 Contour* contour = contourList[cTest];
5977 contour->fixOtherTIndex();
5978 }
5979}
5980
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005981static void sortSegments(SkTDArray<Contour*>& contourList) {
5982 int contourCount = contourList.count();
5983 for (int cTest = 0; cTest < contourCount; ++cTest) {
5984 Contour* contour = contourList[cTest];
5985 contour->sortSegments();
5986 }
5987}
caryclark@google.comfb51afb2012-10-19 15:54:16 +00005988
caryclark@google.com4eeda372012-12-06 21:47:48 +00005989static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list,
5990 bool evenOdd, bool oppEvenOdd) {
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005991 int count = contours.count();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005992 if (count == 0) {
5993 return;
5994 }
caryclark@google.coma833b5c2012-04-30 19:38:50 +00005995 for (int index = 0; index < count; ++index) {
caryclark@google.com4eeda372012-12-06 21:47:48 +00005996 Contour& contour = contours[index];
5997 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
5998 *list.append() = &contour;
caryclark@google.comfa0588f2012-04-26 21:01:06 +00005999 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006000 QSort<Contour>(list.begin(), list.end() - 1);
6001}
6002
caryclark@google.comf839c032012-10-26 21:03:50 +00006003static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006004 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006005}
6006
caryclark@google.com10227bf2012-12-28 22:10:41 +00006007static bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
6008 return distances[one] < distances[two];
6009}
caryclark@google.comf839c032012-10-26 21:03:50 +00006010 /*
6011 check start and end of each contour
6012 if not the same, record them
6013 match them up
6014 connect closest
6015 reassemble contour pieces into new path
6016 */
6017static void assemble(const PathWrapper& path, PathWrapper& simple) {
6018#if DEBUG_PATH_CONSTRUCTION
6019 SkDebugf("%s\n", __FUNCTION__);
6020#endif
6021 SkTArray<Contour> contours;
6022 EdgeBuilder builder(path, contours);
6023 builder.finish();
6024 int count = contours.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006025 int outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006026 SkTDArray<int> runs; // indices of partial contours
caryclark@google.com0b7da432012-10-31 19:00:20 +00006027 for (outer = 0; outer < count; ++outer) {
6028 const Contour& eContour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006029 const SkPoint& eStart = eContour.start();
6030 const SkPoint& eEnd = eContour.end();
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006031#if DEBUG_ASSEMBLE
6032 SkDebugf("%s contour", __FUNCTION__);
6033 if (!approximatelyEqual(eStart, eEnd)) {
6034 SkDebugf("[%d]", runs.count());
6035 } else {
6036 SkDebugf(" ");
6037 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006038 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006039 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
6040#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006041 if (approximatelyEqual(eStart, eEnd)) {
6042 eContour.toPath(simple);
6043 continue;
6044 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006045 *runs.append() = outer;
caryclark@google.comf839c032012-10-26 21:03:50 +00006046 }
6047 count = runs.count();
caryclark@google.com0b7da432012-10-31 19:00:20 +00006048 if (count == 0) {
6049 return;
6050 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006051 SkTDArray<int> sLink, eLink;
6052 sLink.setCount(count);
6053 eLink.setCount(count);
caryclark@google.com10227bf2012-12-28 22:10:41 +00006054 int rIndex, iIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006055 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006056 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006057 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006058 SkTDArray<double> distances;
6059 const int ends = count * 2; // all starts and ends
6060 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
6061 distances.setCount(entries);
6062 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
6063 outer = runs[rIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006064 const Contour& oContour = contours[outer];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006065 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
6066 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
6067 * ends - rIndex - 1;
6068 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
6069 int inner = runs[iIndex >> 1];
caryclark@google.com0b7da432012-10-31 19:00:20 +00006070 const Contour& iContour = contours[inner];
caryclark@google.com10227bf2012-12-28 22:10:41 +00006071 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
6072 double dx = iPt.fX - oPt.fX;
6073 double dy = iPt.fY - oPt.fY;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006074 double dist = dx * dx + dy * dy;
caryclark@google.com10227bf2012-12-28 22:10:41 +00006075 distances[row + iIndex] = dist; // oStart distance from iStart
6076 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006077 }
caryclark@google.com10227bf2012-12-28 22:10:41 +00006078 SkTDArray<int> sortedDist;
6079 sortedDist.setCount(entries);
6080 for (rIndex = 0; rIndex < entries; ++rIndex) {
6081 sortedDist[rIndex] = rIndex;
6082 }
6083 QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
6084 int remaining = count; // number of start/end pairs
6085 for (rIndex = 0; rIndex < entries; ++rIndex) {
6086 int pair = sortedDist[rIndex];
6087 int row = pair / ends;
6088 int col = pair - row * ends;
6089 int thingOne = row < col ? row : ends - row - 2;
6090 int ndxOne = thingOne >> 1;
6091 bool endOne = thingOne & 1;
6092 int* linkOne = endOne ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006093 if (linkOne[ndxOne] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006094 continue;
6095 }
6096 int thingTwo = row < col ? col : ends - row + col - 1;
6097 int ndxTwo = thingTwo >> 1;
6098 bool endTwo = thingTwo & 1;
6099 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
caryclark@google.comaa358312013-01-29 20:28:49 +00006100 if (linkTwo[ndxTwo] != SK_MaxS32) {
caryclark@google.com10227bf2012-12-28 22:10:41 +00006101 continue;
6102 }
6103 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
6104 bool flip = endOne == endTwo;
6105 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
6106 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
6107 if (!--remaining) {
6108 break;
6109 }
6110 }
6111 SkASSERT(!remaining);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006112#if DEBUG_ASSEMBLE
6113 for (rIndex = 0; rIndex < count; ++rIndex) {
6114 int s = sLink[rIndex];
6115 int e = eLink[rIndex];
6116 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
6117 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
caryclark@google.comf839c032012-10-26 21:03:50 +00006118 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006119#endif
6120 rIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +00006121 do {
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006122 bool forward = true;
6123 bool first = true;
6124 int sIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006125 SkASSERT(sIndex != SK_MaxS32);
6126 sLink[rIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006127 int eIndex;
6128 if (sIndex < 0) {
6129 eIndex = sLink[~sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006130 sLink[~sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006131 } else {
6132 eIndex = eLink[sIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006133 eLink[sIndex] = SK_MaxS32;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006134 }
caryclark@google.comaa358312013-01-29 20:28:49 +00006135 SkASSERT(eIndex != SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006136#if DEBUG_ASSEMBLE
6137 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006138 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
6139 eIndex < 0 ? ~eIndex : eIndex);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006140#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006141 do {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006142 outer = runs[rIndex];
6143 const Contour& contour = contours[outer];
caryclark@google.comf839c032012-10-26 21:03:50 +00006144 if (first) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006145 first = false;
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006146 const SkPoint* startPtr = &contour.start();
caryclark@google.comf839c032012-10-26 21:03:50 +00006147 simple.deferredMove(startPtr[0]);
6148 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006149 if (forward) {
6150 contour.toPartialForward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006151 } else {
6152 contour.toPartialBackward(simple);
caryclark@google.comf839c032012-10-26 21:03:50 +00006153 }
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006154#if DEBUG_ASSEMBLE
6155 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +00006156 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006157 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
6158#endif
6159 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006160 simple.close();
caryclark@google.comf839c032012-10-26 21:03:50 +00006161 break;
6162 }
caryclark@google.comf839c032012-10-26 21:03:50 +00006163 if (forward) {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006164 eIndex = eLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006165 SkASSERT(eIndex != SK_MaxS32);
6166 eLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006167 if (eIndex >= 0) {
6168 SkASSERT(sLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006169 sLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006170 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006171 SkASSERT(eLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006172 eLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006173 }
6174 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006175 eIndex = sLink[rIndex];
caryclark@google.comaa358312013-01-29 20:28:49 +00006176 SkASSERT(eIndex != SK_MaxS32);
6177 sLink[rIndex] = SK_MaxS32;
caryclark@google.com0b7da432012-10-31 19:00:20 +00006178 if (eIndex >= 0) {
6179 SkASSERT(eLink[eIndex] == rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006180 eLink[eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006181 } else {
caryclark@google.com0b7da432012-10-31 19:00:20 +00006182 SkASSERT(sLink[~eIndex] == ~rIndex);
caryclark@google.comaa358312013-01-29 20:28:49 +00006183 sLink[~eIndex] = SK_MaxS32;
caryclark@google.comf839c032012-10-26 21:03:50 +00006184 }
6185 }
caryclark@google.com0b7da432012-10-31 19:00:20 +00006186 rIndex = eIndex;
caryclark@google.comf839c032012-10-26 21:03:50 +00006187 if (rIndex < 0) {
6188 forward ^= 1;
6189 rIndex = ~rIndex;
6190 }
6191 } while (true);
6192 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006193 if (sLink[rIndex] != SK_MaxS32) {
caryclark@google.comf839c032012-10-26 21:03:50 +00006194 break;
6195 }
6196 }
6197 } while (rIndex < count);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006198#if DEBUG_ASSEMBLE
6199 for (rIndex = 0; rIndex < count; ++rIndex) {
caryclark@google.comaa358312013-01-29 20:28:49 +00006200 SkASSERT(sLink[rIndex] == SK_MaxS32);
6201 SkASSERT(eLink[rIndex] == SK_MaxS32);
caryclark@google.come7bd5f42012-12-13 19:47:53 +00006202 }
6203#endif
caryclark@google.comf839c032012-10-26 21:03:50 +00006204}
6205
6206void simplifyx(const SkPath& path, SkPath& result) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006207 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
caryclark@google.comf839c032012-10-26 21:03:50 +00006208 result.reset();
6209 result.setFillType(SkPath::kEvenOdd_FillType);
6210 PathWrapper simple(result);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006211
6212 // turn path into list of segments
6213 SkTArray<Contour> contours;
6214 // FIXME: add self-intersecting cubics' T values to segment
6215 EdgeBuilder builder(path, contours);
caryclark@google.com235f56a2012-09-14 14:19:30 +00006216 builder.finish();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006217 SkTDArray<Contour*> contourList;
caryclark@google.com4eeda372012-12-06 21:47:48 +00006218 makeContourList(contours, contourList, false, false);
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006219 Contour** currentPtr = contourList.begin();
6220 if (!currentPtr) {
6221 return;
6222 }
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006223 Contour** listEnd = contourList.end();
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006224 // find all intersections between segments
6225 do {
6226 Contour** nextPtr = currentPtr;
6227 Contour* current = *currentPtr++;
6228 Contour* next;
6229 do {
6230 next = *nextPtr++;
caryclark@google.com65f9f0a2012-05-23 18:09:25 +00006231 } while (addIntersectTs(current, next) && nextPtr != listEnd);
caryclark@google.com1577e8f2012-05-22 17:01:14 +00006232 } while (currentPtr != listEnd);
caryclark@google.coma833b5c2012-04-30 19:38:50 +00006233 // eat through coincident edges
caryclark@google.com4eeda372012-12-06 21:47:48 +00006234 coincidenceCheck(contourList, 0);
caryclark@google.com66ca2fb2012-07-03 14:30:08 +00006235 fixOtherTIndex(contourList);
caryclark@google.comfb51afb2012-10-19 15:54:16 +00006236 sortSegments(contourList);
caryclark@google.com0b7da432012-10-31 19:00:20 +00006237#if DEBUG_ACTIVE_SPANS
6238 debugShowActiveSpans(contourList);
6239#endif
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006240 // construct closed contours
caryclark@google.com3586ece2012-12-27 18:46:58 +00006241 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
skia.committer@gmail.com20c301b2012-10-17 02:01:13 +00006242 : !bridgeXor(contourList, simple))
caryclark@google.comc91dfe42012-10-16 12:06:27 +00006243 { // if some edges could not be resolved, assemble remaining fragments
caryclark@google.comf839c032012-10-26 21:03:50 +00006244 SkPath temp;
6245 temp.setFillType(SkPath::kEvenOdd_FillType);
6246 PathWrapper assembled(temp);
6247 assemble(simple, assembled);
6248 result = *assembled.nativePath();
caryclark@google.com24bec792012-08-20 12:43:57 +00006249 }
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006250}