blob: 4d11eb39e8259b73c79e313c109e1aa314f94402 [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +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 */
7#include "SkIntersections.h"
8#include "SkOpSegment.h"
9#include "SkPathWriter.h"
caryclark@google.com7dfbb072013-04-22 14:37:05 +000010#include "SkTSort.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +000011
12#define F (false) // discard the edge
13#define T (true) // keep the edge
14
15static const bool gUnaryActiveEdge[2][2] = {
16// from=0 from=1
17// to=0,1 to=0,1
18 {F, T}, {T, F},
19};
20
caryclark@google.com07393ca2013-04-08 11:47:37 +000021static const bool gActiveEdge[kXOR_PathOp + 1][2][2][2][2] = {
22// miFrom=0 miFrom=1
23// miTo=0 miTo=1 miTo=0 miTo=1
24// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
25// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
26 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
27 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
28 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
29 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su
30};
31
32#undef F
33#undef T
34
caryclark@google.com570863f2013-09-16 15:55:01 +000035enum {
36 kOutsideTrackedTCount = 16, // FIXME: determine what this should be
37 kMissingSpanCount = 4, // FIXME: determine what this should be
38};
caryclark@google.comd892bd82013-06-17 14:10:36 +000039
caryclark@google.com570863f2013-09-16 15:55:01 +000040// note that this follows the same logic flow as build angles
caryclark@google.comd892bd82013-06-17 14:10:36 +000041bool SkOpSegment::activeAngle(int index, int* done, SkTArray<SkOpAngle, true>* angles) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000042 if (activeAngleInner(index, done, angles)) {
43 return true;
44 }
caryclark@google.com570863f2013-09-16 15:55:01 +000045 double referenceT = fTs[index].fT;
caryclark@google.com07393ca2013-04-08 11:47:37 +000046 int lesser = index;
caryclark@google.com570863f2013-09-16 15:55:01 +000047 while (--lesser >= 0
48 && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].fTiny)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000049 if (activeAngleOther(lesser, done, angles)) {
50 return true;
51 }
52 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000053 do {
54 if (activeAngleOther(index, done, angles)) {
55 return true;
56 }
caryclark@google.com570863f2013-09-16 15:55:01 +000057 if (++index == fTs.count()) {
58 break;
59 }
60 if (fTs[index - 1].fTiny) {
61 referenceT = fTs[index].fT;
62 continue;
63 }
64 } while (precisely_negative(fTs[index].fT - referenceT));
caryclark@google.com07393ca2013-04-08 11:47:37 +000065 return false;
66}
67
caryclark@google.comd892bd82013-06-17 14:10:36 +000068bool SkOpSegment::activeAngleOther(int index, int* done, SkTArray<SkOpAngle, true>* angles) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000069 SkOpSpan* span = &fTs[index];
70 SkOpSegment* other = span->fOther;
71 int oIndex = span->fOtherIndex;
72 return other->activeAngleInner(oIndex, done, angles);
73}
74
caryclark@google.comd892bd82013-06-17 14:10:36 +000075bool SkOpSegment::activeAngleInner(int index, int* done, SkTArray<SkOpAngle, true>* angles) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000076 int next = nextExactSpan(index, 1);
77 if (next > 0) {
78 SkOpSpan& upSpan = fTs[index];
79 if (upSpan.fWindValue || upSpan.fOppValue) {
80 addAngle(angles, index, next);
81 if (upSpan.fDone || upSpan.fUnsortableEnd) {
82 (*done)++;
83 } else if (upSpan.fWindSum != SK_MinS32) {
84 return true;
85 }
86 } else if (!upSpan.fDone) {
87 upSpan.fDone = true;
88 fDoneSpans++;
89 }
90 }
91 int prev = nextExactSpan(index, -1);
92 // edge leading into junction
93 if (prev >= 0) {
94 SkOpSpan& downSpan = fTs[prev];
95 if (downSpan.fWindValue || downSpan.fOppValue) {
96 addAngle(angles, index, prev);
97 if (downSpan.fDone) {
98 (*done)++;
99 } else if (downSpan.fWindSum != SK_MinS32) {
100 return true;
101 }
102 } else if (!downSpan.fDone) {
103 downSpan.fDone = true;
104 fDoneSpans++;
105 }
106 }
107 return false;
108}
109
110SkPoint SkOpSegment::activeLeftTop(bool onlySortable, int* firstT) const {
111 SkASSERT(!done());
112 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
113 int count = fTs.count();
114 // see if either end is not done since we want smaller Y of the pair
115 bool lastDone = true;
116 bool lastUnsortable = false;
117 double lastT = -1;
118 for (int index = 0; index < count; ++index) {
119 const SkOpSpan& span = fTs[index];
120 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
121 goto next;
122 }
123 if (span.fDone && lastDone) {
124 goto next;
125 }
126 if (approximately_negative(span.fT - lastT)) {
127 goto next;
128 }
129 {
130 const SkPoint& xy = xyAtT(&span);
131 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
132 topPt = xy;
133 if (firstT) {
134 *firstT = index;
135 }
136 }
137 if (fVerb != SkPath::kLine_Verb && !lastDone) {
reed@google.com277c3f82013-05-31 15:17:50 +0000138 SkPoint curveTop = (*CurveTop[SkPathOpsVerbToPoints(fVerb)])(fPts, lastT, span.fT);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000139 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
140 && topPt.fX > curveTop.fX)) {
141 topPt = curveTop;
142 if (firstT) {
143 *firstT = index;
144 }
145 }
146 }
147 lastT = span.fT;
148 }
149next:
150 lastDone = span.fDone;
151 lastUnsortable = span.fUnsortableEnd;
152 }
153 return topPt;
154}
155
156bool SkOpSegment::activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op) {
157 int sumMiWinding = updateWinding(endIndex, index);
158 int sumSuWinding = updateOppWinding(endIndex, index);
159 if (fOperand) {
160 SkTSwap<int>(sumMiWinding, sumSuWinding);
161 }
162 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
163 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, &sumMiWinding, &sumSuWinding,
164 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
165}
166
167bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op,
168 int* sumMiWinding, int* sumSuWinding,
169 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) {
170 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
171 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
172 bool miFrom;
173 bool miTo;
174 bool suFrom;
175 bool suTo;
176 if (operand()) {
177 miFrom = (*oppMaxWinding & xorMiMask) != 0;
178 miTo = (*oppSumWinding & xorMiMask) != 0;
179 suFrom = (*maxWinding & xorSuMask) != 0;
180 suTo = (*sumWinding & xorSuMask) != 0;
181 } else {
182 miFrom = (*maxWinding & xorMiMask) != 0;
183 miTo = (*sumWinding & xorMiMask) != 0;
184 suFrom = (*oppMaxWinding & xorSuMask) != 0;
185 suTo = (*oppSumWinding & xorSuMask) != 0;
186 }
187 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
188#if DEBUG_ACTIVE_OP
189 SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__,
caryclark@google.com570863f2013-09-16 15:55:01 +0000190 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000191#endif
192 return result;
193}
194
195bool SkOpSegment::activeWinding(int index, int endIndex) {
196 int sumWinding = updateWinding(endIndex, index);
197 int maxWinding;
198 return activeWinding(index, endIndex, &maxWinding, &sumWinding);
199}
200
201bool SkOpSegment::activeWinding(int index, int endIndex, int* maxWinding, int* sumWinding) {
202 setUpWinding(index, endIndex, maxWinding, sumWinding);
203 bool from = *maxWinding != 0;
204 bool to = *sumWinding != 0;
205 bool result = gUnaryActiveEdge[from][to];
206 return result;
207}
208
caryclark@google.comd892bd82013-06-17 14:10:36 +0000209void SkOpSegment::addAngle(SkTArray<SkOpAngle, true>* anglesPtr, int start, int end) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000210 SkASSERT(start != end);
caryclark@google.comd892bd82013-06-17 14:10:36 +0000211 SkOpAngle& angle = anglesPtr->push_back();
caryclark@google.comd892bd82013-06-17 14:10:36 +0000212 angle.set(this, start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000213}
214
caryclark@google.com570863f2013-09-16 15:55:01 +0000215void SkOpSegment::addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt,
216 SkOpSegment* other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000217 int tIndex = -1;
218 int tCount = fTs.count();
219 int oIndex = -1;
220 int oCount = other->fTs.count();
221 do {
222 ++tIndex;
caryclark@google.com570863f2013-09-16 15:55:01 +0000223 } while (startPt != fTs[tIndex].fPt && tIndex < tCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000224 int tIndexStart = tIndex;
225 do {
226 ++oIndex;
caryclark@google.com570863f2013-09-16 15:55:01 +0000227 } while (endPt != other->fTs[oIndex].fPt && oIndex < oCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000228 int oIndexStart = oIndex;
caryclark@google.com570863f2013-09-16 15:55:01 +0000229 const SkPoint* nextPt;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000230 do {
caryclark@google.com570863f2013-09-16 15:55:01 +0000231 nextPt = &fTs[++tIndex].fPt;
232 SkASSERT(fTs[tIndex].fT < 1 || startPt != *nextPt);
233 } while (startPt == *nextPt);
234 double nextT = fTs[tIndex].fT;
235 const SkPoint* oNextPt;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000236 do {
caryclark@google.com570863f2013-09-16 15:55:01 +0000237 oNextPt = &other->fTs[++oIndex].fPt;
238 SkASSERT(other->fTs[oIndex].fT < 1 || endPt != *oNextPt);
239 } while (endPt == *oNextPt);
240 double oNextT = other->fTs[oIndex].fT;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000241 // at this point, spans before and after are at:
242 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
243 // if tIndexStart == 0, no prior span
244 // if nextT == 1, no following span
245
246 // advance the span with zero winding
247 // if the following span exists (not past the end, non-zero winding)
248 // connect the two edges
249 if (!fTs[tIndexStart].fWindValue) {
250 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
251#if DEBUG_CONCIDENT
252 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
253 __FUNCTION__, fID, other->fID, tIndexStart - 1,
254 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
255 xyAtT(tIndexStart).fY);
256#endif
257 addTPair(fTs[tIndexStart].fT, other, other->fTs[oIndex].fT, false,
258 fTs[tIndexStart].fPt);
259 }
260 if (nextT < 1 && fTs[tIndex].fWindValue) {
261#if DEBUG_CONCIDENT
262 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
263 __FUNCTION__, fID, other->fID, tIndex,
264 fTs[tIndex].fT, xyAtT(tIndex).fX,
265 xyAtT(tIndex).fY);
266#endif
267 addTPair(fTs[tIndex].fT, other, other->fTs[oIndexStart].fT, false, fTs[tIndex].fPt);
268 }
269 } else {
270 SkASSERT(!other->fTs[oIndexStart].fWindValue);
271 if (oIndexStart > 0 && other->fTs[oIndexStart - 1].fWindValue) {
272#if DEBUG_CONCIDENT
273 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
274 __FUNCTION__, fID, other->fID, oIndexStart - 1,
275 other->fTs[oIndexStart].fT, other->xyAtT(oIndexStart).fX,
276 other->xyAtT(oIndexStart).fY);
277 other->debugAddTPair(other->fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
278#endif
279 }
280 if (oNextT < 1 && other->fTs[oIndex].fWindValue) {
281#if DEBUG_CONCIDENT
282 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
283 __FUNCTION__, fID, other->fID, oIndex,
284 other->fTs[oIndex].fT, other->xyAtT(oIndex).fX,
285 other->xyAtT(oIndex).fY);
286 other->debugAddTPair(other->fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
287#endif
288 }
289 }
290}
291
caryclark@google.com570863f2013-09-16 15:55:01 +0000292void SkOpSegment::addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt,
293 SkOpSegment* other) {
294 // walk this to startPt
295 // walk other to startPt
caryclark@google.com07393ca2013-04-08 11:47:37 +0000296 // if either is > 0, add a pointer to the other, copying adjacent winding
297 int tIndex = -1;
298 int oIndex = -1;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000299 do {
300 ++tIndex;
caryclark@google.com570863f2013-09-16 15:55:01 +0000301 } while (startPt != fTs[tIndex].fPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000302 do {
303 ++oIndex;
caryclark@google.com570863f2013-09-16 15:55:01 +0000304 } while (startPt != other->fTs[oIndex].fPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000305 if (tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000306 addTPair(fTs[tIndex].fT, other, other->fTs[oIndex].fT, false, startPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000307 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000308 SkPoint nextPt = startPt;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000309 do {
caryclark@google.com570863f2013-09-16 15:55:01 +0000310 const SkPoint* workPt;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000311 do {
caryclark@google.com570863f2013-09-16 15:55:01 +0000312 workPt = &fTs[++tIndex].fPt;
313 } while (nextPt == *workPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000314 do {
caryclark@google.com570863f2013-09-16 15:55:01 +0000315 workPt = &other->fTs[++oIndex].fPt;
316 } while (nextPt == *workPt);
317 nextPt = *workPt;
318 double tStart = fTs[tIndex].fT;
319 double oStart = other->fTs[oIndex].fT;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000320 if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) {
321 break;
322 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000323 addTPair(tStart, other, oStart, false, nextPt);
324 } while (endPt != nextPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000325}
326
327void SkOpSegment::addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
328 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
329 fBounds.setCubicBounds(pts);
330}
331
332void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active) const {
333 SkPoint edge[4];
334 const SkPoint* ePtr;
335 int lastT = fTs.count() - 1;
336 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
337 ePtr = fPts;
338 } else {
339 // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
340 subDivide(start, end, edge);
341 ePtr = edge;
342 }
343 if (active) {
344 bool reverse = ePtr == fPts && start != 0;
345 if (reverse) {
reed@google.com277c3f82013-05-31 15:17:50 +0000346 path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000347 switch (fVerb) {
348 case SkPath::kLine_Verb:
349 path->deferredLine(ePtr[0]);
350 break;
351 case SkPath::kQuad_Verb:
352 path->quadTo(ePtr[1], ePtr[0]);
353 break;
354 case SkPath::kCubic_Verb:
355 path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
356 break;
357 default:
358 SkASSERT(0);
359 }
360 // return ePtr[0];
361 } else {
362 path->deferredMoveLine(ePtr[0]);
363 switch (fVerb) {
364 case SkPath::kLine_Verb:
365 path->deferredLine(ePtr[1]);
366 break;
367 case SkPath::kQuad_Verb:
368 path->quadTo(ePtr[1], ePtr[2]);
369 break;
370 case SkPath::kCubic_Verb:
371 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
372 break;
373 default:
374 SkASSERT(0);
375 }
376 }
377 }
reed@google.com277c3f82013-05-31 15:17:50 +0000378 // return ePtr[SkPathOpsVerbToPoints(fVerb)];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000379}
380
381void SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
382 init(pts, SkPath::kLine_Verb, operand, evenOdd);
383 fBounds.set(pts, 2);
384}
385
386// add 2 to edge or out of range values to get T extremes
387void SkOpSegment::addOtherT(int index, double otherT, int otherIndex) {
388 SkOpSpan& span = fTs[index];
caryclark@google.com03610322013-04-18 15:58:21 +0000389 if (precisely_zero(otherT)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000390 otherT = 0;
caryclark@google.com03610322013-04-18 15:58:21 +0000391 } else if (precisely_equal(otherT, 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000392 otherT = 1;
393 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000394 span.fOtherT = otherT;
395 span.fOtherIndex = otherIndex;
396}
397
398void SkOpSegment::addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
399 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
400 fBounds.setQuadBounds(pts);
401}
402
403 // Defer all coincident edge processing until
404 // after normal intersections have been computed
405
406// no need to be tricky; insert in normal T order
407// resolve overlapping ts when considering coincidence later
408
409 // add non-coincident intersection. Resulting edges are sorted in T.
caryclark@google.com570863f2013-09-16 15:55:01 +0000410int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT, bool isNear) {
caryclark@google.com03610322013-04-18 15:58:21 +0000411 if (precisely_zero(newT)) {
412 newT = 0;
413 } else if (precisely_equal(newT, 1)) {
414 newT = 1;
415 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000416 // FIXME: in the pathological case where there is a ton of intercepts,
417 // binary search?
418 int insertedAt = -1;
419 size_t tCount = fTs.count();
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000420 const SkPoint& firstPt = fPts[0];
421 const SkPoint& lastPt = fPts[SkPathOpsVerbToPoints(fVerb)];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000422 for (size_t index = 0; index < tCount; ++index) {
423 // OPTIMIZATION: if there are three or more identical Ts, then
424 // the fourth and following could be further insertion-sorted so
425 // that all the edges are clockwise or counterclockwise.
426 // This could later limit segment tests to the two adjacent
427 // neighbors, although it doesn't help with determining which
428 // circular direction to go in.
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000429 const SkOpSpan& span = fTs[index];
430 if (newT < span.fT) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000431 insertedAt = index;
432 break;
433 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000434 if (newT == span.fT) {
435 if (pt == span.fPt) {
436 insertedAt = index;
437 break;
438 }
439 if ((pt == firstPt && newT == 0) || (span.fPt == lastPt && newT == 1)) {
440 insertedAt = index;
441 break;
442 }
443 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000444 }
445 SkOpSpan* span;
446 if (insertedAt >= 0) {
447 span = fTs.insert(insertedAt);
448 } else {
449 insertedAt = tCount;
450 span = fTs.append();
451 }
452 span->fT = newT;
453 span->fOther = other;
454 span->fPt = pt;
caryclark@google.com570863f2013-09-16 15:55:01 +0000455 span->fNear = isNear;
caryclark@google.coma5e55922013-05-07 18:51:31 +0000456#if 0
457 // cubics, for instance, may not be exact enough to satisfy this check (e.g., cubicOp69d)
458 SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX)
459 && approximately_equal(xyAtT(newT).fY, pt.fY));
460#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000461 span->fWindSum = SK_MinS32;
462 span->fOppSum = SK_MinS32;
463 span->fWindValue = 1;
464 span->fOppValue = 0;
caryclark@google.com570863f2013-09-16 15:55:01 +0000465 span->fSmall = false;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000466 span->fTiny = false;
467 span->fLoop = false;
468 if ((span->fDone = newT == 1)) {
469 ++fDoneSpans;
470 }
471 span->fUnsortableStart = false;
472 span->fUnsortableEnd = false;
473 int less = -1;
caryclark@google.com570863f2013-09-16 15:55:01 +0000474 while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt, span->fPt)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000475 if (span[less].fDone) {
476 break;
477 }
478 double tInterval = newT - span[less].fT;
479 if (precisely_negative(tInterval)) {
480 break;
481 }
482 if (fVerb == SkPath::kCubic_Verb) {
483 double tMid = newT - tInterval / 2;
484 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid);
485 if (!midPt.approximatelyEqual(xyAtT(span))) {
486 break;
487 }
488 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000489 span[less].fSmall = true;
490 bool tiny = span[less].fPt == span->fPt;
491 span[less].fTiny = tiny;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000492 span[less].fDone = true;
caryclark@google.com570863f2013-09-16 15:55:01 +0000493 if (approximately_negative(newT - span[less].fT) && tiny) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000494 if (approximately_greater_than_one(newT)) {
495 SkASSERT(&span[less] - fTs.begin() < fTs.count());
496 span[less].fUnsortableStart = true;
497 if (&span[less - 1] - fTs.begin() >= 0) {
498 span[less - 1].fUnsortableEnd = true;
499 }
500 }
501 if (approximately_less_than_zero(span[less].fT)) {
502 SkASSERT(&span[less + 1] - fTs.begin() < fTs.count());
503 SkASSERT(&span[less] - fTs.begin() >= 0);
504 span[less + 1].fUnsortableStart = true;
505 span[less].fUnsortableEnd = true;
506 }
507 }
508 ++fDoneSpans;
509 --less;
510 }
511 int more = 1;
caryclark@google.com570863f2013-09-16 15:55:01 +0000512 while (fTs.end() - &span[more - 1] > 1 && AlmostEqualUlps(span[more].fPt, span->fPt)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000513 if (span[more - 1].fDone) {
514 break;
515 }
516 double tEndInterval = span[more].fT - newT;
517 if (precisely_negative(tEndInterval)) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000518 if ((span->fTiny = span[more].fTiny)) {
519 span->fDone = true;
520 ++fDoneSpans;
521 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000522 break;
523 }
524 if (fVerb == SkPath::kCubic_Verb) {
525 double tMid = newT - tEndInterval / 2;
526 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid);
527 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
528 break;
529 }
530 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000531 span[more - 1].fSmall = true;
532 bool tiny = span[more].fPt == span->fPt;
533 span[more - 1].fTiny = tiny;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000534 span[more - 1].fDone = true;
caryclark@google.com570863f2013-09-16 15:55:01 +0000535 if (approximately_negative(span[more].fT - newT) && tiny) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000536 if (approximately_greater_than_one(span[more].fT)) {
537 span[more + 1].fUnsortableStart = true;
538 span[more].fUnsortableEnd = true;
539 }
540 if (approximately_less_than_zero(newT)) {
541 span[more].fUnsortableStart = true;
542 span[more - 1].fUnsortableEnd = true;
543 }
544 }
545 ++fDoneSpans;
546 ++more;
547 }
548 return insertedAt;
549}
550
551// set spans from start to end to decrement by one
552// note this walks other backwards
caryclark@google.coma5e55922013-05-07 18:51:31 +0000553// FIXME: there's probably an edge case that can be constructed where
caryclark@google.com07393ca2013-04-08 11:47:37 +0000554// two span in one segment are separated by float epsilon on one span but
555// not the other, if one segment is very small. For this
556// case the counts asserted below may or may not be enough to separate the
557// spans. Even if the counts work out, what if the spans aren't correctly
558// sorted? It feels better in such a case to match the span's other span
559// pointer since both coincident segments must contain the same spans.
caryclark@google.coma5e55922013-05-07 18:51:31 +0000560// FIXME? It seems that decrementing by one will fail for complex paths that
561// have three or more coincident edges. Shouldn't this subtract the difference
562// between the winding values?
caryclark@google.com570863f2013-09-16 15:55:01 +0000563/* |--> |-->
564this 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>4
565other 2<<<<1<<<<0 2<<<<1<<<<0 2<<<<1<<<<0
566 ^ ^ <--| <--|
567 startPt endPt test/oTest first pos test/oTest final pos
568*/
569void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000570 bool binary = fOperand != other->fOperand;
571 int index = 0;
caryclark@google.com570863f2013-09-16 15:55:01 +0000572 while (startPt != fTs[index].fPt) {
573 SkASSERT(index < fTs.count());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000574 ++index;
575 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000576 while (index > 0 && fTs[index].fT == fTs[index - 1].fT) {
577 --index;
578 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000579 int oIndex = other->fTs.count();
caryclark@google.com570863f2013-09-16 15:55:01 +0000580 while (startPt != other->fTs[--oIndex].fPt) { // look for startPt match
581 SkASSERT(oIndex > 0);
582 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000583 double oStartT = other->fTs[oIndex].fT;
584 // look for first point beyond match
585 while (startPt == other->fTs[--oIndex].fPt || oStartT == other->fTs[oIndex].fT) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000586 SkASSERT(oIndex > 0);
587 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000588 SkOpSpan* test = &fTs[index];
589 SkOpSpan* oTest = &other->fTs[oIndex];
caryclark@google.com570863f2013-09-16 15:55:01 +0000590 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
591 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000592 do {
caryclark@google.com570863f2013-09-16 15:55:01 +0000593 SkASSERT(test->fT < 1);
594 SkASSERT(oTest->fT < 1);
caryclark@google.coma5e55922013-05-07 18:51:31 +0000595 bool decrement = test->fWindValue && oTest->fWindValue;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000596 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.coma5e55922013-05-07 18:51:31 +0000597 bool bigger = test->fWindValue >= oTest->fWindValue;
caryclark@google.com570863f2013-09-16 15:55:01 +0000598 const SkPoint& testPt = test->fPt;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000599 double testT = test->fT;
caryclark@google.com570863f2013-09-16 15:55:01 +0000600 const SkPoint& oTestPt = oTest->fPt;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000601 double oTestT = oTest->fT;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000602 do {
603 if (decrement) {
caryclark@google.coma5e55922013-05-07 18:51:31 +0000604 if (binary && bigger) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000605 test->fOppValue--;
caryclark@google.coma5e55922013-05-07 18:51:31 +0000606 } else {
caryclark@google.com570863f2013-09-16 15:55:01 +0000607 decrementSpan(test);
caryclark@google.coma5e55922013-05-07 18:51:31 +0000608 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000609 } else if (track) {
610 TrackOutsidePair(&outsidePts, testPt, oTestPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000611 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000612 SkASSERT(index < fTs.count() - 1);
613 test = &fTs[++index];
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000614 } while (testPt == test->fPt || testT == test->fT);
caryclark@google.com570863f2013-09-16 15:55:01 +0000615 SkDEBUGCODE(int originalWindValue = oTest->fWindValue);
616 do {
617 SkASSERT(oTest->fT < 1);
618 SkASSERT(originalWindValue == oTest->fWindValue);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000619 if (decrement) {
caryclark@google.coma5e55922013-05-07 18:51:31 +0000620 if (binary && !bigger) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000621 oTest->fOppValue--;
caryclark@google.coma5e55922013-05-07 18:51:31 +0000622 } else {
caryclark@google.com570863f2013-09-16 15:55:01 +0000623 other->decrementSpan(oTest);
caryclark@google.coma5e55922013-05-07 18:51:31 +0000624 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000625 } else if (track) {
626 TrackOutsidePair(&oOutsidePts, oTestPt, testPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000627 }
628 if (!oIndex) {
629 break;
630 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000631 oTest = &other->fTs[--oIndex];
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000632 } while (oTestPt == oTest->fPt || oTestT == oTest->fT);
633 } while (endPt != test->fPt && test->fT < 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000634 // FIXME: determine if canceled edges need outside ts added
caryclark@google.com570863f2013-09-16 15:55:01 +0000635 int outCount = outsidePts.count();
636 if (!done() && outCount) {
637 addCancelOutsides(outsidePts[0], outsidePts[1], other);
638 if (outCount > 2) {
639 addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1], other);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000640 }
641 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000642 if (!other->done() && oOutsidePts.count()) {
643 other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000644 }
645}
646
647int SkOpSegment::addSelfT(SkOpSegment* other, const SkPoint& pt, double newT) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000648 // if the tail nearly intersects itself but not quite, the caller records this separately
649 int result = addT(other, pt, newT, SkOpSpan::kPointIsExact);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000650 SkOpSpan* span = &fTs[result];
651 span->fLoop = true;
652 return result;
653}
654
caryclark@google.com570863f2013-09-16 15:55:01 +0000655void SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* indexPtr,
656 SkTArray<SkPoint, true>* outsideTs) {
657 int index = *indexPtr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000658 int oWindValue = oTest.fWindValue;
659 int oOppValue = oTest.fOppValue;
caryclark@google.com570863f2013-09-16 15:55:01 +0000660 if (binary) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000661 SkTSwap<int>(oWindValue, oOppValue);
662 }
663 SkOpSpan* const test = &fTs[index];
664 SkOpSpan* end = test;
caryclark@google.com570863f2013-09-16 15:55:01 +0000665 const SkPoint& oStartPt = oTest.fPt;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000666 do {
667 if (bumpSpan(end, oWindValue, oOppValue)) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000668 TrackOutside(outsideTs, oStartPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000669 }
670 end = &fTs[++index];
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000671 } while ((end->fPt == test->fPt || end->fT == test->fT) && end->fT < 1);
caryclark@google.com570863f2013-09-16 15:55:01 +0000672 *indexPtr = index;
673}
674
675bool SkOpSegment::bumpCoincident(SkOpSpan* test, bool bigger, bool binary) {
676 if (bigger) {
677 if (binary) {
678 if (fOppXor) {
679 test->fOppValue ^= 1;
680 } else {
681 test->fOppValue++;
682 }
683 } else {
684 if (fXor) {
685 test->fWindValue ^= 1;
686 } else {
687 test->fWindValue++;
688 }
689 }
690 if (!test->fWindValue && !test->fOppValue) {
691 test->fDone = true;
692 ++fDoneSpans;
693 return true;
694 }
695 return false;
696 }
697 return decrementSpan(test);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000698}
699
700// because of the order in which coincidences are resolved, this and other
701// may not have the same intermediate points. Compute the corresponding
702// intermediate T values (using this as the master, other as the follower)
703// and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com570863f2013-09-16 15:55:01 +0000704void SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr,
705 SkTArray<SkPoint, true>* oOutsidePts) {
706 int oIndex = *oIndexPtr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000707 SkOpSpan* const oTest = &fTs[oIndex];
708 SkOpSpan* oEnd = oTest;
caryclark@google.com570863f2013-09-16 15:55:01 +0000709 const SkPoint& startPt = test.fPt;
710 const SkPoint& oStartPt = oTest->fPt;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000711 double oStartT = oTest->fT;
712 if (oStartPt == oEnd->fPt || oStartT == oEnd->fT) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000713 TrackOutside(oOutsidePts, startPt);
714 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000715 while (oStartPt == oEnd->fPt || oStartT == oEnd->fT) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000716 zeroSpan(oEnd);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000717 oEnd = &fTs[++oIndex];
718 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000719 *oIndexPtr = oIndex;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000720}
721
722// FIXME: need to test this case:
723// contourA has two segments that are coincident
724// contourB has two segments that are coincident in the same place
725// each ends up with +2/0 pairs for winding count
726// since logic below doesn't transfer count (only increments/decrements) can this be
727// resolved to +4/0 ?
728
729// set spans from start to end to increment the greater by one and decrement
730// the lesser
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000731void SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, double endT,
caryclark@google.com570863f2013-09-16 15:55:01 +0000732 SkOpSegment* other) {
733 bool binary = fOperand != other->fOperand;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000734 int index = 0;
caryclark@google.com570863f2013-09-16 15:55:01 +0000735 while (startPt != fTs[index].fPt) {
736 SkASSERT(index < fTs.count());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000737 ++index;
738 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000739 double startT = fTs[index].fT;
740 while (index > 0 && fTs[index - 1].fT == startT) {
741 --index;
742 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000743 int oIndex = 0;
caryclark@google.com570863f2013-09-16 15:55:01 +0000744 while (startPt != other->fTs[oIndex].fPt) {
745 SkASSERT(oIndex < other->fTs.count());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000746 ++oIndex;
747 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000748 double oStartT = other->fTs[oIndex].fT;
749 while (oIndex > 0 && other->fTs[oIndex - 1].fT == oStartT) {
750 --oIndex;
751 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000752 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
753 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000754 SkOpSpan* test = &fTs[index];
caryclark@google.com570863f2013-09-16 15:55:01 +0000755 const SkPoint* testPt = &test->fPt;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000756 double testT = test->fT;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000757 SkOpSpan* oTest = &other->fTs[oIndex];
caryclark@google.com570863f2013-09-16 15:55:01 +0000758 const SkPoint* oTestPt = &oTest->fPt;
759 SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000760 do {
caryclark@google.com570863f2013-09-16 15:55:01 +0000761 SkASSERT(test->fT < 1);
762 SkASSERT(oTest->fT < 1);
763#if 0
caryclark@google.com07393ca2013-04-08 11:47:37 +0000764 if (test->fDone || oTest->fDone) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000765#else // consolidate the winding count even if done
766 if ((test->fWindValue == 0 && test->fOppValue == 0)
767 || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) {
768#endif
769 SkDEBUGCODE(int firstWind = test->fWindValue);
770 SkDEBUGCODE(int firstOpp = test->fOppValue);
771 do {
772 SkASSERT(firstWind == fTs[index].fWindValue);
773 SkASSERT(firstOpp == fTs[index].fOppValue);
774 ++index;
775 SkASSERT(index < fTs.count());
776 } while (*testPt == fTs[index].fPt);
777 SkDEBUGCODE(firstWind = oTest->fWindValue);
778 SkDEBUGCODE(firstOpp = oTest->fOppValue);
779 do {
780 SkASSERT(firstWind == other->fTs[oIndex].fWindValue);
781 SkASSERT(firstOpp == other->fTs[oIndex].fOppValue);
782 ++oIndex;
783 SkASSERT(oIndex < other->fTs.count());
784 } while (*oTestPt == other->fTs[oIndex].fPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000785 } else {
caryclark@google.com570863f2013-09-16 15:55:01 +0000786 if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
787 bumpCoincidentThis(*oTest, binary, &index, &outsidePts);
788 other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts);
789 } else {
790 other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts);
791 bumpCoincidentOther(*oTest, &index, &outsidePts);
792 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000793 }
794 test = &fTs[index];
caryclark@google.com570863f2013-09-16 15:55:01 +0000795 testPt = &test->fPt;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000796 testT = test->fT;
797 if (endPt == *testPt || endT == testT) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000798 break;
799 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000800 oTest = &other->fTs[oIndex];
caryclark@google.com570863f2013-09-16 15:55:01 +0000801 oTestPt = &oTest->fPt;
802 SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
803 } while (endPt != *oTestPt);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000804 if (endPt != *testPt && endT != testT) { // in rare cases, one may have ended before the other
805 int lastWind = test[-1].fWindValue;
806 int lastOpp = test[-1].fOppValue;
807 bool zero = lastWind == 0 && lastOpp == 0;
808 do {
809 if (test->fWindValue || test->fOppValue) {
810 test->fWindValue = lastWind;
811 test->fOppValue = lastOpp;
812 if (zero) {
813 test->fDone = true;
814 ++fDoneSpans;
815 }
816 }
817 test = &fTs[++index];
818 testPt = &test->fPt;
819 } while (endPt != *testPt);
820 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000821 int outCount = outsidePts.count();
822 if (!done() && outCount) {
823 addCoinOutsides(outsidePts[0], endPt, other);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000824 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000825 if (!other->done() && oOutsidePts.count()) {
826 other->addCoinOutsides(oOutsidePts[0], endPt, this);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000827 }
828}
829
830// FIXME: this doesn't prevent the same span from being added twice
831// fix in caller, SkASSERT here?
832void SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
833 const SkPoint& pt) {
834 int tCount = fTs.count();
835 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
836 const SkOpSpan& span = fTs[tIndex];
837 if (!approximately_negative(span.fT - t)) {
838 break;
839 }
840 if (approximately_negative(span.fT - t) && span.fOther == other
841 && approximately_equal(span.fOtherT, otherT)) {
842#if DEBUG_ADD_T_PAIR
843 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
844 __FUNCTION__, fID, t, other->fID, otherT);
845#endif
846 return;
847 }
848 }
849#if DEBUG_ADD_T_PAIR
850 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
851 __FUNCTION__, fID, t, other->fID, otherT);
852#endif
caryclark@google.com570863f2013-09-16 15:55:01 +0000853 int insertedAt = addT(other, pt, t, SkOpSpan::kPointIsExact);
854 int otherInsertedAt = other->addT(this, pt, otherT, SkOpSpan::kPointIsExact);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000855 addOtherT(insertedAt, otherT, otherInsertedAt);
856 other->addOtherT(otherInsertedAt, t, insertedAt);
857 matchWindingValue(insertedAt, t, borrowWind);
858 other->matchWindingValue(otherInsertedAt, otherT, borrowWind);
859}
860
caryclark@google.comd892bd82013-06-17 14:10:36 +0000861void SkOpSegment::addTwoAngles(int start, int end, SkTArray<SkOpAngle, true>* angles) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000862 // add edge leading into junction
863 int min = SkMin32(end, start);
caryclark@google.coma5e55922013-05-07 18:51:31 +0000864 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000865 addAngle(angles, end, start);
866 }
867 // add edge leading away from junction
868 int step = SkSign32(end - start);
869 int tIndex = nextExactSpan(end, step);
870 min = SkMin32(end, tIndex);
caryclark@google.coma5e55922013-05-07 18:51:31 +0000871 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000872 addAngle(angles, end, tIndex);
873 }
874}
875
caryclark@google.com570863f2013-09-16 15:55:01 +0000876SkOpSegment::MissingSpan::Command SkOpSegment::adjustThisNear(double startT, const SkPoint& startPt,
877 const SkPoint& endPt, SkTArray<MissingSpan, true>* missingSpans) {
878 // see if endPt exists on this curve, and if it has the same t or a different T than the startT
879 int count = this->count();
880 SkASSERT(count > 0);
881 int startIndex, endIndex, step;
882 if (startT == 0) {
883 startIndex = 0;
884 endIndex = count;
885 step = 1;
886 } else {
887 SkASSERT(startT == 1);
888 startIndex = count - 1;
889 endIndex = -1;
890 step = -1;
891 }
892 int index = startIndex;
893 do {
894 const SkOpSpan& span = fTs[index];
895 if (span.fPt != endPt) {
896 continue;
897 }
898 if (span.fT == startT) {
899 // check to see if otherT matches some other mid curve intersection
900 int inner = startIndex;
901 do {
902 if (inner == index) {
903 continue;
904 }
905 const SkOpSpan& matchSpan = fTs[inner];
906 double matchT = span.fOther->missingNear(span.fOtherT, matchSpan.fOther, startPt,
907 endPt);
908 if (matchT >= 0) {
909 SkASSERT(missingSpans);
910 MissingSpan& missingSpan = missingSpans->push_back();
911 SkDEBUGCODE(sk_bzero(&missingSpan, sizeof(missingSpan)));
912 missingSpan.fCommand = MissingSpan::kRemoveNear;
913 missingSpan.fT = startT;
914 missingSpan.fSegment = this;
915 missingSpan.fOther = span.fOther;
916 missingSpan.fOtherT = matchT;
917 return missingSpan.fCommand;
918 }
919 } while ((inner += step) != endIndex);
920 break;
921 }
922 double midT = (startT + span.fT) / 2;
923 if (betweenPoints(midT, startPt, endPt)) {
924 if (!missingSpans) {
925 return MissingSpan::kZeroSpan;
926 }
927 MissingSpan& missingSpan = missingSpans->push_back();
928 SkDEBUGCODE(sk_bzero(&missingSpan, sizeof(missingSpan)));
929 missingSpan.fCommand = MissingSpan::kZeroSpan;
930 missingSpan.fT = SkTMin(startT, span.fT);
931 missingSpan.fEndT = SkTMax(startT, span.fT);
932 missingSpan.fSegment = this;
933 return missingSpan.fCommand;
934 }
935 } while ((index += step) != endIndex);
936 return MissingSpan::kNoAction;
937}
938
939void SkOpSegment::adjustOtherNear(double startT, const SkPoint& startPt, const SkPoint& endPt,
940 SkTArray<MissingSpan, true>* missingSpans) {
941 int count = this->count();
942 SkASSERT(count > 0);
943 int startIndex, endIndex, step;
944 if (startT == 0) {
945 startIndex = 0;
946 endIndex = count;
947 step = 1;
948 } else {
949 SkASSERT(startT == 1);
950 startIndex = count - 1;
951 endIndex = -1;
952 step = -1;
953 }
954 int index = startIndex;
955 do {
956 const SkOpSpan& span = fTs[index];
957 if (span.fT != startT) {
958 return;
959 }
960 SkOpSegment* other = span.fOther;
961 if (other->fPts[0] == endPt) {
962 other->adjustThisNear(0, endPt, startPt, missingSpans);
963 } else if (other->fPts[0] == startPt) {
964 other->adjustThisNear(0, startPt, endPt, missingSpans);
965 }
966 if (other->ptAtT(1) == endPt) {
967 other->adjustThisNear(1, endPt, startPt, missingSpans);
968 } else if (other->ptAtT(1) == startPt) {
969 other->adjustThisNear(1, startPt, endPt, missingSpans);
970 }
971 } while ((index += step) != endIndex);
972}
973
974void SkOpSegment::adjustMissingNear(const SkPoint& startPt, const SkPoint& endPt,
975 SkTArray<MissingSpan, true>* missingSpans) {
976 int count = missingSpans->count();
977 for (int index = 0; index < count; ) {
978 MissingSpan& missing = (*missingSpans)[index];
979 SkOpSegment* other = missing.fOther;
980 MissingSpan::Command command = MissingSpan::kNoAction;
981 if (missing.fPt == startPt) {
982 if (missingNear(missing.fT, other, startPt, endPt) >= 0) {
983 command = MissingSpan::kZeroSpan;
984 } else if (other->ptAtT(0) == endPt) {
985 command = other->adjustThisNear(0, endPt, startPt, NULL);
986 } else if (other->ptAtT(1) == endPt) {
987 command = other->adjustThisNear(1, endPt, startPt, NULL);
988 }
989 } else if (missing.fPt == endPt) {
990 if (missingNear(missing.fT, other, endPt, startPt) >= 0) {
991 command = MissingSpan::kZeroSpan;
992 } else if (other->ptAtT(0) == startPt) {
993 command = other->adjustThisNear(0, startPt, endPt, NULL);
994 } else if (other->ptAtT(1) == startPt) {
995 command = other->adjustThisNear(1, startPt, endPt, NULL);
996 }
997 }
998 if (command == MissingSpan::kZeroSpan) {
999#if 1
1000 missing = missingSpans->back();
1001 missingSpans->pop_back();
1002#else // if this is supported in the future ...
1003 missingSpans->removeShuffle(index);
1004#endif
1005 --count;
1006 continue;
1007 }
1008 ++index;
1009 }
1010}
1011
1012void SkOpSegment::adjustNear(double startT, const SkPoint& endPt,
1013 SkTArray<MissingSpan, true>* missingSpans) {
1014 const SkPoint startPt = ptAtT(startT);
1015 adjustMissingNear(startPt, endPt, missingSpans);
1016 adjustThisNear(startT, startPt, endPt, missingSpans);
1017 adjustOtherNear(startT, startPt, endPt, missingSpans);
1018}
1019
1020int SkOpSegment::advanceCoincidentThis(int index) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001021 SkOpSpan* const test = &fTs[index];
1022 SkOpSpan* end;
1023 do {
1024 end = &fTs[++index];
1025 } while (approximately_negative(end->fT - test->fT));
1026 return index;
1027}
1028
caryclark@google.com570863f2013-09-16 15:55:01 +00001029int SkOpSegment::advanceCoincidentOther(double oEndT, int oIndex) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001030 SkOpSpan* const oTest = &fTs[oIndex];
1031 SkOpSpan* oEnd = oTest;
1032 const double oStartT = oTest->fT;
1033 while (!approximately_negative(oEndT - oEnd->fT)
1034 && approximately_negative(oEnd->fT - oStartT)) {
1035 oEnd = &fTs[++oIndex];
1036 }
1037 return oIndex;
1038}
1039
caryclark@google.com570863f2013-09-16 15:55:01 +00001040bool SkOpSegment::betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const {
1041 const SkPoint midPt = ptAtT(midT);
1042 SkPathOpsBounds bounds;
1043 bounds.set(pt1.fX, pt1.fY, pt2.fX, pt2.fY);
1044 bounds.sort();
1045 return bounds.almostContains(midPt);
1046}
1047
caryclark@google.com07393ca2013-04-08 11:47:37 +00001048bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const {
1049 if (lesser > greater) {
1050 SkTSwap<int>(lesser, greater);
1051 }
1052 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
1053}
1054
caryclark@google.com570863f2013-09-16 15:55:01 +00001055// note that this follows the same logic flow as active angle
1056bool SkOpSegment::buildAngles(int index, SkTArray<SkOpAngle, true>* angles, bool allowOpp) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001057 double referenceT = fTs[index].fT;
caryclark@google.com570863f2013-09-16 15:55:01 +00001058 const SkPoint& referencePt = fTs[index].fPt;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001059 int lesser = index;
caryclark@google.com570863f2013-09-16 15:55:01 +00001060 while (--lesser >= 0 && (allowOpp || fTs[lesser].fOther->fOperand == fOperand)
1061 && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].fTiny)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001062 buildAnglesInner(lesser, angles);
1063 }
1064 do {
1065 buildAnglesInner(index, angles);
caryclark@google.com570863f2013-09-16 15:55:01 +00001066 if (++index == fTs.count()) {
1067 break;
1068 }
1069 if (!allowOpp && fTs[index].fOther->fOperand != fOperand) {
1070 break;
1071 }
1072 if (fTs[index - 1].fTiny) {
1073 referenceT = fTs[index].fT;
1074 continue;
1075 }
1076 if (!precisely_negative(fTs[index].fT - referenceT) && fTs[index].fPt == referencePt) {
1077 // FIXME
1078 // testQuad8 generates the wrong output unless false is returned here. Other tests will
1079 // take this path although they aren't required to. This means that many go much slower
1080 // because of this sort fail.
1081 // SkDebugf("!!!\n");
1082 return false;
1083 }
1084 } while (precisely_negative(fTs[index].fT - referenceT));
1085 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001086}
1087
caryclark@google.comd892bd82013-06-17 14:10:36 +00001088void SkOpSegment::buildAnglesInner(int index, SkTArray<SkOpAngle, true>* angles) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001089 const SkOpSpan* span = &fTs[index];
1090 SkOpSegment* other = span->fOther;
1091// if there is only one live crossing, and no coincidence, continue
1092// in the same direction
1093// if there is coincidence, the only choice may be to reverse direction
1094 // find edge on either side of intersection
1095 int oIndex = span->fOtherIndex;
1096 // if done == -1, prior span has already been processed
1097 int step = 1;
1098 int next = other->nextExactSpan(oIndex, step);
1099 if (next < 0) {
1100 step = -step;
1101 next = other->nextExactSpan(oIndex, step);
1102 }
1103 // add candidate into and away from junction
1104 other->addTwoAngles(next, oIndex, angles);
1105}
1106
caryclark@google.com570863f2013-09-16 15:55:01 +00001107int SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType,
1108 SkTArray<SkOpAngle, true>* angles, SkTArray<SkOpAngle*, true>* sorted) {
1109 addTwoAngles(startIndex, endIndex, angles);
1110 if (!buildAngles(endIndex, angles, includeType == SkOpAngle::kBinaryOpp)) {
1111 return SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001112 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001113 int angleCount = angles->count();
1114 // abort early before sorting if an unsortable (not an unorderable) angle is found
1115 if (includeType != SkOpAngle::kUnaryXor) {
1116 int firstIndex = -1;
1117 while (++firstIndex < angleCount) {
1118 const SkOpAngle& angle = (*angles)[firstIndex];
1119 if (angle.segment()->windSum(&angle) != SK_MinS32) {
1120 break;
1121 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001122 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001123 if (firstIndex == angleCount) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001124 return SK_MinS32;
1125 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001126 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001127 bool sortable = SortAngles2(*angles, sorted);
1128#if DEBUG_SORT_RAW
1129 if (sorted->count() > 0) {
1130 (*sorted)[0]->segment()->debugShowSort(__FUNCTION__, *sorted, 0, 0, 0, sortable);
1131 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001132#endif
caryclark@google.com570863f2013-09-16 15:55:01 +00001133 if (!sortable) {
1134 return SK_NaN32;
1135 }
1136 if (includeType == SkOpAngle::kUnaryXor) {
1137 return SK_MinS32;
1138 }
1139 // if all angles have a computed winding,
1140 // or if no adjacent angles are orderable,
1141 // or if adjacent orderable angles have no computed winding,
1142 // there's nothing to do
1143 // if two orderable angles are adjacent, and one has winding computed, transfer to the other
1144 const SkOpAngle* baseAngle = NULL;
1145 int last = angleCount;
1146 int finalInitialOrderable = -1;
1147 bool tryReverse = false;
1148 // look for counterclockwise transfers
caryclark@google.com07393ca2013-04-08 11:47:37 +00001149 do {
caryclark@google.com570863f2013-09-16 15:55:01 +00001150 int index = 0;
1151 do {
1152 SkOpAngle* testAngle = (*sorted)[index];
1153 int testWinding = testAngle->segment()->windSum(testAngle);
1154 if (SK_MinS32 != testWinding && !testAngle->unorderable()) {
1155 baseAngle = testAngle;
1156 continue;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001157 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001158 if (testAngle->unorderable()) {
1159 baseAngle = NULL;
1160 tryReverse = true;
1161 continue;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001162 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001163 if (baseAngle) {
1164 ComputeOneSum(baseAngle, testAngle, includeType);
1165 baseAngle = SK_MinS32 != testAngle->segment()->windSum(testAngle) ? testAngle
1166 : NULL;
1167 tryReverse |= !baseAngle;
1168 continue;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001169 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001170 if (finalInitialOrderable + 1 == index) {
1171 finalInitialOrderable = index;
1172 }
1173 } while (++index != last);
1174 if (finalInitialOrderable < 0) {
1175 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001176 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001177 last = finalInitialOrderable + 1;
1178 finalInitialOrderable = -2; // make this always negative the second time through
1179 } while (baseAngle);
1180 if (tryReverse) {
1181 baseAngle = NULL;
1182 last = 0;
1183 finalInitialOrderable = angleCount;
1184 do {
1185 int index = angleCount;
1186 while (--index >= last) {
1187 SkOpAngle* testAngle = (*sorted)[index];
1188 int testWinding = testAngle->segment()->windSum(testAngle);
1189 if (SK_MinS32 != testWinding) {
1190 baseAngle = testAngle;
1191 continue;
1192 }
1193 if (testAngle->unorderable()) {
1194 baseAngle = NULL;
1195 continue;
1196 }
1197 if (baseAngle) {
1198 ComputeOneSumReverse(baseAngle, testAngle, includeType);
1199 baseAngle = SK_MinS32 != testAngle->segment()->windSum(testAngle) ? testAngle
1200 : NULL;
1201 continue;
1202 }
1203 if (finalInitialOrderable - 1 == index) {
1204 finalInitialOrderable = index;
1205 }
1206 }
1207 if (finalInitialOrderable >= angleCount) {
1208 break;
1209 }
1210 last = finalInitialOrderable;
1211 finalInitialOrderable = angleCount + 1; // make this inactive 2nd time through
1212 } while (baseAngle);
1213 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001214 int minIndex = SkMin32(startIndex, endIndex);
1215 return windSum(minIndex);
1216}
1217
caryclark@google.com570863f2013-09-16 15:55:01 +00001218void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
1219 SkOpAngle::IncludeType includeType) {
1220 const SkOpSegment* baseSegment = baseAngle->segment();
1221 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
1222 int sumSuWinding;
1223 bool binary = includeType >= SkOpAngle::kBinarySingle;
1224 if (binary) {
1225 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
1226 if (baseSegment->operand()) {
1227 SkTSwap<int>(sumMiWinding, sumSuWinding);
1228 }
1229 }
1230 SkOpSegment* nextSegment = nextAngle->segment();
1231 int maxWinding, sumWinding;
1232 SkOpSpan* last;
1233 if (binary) {
1234 int oppMaxWinding, oppSumWinding;
1235 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
1236 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1237 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
1238 true, nextAngle);
1239 } else {
1240 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
1241 &maxWinding, &sumWinding);
1242 last = nextSegment->markAngle(maxWinding, sumWinding, true, nextAngle);
1243 }
1244 nextAngle->setLastMarked(last);
1245}
1246
1247void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
1248 SkOpAngle::IncludeType includeType) {
1249 const SkOpSegment* baseSegment = baseAngle->segment();
1250 int sumMiWinding = baseSegment->updateWinding(baseAngle);
1251 int sumSuWinding;
1252 bool binary = includeType >= SkOpAngle::kBinarySingle;
1253 if (binary) {
1254 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
1255 if (baseSegment->operand()) {
1256 SkTSwap<int>(sumMiWinding, sumSuWinding);
1257 }
1258 }
1259 SkOpSegment* nextSegment = nextAngle->segment();
1260 int maxWinding, sumWinding;
1261 SkOpSpan* last;
1262 if (binary) {
1263 int oppMaxWinding, oppSumWinding;
1264 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
1265 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1266 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
1267 true, nextAngle);
1268 } else {
1269 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
1270 &maxWinding, &sumWinding);
1271 last = nextSegment->markAngle(maxWinding, sumWinding, true, nextAngle);
1272 }
1273 nextAngle->setLastMarked(last);
1274}
1275
caryclark@google.com07393ca2013-04-08 11:47:37 +00001276int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT,
1277 bool* hitSomething, double mid, bool opp, bool current) const {
1278 SkScalar bottom = fBounds.fBottom;
1279 int bestTIndex = -1;
1280 if (bottom <= *bestY) {
1281 return bestTIndex;
1282 }
1283 SkScalar top = fBounds.fTop;
1284 if (top >= basePt.fY) {
1285 return bestTIndex;
1286 }
1287 if (fBounds.fLeft > basePt.fX) {
1288 return bestTIndex;
1289 }
1290 if (fBounds.fRight < basePt.fX) {
1291 return bestTIndex;
1292 }
1293 if (fBounds.fLeft == fBounds.fRight) {
1294 // if vertical, and directly above test point, wait for another one
1295 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
1296 }
1297 // intersect ray starting at basePt with edge
1298 SkIntersections intersections;
1299 // OPTIMIZE: use specialty function that intersects ray with curve,
1300 // returning t values only for curve (we don't care about t on ray)
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001301 int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)])
1302 (fPts, top, bottom, basePt.fX, false);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001303 if (pts == 0 || (current && pts == 1)) {
1304 return bestTIndex;
1305 }
1306 if (current) {
1307 SkASSERT(pts > 1);
1308 int closestIdx = 0;
1309 double closest = fabs(intersections[0][0] - mid);
1310 for (int idx = 1; idx < pts; ++idx) {
1311 double test = fabs(intersections[0][idx] - mid);
1312 if (closest > test) {
1313 closestIdx = idx;
1314 closest = test;
1315 }
1316 }
1317 intersections.quickRemoveOne(closestIdx, --pts);
1318 }
1319 double bestT = -1;
1320 for (int index = 0; index < pts; ++index) {
1321 double foundT = intersections[0][index];
1322 if (approximately_less_than_zero(foundT)
1323 || approximately_greater_than_one(foundT)) {
1324 continue;
1325 }
reed@google.com277c3f82013-05-31 15:17:50 +00001326 SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fY;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001327 if (approximately_negative(testY - *bestY)
1328 || approximately_negative(basePt.fY - testY)) {
1329 continue;
1330 }
1331 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
1332 return SK_MinS32; // if the intersection is edge on, wait for another one
1333 }
1334 if (fVerb > SkPath::kLine_Verb) {
reed@google.com277c3f82013-05-31 15:17:50 +00001335 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fX;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001336 if (approximately_zero(dx)) {
1337 return SK_MinS32; // hit vertical, wait for another one
1338 }
1339 }
1340 *bestY = testY;
1341 bestT = foundT;
1342 }
1343 if (bestT < 0) {
1344 return bestTIndex;
1345 }
1346 SkASSERT(bestT >= 0);
1347 SkASSERT(bestT <= 1);
1348 int start;
1349 int end = 0;
1350 do {
1351 start = end;
1352 end = nextSpan(start, 1);
1353 } while (fTs[end].fT < bestT);
1354 // FIXME: see next candidate for a better pattern to find the next start/end pair
1355 while (start + 1 < end && fTs[start].fDone) {
1356 ++start;
1357 }
1358 if (!isCanceled(start)) {
1359 *hitT = bestT;
1360 bestTIndex = start;
1361 *hitSomething = true;
1362 }
1363 return bestTIndex;
1364}
1365
caryclark@google.com570863f2013-09-16 15:55:01 +00001366bool SkOpSegment::decrementSpan(SkOpSpan* span) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001367 SkASSERT(span->fWindValue > 0);
1368 if (--(span->fWindValue) == 0) {
1369 if (!span->fOppValue && !span->fDone) {
1370 span->fDone = true;
1371 ++fDoneSpans;
caryclark@google.com570863f2013-09-16 15:55:01 +00001372 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001373 }
1374 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001375 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001376}
1377
1378bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00001379 SkASSERT(!span->fDone || span->fTiny || span->fSmall);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001380 span->fWindValue += windDelta;
1381 SkASSERT(span->fWindValue >= 0);
1382 span->fOppValue += oppDelta;
1383 SkASSERT(span->fOppValue >= 0);
1384 if (fXor) {
1385 span->fWindValue &= 1;
1386 }
1387 if (fOppXor) {
1388 span->fOppValue &= 1;
1389 }
1390 if (!span->fWindValue && !span->fOppValue) {
1391 span->fDone = true;
1392 ++fDoneSpans;
1393 return true;
1394 }
1395 return false;
1396}
1397
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001398// look to see if the curve end intersects an intermediary that intersects the other
1399void SkOpSegment::checkEnds() {
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001400 debugValidate();
caryclark@google.com570863f2013-09-16 15:55:01 +00001401 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001402 int count = fTs.count();
1403 for (int index = 0; index < count; ++index) {
1404 const SkOpSpan& span = fTs[index];
caryclark@google.com570863f2013-09-16 15:55:01 +00001405 double otherT = span.fOtherT;
1406 if (otherT != 0 && otherT != 1) { // only check ends
1407 continue;
1408 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001409 const SkOpSegment* other = span.fOther;
caryclark@google.com570863f2013-09-16 15:55:01 +00001410 // peek start/last describe the range of spans that match the other t of this span
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001411 int peekStart = span.fOtherIndex;
caryclark@google.com570863f2013-09-16 15:55:01 +00001412 while (--peekStart >= 0 && other->fTs[peekStart].fT == otherT)
1413 ;
1414 int otherCount = other->fTs.count();
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001415 int peekLast = span.fOtherIndex;
caryclark@google.com570863f2013-09-16 15:55:01 +00001416 while (++peekLast < otherCount && other->fTs[peekLast].fT == otherT)
1417 ;
1418 if (++peekStart == --peekLast) { // if there isn't a range, there's nothing to do
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001419 continue;
1420 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001421 // t start/last describe the range of spans that match the t of this span
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001422 double t = span.fT;
1423 int tStart = index;
caryclark@google.com570863f2013-09-16 15:55:01 +00001424 while (--tStart >= 0 && (t == fTs[tStart].fT || fTs[tStart].fTiny))
1425 ;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001426 int tLast = index;
caryclark@google.com570863f2013-09-16 15:55:01 +00001427 while (fTs[tLast].fTiny) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001428 ++tLast;
1429 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001430 while (++tLast < count && t == fTs[tLast].fT)
1431 ;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001432 for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) {
caryclark@google.com570863f2013-09-16 15:55:01 +00001433 if (peekIndex == span.fOtherIndex) { // skip the other span pointed to by this span
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001434 continue;
1435 }
1436 const SkOpSpan& peekSpan = other->fTs[peekIndex];
1437 SkOpSegment* match = peekSpan.fOther;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00001438 if (match->done()) {
1439 continue; // if the edge has already been eaten (likely coincidence), ignore it
1440 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001441 const double matchT = peekSpan.fOtherT;
caryclark@google.com570863f2013-09-16 15:55:01 +00001442 // see if any of the spans match the other spans
1443 for (int tIndex = tStart + 1; tIndex < tLast; ++tIndex) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001444 const SkOpSpan& tSpan = fTs[tIndex];
caryclark@google.com570863f2013-09-16 15:55:01 +00001445 if (tSpan.fOther == match) {
1446 if (tSpan.fOtherT == matchT) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00001447 goto nextPeekIndex;
caryclark@google.com570863f2013-09-16 15:55:01 +00001448 }
1449 double midT = (tSpan.fOtherT + matchT) / 2;
1450 if (match->betweenPoints(midT, tSpan.fPt, peekSpan.fPt)) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00001451 goto nextPeekIndex;
caryclark@google.com570863f2013-09-16 15:55:01 +00001452 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001453 }
1454 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001455 if (missingSpans.count() > 0) {
1456 const MissingSpan& lastMissing = missingSpans.back();
1457 if (lastMissing.fCommand == MissingSpan::kAddMissing
1458 && lastMissing.fT == t
1459 && lastMissing.fOther == match
1460 && lastMissing.fOtherT == matchT) {
1461 SkASSERT(lastMissing.fPt == peekSpan.fPt);
1462 continue;
1463 }
1464 }
1465#if DEBUG_CHECK_ENDS
1466 SkDebugf("%s id=%d missing t=%1.9g other=%d otherT=%1.9g pt=(%1.9g,%1.9g)\n",
1467 __FUNCTION__, fID, t, match->fID, matchT, peekSpan.fPt.fX, peekSpan.fPt.fY);
1468#endif
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001469 // this segment is missing a entry that the other contains
1470 // remember so we can add the missing one and recompute the indices
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00001471 {
1472 MissingSpan& missing = missingSpans.push_back();
1473 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
1474 missing.fCommand = MissingSpan::kAddMissing;
1475 missing.fT = t;
1476 missing.fOther = match;
1477 missing.fOtherT = matchT;
1478 missing.fPt = peekSpan.fPt;
1479 }
1480 break;
1481nextPeekIndex:
1482 ;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001483 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001484 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001485 if (missingSpans.count() == 0) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00001486 debugValidate();
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001487 return;
1488 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001489 // if one end is near the other point, look for a coincident span
1490 for (int index = 0; index < count; ++index) {
1491 const SkOpSpan& span = fTs[index];
1492 if (span.fT > 0) {
1493 break;
1494 }
1495 const SkOpSpan& otherSpan = span.fOther->span(span.fOtherIndex);
1496 if (span.fNear) {
1497 SkASSERT(otherSpan.fPt == fPts[0]);
1498 adjustNear(0, span.fPt, &missingSpans);
1499 continue;
1500 }
1501 if (otherSpan.fNear) {
1502 SkASSERT(span.fPt == fPts[0]);
1503 adjustNear(0, otherSpan.fPt, &missingSpans);
1504 }
1505 }
1506 for (int index = count; --index >= 0; ) {
1507 const SkOpSpan& span = fTs[index];
1508 if (span.fT < 1) {
1509 break;
1510 }
1511 const SkOpSegment* other = span.fOther;
1512 if (span.fNear) {
1513 SkASSERT(other->ptAtT(span.fOtherT) == ptAtT(1));
1514 const SkPoint& otherPt = other->xyAtT(span.fOtherIndex);
1515 SkASSERT(otherPt != ptAtT(1));
1516 adjustNear(1, otherPt, &missingSpans);
1517 continue;
1518 }
1519 const SkOpSpan& otherSpan = other->span(span.fOtherIndex);
1520 if (otherSpan.fNear) {
1521 SkASSERT(otherSpan.fPt == ptAtT(1));
1522 SkPoint otherPt = other->ptAtT(span.fOtherT);
1523 SkASSERT(otherPt != ptAtT(1));
1524 adjustNear(1, otherPt, &missingSpans);
1525 }
1526 }
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001527 debugValidate();
caryclark@google.com570863f2013-09-16 15:55:01 +00001528 int missingCount = missingSpans.count();
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001529 for (int index = 0; index < missingCount; ++index) {
caryclark@google.com570863f2013-09-16 15:55:01 +00001530 MissingSpan& missing = missingSpans[index];
1531 switch (missing.fCommand) {
1532 case MissingSpan::kNoAction:
1533 break;
1534 case MissingSpan::kAddMissing:
1535 addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt);
1536 break;
1537 case MissingSpan::kRemoveNear: {
1538 SkOpSegment* segment = missing.fSegment;
1539 int count = segment->count();
1540 for (int inner = 0; inner < count; ++inner) {
1541 const SkOpSpan& span = segment->span(inner);
1542 if (span.fT != missing.fT && span.fOther != missing.fOther) {
1543 continue;
1544 }
1545 SkASSERT(span.fNear);
1546 SkOpSegment* other = span.fOther;
1547 int otherCount = other->count();
1548 for (int otherIndex = 0; otherIndex < otherCount; ++otherIndex) {
1549 const SkOpSpan& otherSpan = other->span(otherIndex);
1550 if (otherSpan.fT == span.fOtherT && otherSpan.fOther == segment
1551 && otherSpan.fOtherT == span.fT) {
1552 if (otherSpan.fDone) {
1553 other->fDoneSpans--;
1554 }
1555 other->fTs.remove(otherIndex);
1556 // FIXME: remove may leave a tiny dangling -- recompute tiny w/index
1557 break;
1558 }
1559 }
1560 if (span.fDone) {
1561 segment->fDoneSpans--;
1562 }
1563 segment->fTs.remove(inner);
1564 // FIXME: remove may leave a tiny dangling -- recompute tiny w/index
1565 break;
1566 }
1567 break;
1568 }
1569 case MissingSpan::kZeroSpan: {
1570 SkOpSegment* segment = missing.fSegment;
1571 int count = segment->count();
1572 for (int inner = 0; inner < count; ++inner) {
1573 SkOpSpan& span = segment->fTs[inner];
1574 if (span.fT < missing.fT) {
1575 continue;
1576 }
1577 if (span.fT >= missing.fEndT) {
1578 break;
1579 }
1580 span.fWindValue = span.fOppValue = 0;
1581 if (!span.fDone) {
1582 span.fDone = true;
1583 ++segment->fDoneSpans;
1584 }
1585 }
1586 break;
1587 }
1588 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001589 }
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001590 fixOtherTIndex();
caryclark@google.com570863f2013-09-16 15:55:01 +00001591 // OPTIMIZATION: this may fix indices more than once. Build an array of unique segments to
1592 // avoid this
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001593 for (int index = 0; index < missingCount; ++index) {
caryclark@google.com570863f2013-09-16 15:55:01 +00001594 const MissingSpan& missing = missingSpans[index];
1595 switch (missing.fCommand) {
1596 case MissingSpan::kNoAction:
1597 break;
1598 case MissingSpan::kAddMissing:
1599 missing.fOther->fixOtherTIndex();
1600 break;
1601 case MissingSpan::kRemoveNear:
1602 missing.fSegment->fixOtherTIndex();
1603 missing.fOther->fixOtherTIndex();
1604 break;
1605 case MissingSpan::kZeroSpan:
1606 break;
1607 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001608 }
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001609 debugValidate();
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001610}
1611
caryclark@google.com570863f2013-09-16 15:55:01 +00001612bool SkOpSegment::checkSmall(int index) const {
1613 if (fTs[index].fSmall) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001614 return true;
1615 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001616 double tBase = fTs[index].fT;
1617 while (index > 0 && precisely_negative(tBase - fTs[--index].fT))
1618 ;
1619 return fTs[index].fSmall;
1620}
1621
1622// if pair of spans on either side of tiny have the same end point and mid point, mark
1623// them as parallel
1624// OPTIMIZATION : mark the segment to note that some span is tiny
1625void SkOpSegment::checkTiny() {
1626 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
1627 SkOpSpan* thisSpan = fTs.begin() - 1;
1628 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be tiny
1629 while (++thisSpan < endSpan) {
1630 if (!thisSpan->fTiny) {
1631 continue;
1632 }
1633 SkOpSpan* nextSpan = thisSpan + 1;
1634 double thisT = thisSpan->fT;
1635 double nextT = nextSpan->fT;
1636 if (thisT == nextT) {
1637 continue;
1638 }
1639 SkASSERT(thisT < nextT);
1640 SkASSERT(thisSpan->fPt == nextSpan->fPt);
1641 SkOpSegment* thisOther = thisSpan->fOther;
1642 SkOpSegment* nextOther = nextSpan->fOther;
1643 int oIndex = thisSpan->fOtherIndex;
1644 for (int oStep = -1; oStep <= 1; oStep += 2) {
1645 int oEnd = thisOther->nextExactSpan(oIndex, oStep);
1646 if (oEnd < 0) {
1647 continue;
1648 }
1649 const SkOpSpan& oSpan = thisOther->span(oEnd);
1650 int nIndex = nextSpan->fOtherIndex;
1651 for (int nStep = -1; nStep <= 1; nStep += 2) {
1652 int nEnd = nextOther->nextExactSpan(nIndex, nStep);
1653 if (nEnd < 0) {
1654 continue;
1655 }
1656 const SkOpSpan& nSpan = nextOther->span(nEnd);
1657 if (oSpan.fPt != nSpan.fPt) {
1658 continue;
1659 }
1660 double oMidT = (thisSpan->fOtherT + oSpan.fT) / 2;
1661 const SkPoint& oPt = thisOther->ptAtT(oMidT);
1662 double nMidT = (nextSpan->fOtherT + nSpan.fT) / 2;
1663 const SkPoint& nPt = nextOther->ptAtT(nMidT);
1664 if (!AlmostEqualUlps(oPt, nPt)) {
1665 continue;
1666 }
1667#if DEBUG_CHECK_TINY
1668 SkDebugf("%s [%d] add coincidence [%d] [%d]\n", __FUNCTION__, fID,
1669 thisOther->fID, nextOther->fID);
1670#endif
1671 // this segment is missing a entry that the other contains
1672 // remember so we can add the missing one and recompute the indices
1673 MissingSpan& missing = missingSpans.push_back();
1674 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
1675 missing.fCommand = MissingSpan::kAddMissing;
1676 missing.fSegment = thisOther;
1677 missing.fT = thisSpan->fOtherT;
1678 missing.fOther = nextOther;
1679 missing.fOtherT = nextSpan->fOtherT;
1680 missing.fPt = thisSpan->fPt;
1681 }
1682 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001683 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001684 int missingCount = missingSpans.count();
1685 if (!missingCount) {
1686 return;
1687 }
1688 for (int index = 0; index < missingCount; ++index) {
1689 MissingSpan& missing = missingSpans[index];
1690 missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt);
1691 }
1692 for (int index = 0; index < missingCount; ++index) {
1693 MissingSpan& missing = missingSpans[index];
1694 missing.fSegment->fixOtherTIndex();
1695 missing.fOther->fixOtherTIndex();
1696 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001697}
1698
1699/*
1700 The M and S variable name parts stand for the operators.
1701 Mi stands for Minuend (see wiki subtraction, analogous to difference)
1702 Su stands for Subtrahend
1703 The Opp variable name part designates that the value is for the Opposite operator.
1704 Opposite values result from combining coincident spans.
1705 */
1706SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
1707 bool* unsortable, SkPathOp op, const int xorMiMask,
1708 const int xorSuMask) {
1709 const int startIndex = *nextStart;
1710 const int endIndex = *nextEnd;
1711 SkASSERT(startIndex != endIndex);
1712 SkDEBUGCODE(const int count = fTs.count());
1713 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
1714 const int step = SkSign32(endIndex - startIndex);
1715 const int end = nextExactSpan(startIndex, step);
1716 SkASSERT(end >= 0);
1717 SkOpSpan* endSpan = &fTs[end];
1718 SkOpSegment* other;
1719 if (isSimple(end)) {
1720 // mark the smaller of startIndex, endIndex done, and all adjacent
1721 // spans with the same T value (but not 'other' spans)
1722#if DEBUG_WINDING
1723 SkDebugf("%s simple\n", __FUNCTION__);
1724#endif
1725 int min = SkMin32(startIndex, endIndex);
1726 if (fTs[min].fDone) {
1727 return NULL;
1728 }
1729 markDoneBinary(min);
1730 other = endSpan->fOther;
1731 *nextStart = endSpan->fOtherIndex;
1732 double startT = other->fTs[*nextStart].fT;
1733 *nextEnd = *nextStart;
1734 do {
1735 *nextEnd += step;
caryclark@google.com570863f2013-09-16 15:55:01 +00001736 } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
caryclark@google.com07393ca2013-04-08 11:47:37 +00001737 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001738 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001739 *unsortable = true;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001740 return NULL;
1741 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001742 return other;
1743 }
1744 // more than one viable candidate -- measure angles to find best
caryclark@google.comd892bd82013-06-17 14:10:36 +00001745 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001746 SkASSERT(startIndex - endIndex != 0);
1747 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
caryclark@google.comd892bd82013-06-17 14:10:36 +00001748 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.com570863f2013-09-16 15:55:01 +00001749 int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp, &angles, &sorted);
1750 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00001751 if (sortable && sorted.count() == 0) {
1752 // if no edge has a computed winding sum, we can go no further
1753 *unsortable = true;
1754 return NULL;
1755 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001756 int angleCount = angles.count();
1757 int firstIndex = findStartingEdge(sorted, startIndex, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001758 SkASSERT(!sortable || firstIndex >= 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001759#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001760 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001761#endif
1762 if (!sortable) {
1763 *unsortable = true;
1764 return NULL;
1765 }
1766 SkASSERT(sorted[firstIndex]->segment() == this);
1767#if DEBUG_WINDING
1768 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
1769 sorted[firstIndex]->sign());
1770#endif
1771 int sumMiWinding = updateWinding(endIndex, startIndex);
1772 int sumSuWinding = updateOppWinding(endIndex, startIndex);
1773 if (operand()) {
1774 SkTSwap<int>(sumMiWinding, sumSuWinding);
1775 }
1776 int nextIndex = firstIndex + 1;
1777 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1778 const SkOpAngle* foundAngle = NULL;
1779 bool foundDone = false;
1780 // iterate through the angle, and compute everyone's winding
1781 SkOpSegment* nextSegment;
1782 int activeCount = 0;
1783 do {
1784 SkASSERT(nextIndex != firstIndex);
1785 if (nextIndex == angleCount) {
1786 nextIndex = 0;
1787 }
1788 const SkOpAngle* nextAngle = sorted[nextIndex];
1789 nextSegment = nextAngle->segment();
1790 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1791 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
1792 nextAngle->end(), op, &sumMiWinding, &sumSuWinding,
1793 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1794 if (activeAngle) {
1795 ++activeCount;
1796 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001797 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001798 *unsortable = true;
1799 return NULL;
1800 }
1801 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +00001802 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001803 }
1804 }
1805 if (nextSegment->done()) {
1806 continue;
1807 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001808 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001809 continue;
1810 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001811 if (!activeAngle) {
1812 nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextAngle->end());
1813 }
1814 SkOpSpan* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001815 if (last) {
1816 *chase->append() = last;
1817#if DEBUG_WINDING
caryclark@google.com570863f2013-09-16 15:55:01 +00001818 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
1819 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
1820 last->fSmall);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001821#endif
1822 }
1823 } while (++nextIndex != lastIndex);
1824 markDoneBinary(SkMin32(startIndex, endIndex));
1825 if (!foundAngle) {
1826 return NULL;
1827 }
1828 *nextStart = foundAngle->start();
1829 *nextEnd = foundAngle->end();
1830 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001831#if DEBUG_WINDING
1832 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1833 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1834 #endif
1835 return nextSegment;
1836}
1837
1838SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart,
1839 int* nextEnd, bool* unsortable) {
1840 const int startIndex = *nextStart;
1841 const int endIndex = *nextEnd;
1842 SkASSERT(startIndex != endIndex);
1843 SkDEBUGCODE(const int count = fTs.count());
1844 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
1845 const int step = SkSign32(endIndex - startIndex);
1846 const int end = nextExactSpan(startIndex, step);
1847 SkASSERT(end >= 0);
1848 SkOpSpan* endSpan = &fTs[end];
1849 SkOpSegment* other;
1850 if (isSimple(end)) {
1851 // mark the smaller of startIndex, endIndex done, and all adjacent
1852 // spans with the same T value (but not 'other' spans)
1853#if DEBUG_WINDING
1854 SkDebugf("%s simple\n", __FUNCTION__);
1855#endif
1856 int min = SkMin32(startIndex, endIndex);
1857 if (fTs[min].fDone) {
1858 return NULL;
1859 }
1860 markDoneUnary(min);
1861 other = endSpan->fOther;
1862 *nextStart = endSpan->fOtherIndex;
1863 double startT = other->fTs[*nextStart].fT;
1864 *nextEnd = *nextStart;
1865 do {
1866 *nextEnd += step;
caryclark@google.com570863f2013-09-16 15:55:01 +00001867 } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
caryclark@google.com07393ca2013-04-08 11:47:37 +00001868 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
caryclark@google.com570863f2013-09-16 15:55:01 +00001869 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
1870 *unsortable = true;
1871 return NULL;
1872 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001873 return other;
1874 }
1875 // more than one viable candidate -- measure angles to find best
caryclark@google.comd892bd82013-06-17 14:10:36 +00001876 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001877 SkASSERT(startIndex - endIndex != 0);
1878 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
caryclark@google.comd892bd82013-06-17 14:10:36 +00001879 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.com570863f2013-09-16 15:55:01 +00001880 int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryWinding, &angles, &sorted);
1881 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001882 int angleCount = angles.count();
1883 int firstIndex = findStartingEdge(sorted, startIndex, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001884 SkASSERT(!sortable || firstIndex >= 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001885#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001886 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001887#endif
1888 if (!sortable) {
1889 *unsortable = true;
1890 return NULL;
1891 }
1892 SkASSERT(sorted[firstIndex]->segment() == this);
1893#if DEBUG_WINDING
1894 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
1895 sorted[firstIndex]->sign());
1896#endif
1897 int sumWinding = updateWinding(endIndex, startIndex);
1898 int nextIndex = firstIndex + 1;
1899 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1900 const SkOpAngle* foundAngle = NULL;
1901 bool foundDone = false;
1902 // iterate through the angle, and compute everyone's winding
1903 SkOpSegment* nextSegment;
1904 int activeCount = 0;
1905 do {
1906 SkASSERT(nextIndex != firstIndex);
1907 if (nextIndex == angleCount) {
1908 nextIndex = 0;
1909 }
1910 const SkOpAngle* nextAngle = sorted[nextIndex];
1911 nextSegment = nextAngle->segment();
1912 int maxWinding;
1913 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
1914 &maxWinding, &sumWinding);
1915 if (activeAngle) {
1916 ++activeCount;
1917 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001918 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001919 *unsortable = true;
1920 return NULL;
1921 }
1922 foundAngle = nextAngle;
1923 foundDone = nextSegment->done(nextAngle);
1924 }
1925 }
1926 if (nextSegment->done()) {
1927 continue;
1928 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001929 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001930 continue;
1931 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001932 if (!activeAngle) {
1933 nextSegment->markAndChaseDoneUnary(nextAngle->start(), nextAngle->end());
1934 }
1935 SkOpSpan* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001936 if (last) {
1937 *chase->append() = last;
1938#if DEBUG_WINDING
caryclark@google.com570863f2013-09-16 15:55:01 +00001939 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
1940 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
1941 last->fSmall);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001942#endif
1943 }
1944 } while (++nextIndex != lastIndex);
1945 markDoneUnary(SkMin32(startIndex, endIndex));
1946 if (!foundAngle) {
1947 return NULL;
1948 }
1949 *nextStart = foundAngle->start();
1950 *nextEnd = foundAngle->end();
1951 nextSegment = foundAngle->segment();
1952#if DEBUG_WINDING
1953 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1954 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1955 #endif
1956 return nextSegment;
1957}
1958
1959SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsortable) {
1960 const int startIndex = *nextStart;
1961 const int endIndex = *nextEnd;
1962 SkASSERT(startIndex != endIndex);
1963 SkDEBUGCODE(int count = fTs.count());
caryclark@google.com570863f2013-09-16 15:55:01 +00001964 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001965 int step = SkSign32(endIndex - startIndex);
1966 int end = nextExactSpan(startIndex, step);
1967 SkASSERT(end >= 0);
1968 SkOpSpan* endSpan = &fTs[end];
1969 SkOpSegment* other;
1970 if (isSimple(end)) {
1971#if DEBUG_WINDING
1972 SkDebugf("%s simple\n", __FUNCTION__);
1973#endif
1974 int min = SkMin32(startIndex, endIndex);
1975 if (fTs[min].fDone) {
1976 return NULL;
1977 }
1978 markDone(min, 1);
1979 other = endSpan->fOther;
1980 *nextStart = endSpan->fOtherIndex;
1981 double startT = other->fTs[*nextStart].fT;
1982 // FIXME: I don't know why the logic here is difference from the winding case
1983 SkDEBUGCODE(bool firstLoop = true;)
1984 if ((approximately_less_than_zero(startT) && step < 0)
1985 || (approximately_greater_than_one(startT) && step > 0)) {
1986 step = -step;
1987 SkDEBUGCODE(firstLoop = false;)
1988 }
1989 do {
1990 *nextEnd = *nextStart;
1991 do {
1992 *nextEnd += step;
caryclark@google.com570863f2013-09-16 15:55:01 +00001993 } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
caryclark@google.com07393ca2013-04-08 11:47:37 +00001994 if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) {
1995 break;
1996 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001997 SkASSERT(firstLoop);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001998 SkDEBUGCODE(firstLoop = false;)
1999 step = -step;
2000 } while (true);
2001 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
2002 return other;
2003 }
caryclark@google.comd892bd82013-06-17 14:10:36 +00002004 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002005 SkASSERT(startIndex - endIndex != 0);
2006 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
caryclark@google.comd892bd82013-06-17 14:10:36 +00002007 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.com570863f2013-09-16 15:55:01 +00002008 int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryXor, &angles, &sorted);
2009 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002010 int angleCount = angles.count();
2011 int firstIndex = findStartingEdge(sorted, startIndex, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00002012 SkASSERT(!sortable || firstIndex >= 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002013#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +00002014 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002015#endif
caryclark@google.com570863f2013-09-16 15:55:01 +00002016 if (!sortable) {
2017 *unsortable = true;
2018 return NULL;
2019 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002020 SkASSERT(sorted[firstIndex]->segment() == this);
caryclark@google.com570863f2013-09-16 15:55:01 +00002021#if DEBUG_WINDING
2022 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
2023 sorted[firstIndex]->sign());
2024#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00002025 int nextIndex = firstIndex + 1;
2026 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
2027 const SkOpAngle* foundAngle = NULL;
2028 bool foundDone = false;
2029 SkOpSegment* nextSegment;
2030 int activeCount = 0;
2031 do {
2032 SkASSERT(nextIndex != firstIndex);
2033 if (nextIndex == angleCount) {
2034 nextIndex = 0;
2035 }
2036 const SkOpAngle* nextAngle = sorted[nextIndex];
2037 nextSegment = nextAngle->segment();
2038 ++activeCount;
2039 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002040 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002041 *unsortable = true;
2042 return NULL;
2043 }
2044 foundAngle = nextAngle;
2045 foundDone = nextSegment->done(nextAngle);
2046 }
2047 if (nextSegment->done()) {
2048 continue;
2049 }
2050 } while (++nextIndex != lastIndex);
2051 markDone(SkMin32(startIndex, endIndex), 1);
2052 if (!foundAngle) {
2053 return NULL;
2054 }
2055 *nextStart = foundAngle->start();
2056 *nextEnd = foundAngle->end();
2057 nextSegment = foundAngle->segment();
2058#if DEBUG_WINDING
2059 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2060 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
2061 #endif
2062 return nextSegment;
2063}
2064
caryclark@google.comd892bd82013-06-17 14:10:36 +00002065int SkOpSegment::findStartingEdge(const SkTArray<SkOpAngle*, true>& sorted, int start, int end) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002066 int angleCount = sorted.count();
2067 int firstIndex = -1;
2068 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2069 const SkOpAngle* angle = sorted[angleIndex];
2070 if (angle->segment() == this && angle->start() == end &&
2071 angle->end() == start) {
2072 firstIndex = angleIndex;
2073 break;
2074 }
2075 }
2076 return firstIndex;
2077}
2078
caryclark@google.com07393ca2013-04-08 11:47:37 +00002079// FIXME: either:
2080// a) mark spans with either end unsortable as done, or
2081// b) rewrite findTop / findTopSegment / findTopContour to iterate further
2082// when encountering an unsortable span
2083
2084// OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2085// and use more concise logic like the old edge walker code?
2086// FIXME: this needs to deal with coincident edges
2087SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable,
2088 bool onlySortable) {
2089 // iterate through T intersections and return topmost
2090 // topmost tangent from y-min to first pt is closer to horizontal
2091 SkASSERT(!done());
2092 int firstT = -1;
2093 /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT);
2094 if (firstT < 0) {
2095 *unsortable = true;
2096 firstT = 0;
2097 while (fTs[firstT].fDone) {
2098 SkASSERT(firstT < fTs.count());
2099 ++firstT;
2100 }
2101 *tIndexPtr = firstT;
2102 *endIndexPtr = nextExactSpan(firstT, 1);
2103 return this;
2104 }
2105 // sort the edges to find the leftmost
2106 int step = 1;
2107 int end = nextSpan(firstT, step);
2108 if (end == -1) {
2109 step = -1;
2110 end = nextSpan(firstT, step);
2111 SkASSERT(end != -1);
2112 }
2113 // if the topmost T is not on end, or is three-way or more, find left
2114 // look for left-ness from tLeft to firstT (matching y of other)
caryclark@google.comd892bd82013-06-17 14:10:36 +00002115 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002116 SkASSERT(firstT - end != 0);
2117 addTwoAngles(end, firstT, &angles);
caryclark@google.com570863f2013-09-16 15:55:01 +00002118 if (!buildAngles(firstT, &angles, true) && onlySortable) {
2119// *unsortable = true;
2120// return NULL;
2121 }
caryclark@google.comd892bd82013-06-17 14:10:36 +00002122 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002123 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMayBeUnordered_SortAngleKind);
caryclark@google.com570863f2013-09-16 15:55:01 +00002124 if (onlySortable && !sortable) {
2125 *unsortable = true;
2126 return NULL;
2127 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002128 int first = SK_MaxS32;
2129 SkScalar top = SK_ScalarMax;
2130 int count = sorted.count();
2131 for (int index = 0; index < count; ++index) {
2132 const SkOpAngle* angle = sorted[index];
caryclark@google.com570863f2013-09-16 15:55:01 +00002133 if (onlySortable && angle->unorderable()) {
2134 continue;
2135 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002136 SkOpSegment* next = angle->segment();
2137 SkPathOpsBounds bounds;
2138 next->subDivideBounds(angle->end(), angle->start(), &bounds);
2139 if (approximately_greater(top, bounds.fTop)) {
2140 top = bounds.fTop;
2141 first = index;
2142 }
2143 }
2144 SkASSERT(first < SK_MaxS32);
2145#if DEBUG_SORT // || DEBUG_SWAP_TOP
caryclark@google.com07e97fc2013-07-08 17:17:02 +00002146 sorted[first]->segment()->debugShowSort(__FUNCTION__, sorted, first, 0, 0, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002147#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00002148 // skip edges that have already been processed
2149 firstT = first - 1;
2150 SkOpSegment* leftSegment;
2151 do {
2152 if (++firstT == count) {
2153 firstT = 0;
2154 }
2155 const SkOpAngle* angle = sorted[firstT];
2156 SkASSERT(!onlySortable || !angle->unsortable());
2157 leftSegment = angle->segment();
2158 *tIndexPtr = angle->end();
2159 *endIndexPtr = angle->start();
2160 } while (leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone);
2161 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
2162 const int tIndex = *tIndexPtr;
2163 const int endIndex = *endIndexPtr;
2164 if (!leftSegment->clockwise(tIndex, endIndex)) {
2165 bool swap = !leftSegment->monotonicInY(tIndex, endIndex)
2166 && !leftSegment->serpentine(tIndex, endIndex);
2167 #if DEBUG_SWAP_TOP
2168 SkDebugf("%s swap=%d serpentine=%d containedByEnds=%d monotonic=%d\n", __FUNCTION__,
2169 swap,
2170 leftSegment->serpentine(tIndex, endIndex),
2171 leftSegment->controlsContainedByEnds(tIndex, endIndex),
2172 leftSegment->monotonicInY(tIndex, endIndex));
2173 #endif
2174 if (swap) {
2175 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first
2176 // sorted but merely the first not already processed (i.e., not done)
2177 SkTSwap(*tIndexPtr, *endIndexPtr);
2178 }
2179 }
2180 }
2181 SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny);
2182 return leftSegment;
2183}
2184
2185// FIXME: not crazy about this
2186// when the intersections are performed, the other index is into an
2187// incomplete array. As the array grows, the indices become incorrect
2188// while the following fixes the indices up again, it isn't smart about
2189// skipping segments whose indices are already correct
2190// assuming we leave the code that wrote the index in the first place
caryclark@google.com570863f2013-09-16 15:55:01 +00002191// FIXME: if called after remove, this needs to correct tiny
caryclark@google.com07393ca2013-04-08 11:47:37 +00002192void SkOpSegment::fixOtherTIndex() {
2193 int iCount = fTs.count();
2194 for (int i = 0; i < iCount; ++i) {
2195 SkOpSpan& iSpan = fTs[i];
2196 double oT = iSpan.fOtherT;
2197 SkOpSegment* other = iSpan.fOther;
2198 int oCount = other->fTs.count();
caryclark@google.com4fdbb222013-07-23 15:27:41 +00002199 SkDEBUGCODE(iSpan.fOtherIndex = -1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002200 for (int o = 0; o < oCount; ++o) {
2201 SkOpSpan& oSpan = other->fTs[o];
2202 if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan.fT) {
2203 iSpan.fOtherIndex = o;
caryclark@google.com4fdbb222013-07-23 15:27:41 +00002204 oSpan.fOtherIndex = i;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002205 break;
2206 }
2207 }
caryclark@google.com4fdbb222013-07-23 15:27:41 +00002208 SkASSERT(iSpan.fOtherIndex >= 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002209 }
2210}
2211
2212void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
2213 fDoneSpans = 0;
2214 fOperand = operand;
2215 fXor = evenOdd;
2216 fPts = pts;
2217 fVerb = verb;
2218}
2219
2220void SkOpSegment::initWinding(int start, int end) {
2221 int local = spanSign(start, end);
2222 int oppLocal = oppSign(start, end);
2223 (void) markAndChaseWinding(start, end, local, oppLocal);
2224 // OPTIMIZATION: the reverse mark and chase could skip the first marking
2225 (void) markAndChaseWinding(end, start, local, oppLocal);
2226}
2227
2228/*
2229when we start with a vertical intersect, we try to use the dx to determine if the edge is to
2230the left or the right of vertical. This determines if we need to add the span's
2231sign or not. However, this isn't enough.
2232If the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed.
2233If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
2234from has the same x direction as this span, the winding should change. If the dx is opposite, then
2235the same winding is shared by both.
2236*/
2237void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkScalar hitDx,
2238 int oppWind, SkScalar hitOppDx) {
2239 SkASSERT(hitDx || !winding);
reed@google.com277c3f82013-05-31 15:17:50 +00002240 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002241 SkASSERT(dx);
2242 int windVal = windValue(SkMin32(start, end));
2243#if DEBUG_WINDING_AT_T
2244 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
2245 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
2246#endif
2247 if (!winding) {
2248 winding = dx < 0 ? windVal : -windVal;
2249 } else if (winding * dx < 0) {
2250 int sideWind = winding + (dx < 0 ? windVal : -windVal);
2251 if (abs(winding) < abs(sideWind)) {
2252 winding = sideWind;
2253 }
2254 }
2255#if DEBUG_WINDING_AT_T
2256 SkDebugf(" winding=%d\n", winding);
2257#endif
2258 SkDEBUGCODE(int oppLocal = oppSign(start, end));
2259 SkASSERT(hitOppDx || !oppWind || !oppLocal);
2260 int oppWindVal = oppValue(SkMin32(start, end));
2261 if (!oppWind) {
2262 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
2263 } else if (hitOppDx * dx >= 0) {
2264 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
2265 if (abs(oppWind) < abs(oppSideWind)) {
2266 oppWind = oppSideWind;
2267 }
2268 }
2269 (void) markAndChaseWinding(start, end, winding, oppWind);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00002270 // OPTIMIZATION: the reverse mark and chase could skip the first marking
2271 (void) markAndChaseWinding(end, start, winding, oppWind);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002272}
2273
caryclark@google.com07393ca2013-04-08 11:47:37 +00002274// OPTIMIZE: successive calls could start were the last leaves off
2275// or calls could specialize to walk forwards or backwards
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00002276bool SkOpSegment::isMissing(double startT, const SkPoint& pt) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002277 size_t tCount = fTs.count();
2278 for (size_t index = 0; index < tCount; ++index) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00002279 const SkOpSpan& span = fTs[index];
2280 if (approximately_zero(startT - span.fT) && pt == span.fPt) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002281 return false;
2282 }
2283 }
2284 return true;
2285}
2286
2287bool SkOpSegment::isSimple(int end) const {
2288 int count = fTs.count();
2289 if (count == 2) {
2290 return true;
2291 }
2292 double t = fTs[end].fT;
2293 if (approximately_less_than_zero(t)) {
2294 return !approximately_less_than_zero(fTs[1].fT);
2295 }
2296 if (approximately_greater_than_one(t)) {
2297 return !approximately_greater_than_one(fTs[count - 2].fT);
2298 }
2299 return false;
2300}
2301
2302// this span is excluded by the winding rule -- chase the ends
2303// as long as they are unambiguous to mark connections as done
2304// and give them the same winding value
2305SkOpSpan* SkOpSegment::markAndChaseDone(int index, int endIndex, int winding) {
2306 int step = SkSign32(endIndex - index);
2307 int min = SkMin32(index, endIndex);
2308 markDone(min, winding);
2309 SkOpSpan* last;
2310 SkOpSegment* other = this;
2311 while ((other = other->nextChase(&index, step, &min, &last))) {
2312 other->markDone(min, winding);
2313 }
2314 return last;
2315}
2316
2317SkOpSpan* SkOpSegment::markAndChaseDoneBinary(const SkOpAngle* angle, int winding, int oppWinding) {
2318 int index = angle->start();
2319 int endIndex = angle->end();
2320 int step = SkSign32(endIndex - index);
2321 int min = SkMin32(index, endIndex);
2322 markDoneBinary(min, winding, oppWinding);
2323 SkOpSpan* last;
2324 SkOpSegment* other = this;
2325 while ((other = other->nextChase(&index, step, &min, &last))) {
2326 other->markDoneBinary(min, winding, oppWinding);
2327 }
2328 return last;
2329}
2330
2331SkOpSpan* SkOpSegment::markAndChaseDoneBinary(int index, int endIndex) {
2332 int step = SkSign32(endIndex - index);
2333 int min = SkMin32(index, endIndex);
2334 markDoneBinary(min);
2335 SkOpSpan* last;
2336 SkOpSegment* other = this;
2337 while ((other = other->nextChase(&index, step, &min, &last))) {
2338 if (other->done()) {
2339 return NULL;
2340 }
2341 other->markDoneBinary(min);
2342 }
2343 return last;
2344}
2345
2346SkOpSpan* SkOpSegment::markAndChaseDoneUnary(int index, int endIndex) {
2347 int step = SkSign32(endIndex - index);
2348 int min = SkMin32(index, endIndex);
2349 markDoneUnary(min);
2350 SkOpSpan* last;
2351 SkOpSegment* other = this;
2352 while ((other = other->nextChase(&index, step, &min, &last))) {
2353 if (other->done()) {
2354 return NULL;
2355 }
2356 other->markDoneUnary(min);
2357 }
2358 return last;
2359}
2360
2361SkOpSpan* SkOpSegment::markAndChaseDoneUnary(const SkOpAngle* angle, int winding) {
2362 int index = angle->start();
2363 int endIndex = angle->end();
2364 return markAndChaseDone(index, endIndex, winding);
2365}
2366
2367SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, const int winding) {
2368 int index = angle->start();
2369 int endIndex = angle->end();
2370 int step = SkSign32(endIndex - index);
2371 int min = SkMin32(index, endIndex);
2372 markWinding(min, winding);
2373 SkOpSpan* last;
2374 SkOpSegment* other = this;
2375 while ((other = other->nextChase(&index, step, &min, &last))) {
2376 if (other->fTs[min].fWindSum != SK_MinS32) {
2377 SkASSERT(other->fTs[min].fWindSum == winding);
2378 return NULL;
2379 }
2380 other->markWinding(min, winding);
2381 }
2382 return last;
2383}
2384
2385SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
2386 int min = SkMin32(index, endIndex);
2387 int step = SkSign32(endIndex - index);
2388 markWinding(min, winding, oppWinding);
2389 SkOpSpan* last;
2390 SkOpSegment* other = this;
2391 while ((other = other->nextChase(&index, step, &min, &last))) {
2392 if (other->fTs[min].fWindSum != SK_MinS32) {
2393 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
2394 return NULL;
2395 }
2396 other->markWinding(min, winding, oppWinding);
2397 }
2398 return last;
2399}
2400
2401SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding) {
2402 int start = angle->start();
2403 int end = angle->end();
2404 return markAndChaseWinding(start, end, winding, oppWinding);
2405}
2406
2407SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, bool activeAngle,
2408 const SkOpAngle* angle) {
2409 SkASSERT(angle->segment() == this);
2410 if (UseInnerWinding(maxWinding, sumWinding)) {
2411 maxWinding = sumWinding;
2412 }
2413 SkOpSpan* last;
2414 if (activeAngle) {
2415 last = markAndChaseWinding(angle, maxWinding);
2416 } else {
2417 last = markAndChaseDoneUnary(angle, maxWinding);
2418 }
caryclark@google.com570863f2013-09-16 15:55:01 +00002419#if DEBUG_WINDING
2420 if (last) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00002421 SkDebugf("%s last id=%d windSum=", __FUNCTION__,
2422 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2423 SkPathOpsDebug::WindingPrintf(last->fWindSum);
2424 SkDebugf(" small=%d\n", last->fSmall);
caryclark@google.com570863f2013-09-16 15:55:01 +00002425 }
2426#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00002427 return last;
2428}
2429
2430SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
2431 int oppSumWinding, bool activeAngle, const SkOpAngle* angle) {
2432 SkASSERT(angle->segment() == this);
2433 if (UseInnerWinding(maxWinding, sumWinding)) {
2434 maxWinding = sumWinding;
2435 }
2436 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
2437 oppMaxWinding = oppSumWinding;
2438 }
2439 SkOpSpan* last;
2440 if (activeAngle) {
2441 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
2442 } else {
2443 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
2444 }
caryclark@google.com570863f2013-09-16 15:55:01 +00002445#if DEBUG_WINDING
2446 if (last) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00002447 SkDebugf("%s last id=%d windSum=", __FUNCTION__,
2448 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
2449 SkPathOpsDebug::WindingPrintf(last->fWindSum);
2450 SkDebugf(" small=%d\n", last->fSmall);
caryclark@google.com570863f2013-09-16 15:55:01 +00002451 }
2452#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00002453 return last;
2454}
2455
2456// FIXME: this should also mark spans with equal (x,y)
2457// This may be called when the segment is already marked done. While this
2458// wastes time, it shouldn't do any more than spin through the T spans.
2459// OPTIMIZATION: abort on first done found (assuming that this code is
2460// always called to mark segments done).
2461void SkOpSegment::markDone(int index, int winding) {
2462 // SkASSERT(!done());
2463 SkASSERT(winding);
2464 double referenceT = fTs[index].fT;
2465 int lesser = index;
2466 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2467 markOneDone(__FUNCTION__, lesser, winding);
2468 }
2469 do {
2470 markOneDone(__FUNCTION__, index, winding);
2471 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2472}
2473
2474void SkOpSegment::markDoneBinary(int index, int winding, int oppWinding) {
2475 // SkASSERT(!done());
2476 SkASSERT(winding || oppWinding);
2477 double referenceT = fTs[index].fT;
2478 int lesser = index;
2479 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2480 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
2481 }
2482 do {
2483 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
2484 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2485}
2486
2487void SkOpSegment::markDoneBinary(int index) {
2488 double referenceT = fTs[index].fT;
2489 int lesser = index;
2490 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2491 markOneDoneBinary(__FUNCTION__, lesser);
2492 }
2493 do {
2494 markOneDoneBinary(__FUNCTION__, index);
2495 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2496}
2497
2498void SkOpSegment::markDoneUnary(int index) {
2499 double referenceT = fTs[index].fT;
2500 int lesser = index;
2501 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2502 markOneDoneUnary(__FUNCTION__, lesser);
2503 }
2504 do {
2505 markOneDoneUnary(__FUNCTION__, index);
2506 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2507}
2508
2509void SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) {
2510 SkOpSpan* span = markOneWinding(funName, tIndex, winding);
2511 if (!span) {
2512 return;
2513 }
2514 span->fDone = true;
2515 fDoneSpans++;
2516}
2517
2518void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) {
2519 SkOpSpan* span = verifyOneWinding(funName, tIndex);
2520 if (!span) {
2521 return;
2522 }
2523 span->fDone = true;
2524 fDoneSpans++;
2525}
2526
2527void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
2528 SkOpSpan* span = markOneWinding(funName, tIndex, winding, oppWinding);
2529 if (!span) {
2530 return;
2531 }
2532 span->fDone = true;
2533 fDoneSpans++;
2534}
2535
2536void SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) {
2537 SkOpSpan* span = verifyOneWindingU(funName, tIndex);
2538 if (!span) {
2539 return;
2540 }
2541 span->fDone = true;
2542 fDoneSpans++;
2543}
2544
2545SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding) {
2546 SkOpSpan& span = fTs[tIndex];
2547 if (span.fDone) {
2548 return NULL;
2549 }
2550#if DEBUG_MARK_DONE
2551 debugShowNewWinding(funName, span, winding);
2552#endif
2553 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com570863f2013-09-16 15:55:01 +00002554 SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002555 span.fWindSum = winding;
2556 return &span;
2557}
2558
2559SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding,
2560 int oppWinding) {
2561 SkOpSpan& span = fTs[tIndex];
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00002562 if (span.fDone && !span.fSmall) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002563 return NULL;
2564 }
2565#if DEBUG_MARK_DONE
2566 debugShowNewWinding(funName, span, winding, oppWinding);
2567#endif
2568 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com570863f2013-09-16 15:55:01 +00002569 SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002570 span.fWindSum = winding;
2571 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00002572 SkASSERT(abs(oppWinding) <= SkPathOpsDebug::gMaxWindSum);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002573 span.fOppSum = oppWinding;
2574 return &span;
2575}
2576
2577// from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
2578bool SkOpSegment::clockwise(int tStart, int tEnd) const {
2579 SkASSERT(fVerb != SkPath::kLine_Verb);
2580 SkPoint edge[4];
2581 subDivide(tStart, tEnd, edge);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002582 int points = SkPathOpsVerbToPoints(fVerb);
2583 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002584 if (fVerb == SkPath::kCubic_Verb) {
2585 SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY);
2586 if (edge[1].fY < lesser && edge[2].fY < lesser) {
2587 SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1].fY} }};
2588 SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3].fY} }};
2589 if (SkIntersections::Test(tangent1, tangent2)) {
2590 SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2591 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY);
2592 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY);
2593 return sum <= 0;
2594 }
2595 }
2596 }
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002597 for (int idx = 0; idx < points; ++idx){
caryclark@google.com07393ca2013-04-08 11:47:37 +00002598 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
2599 }
2600 return sum <= 0;
2601}
2602
2603bool SkOpSegment::monotonicInY(int tStart, int tEnd) const {
2604 if (fVerb == SkPath::kLine_Verb) {
2605 return false;
2606 }
2607 if (fVerb == SkPath::kQuad_Verb) {
2608 SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2609 return dst.monotonicInY();
2610 }
2611 SkASSERT(fVerb == SkPath::kCubic_Verb);
2612 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2613 return dst.monotonicInY();
2614}
2615
2616bool SkOpSegment::serpentine(int tStart, int tEnd) const {
2617 if (fVerb != SkPath::kCubic_Verb) {
2618 return false;
2619 }
2620 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2621 return dst.serpentine();
2622}
2623
2624SkOpSpan* SkOpSegment::verifyOneWinding(const char* funName, int tIndex) {
2625 SkOpSpan& span = fTs[tIndex];
2626 if (span.fDone) {
2627 return NULL;
2628 }
2629#if DEBUG_MARK_DONE
2630 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
2631#endif
2632 SkASSERT(span.fWindSum != SK_MinS32);
2633 SkASSERT(span.fOppSum != SK_MinS32);
2634 return &span;
2635}
2636
2637SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) {
2638 SkOpSpan& span = fTs[tIndex];
2639 if (span.fDone) {
2640 return NULL;
2641 }
2642#if DEBUG_MARK_DONE
2643 debugShowNewWinding(funName, span, span.fWindSum);
2644#endif
2645 SkASSERT(span.fWindSum != SK_MinS32);
2646 return &span;
2647}
2648
2649// note that just because a span has one end that is unsortable, that's
2650// not enough to mark it done. The other end may be sortable, allowing the
2651// span to be added.
2652// FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
2653void SkOpSegment::markUnsortable(int start, int end) {
2654 SkOpSpan* span = &fTs[start];
2655 if (start < end) {
2656#if DEBUG_UNSORTABLE
2657 debugShowNewWinding(__FUNCTION__, *span, 0);
2658#endif
2659 span->fUnsortableStart = true;
2660 } else {
2661 --span;
2662#if DEBUG_UNSORTABLE
2663 debugShowNewWinding(__FUNCTION__, *span, 0);
2664#endif
2665 span->fUnsortableEnd = true;
2666 }
2667 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
2668 return;
2669 }
2670 span->fDone = true;
2671 fDoneSpans++;
2672}
2673
2674void SkOpSegment::markWinding(int index, int winding) {
2675// SkASSERT(!done());
2676 SkASSERT(winding);
2677 double referenceT = fTs[index].fT;
2678 int lesser = index;
2679 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2680 markOneWinding(__FUNCTION__, lesser, winding);
2681 }
2682 do {
2683 markOneWinding(__FUNCTION__, index, winding);
2684 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2685}
2686
2687void SkOpSegment::markWinding(int index, int winding, int oppWinding) {
2688// SkASSERT(!done());
2689 SkASSERT(winding || oppWinding);
2690 double referenceT = fTs[index].fT;
2691 int lesser = index;
2692 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2693 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
2694 }
2695 do {
2696 markOneWinding(__FUNCTION__, index, winding, oppWinding);
2697 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2698}
2699
2700void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) {
2701 int nextDoorWind = SK_MaxS32;
2702 int nextOppWind = SK_MaxS32;
2703 if (tIndex > 0) {
2704 const SkOpSpan& below = fTs[tIndex - 1];
2705 if (approximately_negative(t - below.fT)) {
2706 nextDoorWind = below.fWindValue;
2707 nextOppWind = below.fOppValue;
2708 }
2709 }
2710 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
2711 const SkOpSpan& above = fTs[tIndex + 1];
2712 if (approximately_negative(above.fT - t)) {
2713 nextDoorWind = above.fWindValue;
2714 nextOppWind = above.fOppValue;
2715 }
2716 }
2717 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
2718 const SkOpSpan& below = fTs[tIndex - 1];
2719 nextDoorWind = below.fWindValue;
2720 nextOppWind = below.fOppValue;
2721 }
2722 if (nextDoorWind != SK_MaxS32) {
2723 SkOpSpan& newSpan = fTs[tIndex];
2724 newSpan.fWindValue = nextDoorWind;
2725 newSpan.fOppValue = nextOppWind;
2726 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
2727 newSpan.fDone = true;
2728 ++fDoneSpans;
2729 }
2730 }
2731}
2732
caryclark@google.com570863f2013-09-16 15:55:01 +00002733double SkOpSegment::missingNear(double t, const SkOpSegment* other, const SkPoint& startPt,
2734 const SkPoint& endPt) const {
2735 int count = this->count();
2736 for (int index = 0; index < count; ++index) {
2737 const SkOpSpan& span = this->span(index);
2738 if (span.fOther == other && span.fPt == startPt) {
2739 double midT = (t + span.fT) / 2;
2740 if (betweenPoints(midT, startPt, endPt)) {
2741 return span.fT;
2742 }
2743 }
2744 }
2745 return -1;
2746}
2747
caryclark@google.com07393ca2013-04-08 11:47:37 +00002748// return span if when chasing, two or more radiating spans are not done
2749// OPTIMIZATION: ? multiple spans is detected when there is only one valid
2750// candidate and the remaining spans have windValue == 0 (canceled by
2751// coincidence). The coincident edges could either be removed altogether,
2752// or this code could be more complicated in detecting this case. Worth it?
2753bool SkOpSegment::multipleSpans(int end) const {
2754 return end > 0 && end < fTs.count() - 1;
2755}
2756
2757bool SkOpSegment::nextCandidate(int* start, int* end) const {
2758 while (fTs[*end].fDone) {
2759 if (fTs[*end].fT == 1) {
2760 return false;
2761 }
2762 ++(*end);
2763 }
2764 *start = *end;
2765 *end = nextExactSpan(*start, 1);
2766 return true;
2767}
2768
2769SkOpSegment* SkOpSegment::nextChase(int* index, const int step, int* min, SkOpSpan** last) {
2770 int end = nextExactSpan(*index, step);
2771 SkASSERT(end >= 0);
caryclark@google.com570863f2013-09-16 15:55:01 +00002772 if (fTs[end].fSmall) {
2773 *last = NULL;
2774 return NULL;
2775 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002776 if (multipleSpans(end)) {
2777 *last = &fTs[end];
2778 return NULL;
2779 }
2780 const SkOpSpan& endSpan = fTs[end];
2781 SkOpSegment* other = endSpan.fOther;
2782 *index = endSpan.fOtherIndex;
fmalita@google.com22eb7942013-05-01 20:35:51 +00002783 SkASSERT(*index >= 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002784 int otherEnd = other->nextExactSpan(*index, step);
2785 SkASSERT(otherEnd >= 0);
2786 *min = SkMin32(*index, otherEnd);
caryclark@google.com570863f2013-09-16 15:55:01 +00002787 if (other->fTs[*min].fSmall) {
caryclark@google.coma5e55922013-05-07 18:51:31 +00002788 *last = NULL;
2789 return NULL;
2790 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002791 return other;
2792}
2793
2794// This has callers for two different situations: one establishes the end
2795// of the current span, and one establishes the beginning of the next span
2796// (thus the name). When this is looking for the end of the current span,
2797// coincidence is found when the beginning Ts contain -step and the end
2798// contains step. When it is looking for the beginning of the next, the
2799// first Ts found can be ignored and the last Ts should contain -step.
2800// OPTIMIZATION: probably should split into two functions
2801int SkOpSegment::nextSpan(int from, int step) const {
2802 const SkOpSpan& fromSpan = fTs[from];
2803 int count = fTs.count();
2804 int to = from;
2805 while (step > 0 ? ++to < count : --to >= 0) {
2806 const SkOpSpan& span = fTs[to];
2807 if (approximately_zero(span.fT - fromSpan.fT)) {
2808 continue;
2809 }
2810 return to;
2811 }
2812 return -1;
2813}
2814
2815// FIXME
2816// this returns at any difference in T, vs. a preset minimum. It may be
2817// that all callers to nextSpan should use this instead.
caryclark@google.com07393ca2013-04-08 11:47:37 +00002818int SkOpSegment::nextExactSpan(int from, int step) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002819 int to = from;
caryclark@google.com570863f2013-09-16 15:55:01 +00002820 if (step < 0) {
2821 const SkOpSpan& fromSpan = fTs[from];
2822 while (--to >= 0) {
2823 const SkOpSpan& span = fTs[to];
2824 if (precisely_negative(fromSpan.fT - span.fT) || span.fTiny) {
2825 continue;
2826 }
2827 return to;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002828 }
caryclark@google.com570863f2013-09-16 15:55:01 +00002829 } else {
2830 while (fTs[from].fTiny) {
2831 from++;
2832 }
2833 const SkOpSpan& fromSpan = fTs[from];
2834 int count = fTs.count();
2835 while (++to < count) {
2836 const SkOpSpan& span = fTs[to];
2837 if (precisely_negative(span.fT - fromSpan.fT)) {
2838 continue;
2839 }
2840 return to;
2841 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002842 }
2843 return -1;
2844}
2845
2846void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
2847 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) {
2848 int deltaSum = spanSign(index, endIndex);
2849 int oppDeltaSum = oppSign(index, endIndex);
2850 if (operand()) {
2851 *maxWinding = *sumSuWinding;
2852 *sumWinding = *sumSuWinding -= deltaSum;
2853 *oppMaxWinding = *sumMiWinding;
2854 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
2855 } else {
2856 *maxWinding = *sumMiWinding;
2857 *sumWinding = *sumMiWinding -= deltaSum;
2858 *oppMaxWinding = *sumSuWinding;
2859 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
2860 }
caryclark@google.com570863f2013-09-16 15:55:01 +00002861 SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum);
2862 SkASSERT(abs(*oppSumWinding) <= SkPathOpsDebug::gMaxWindSum);
2863}
2864
2865void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding,
2866 int* maxWinding, int* sumWinding) {
2867 int deltaSum = spanSign(index, endIndex);
2868 *maxWinding = *sumMiWinding;
2869 *sumWinding = *sumMiWinding -= deltaSum;
2870 SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002871}
2872
2873// This marks all spans unsortable so that this info is available for early
2874// exclusion in find top and others. This could be optimized to only mark
2875// adjacent spans that unsortable. However, this makes it difficult to later
2876// determine starting points for edge detection in find top and the like.
caryclark@google.comd892bd82013-06-17 14:10:36 +00002877bool SkOpSegment::SortAngles(const SkTArray<SkOpAngle, true>& angles,
2878 SkTArray<SkOpAngle*, true>* angleList,
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002879 SortAngleKind orderKind) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002880 bool sortable = true;
2881 int angleCount = angles.count();
2882 int angleIndex;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002883 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2884 const SkOpAngle& angle = angles[angleIndex];
caryclark@google.comd892bd82013-06-17 14:10:36 +00002885 angleList->push_back(const_cast<SkOpAngle*>(&angle));
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002886#if DEBUG_ANGLE
2887 (*(angleList->end() - 1))->setID(angleIndex);
2888#endif
2889 sortable &= !(angle.unsortable() || (orderKind == kMustBeOrdered_SortAngleKind
2890 && angle.unorderable()));
caryclark@google.com07393ca2013-04-08 11:47:37 +00002891 }
2892 if (sortable) {
caryclark@google.com7dfbb072013-04-22 14:37:05 +00002893 SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002894 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002895 if (angles[angleIndex].unsortable() || (orderKind == kMustBeOrdered_SortAngleKind
2896 && angles[angleIndex].unorderable())) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002897 sortable = false;
2898 break;
2899 }
2900 }
2901 }
2902 if (!sortable) {
2903 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2904 const SkOpAngle& angle = angles[angleIndex];
2905 angle.segment()->markUnsortable(angle.start(), angle.end());
2906 }
2907 }
2908 return sortable;
2909}
2910
caryclark@google.com570863f2013-09-16 15:55:01 +00002911// set segments to unsortable if angle is unsortable, but do not set all angles
2912// note that for a simple 4 way crossing, two of the edges may be orderable even though
2913// two edges are too short to be orderable.
2914// perhaps some classes of unsortable angles should make all shared angles unsortable, but
2915// simple lines that have tiny crossings are always sortable on the large ends
2916// OPTIMIZATION: check earlier when angles are added to input if any are unsortable
2917// may make sense then to mark all segments in angle sweep as unsortableStart/unsortableEnd
2918// solely for the purpose of short-circuiting future angle building around this center
2919bool SkOpSegment::SortAngles2(const SkTArray<SkOpAngle, true>& angles,
2920 SkTArray<SkOpAngle*, true>* angleList) {
2921 int angleCount = angles.count();
2922 int angleIndex;
2923 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2924 const SkOpAngle& angle = angles[angleIndex];
2925 if (angle.unsortable()) {
2926 return false;
2927 }
2928 angleList->push_back(const_cast<SkOpAngle*>(&angle));
2929#if DEBUG_ANGLE
2930 (*(angleList->end() - 1))->setID(angleIndex);
2931#endif
2932 }
2933 SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1);
2934 // at this point angles are sorted but individually may not be orderable
2935 // this means that only adjcent orderable segments may transfer winding
2936 return true;
2937}
2938
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002939// return true if midpoints were computed
2940bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const {
2941 SkASSERT(start != end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002942 edge[0] = fTs[start].fPt;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002943 int points = SkPathOpsVerbToPoints(fVerb);
2944 edge[points] = fTs[end].fPt;
2945 if (fVerb == SkPath::kLine_Verb) {
2946 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002947 }
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002948 double startT = fTs[start].fT;
2949 double endT = fTs[end].fT;
2950 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
2951 // don't compute midpoints if we already have them
2952 if (fVerb == SkPath::kQuad_Verb) {
2953 edge[1] = fPts[1];
2954 return false;
2955 }
2956 SkASSERT(fVerb == SkPath::kCubic_Verb);
2957 if (start < end) {
2958 edge[1] = fPts[1];
2959 edge[2] = fPts[2];
2960 return false;
2961 }
2962 edge[1] = fPts[2];
2963 edge[2] = fPts[1];
2964 return false;
2965 }
2966 const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[points].fY }};
2967 if (fVerb == SkPath::kQuad_Verb) {
2968 edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
2969 } else {
2970 SkASSERT(fVerb == SkPath::kCubic_Verb);
2971 SkDPoint ctrl[2];
2972 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
2973 edge[1] = ctrl[0].asSkPoint();
2974 edge[2] = ctrl[1].asSkPoint();
2975 }
2976 return true;
2977}
2978
2979// return true if midpoints were computed
2980bool SkOpSegment::subDivide(int start, int end, SkDCubic* result) const {
2981 SkASSERT(start != end);
2982 (*result)[0].set(fTs[start].fPt);
2983 int points = SkPathOpsVerbToPoints(fVerb);
2984 (*result)[points].set(fTs[end].fPt);
2985 if (fVerb == SkPath::kLine_Verb) {
2986 return false;
2987 }
2988 double startT = fTs[start].fT;
2989 double endT = fTs[end].fT;
2990 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
2991 // don't compute midpoints if we already have them
2992 if (fVerb == SkPath::kQuad_Verb) {
2993 (*result)[1].set(fPts[1]);
2994 return false;
2995 }
2996 SkASSERT(fVerb == SkPath::kCubic_Verb);
2997 if (start < end) {
2998 (*result)[1].set(fPts[1]);
2999 (*result)[2].set(fPts[2]);
3000 return false;
3001 }
3002 (*result)[1].set(fPts[2]);
3003 (*result)[2].set(fPts[1]);
3004 return false;
3005 }
3006 if (fVerb == SkPath::kQuad_Verb) {
3007 (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], startT, endT);
3008 } else {
3009 SkASSERT(fVerb == SkPath::kCubic_Verb);
3010 SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*result)[1]);
3011 }
3012 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00003013}
3014
3015void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const {
3016 SkPoint edge[4];
3017 subDivide(start, end, edge);
reed@google.com277c3f82013-05-31 15:17:50 +00003018 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003019}
3020
caryclark@google.comcffbcc32013-06-04 17:59:42 +00003021bool SkOpSegment::isTiny(const SkOpAngle* angle) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +00003022 int start = angle->start();
3023 int end = angle->end();
3024 const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
3025 return mSpan.fTiny;
3026}
3027
caryclark@google.comcffbcc32013-06-04 17:59:42 +00003028bool SkOpSegment::isTiny(int index) const {
3029 return fTs[index].fTiny;
3030}
3031
caryclark@google.com570863f2013-09-16 15:55:01 +00003032void SkOpSegment::TrackOutsidePair(SkTArray<SkPoint, true>* outsidePts, const SkPoint& endPt,
3033 const SkPoint& startPt) {
3034 int outCount = outsidePts->count();
3035 if (outCount == 0 || endPt != (*outsidePts)[outCount - 2]) {
3036 outsidePts->push_back(endPt);
3037 outsidePts->push_back(startPt);
3038 }
3039}
3040
3041void SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoint& startPt) {
3042 int outCount = outsidePts->count();
3043 if (outCount == 0 || startPt != (*outsidePts)[outCount - 1]) {
3044 outsidePts->push_back(startPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003045 }
3046}
3047
3048void SkOpSegment::undoneSpan(int* start, int* end) {
3049 size_t tCount = fTs.count();
3050 size_t index;
3051 for (index = 0; index < tCount; ++index) {
3052 if (!fTs[index].fDone) {
3053 break;
3054 }
3055 }
3056 SkASSERT(index < tCount - 1);
3057 *start = index;
3058 double startT = fTs[index].fT;
3059 while (approximately_negative(fTs[++index].fT - startT))
3060 SkASSERT(index < tCount);
3061 SkASSERT(index < tCount);
3062 *end = index;
3063}
3064
3065int SkOpSegment::updateOppWinding(int index, int endIndex) const {
3066 int lesser = SkMin32(index, endIndex);
3067 int oppWinding = oppSum(lesser);
3068 int oppSpanWinding = oppSign(index, endIndex);
3069 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
3070 && oppWinding != SK_MaxS32) {
3071 oppWinding -= oppSpanWinding;
3072 }
3073 return oppWinding;
3074}
3075
3076int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
3077 int startIndex = angle->start();
3078 int endIndex = angle->end();
3079 return updateOppWinding(endIndex, startIndex);
3080}
3081
3082int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
3083 int startIndex = angle->start();
3084 int endIndex = angle->end();
3085 return updateOppWinding(startIndex, endIndex);
3086}
3087
3088int SkOpSegment::updateWinding(int index, int endIndex) const {
3089 int lesser = SkMin32(index, endIndex);
3090 int winding = windSum(lesser);
3091 int spanWinding = spanSign(index, endIndex);
caryclark@google.com570863f2013-09-16 15:55:01 +00003092 if (winding && UseInnerWinding(winding - spanWinding, winding)
3093 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00003094 winding -= spanWinding;
3095 }
3096 return winding;
3097}
3098
3099int SkOpSegment::updateWinding(const SkOpAngle* angle) const {
3100 int startIndex = angle->start();
3101 int endIndex = angle->end();
3102 return updateWinding(endIndex, startIndex);
3103}
3104
caryclark@google.com570863f2013-09-16 15:55:01 +00003105int SkOpSegment::updateWindingReverse(int index, int endIndex) const {
3106 int lesser = SkMin32(index, endIndex);
3107 int winding = windSum(lesser);
3108 int spanWinding = spanSign(endIndex, index);
3109 if (winding && UseInnerWindingReverse(winding - spanWinding, winding)
3110 && winding != SK_MaxS32) {
3111 winding -= spanWinding;
3112 }
3113 return winding;
3114}
3115
caryclark@google.com07393ca2013-04-08 11:47:37 +00003116int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const {
3117 int startIndex = angle->start();
3118 int endIndex = angle->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00003119 return updateWindingReverse(endIndex, startIndex);
3120}
3121
3122// OPTIMIZATION: does the following also work, and is it any faster?
3123// return outerWinding * innerWinding > 0
3124// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
3125bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
3126 SkASSERT(outerWinding != SK_MaxS32);
3127 SkASSERT(innerWinding != SK_MaxS32);
3128 int absOut = abs(outerWinding);
3129 int absIn = abs(innerWinding);
3130 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
3131 return result;
3132}
3133
3134bool SkOpSegment::UseInnerWindingReverse(int outerWinding, int innerWinding) {
3135 SkASSERT(outerWinding != SK_MaxS32);
3136 SkASSERT(innerWinding != SK_MaxS32);
3137 int absOut = abs(outerWinding);
3138 int absIn = abs(innerWinding);
3139 bool result = absOut == absIn ? true : absOut < absIn;
3140 return result;
caryclark@google.com07393ca2013-04-08 11:47:37 +00003141}
3142
3143int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const {
3144 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3145 return SK_MinS32;
3146 }
3147 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3148 SkASSERT(winding != SK_MinS32);
3149 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
3150#if DEBUG_WINDING_AT_T
3151 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
3152#endif
3153 // see if a + change in T results in a +/- change in X (compute x'(T))
reed@google.com277c3f82013-05-31 15:17:50 +00003154 *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
caryclark@google.com07393ca2013-04-08 11:47:37 +00003155 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
3156 *dx = fPts[2].fX - fPts[1].fX - *dx;
3157 }
3158 if (*dx == 0) {
3159#if DEBUG_WINDING_AT_T
3160 SkDebugf(" dx=0 winding=SK_MinS32\n");
3161#endif
3162 return SK_MinS32;
3163 }
skia.committer@gmail.coma4aced42013-07-09 07:00:56 +00003164 if (windVal < 0) { // reverse sign if opp contour traveled in reverse
caryclark@google.com07e97fc2013-07-08 17:17:02 +00003165 *dx = -*dx;
3166 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00003167 if (winding * *dx > 0) { // if same signs, result is negative
3168 winding += *dx > 0 ? -windVal : windVal;
3169 }
3170#if DEBUG_WINDING_AT_T
3171 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding);
3172#endif
3173 return winding;
3174}
3175
3176int SkOpSegment::windSum(const SkOpAngle* angle) const {
3177 int start = angle->start();
3178 int end = angle->end();
3179 int index = SkMin32(start, end);
3180 return windSum(index);
3181}
3182
3183int SkOpSegment::windValue(const SkOpAngle* angle) const {
3184 int start = angle->start();
3185 int end = angle->end();
3186 int index = SkMin32(start, end);
3187 return windValue(index);
3188}
3189
3190int SkOpSegment::windValueAt(double t) const {
3191 int count = fTs.count();
3192 for (int index = 0; index < count; ++index) {
3193 if (fTs[index].fT == t) {
3194 return fTs[index].fWindValue;
3195 }
3196 }
3197 SkASSERT(0);
3198 return 0;
3199}
3200
3201void SkOpSegment::zeroSpan(SkOpSpan* span) {
caryclark@google.coma5e55922013-05-07 18:51:31 +00003202 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003203 span->fWindValue = 0;
3204 span->fOppValue = 0;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00003205 if (span->fTiny || span->fSmall) {
3206 return;
3207 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00003208 SkASSERT(!span->fDone);
3209 span->fDone = true;
3210 ++fDoneSpans;
3211}
skia.committer@gmail.com32840172013-04-09 07:01:27 +00003212
caryclark@google.com07393ca2013-04-08 11:47:37 +00003213#if DEBUG_SWAP_TOP
3214bool SkOpSegment::controlsContainedByEnds(int tStart, int tEnd) const {
3215 if (fVerb != SkPath::kCubic_Verb) {
3216 return false;
3217 }
3218 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
3219 return dst.controlsContainedByEnds();
3220}
3221#endif
3222
3223#if DEBUG_CONCIDENT
3224// SkASSERT if pair has not already been added
3225void SkOpSegment::debugAddTPair(double t, const SkOpSegment& other, double otherT) const {
3226 for (int i = 0; i < fTs.count(); ++i) {
3227 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
3228 return;
3229 }
3230 }
3231 SkASSERT(0);
3232}
3233#endif
3234
3235#if DEBUG_CONCIDENT
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00003236void SkOpSegment::debugShowTs(const char* prefix) const {
3237 SkDebugf("%s %s id=%d", __FUNCTION__, prefix, fID);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003238 int lastWind = -1;
3239 int lastOpp = -1;
3240 double lastT = -1;
3241 int i;
3242 for (i = 0; i < fTs.count(); ++i) {
3243 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
3244 || lastOpp != fTs[i].fOppValue;
3245 if (change && lastWind >= 0) {
3246 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3247 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3248 }
3249 if (change) {
3250 SkDebugf(" [o=%d", fTs[i].fOther->fID);
3251 lastWind = fTs[i].fWindValue;
3252 lastOpp = fTs[i].fOppValue;
3253 lastT = fTs[i].fT;
3254 } else {
3255 SkDebugf(",%d", fTs[i].fOther->fID);
3256 }
3257 }
3258 if (i <= 0) {
3259 return;
3260 }
3261 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3262 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3263 if (fOperand) {
3264 SkDebugf(" operand");
3265 }
3266 if (done()) {
3267 SkDebugf(" done");
3268 }
3269 SkDebugf("\n");
3270}
3271#endif
3272
caryclark@google.coma5e55922013-05-07 18:51:31 +00003273#if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
caryclark@google.com07393ca2013-04-08 11:47:37 +00003274void SkOpSegment::debugShowActiveSpans() const {
caryclark@google.com4fdbb222013-07-23 15:27:41 +00003275 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00003276 if (done()) {
3277 return;
3278 }
3279#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3280 int lastId = -1;
3281 double lastT = -1;
3282#endif
3283 for (int i = 0; i < fTs.count(); ++i) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00003284 if (fTs[i].fDone) {
3285 continue;
3286 }
caryclark@google.coma5e55922013-05-07 18:51:31 +00003287 SkASSERT(i < fTs.count() - 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003288#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3289 if (lastId == fID && lastT == fTs[i].fT) {
3290 continue;
3291 }
3292 lastId = fID;
3293 lastT = fTs[i].fT;
3294#endif
3295 SkDebugf("%s id=%d", __FUNCTION__, fID);
3296 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
reed@google.com277c3f82013-05-31 15:17:50 +00003297 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00003298 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3299 }
3300 const SkOpSpan* span = &fTs[i];
3301 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", span->fT, xAtT(span), yAtT(span));
3302 int iEnd = i + 1;
3303 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) {
3304 ++iEnd;
3305 }
3306 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT);
3307 const SkOpSegment* other = fTs[i].fOther;
3308 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
3309 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
3310 if (fTs[i].fWindSum == SK_MinS32) {
3311 SkDebugf("?");
3312 } else {
3313 SkDebugf("%d", fTs[i].fWindSum);
3314 }
3315 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
3316 }
3317}
3318#endif
3319
3320
3321#if DEBUG_MARK_DONE || DEBUG_UNSORTABLE
3322void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding) {
3323 const SkPoint& pt = xyAtT(&span);
3324 SkDebugf("%s id=%d", fun, fID);
3325 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
reed@google.com277c3f82013-05-31 15:17:50 +00003326 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00003327 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3328 }
3329 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3330 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3331 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d windSum=",
3332 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
3333 (&span)[1].fT, winding);
3334 if (span.fWindSum == SK_MinS32) {
3335 SkDebugf("?");
3336 } else {
3337 SkDebugf("%d", span.fWindSum);
3338 }
3339 SkDebugf(" windValue=%d\n", span.fWindValue);
3340}
3341
3342void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding,
3343 int oppWinding) {
3344 const SkPoint& pt = xyAtT(&span);
3345 SkDebugf("%s id=%d", fun, fID);
3346 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
reed@google.com277c3f82013-05-31 15:17:50 +00003347 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00003348 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3349 }
3350 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3351 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3352 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d newOppSum=%d oppSum=",
3353 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
3354 (&span)[1].fT, winding, oppWinding);
3355 if (span.fOppSum == SK_MinS32) {
3356 SkDebugf("?");
3357 } else {
3358 SkDebugf("%d", span.fOppSum);
3359 }
3360 SkDebugf(" windSum=");
3361 if (span.fWindSum == SK_MinS32) {
3362 SkDebugf("?");
3363 } else {
3364 SkDebugf("%d", span.fWindSum);
3365 }
3366 SkDebugf(" windValue=%d\n", span.fWindValue);
3367}
3368#endif
3369
3370#if DEBUG_SORT || DEBUG_SWAP_TOP
caryclark@google.comd892bd82013-06-17 14:10:36 +00003371void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles,
3372 int first, const int contourWinding,
caryclark@google.com07e97fc2013-07-08 17:17:02 +00003373 const int oppContourWinding, bool sortable) const {
caryclark@google.com570863f2013-09-16 15:55:01 +00003374 if (--SkPathOpsDebug::gSortCount < 0) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00003375 return;
3376 }
caryclark@google.com570863f2013-09-16 15:55:01 +00003377 if (!sortable) {
3378 if (angles.count() == 0) {
3379 return;
3380 }
3381 if (first < 0) {
3382 first = 0;
3383 }
3384 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00003385 SkASSERT(angles[first]->segment() == this);
caryclark@google.com07e97fc2013-07-08 17:17:02 +00003386 SkASSERT(!sortable || angles.count() > 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003387 int lastSum = contourWinding;
3388 int oppLastSum = oppContourWinding;
3389 const SkOpAngle* firstAngle = angles[first];
3390 int windSum = lastSum - spanSign(firstAngle);
3391 int oppoSign = oppSign(firstAngle);
3392 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.com570863f2013-09-16 15:55:01 +00003393 #define WIND_AS_STRING(x) char x##Str[12]; \
3394 if (!SkPathOpsDebug::ValidWind(x)) strcpy(x##Str, "?"); \
3395 else SK_SNPRINTF(x##Str, sizeof(x##Str), "%d", x)
caryclark@google.com07393ca2013-04-08 11:47:37 +00003396 WIND_AS_STRING(contourWinding);
3397 WIND_AS_STRING(oppContourWinding);
3398 SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FUNCTION__,
3399 contourWindingStr, oppContourWindingStr, spanSign(angles[first]));
3400 int index = first;
3401 bool firstTime = true;
3402 do {
3403 const SkOpAngle& angle = *angles[index];
3404 const SkOpSegment& segment = *angle.segment();
3405 int start = angle.start();
3406 int end = angle.end();
3407 const SkOpSpan& sSpan = segment.fTs[start];
3408 const SkOpSpan& eSpan = segment.fTs[end];
3409 const SkOpSpan& mSpan = segment.fTs[SkMin32(start, end)];
3410 bool opp = segment.fOperand ^ fOperand;
3411 if (!firstTime) {
3412 oppoSign = segment.oppSign(&angle);
3413 if (opp) {
3414 oppLastSum = oppWindSum;
3415 oppWindSum -= segment.spanSign(&angle);
3416 if (oppoSign) {
3417 lastSum = windSum;
3418 windSum -= oppoSign;
3419 }
3420 } else {
3421 lastSum = windSum;
3422 windSum -= segment.spanSign(&angle);
3423 if (oppoSign) {
3424 oppLastSum = oppWindSum;
3425 oppWindSum -= oppoSign;
3426 }
3427 }
3428 }
3429 SkDebugf("%s [%d] %s", __FUNCTION__, index,
3430 angle.unsortable() ? "*** UNSORTABLE *** " : "");
caryclark@google.comcffbcc32013-06-04 17:59:42 +00003431 #if DEBUG_SORT_COMPACT
3432 SkDebugf("id=%d %s start=%d (%1.9g,%1.9g) end=%d (%1.9g,%1.9g)",
reed@google.com277c3f82013-05-31 15:17:50 +00003433 segment.fID, kLVerbStr[SkPathOpsVerbToPoints(segment.fVerb)],
caryclark@google.com07393ca2013-04-08 11:47:37 +00003434 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
3435 segment.xAtT(&eSpan), segment.yAtT(&eSpan));
3436 #else
3437 switch (segment.fVerb) {
3438 case SkPath::kLine_Verb:
3439 SkDebugf(LINE_DEBUG_STR, LINE_DEBUG_DATA(segment.fPts));
3440 break;
3441 case SkPath::kQuad_Verb:
3442 SkDebugf(QUAD_DEBUG_STR, QUAD_DEBUG_DATA(segment.fPts));
3443 break;
3444 case SkPath::kCubic_Verb:
3445 SkDebugf(CUBIC_DEBUG_STR, CUBIC_DEBUG_DATA(segment.fPts));
3446 break;
3447 default:
3448 SkASSERT(0);
3449 }
3450 SkDebugf(" tStart=%1.9g tEnd=%1.9g", sSpan.fT, eSpan.fT);
3451 #endif
3452 SkDebugf(" sign=%d windValue=%d windSum=", angle.sign(), mSpan.fWindValue);
caryclark@google.com570863f2013-09-16 15:55:01 +00003453 SkPathOpsDebug::WindingPrintf(mSpan.fWindSum);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003454 int last, wind;
3455 if (opp) {
3456 last = oppLastSum;
3457 wind = oppWindSum;
3458 } else {
3459 last = lastSum;
3460 wind = windSum;
3461 }
caryclark@google.com570863f2013-09-16 15:55:01 +00003462 bool useInner = SkPathOpsDebug::ValidWind(last) && SkPathOpsDebug::ValidWind(wind)
3463 && UseInnerWinding(last, wind);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003464 WIND_AS_STRING(last);
3465 WIND_AS_STRING(wind);
3466 WIND_AS_STRING(lastSum);
3467 WIND_AS_STRING(oppLastSum);
3468 WIND_AS_STRING(windSum);
3469 WIND_AS_STRING(oppWindSum);
3470 #undef WIND_AS_STRING
3471 if (!oppoSign) {
3472 SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr : lastStr);
3473 } else {
3474 SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : oppLastSumStr,
3475 opp ? windSumStr : oppWindSumStr);
3476 }
caryclark@google.com570863f2013-09-16 15:55:01 +00003477 SkDebugf(" done=%d unord=%d small=%d tiny=%d opp=%d\n",
3478 mSpan.fDone, angle.unorderable(), mSpan.fSmall, mSpan.fTiny, opp);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003479 ++index;
3480 if (index == angles.count()) {
3481 index = 0;
3482 }
3483 if (firstTime) {
3484 firstTime = false;
3485 }
3486 } while (index != first);
3487}
3488
caryclark@google.comd892bd82013-06-17 14:10:36 +00003489void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles,
caryclark@google.com07e97fc2013-07-08 17:17:02 +00003490 int first, bool sortable) {
caryclark@google.com570863f2013-09-16 15:55:01 +00003491 if (!sortable) {
3492 if (angles.count() == 0) {
3493 return;
3494 }
3495 if (first < 0) {
3496 first = 0;
3497 }
3498 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00003499 const SkOpAngle* firstAngle = angles[first];
3500 const SkOpSegment* segment = firstAngle->segment();
3501 int winding = segment->updateWinding(firstAngle);
3502 int oppWinding = segment->updateOppWinding(firstAngle);
caryclark@google.com07e97fc2013-07-08 17:17:02 +00003503 debugShowSort(fun, angles, first, winding, oppWinding, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003504}
3505
3506#endif
3507
3508#if DEBUG_SHOW_WINDING
3509int SkOpSegment::debugShowWindingValues(int slotCount, int ofInterest) const {
3510 if (!(1 << fID & ofInterest)) {
3511 return 0;
3512 }
3513 int sum = 0;
caryclark@google.comd892bd82013-06-17 14:10:36 +00003514 SkTArray<char, true> slots(slotCount * 2);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003515 memset(slots.begin(), ' ', slotCount * 2);
3516 for (int i = 0; i < fTs.count(); ++i) {
3517 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
3518 // continue;
3519 // }
3520 sum += fTs[i].fWindValue;
3521 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
3522 sum += fTs[i].fOppValue;
3523 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
3524 }
3525 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
3526 slots.begin() + slotCount);
3527 return sum;
3528}
3529#endif
caryclark@google.com4fdbb222013-07-23 15:27:41 +00003530
3531void SkOpSegment::debugValidate() const {
3532#if DEBUG_VALIDATE
3533 int count = fTs.count();
3534 SkASSERT(count >= 2);
3535 SkASSERT(fTs[0].fT == 0);
3536 SkASSERT(fTs[count - 1].fT == 1);
3537 int done = 0;
3538 double t = -1;
3539 for (int i = 0; i < count; ++i) {
3540 const SkOpSpan& span = fTs[i];
3541 SkASSERT(t <= span.fT);
3542 t = span.fT;
3543 int otherIndex = span.fOtherIndex;
3544 const SkOpSegment* other = span.fOther;
3545 const SkOpSpan& otherSpan = other->fTs[otherIndex];
3546 SkASSERT(otherSpan.fPt == span.fPt);
3547 SkASSERT(otherSpan.fOtherT == t);
3548 SkASSERT(&fTs[i] == &otherSpan.fOther->fTs[otherSpan.fOtherIndex]);
3549 done += span.fDone;
3550 }
3551 SkASSERT(done == fDoneSpans);
3552#endif
3553}
caryclark@google.com570863f2013-09-16 15:55:01 +00003554
3555#ifdef SK_DEBUG
3556void SkOpSegment::dumpPts() const {
3557 int last = SkPathOpsVerbToPoints(fVerb);
3558 SkDebugf("{{");
3559 int index = 0;
3560 do {
3561 SkDPoint::DumpSkPoint(fPts[index]);
3562 SkDebugf(", ");
3563 } while (++index < last);
3564 SkDPoint::DumpSkPoint(fPts[index]);
3565 SkDebugf("}}\n");
3566}
3567
3568void SkOpSegment::dumpDPts() const {
3569 int count = SkPathOpsVerbToPoints(fVerb);
3570 SkDebugf("{{");
3571 int index = 0;
3572 do {
3573 SkDPoint dPt = {fPts[index].fX, fPts[index].fY};
3574 dPt.dump();
3575 if (index != count) {
3576 SkDebugf(", ");
3577 }
3578 } while (++index <= count);
3579 SkDebugf("}}\n");
3580}
3581
3582void SkOpSegment::dumpSpans() const {
3583 int count = this->count();
3584 for (int index = 0; index < count; ++index) {
3585 const SkOpSpan& span = this->span(index);
3586 SkDebugf("[%d] ", index);
3587 span.dump();
3588 }
3589}
3590#endif