blob: c0ef1f8e1170ea8989beccadf6507c267ce7d579 [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();
420 for (size_t index = 0; index < tCount; ++index) {
421 // OPTIMIZATION: if there are three or more identical Ts, then
422 // the fourth and following could be further insertion-sorted so
423 // that all the edges are clockwise or counterclockwise.
424 // This could later limit segment tests to the two adjacent
425 // neighbors, although it doesn't help with determining which
426 // circular direction to go in.
427 if (newT < fTs[index].fT) {
428 insertedAt = index;
429 break;
430 }
431 }
432 SkOpSpan* span;
433 if (insertedAt >= 0) {
434 span = fTs.insert(insertedAt);
435 } else {
436 insertedAt = tCount;
437 span = fTs.append();
438 }
439 span->fT = newT;
440 span->fOther = other;
441 span->fPt = pt;
caryclark@google.com570863f2013-09-16 15:55:01 +0000442 span->fNear = isNear;
caryclark@google.coma5e55922013-05-07 18:51:31 +0000443#if 0
444 // cubics, for instance, may not be exact enough to satisfy this check (e.g., cubicOp69d)
445 SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX)
446 && approximately_equal(xyAtT(newT).fY, pt.fY));
447#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000448 span->fWindSum = SK_MinS32;
449 span->fOppSum = SK_MinS32;
450 span->fWindValue = 1;
451 span->fOppValue = 0;
caryclark@google.com570863f2013-09-16 15:55:01 +0000452 span->fSmall = false;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000453 span->fTiny = false;
454 span->fLoop = false;
455 if ((span->fDone = newT == 1)) {
456 ++fDoneSpans;
457 }
458 span->fUnsortableStart = false;
459 span->fUnsortableEnd = false;
460 int less = -1;
caryclark@google.com570863f2013-09-16 15:55:01 +0000461 while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt, span->fPt)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000462 if (span[less].fDone) {
463 break;
464 }
465 double tInterval = newT - span[less].fT;
466 if (precisely_negative(tInterval)) {
467 break;
468 }
469 if (fVerb == SkPath::kCubic_Verb) {
470 double tMid = newT - tInterval / 2;
471 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid);
472 if (!midPt.approximatelyEqual(xyAtT(span))) {
473 break;
474 }
475 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000476 span[less].fSmall = true;
477 bool tiny = span[less].fPt == span->fPt;
478 span[less].fTiny = tiny;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000479 span[less].fDone = true;
caryclark@google.com570863f2013-09-16 15:55:01 +0000480 if (approximately_negative(newT - span[less].fT) && tiny) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000481 if (approximately_greater_than_one(newT)) {
482 SkASSERT(&span[less] - fTs.begin() < fTs.count());
483 span[less].fUnsortableStart = true;
484 if (&span[less - 1] - fTs.begin() >= 0) {
485 span[less - 1].fUnsortableEnd = true;
486 }
487 }
488 if (approximately_less_than_zero(span[less].fT)) {
489 SkASSERT(&span[less + 1] - fTs.begin() < fTs.count());
490 SkASSERT(&span[less] - fTs.begin() >= 0);
491 span[less + 1].fUnsortableStart = true;
492 span[less].fUnsortableEnd = true;
493 }
494 }
495 ++fDoneSpans;
496 --less;
497 }
498 int more = 1;
caryclark@google.com570863f2013-09-16 15:55:01 +0000499 while (fTs.end() - &span[more - 1] > 1 && AlmostEqualUlps(span[more].fPt, span->fPt)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000500 if (span[more - 1].fDone) {
501 break;
502 }
503 double tEndInterval = span[more].fT - newT;
504 if (precisely_negative(tEndInterval)) {
505 break;
506 }
507 if (fVerb == SkPath::kCubic_Verb) {
508 double tMid = newT - tEndInterval / 2;
509 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid);
510 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
511 break;
512 }
513 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000514 span[more - 1].fSmall = true;
515 bool tiny = span[more].fPt == span->fPt;
516 span[more - 1].fTiny = tiny;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000517 span[more - 1].fDone = true;
caryclark@google.com570863f2013-09-16 15:55:01 +0000518 if (approximately_negative(span[more].fT - newT) && tiny) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000519 if (approximately_greater_than_one(span[more].fT)) {
520 span[more + 1].fUnsortableStart = true;
521 span[more].fUnsortableEnd = true;
522 }
523 if (approximately_less_than_zero(newT)) {
524 span[more].fUnsortableStart = true;
525 span[more - 1].fUnsortableEnd = true;
526 }
527 }
528 ++fDoneSpans;
529 ++more;
530 }
531 return insertedAt;
532}
533
534// set spans from start to end to decrement by one
535// note this walks other backwards
caryclark@google.coma5e55922013-05-07 18:51:31 +0000536// FIXME: there's probably an edge case that can be constructed where
caryclark@google.com07393ca2013-04-08 11:47:37 +0000537// two span in one segment are separated by float epsilon on one span but
538// not the other, if one segment is very small. For this
539// case the counts asserted below may or may not be enough to separate the
540// spans. Even if the counts work out, what if the spans aren't correctly
541// sorted? It feels better in such a case to match the span's other span
542// pointer since both coincident segments must contain the same spans.
caryclark@google.coma5e55922013-05-07 18:51:31 +0000543// FIXME? It seems that decrementing by one will fail for complex paths that
544// have three or more coincident edges. Shouldn't this subtract the difference
545// between the winding values?
caryclark@google.com570863f2013-09-16 15:55:01 +0000546/* |--> |-->
547this 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>4
548other 2<<<<1<<<<0 2<<<<1<<<<0 2<<<<1<<<<0
549 ^ ^ <--| <--|
550 startPt endPt test/oTest first pos test/oTest final pos
551*/
552void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000553 bool binary = fOperand != other->fOperand;
554 int index = 0;
caryclark@google.com570863f2013-09-16 15:55:01 +0000555 while (startPt != fTs[index].fPt) {
556 SkASSERT(index < fTs.count());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000557 ++index;
558 }
559 int oIndex = other->fTs.count();
caryclark@google.com570863f2013-09-16 15:55:01 +0000560 while (startPt != other->fTs[--oIndex].fPt) { // look for startPt match
561 SkASSERT(oIndex > 0);
562 }
563 while (startPt == other->fTs[--oIndex].fPt) { // look for first point beyond match
564 SkASSERT(oIndex > 0);
565 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000566 SkOpSpan* test = &fTs[index];
567 SkOpSpan* oTest = &other->fTs[oIndex];
caryclark@google.com570863f2013-09-16 15:55:01 +0000568 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
569 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000570 do {
caryclark@google.com570863f2013-09-16 15:55:01 +0000571 SkASSERT(test->fT < 1);
572 SkASSERT(oTest->fT < 1);
caryclark@google.coma5e55922013-05-07 18:51:31 +0000573 bool decrement = test->fWindValue && oTest->fWindValue;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000574 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.coma5e55922013-05-07 18:51:31 +0000575 bool bigger = test->fWindValue >= oTest->fWindValue;
caryclark@google.com570863f2013-09-16 15:55:01 +0000576 const SkPoint& testPt = test->fPt;
577 const SkPoint& oTestPt = oTest->fPt;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000578 do {
579 if (decrement) {
caryclark@google.coma5e55922013-05-07 18:51:31 +0000580 if (binary && bigger) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000581 test->fOppValue--;
caryclark@google.coma5e55922013-05-07 18:51:31 +0000582 } else {
caryclark@google.com570863f2013-09-16 15:55:01 +0000583 decrementSpan(test);
caryclark@google.coma5e55922013-05-07 18:51:31 +0000584 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000585 } else if (track) {
586 TrackOutsidePair(&outsidePts, testPt, oTestPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000587 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000588 SkASSERT(index < fTs.count() - 1);
589 test = &fTs[++index];
590 } while (testPt == test->fPt);
591 SkDEBUGCODE(int originalWindValue = oTest->fWindValue);
592 do {
593 SkASSERT(oTest->fT < 1);
594 SkASSERT(originalWindValue == oTest->fWindValue);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000595 if (decrement) {
caryclark@google.coma5e55922013-05-07 18:51:31 +0000596 if (binary && !bigger) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000597 oTest->fOppValue--;
caryclark@google.coma5e55922013-05-07 18:51:31 +0000598 } else {
caryclark@google.com570863f2013-09-16 15:55:01 +0000599 other->decrementSpan(oTest);
caryclark@google.coma5e55922013-05-07 18:51:31 +0000600 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000601 } else if (track) {
602 TrackOutsidePair(&oOutsidePts, oTestPt, testPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000603 }
604 if (!oIndex) {
605 break;
606 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000607 oTest = &other->fTs[--oIndex];
608 } while (oTestPt == oTest->fPt);
609 SkASSERT(endPt != test->fPt || oTestPt == endPt);
610 } while (endPt != test->fPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000611 // FIXME: determine if canceled edges need outside ts added
caryclark@google.com570863f2013-09-16 15:55:01 +0000612 int outCount = outsidePts.count();
613 if (!done() && outCount) {
614 addCancelOutsides(outsidePts[0], outsidePts[1], other);
615 if (outCount > 2) {
616 addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1], other);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000617 }
618 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000619 if (!other->done() && oOutsidePts.count()) {
620 other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000621 }
622}
623
624int SkOpSegment::addSelfT(SkOpSegment* other, const SkPoint& pt, double newT) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000625 // if the tail nearly intersects itself but not quite, the caller records this separately
626 int result = addT(other, pt, newT, SkOpSpan::kPointIsExact);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000627 SkOpSpan* span = &fTs[result];
628 span->fLoop = true;
629 return result;
630}
631
caryclark@google.com570863f2013-09-16 15:55:01 +0000632void SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* indexPtr,
633 SkTArray<SkPoint, true>* outsideTs) {
634 int index = *indexPtr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000635 int oWindValue = oTest.fWindValue;
636 int oOppValue = oTest.fOppValue;
caryclark@google.com570863f2013-09-16 15:55:01 +0000637 if (binary) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000638 SkTSwap<int>(oWindValue, oOppValue);
639 }
640 SkOpSpan* const test = &fTs[index];
641 SkOpSpan* end = test;
caryclark@google.com570863f2013-09-16 15:55:01 +0000642 const SkPoint& oStartPt = oTest.fPt;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000643 do {
644 if (bumpSpan(end, oWindValue, oOppValue)) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000645 TrackOutside(outsideTs, oStartPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000646 }
647 end = &fTs[++index];
caryclark@google.com570863f2013-09-16 15:55:01 +0000648 } while (end->fPt == test->fPt);
649 *indexPtr = index;
650}
651
652bool SkOpSegment::bumpCoincident(SkOpSpan* test, bool bigger, bool binary) {
653 if (bigger) {
654 if (binary) {
655 if (fOppXor) {
656 test->fOppValue ^= 1;
657 } else {
658 test->fOppValue++;
659 }
660 } else {
661 if (fXor) {
662 test->fWindValue ^= 1;
663 } else {
664 test->fWindValue++;
665 }
666 }
667 if (!test->fWindValue && !test->fOppValue) {
668 test->fDone = true;
669 ++fDoneSpans;
670 return true;
671 }
672 return false;
673 }
674 return decrementSpan(test);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000675}
676
677// because of the order in which coincidences are resolved, this and other
678// may not have the same intermediate points. Compute the corresponding
679// intermediate T values (using this as the master, other as the follower)
680// and walk other conditionally -- hoping that it catches up in the end
caryclark@google.com570863f2013-09-16 15:55:01 +0000681void SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr,
682 SkTArray<SkPoint, true>* oOutsidePts) {
683 int oIndex = *oIndexPtr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000684 SkOpSpan* const oTest = &fTs[oIndex];
685 SkOpSpan* oEnd = oTest;
caryclark@google.com570863f2013-09-16 15:55:01 +0000686 const SkPoint& startPt = test.fPt;
687 const SkPoint& oStartPt = oTest->fPt;
688 if (oStartPt == oEnd->fPt) {
689 TrackOutside(oOutsidePts, startPt);
690 }
691 while (oStartPt == oEnd->fPt) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000692 zeroSpan(oEnd);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000693 oEnd = &fTs[++oIndex];
694 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000695 *oIndexPtr = oIndex;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000696}
697
698// FIXME: need to test this case:
699// contourA has two segments that are coincident
700// contourB has two segments that are coincident in the same place
701// each ends up with +2/0 pairs for winding count
702// since logic below doesn't transfer count (only increments/decrements) can this be
703// resolved to +4/0 ?
704
705// set spans from start to end to increment the greater by one and decrement
706// the lesser
caryclark@google.com570863f2013-09-16 15:55:01 +0000707void SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt,
708 SkOpSegment* other) {
709 bool binary = fOperand != other->fOperand;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000710 int index = 0;
caryclark@google.com570863f2013-09-16 15:55:01 +0000711 while (startPt != fTs[index].fPt) {
712 SkASSERT(index < fTs.count());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000713 ++index;
714 }
715 int oIndex = 0;
caryclark@google.com570863f2013-09-16 15:55:01 +0000716 while (startPt != other->fTs[oIndex].fPt) {
717 SkASSERT(oIndex < other->fTs.count());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000718 ++oIndex;
719 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000720 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
721 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000722 SkOpSpan* test = &fTs[index];
caryclark@google.com570863f2013-09-16 15:55:01 +0000723 const SkPoint* testPt = &test->fPt;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000724 SkOpSpan* oTest = &other->fTs[oIndex];
caryclark@google.com570863f2013-09-16 15:55:01 +0000725 const SkPoint* oTestPt = &oTest->fPt;
726 SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000727 do {
caryclark@google.com570863f2013-09-16 15:55:01 +0000728 SkASSERT(test->fT < 1);
729 SkASSERT(oTest->fT < 1);
730#if 0
caryclark@google.com07393ca2013-04-08 11:47:37 +0000731 if (test->fDone || oTest->fDone) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000732#else // consolidate the winding count even if done
733 if ((test->fWindValue == 0 && test->fOppValue == 0)
734 || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) {
735#endif
736 SkDEBUGCODE(int firstWind = test->fWindValue);
737 SkDEBUGCODE(int firstOpp = test->fOppValue);
738 do {
739 SkASSERT(firstWind == fTs[index].fWindValue);
740 SkASSERT(firstOpp == fTs[index].fOppValue);
741 ++index;
742 SkASSERT(index < fTs.count());
743 } while (*testPt == fTs[index].fPt);
744 SkDEBUGCODE(firstWind = oTest->fWindValue);
745 SkDEBUGCODE(firstOpp = oTest->fOppValue);
746 do {
747 SkASSERT(firstWind == other->fTs[oIndex].fWindValue);
748 SkASSERT(firstOpp == other->fTs[oIndex].fOppValue);
749 ++oIndex;
750 SkASSERT(oIndex < other->fTs.count());
751 } while (*oTestPt == other->fTs[oIndex].fPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000752 } else {
caryclark@google.com570863f2013-09-16 15:55:01 +0000753 if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
754 bumpCoincidentThis(*oTest, binary, &index, &outsidePts);
755 other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts);
756 } else {
757 other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts);
758 bumpCoincidentOther(*oTest, &index, &outsidePts);
759 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000760 }
761 test = &fTs[index];
caryclark@google.com570863f2013-09-16 15:55:01 +0000762 testPt = &test->fPt;
763 if (endPt == *testPt) {
764 break;
765 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000766 oTest = &other->fTs[oIndex];
caryclark@google.com570863f2013-09-16 15:55:01 +0000767 oTestPt = &oTest->fPt;
768 SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
769 } while (endPt != *oTestPt);
770 int outCount = outsidePts.count();
771 if (!done() && outCount) {
772 addCoinOutsides(outsidePts[0], endPt, other);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000773 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000774 if (!other->done() && oOutsidePts.count()) {
775 other->addCoinOutsides(oOutsidePts[0], endPt, this);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000776 }
777}
778
779// FIXME: this doesn't prevent the same span from being added twice
780// fix in caller, SkASSERT here?
781void SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
782 const SkPoint& pt) {
783 int tCount = fTs.count();
784 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
785 const SkOpSpan& span = fTs[tIndex];
786 if (!approximately_negative(span.fT - t)) {
787 break;
788 }
789 if (approximately_negative(span.fT - t) && span.fOther == other
790 && approximately_equal(span.fOtherT, otherT)) {
791#if DEBUG_ADD_T_PAIR
792 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
793 __FUNCTION__, fID, t, other->fID, otherT);
794#endif
795 return;
796 }
797 }
798#if DEBUG_ADD_T_PAIR
799 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
800 __FUNCTION__, fID, t, other->fID, otherT);
801#endif
caryclark@google.com570863f2013-09-16 15:55:01 +0000802 int insertedAt = addT(other, pt, t, SkOpSpan::kPointIsExact);
803 int otherInsertedAt = other->addT(this, pt, otherT, SkOpSpan::kPointIsExact);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000804 addOtherT(insertedAt, otherT, otherInsertedAt);
805 other->addOtherT(otherInsertedAt, t, insertedAt);
806 matchWindingValue(insertedAt, t, borrowWind);
807 other->matchWindingValue(otherInsertedAt, otherT, borrowWind);
808}
809
caryclark@google.comd892bd82013-06-17 14:10:36 +0000810void SkOpSegment::addTwoAngles(int start, int end, SkTArray<SkOpAngle, true>* angles) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000811 // add edge leading into junction
812 int min = SkMin32(end, start);
caryclark@google.coma5e55922013-05-07 18:51:31 +0000813 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000814 addAngle(angles, end, start);
815 }
816 // add edge leading away from junction
817 int step = SkSign32(end - start);
818 int tIndex = nextExactSpan(end, step);
819 min = SkMin32(end, tIndex);
caryclark@google.coma5e55922013-05-07 18:51:31 +0000820 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000821 addAngle(angles, end, tIndex);
822 }
823}
824
caryclark@google.com570863f2013-09-16 15:55:01 +0000825SkOpSegment::MissingSpan::Command SkOpSegment::adjustThisNear(double startT, const SkPoint& startPt,
826 const SkPoint& endPt, SkTArray<MissingSpan, true>* missingSpans) {
827 // see if endPt exists on this curve, and if it has the same t or a different T than the startT
828 int count = this->count();
829 SkASSERT(count > 0);
830 int startIndex, endIndex, step;
831 if (startT == 0) {
832 startIndex = 0;
833 endIndex = count;
834 step = 1;
835 } else {
836 SkASSERT(startT == 1);
837 startIndex = count - 1;
838 endIndex = -1;
839 step = -1;
840 }
841 int index = startIndex;
842 do {
843 const SkOpSpan& span = fTs[index];
844 if (span.fPt != endPt) {
845 continue;
846 }
847 if (span.fT == startT) {
848 // check to see if otherT matches some other mid curve intersection
849 int inner = startIndex;
850 do {
851 if (inner == index) {
852 continue;
853 }
854 const SkOpSpan& matchSpan = fTs[inner];
855 double matchT = span.fOther->missingNear(span.fOtherT, matchSpan.fOther, startPt,
856 endPt);
857 if (matchT >= 0) {
858 SkASSERT(missingSpans);
859 MissingSpan& missingSpan = missingSpans->push_back();
860 SkDEBUGCODE(sk_bzero(&missingSpan, sizeof(missingSpan)));
861 missingSpan.fCommand = MissingSpan::kRemoveNear;
862 missingSpan.fT = startT;
863 missingSpan.fSegment = this;
864 missingSpan.fOther = span.fOther;
865 missingSpan.fOtherT = matchT;
866 return missingSpan.fCommand;
867 }
868 } while ((inner += step) != endIndex);
869 break;
870 }
871 double midT = (startT + span.fT) / 2;
872 if (betweenPoints(midT, startPt, endPt)) {
873 if (!missingSpans) {
874 return MissingSpan::kZeroSpan;
875 }
876 MissingSpan& missingSpan = missingSpans->push_back();
877 SkDEBUGCODE(sk_bzero(&missingSpan, sizeof(missingSpan)));
878 missingSpan.fCommand = MissingSpan::kZeroSpan;
879 missingSpan.fT = SkTMin(startT, span.fT);
880 missingSpan.fEndT = SkTMax(startT, span.fT);
881 missingSpan.fSegment = this;
882 return missingSpan.fCommand;
883 }
884 } while ((index += step) != endIndex);
885 return MissingSpan::kNoAction;
886}
887
888void SkOpSegment::adjustOtherNear(double startT, const SkPoint& startPt, const SkPoint& endPt,
889 SkTArray<MissingSpan, true>* missingSpans) {
890 int count = this->count();
891 SkASSERT(count > 0);
892 int startIndex, endIndex, step;
893 if (startT == 0) {
894 startIndex = 0;
895 endIndex = count;
896 step = 1;
897 } else {
898 SkASSERT(startT == 1);
899 startIndex = count - 1;
900 endIndex = -1;
901 step = -1;
902 }
903 int index = startIndex;
904 do {
905 const SkOpSpan& span = fTs[index];
906 if (span.fT != startT) {
907 return;
908 }
909 SkOpSegment* other = span.fOther;
910 if (other->fPts[0] == endPt) {
911 other->adjustThisNear(0, endPt, startPt, missingSpans);
912 } else if (other->fPts[0] == startPt) {
913 other->adjustThisNear(0, startPt, endPt, missingSpans);
914 }
915 if (other->ptAtT(1) == endPt) {
916 other->adjustThisNear(1, endPt, startPt, missingSpans);
917 } else if (other->ptAtT(1) == startPt) {
918 other->adjustThisNear(1, startPt, endPt, missingSpans);
919 }
920 } while ((index += step) != endIndex);
921}
922
923void SkOpSegment::adjustMissingNear(const SkPoint& startPt, const SkPoint& endPt,
924 SkTArray<MissingSpan, true>* missingSpans) {
925 int count = missingSpans->count();
926 for (int index = 0; index < count; ) {
927 MissingSpan& missing = (*missingSpans)[index];
928 SkOpSegment* other = missing.fOther;
929 MissingSpan::Command command = MissingSpan::kNoAction;
930 if (missing.fPt == startPt) {
931 if (missingNear(missing.fT, other, startPt, endPt) >= 0) {
932 command = MissingSpan::kZeroSpan;
933 } else if (other->ptAtT(0) == endPt) {
934 command = other->adjustThisNear(0, endPt, startPt, NULL);
935 } else if (other->ptAtT(1) == endPt) {
936 command = other->adjustThisNear(1, endPt, startPt, NULL);
937 }
938 } else if (missing.fPt == endPt) {
939 if (missingNear(missing.fT, other, endPt, startPt) >= 0) {
940 command = MissingSpan::kZeroSpan;
941 } else if (other->ptAtT(0) == startPt) {
942 command = other->adjustThisNear(0, startPt, endPt, NULL);
943 } else if (other->ptAtT(1) == startPt) {
944 command = other->adjustThisNear(1, startPt, endPt, NULL);
945 }
946 }
947 if (command == MissingSpan::kZeroSpan) {
948#if 1
949 missing = missingSpans->back();
950 missingSpans->pop_back();
951#else // if this is supported in the future ...
952 missingSpans->removeShuffle(index);
953#endif
954 --count;
955 continue;
956 }
957 ++index;
958 }
959}
960
961void SkOpSegment::adjustNear(double startT, const SkPoint& endPt,
962 SkTArray<MissingSpan, true>* missingSpans) {
963 const SkPoint startPt = ptAtT(startT);
964 adjustMissingNear(startPt, endPt, missingSpans);
965 adjustThisNear(startT, startPt, endPt, missingSpans);
966 adjustOtherNear(startT, startPt, endPt, missingSpans);
967}
968
969int SkOpSegment::advanceCoincidentThis(int index) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000970 SkOpSpan* const test = &fTs[index];
971 SkOpSpan* end;
972 do {
973 end = &fTs[++index];
974 } while (approximately_negative(end->fT - test->fT));
975 return index;
976}
977
caryclark@google.com570863f2013-09-16 15:55:01 +0000978int SkOpSegment::advanceCoincidentOther(double oEndT, int oIndex) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000979 SkOpSpan* const oTest = &fTs[oIndex];
980 SkOpSpan* oEnd = oTest;
981 const double oStartT = oTest->fT;
982 while (!approximately_negative(oEndT - oEnd->fT)
983 && approximately_negative(oEnd->fT - oStartT)) {
984 oEnd = &fTs[++oIndex];
985 }
986 return oIndex;
987}
988
caryclark@google.com570863f2013-09-16 15:55:01 +0000989bool SkOpSegment::betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const {
990 const SkPoint midPt = ptAtT(midT);
991 SkPathOpsBounds bounds;
992 bounds.set(pt1.fX, pt1.fY, pt2.fX, pt2.fY);
993 bounds.sort();
994 return bounds.almostContains(midPt);
995}
996
caryclark@google.com07393ca2013-04-08 11:47:37 +0000997bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const {
998 if (lesser > greater) {
999 SkTSwap<int>(lesser, greater);
1000 }
1001 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
1002}
1003
caryclark@google.com570863f2013-09-16 15:55:01 +00001004// note that this follows the same logic flow as active angle
1005bool SkOpSegment::buildAngles(int index, SkTArray<SkOpAngle, true>* angles, bool allowOpp) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001006 double referenceT = fTs[index].fT;
caryclark@google.com570863f2013-09-16 15:55:01 +00001007 const SkPoint& referencePt = fTs[index].fPt;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001008 int lesser = index;
caryclark@google.com570863f2013-09-16 15:55:01 +00001009 while (--lesser >= 0 && (allowOpp || fTs[lesser].fOther->fOperand == fOperand)
1010 && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].fTiny)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001011 buildAnglesInner(lesser, angles);
1012 }
1013 do {
1014 buildAnglesInner(index, angles);
caryclark@google.com570863f2013-09-16 15:55:01 +00001015 if (++index == fTs.count()) {
1016 break;
1017 }
1018 if (!allowOpp && fTs[index].fOther->fOperand != fOperand) {
1019 break;
1020 }
1021 if (fTs[index - 1].fTiny) {
1022 referenceT = fTs[index].fT;
1023 continue;
1024 }
1025 if (!precisely_negative(fTs[index].fT - referenceT) && fTs[index].fPt == referencePt) {
1026 // FIXME
1027 // testQuad8 generates the wrong output unless false is returned here. Other tests will
1028 // take this path although they aren't required to. This means that many go much slower
1029 // because of this sort fail.
1030 // SkDebugf("!!!\n");
1031 return false;
1032 }
1033 } while (precisely_negative(fTs[index].fT - referenceT));
1034 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001035}
1036
caryclark@google.comd892bd82013-06-17 14:10:36 +00001037void SkOpSegment::buildAnglesInner(int index, SkTArray<SkOpAngle, true>* angles) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001038 const SkOpSpan* span = &fTs[index];
1039 SkOpSegment* other = span->fOther;
1040// if there is only one live crossing, and no coincidence, continue
1041// in the same direction
1042// if there is coincidence, the only choice may be to reverse direction
1043 // find edge on either side of intersection
1044 int oIndex = span->fOtherIndex;
1045 // if done == -1, prior span has already been processed
1046 int step = 1;
1047 int next = other->nextExactSpan(oIndex, step);
1048 if (next < 0) {
1049 step = -step;
1050 next = other->nextExactSpan(oIndex, step);
1051 }
1052 // add candidate into and away from junction
1053 other->addTwoAngles(next, oIndex, angles);
1054}
1055
caryclark@google.com570863f2013-09-16 15:55:01 +00001056int SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType,
1057 SkTArray<SkOpAngle, true>* angles, SkTArray<SkOpAngle*, true>* sorted) {
1058 addTwoAngles(startIndex, endIndex, angles);
1059 if (!buildAngles(endIndex, angles, includeType == SkOpAngle::kBinaryOpp)) {
1060 return SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001061 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001062 int angleCount = angles->count();
1063 // abort early before sorting if an unsortable (not an unorderable) angle is found
1064 if (includeType != SkOpAngle::kUnaryXor) {
1065 int firstIndex = -1;
1066 while (++firstIndex < angleCount) {
1067 const SkOpAngle& angle = (*angles)[firstIndex];
1068 if (angle.segment()->windSum(&angle) != SK_MinS32) {
1069 break;
1070 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001071 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001072 if (firstIndex == angleCount) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001073 return SK_MinS32;
1074 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001075 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001076 bool sortable = SortAngles2(*angles, sorted);
1077#if DEBUG_SORT_RAW
1078 if (sorted->count() > 0) {
1079 (*sorted)[0]->segment()->debugShowSort(__FUNCTION__, *sorted, 0, 0, 0, sortable);
1080 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001081#endif
caryclark@google.com570863f2013-09-16 15:55:01 +00001082 if (!sortable) {
1083 return SK_NaN32;
1084 }
1085 if (includeType == SkOpAngle::kUnaryXor) {
1086 return SK_MinS32;
1087 }
1088 // if all angles have a computed winding,
1089 // or if no adjacent angles are orderable,
1090 // or if adjacent orderable angles have no computed winding,
1091 // there's nothing to do
1092 // if two orderable angles are adjacent, and one has winding computed, transfer to the other
1093 const SkOpAngle* baseAngle = NULL;
1094 int last = angleCount;
1095 int finalInitialOrderable = -1;
1096 bool tryReverse = false;
1097 // look for counterclockwise transfers
caryclark@google.com07393ca2013-04-08 11:47:37 +00001098 do {
caryclark@google.com570863f2013-09-16 15:55:01 +00001099 int index = 0;
1100 do {
1101 SkOpAngle* testAngle = (*sorted)[index];
1102 int testWinding = testAngle->segment()->windSum(testAngle);
1103 if (SK_MinS32 != testWinding && !testAngle->unorderable()) {
1104 baseAngle = testAngle;
1105 continue;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001106 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001107 if (testAngle->unorderable()) {
1108 baseAngle = NULL;
1109 tryReverse = true;
1110 continue;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001111 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001112 if (baseAngle) {
1113 ComputeOneSum(baseAngle, testAngle, includeType);
1114 baseAngle = SK_MinS32 != testAngle->segment()->windSum(testAngle) ? testAngle
1115 : NULL;
1116 tryReverse |= !baseAngle;
1117 continue;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001118 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001119 if (finalInitialOrderable + 1 == index) {
1120 finalInitialOrderable = index;
1121 }
1122 } while (++index != last);
1123 if (finalInitialOrderable < 0) {
1124 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001125 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001126 last = finalInitialOrderable + 1;
1127 finalInitialOrderable = -2; // make this always negative the second time through
1128 } while (baseAngle);
1129 if (tryReverse) {
1130 baseAngle = NULL;
1131 last = 0;
1132 finalInitialOrderable = angleCount;
1133 do {
1134 int index = angleCount;
1135 while (--index >= last) {
1136 SkOpAngle* testAngle = (*sorted)[index];
1137 int testWinding = testAngle->segment()->windSum(testAngle);
1138 if (SK_MinS32 != testWinding) {
1139 baseAngle = testAngle;
1140 continue;
1141 }
1142 if (testAngle->unorderable()) {
1143 baseAngle = NULL;
1144 continue;
1145 }
1146 if (baseAngle) {
1147 ComputeOneSumReverse(baseAngle, testAngle, includeType);
1148 baseAngle = SK_MinS32 != testAngle->segment()->windSum(testAngle) ? testAngle
1149 : NULL;
1150 continue;
1151 }
1152 if (finalInitialOrderable - 1 == index) {
1153 finalInitialOrderable = index;
1154 }
1155 }
1156 if (finalInitialOrderable >= angleCount) {
1157 break;
1158 }
1159 last = finalInitialOrderable;
1160 finalInitialOrderable = angleCount + 1; // make this inactive 2nd time through
1161 } while (baseAngle);
1162 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001163 int minIndex = SkMin32(startIndex, endIndex);
1164 return windSum(minIndex);
1165}
1166
caryclark@google.com570863f2013-09-16 15:55:01 +00001167void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
1168 SkOpAngle::IncludeType includeType) {
1169 const SkOpSegment* baseSegment = baseAngle->segment();
1170 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
1171 int sumSuWinding;
1172 bool binary = includeType >= SkOpAngle::kBinarySingle;
1173 if (binary) {
1174 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
1175 if (baseSegment->operand()) {
1176 SkTSwap<int>(sumMiWinding, sumSuWinding);
1177 }
1178 }
1179 SkOpSegment* nextSegment = nextAngle->segment();
1180 int maxWinding, sumWinding;
1181 SkOpSpan* last;
1182 if (binary) {
1183 int oppMaxWinding, oppSumWinding;
1184 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
1185 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1186 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
1187 true, nextAngle);
1188 } else {
1189 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
1190 &maxWinding, &sumWinding);
1191 last = nextSegment->markAngle(maxWinding, sumWinding, true, nextAngle);
1192 }
1193 nextAngle->setLastMarked(last);
1194}
1195
1196void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
1197 SkOpAngle::IncludeType includeType) {
1198 const SkOpSegment* baseSegment = baseAngle->segment();
1199 int sumMiWinding = baseSegment->updateWinding(baseAngle);
1200 int sumSuWinding;
1201 bool binary = includeType >= SkOpAngle::kBinarySingle;
1202 if (binary) {
1203 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
1204 if (baseSegment->operand()) {
1205 SkTSwap<int>(sumMiWinding, sumSuWinding);
1206 }
1207 }
1208 SkOpSegment* nextSegment = nextAngle->segment();
1209 int maxWinding, sumWinding;
1210 SkOpSpan* last;
1211 if (binary) {
1212 int oppMaxWinding, oppSumWinding;
1213 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
1214 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1215 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
1216 true, nextAngle);
1217 } else {
1218 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
1219 &maxWinding, &sumWinding);
1220 last = nextSegment->markAngle(maxWinding, sumWinding, true, nextAngle);
1221 }
1222 nextAngle->setLastMarked(last);
1223}
1224
caryclark@google.com07393ca2013-04-08 11:47:37 +00001225int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT,
1226 bool* hitSomething, double mid, bool opp, bool current) const {
1227 SkScalar bottom = fBounds.fBottom;
1228 int bestTIndex = -1;
1229 if (bottom <= *bestY) {
1230 return bestTIndex;
1231 }
1232 SkScalar top = fBounds.fTop;
1233 if (top >= basePt.fY) {
1234 return bestTIndex;
1235 }
1236 if (fBounds.fLeft > basePt.fX) {
1237 return bestTIndex;
1238 }
1239 if (fBounds.fRight < basePt.fX) {
1240 return bestTIndex;
1241 }
1242 if (fBounds.fLeft == fBounds.fRight) {
1243 // if vertical, and directly above test point, wait for another one
1244 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
1245 }
1246 // intersect ray starting at basePt with edge
1247 SkIntersections intersections;
1248 // OPTIMIZE: use specialty function that intersects ray with curve,
1249 // returning t values only for curve (we don't care about t on ray)
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001250 int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)])
1251 (fPts, top, bottom, basePt.fX, false);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001252 if (pts == 0 || (current && pts == 1)) {
1253 return bestTIndex;
1254 }
1255 if (current) {
1256 SkASSERT(pts > 1);
1257 int closestIdx = 0;
1258 double closest = fabs(intersections[0][0] - mid);
1259 for (int idx = 1; idx < pts; ++idx) {
1260 double test = fabs(intersections[0][idx] - mid);
1261 if (closest > test) {
1262 closestIdx = idx;
1263 closest = test;
1264 }
1265 }
1266 intersections.quickRemoveOne(closestIdx, --pts);
1267 }
1268 double bestT = -1;
1269 for (int index = 0; index < pts; ++index) {
1270 double foundT = intersections[0][index];
1271 if (approximately_less_than_zero(foundT)
1272 || approximately_greater_than_one(foundT)) {
1273 continue;
1274 }
reed@google.com277c3f82013-05-31 15:17:50 +00001275 SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fY;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001276 if (approximately_negative(testY - *bestY)
1277 || approximately_negative(basePt.fY - testY)) {
1278 continue;
1279 }
1280 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
1281 return SK_MinS32; // if the intersection is edge on, wait for another one
1282 }
1283 if (fVerb > SkPath::kLine_Verb) {
reed@google.com277c3f82013-05-31 15:17:50 +00001284 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fX;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001285 if (approximately_zero(dx)) {
1286 return SK_MinS32; // hit vertical, wait for another one
1287 }
1288 }
1289 *bestY = testY;
1290 bestT = foundT;
1291 }
1292 if (bestT < 0) {
1293 return bestTIndex;
1294 }
1295 SkASSERT(bestT >= 0);
1296 SkASSERT(bestT <= 1);
1297 int start;
1298 int end = 0;
1299 do {
1300 start = end;
1301 end = nextSpan(start, 1);
1302 } while (fTs[end].fT < bestT);
1303 // FIXME: see next candidate for a better pattern to find the next start/end pair
1304 while (start + 1 < end && fTs[start].fDone) {
1305 ++start;
1306 }
1307 if (!isCanceled(start)) {
1308 *hitT = bestT;
1309 bestTIndex = start;
1310 *hitSomething = true;
1311 }
1312 return bestTIndex;
1313}
1314
caryclark@google.com570863f2013-09-16 15:55:01 +00001315bool SkOpSegment::decrementSpan(SkOpSpan* span) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001316 SkASSERT(span->fWindValue > 0);
1317 if (--(span->fWindValue) == 0) {
1318 if (!span->fOppValue && !span->fDone) {
1319 span->fDone = true;
1320 ++fDoneSpans;
caryclark@google.com570863f2013-09-16 15:55:01 +00001321 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001322 }
1323 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001324 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001325}
1326
1327bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) {
caryclark@google.com570863f2013-09-16 15:55:01 +00001328 SkASSERT(!span->fDone || span->fTiny);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001329 span->fWindValue += windDelta;
1330 SkASSERT(span->fWindValue >= 0);
1331 span->fOppValue += oppDelta;
1332 SkASSERT(span->fOppValue >= 0);
1333 if (fXor) {
1334 span->fWindValue &= 1;
1335 }
1336 if (fOppXor) {
1337 span->fOppValue &= 1;
1338 }
1339 if (!span->fWindValue && !span->fOppValue) {
1340 span->fDone = true;
1341 ++fDoneSpans;
1342 return true;
1343 }
1344 return false;
1345}
1346
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001347// look to see if the curve end intersects an intermediary that intersects the other
1348void SkOpSegment::checkEnds() {
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001349 debugValidate();
caryclark@google.com570863f2013-09-16 15:55:01 +00001350 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001351 int count = fTs.count();
1352 for (int index = 0; index < count; ++index) {
1353 const SkOpSpan& span = fTs[index];
caryclark@google.com570863f2013-09-16 15:55:01 +00001354 double otherT = span.fOtherT;
1355 if (otherT != 0 && otherT != 1) { // only check ends
1356 continue;
1357 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001358 const SkOpSegment* other = span.fOther;
caryclark@google.com570863f2013-09-16 15:55:01 +00001359 // peek start/last describe the range of spans that match the other t of this span
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001360 int peekStart = span.fOtherIndex;
caryclark@google.com570863f2013-09-16 15:55:01 +00001361 while (--peekStart >= 0 && other->fTs[peekStart].fT == otherT)
1362 ;
1363 int otherCount = other->fTs.count();
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001364 int peekLast = span.fOtherIndex;
caryclark@google.com570863f2013-09-16 15:55:01 +00001365 while (++peekLast < otherCount && other->fTs[peekLast].fT == otherT)
1366 ;
1367 if (++peekStart == --peekLast) { // if there isn't a range, there's nothing to do
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001368 continue;
1369 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001370 // t start/last describe the range of spans that match the t of this span
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001371 double t = span.fT;
1372 int tStart = index;
caryclark@google.com570863f2013-09-16 15:55:01 +00001373 while (--tStart >= 0 && (t == fTs[tStart].fT || fTs[tStart].fTiny))
1374 ;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001375 int tLast = index;
caryclark@google.com570863f2013-09-16 15:55:01 +00001376 while (fTs[tLast].fTiny) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001377 ++tLast;
1378 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001379 while (++tLast < count && t == fTs[tLast].fT)
1380 ;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001381 for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) {
caryclark@google.com570863f2013-09-16 15:55:01 +00001382 if (peekIndex == span.fOtherIndex) { // skip the other span pointed to by this span
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001383 continue;
1384 }
1385 const SkOpSpan& peekSpan = other->fTs[peekIndex];
1386 SkOpSegment* match = peekSpan.fOther;
1387 const double matchT = peekSpan.fOtherT;
caryclark@google.com570863f2013-09-16 15:55:01 +00001388 // see if any of the spans match the other spans
1389 for (int tIndex = tStart + 1; tIndex < tLast; ++tIndex) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001390 const SkOpSpan& tSpan = fTs[tIndex];
caryclark@google.com570863f2013-09-16 15:55:01 +00001391 if (tSpan.fOther == match) {
1392 if (tSpan.fOtherT == matchT) {
1393 goto nextPeeker;
1394 }
1395 double midT = (tSpan.fOtherT + matchT) / 2;
1396 if (match->betweenPoints(midT, tSpan.fPt, peekSpan.fPt)) {
1397 goto nextPeeker;
1398 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001399 }
1400 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001401 if (missingSpans.count() > 0) {
1402 const MissingSpan& lastMissing = missingSpans.back();
1403 if (lastMissing.fCommand == MissingSpan::kAddMissing
1404 && lastMissing.fT == t
1405 && lastMissing.fOther == match
1406 && lastMissing.fOtherT == matchT) {
1407 SkASSERT(lastMissing.fPt == peekSpan.fPt);
1408 continue;
1409 }
1410 }
1411#if DEBUG_CHECK_ENDS
1412 SkDebugf("%s id=%d missing t=%1.9g other=%d otherT=%1.9g pt=(%1.9g,%1.9g)\n",
1413 __FUNCTION__, fID, t, match->fID, matchT, peekSpan.fPt.fX, peekSpan.fPt.fY);
1414#endif
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001415 // this segment is missing a entry that the other contains
1416 // remember so we can add the missing one and recompute the indices
caryclark@google.com570863f2013-09-16 15:55:01 +00001417 MissingSpan& missing = missingSpans.push_back();
1418 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
1419 missing.fCommand = MissingSpan::kAddMissing;
1420 missing.fT = t;
1421 missing.fOther = match;
1422 missing.fOtherT = matchT;
1423 missing.fPt = peekSpan.fPt;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001424 }
1425nextPeeker:
1426 ;
1427 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001428 if (missingSpans.count() == 0) {
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001429 return;
1430 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001431 // if one end is near the other point, look for a coincident span
1432 for (int index = 0; index < count; ++index) {
1433 const SkOpSpan& span = fTs[index];
1434 if (span.fT > 0) {
1435 break;
1436 }
1437 const SkOpSpan& otherSpan = span.fOther->span(span.fOtherIndex);
1438 if (span.fNear) {
1439 SkASSERT(otherSpan.fPt == fPts[0]);
1440 adjustNear(0, span.fPt, &missingSpans);
1441 continue;
1442 }
1443 if (otherSpan.fNear) {
1444 SkASSERT(span.fPt == fPts[0]);
1445 adjustNear(0, otherSpan.fPt, &missingSpans);
1446 }
1447 }
1448 for (int index = count; --index >= 0; ) {
1449 const SkOpSpan& span = fTs[index];
1450 if (span.fT < 1) {
1451 break;
1452 }
1453 const SkOpSegment* other = span.fOther;
1454 if (span.fNear) {
1455 SkASSERT(other->ptAtT(span.fOtherT) == ptAtT(1));
1456 const SkPoint& otherPt = other->xyAtT(span.fOtherIndex);
1457 SkASSERT(otherPt != ptAtT(1));
1458 adjustNear(1, otherPt, &missingSpans);
1459 continue;
1460 }
1461 const SkOpSpan& otherSpan = other->span(span.fOtherIndex);
1462 if (otherSpan.fNear) {
1463 SkASSERT(otherSpan.fPt == ptAtT(1));
1464 SkPoint otherPt = other->ptAtT(span.fOtherT);
1465 SkASSERT(otherPt != ptAtT(1));
1466 adjustNear(1, otherPt, &missingSpans);
1467 }
1468 }
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001469 debugValidate();
caryclark@google.com570863f2013-09-16 15:55:01 +00001470 int missingCount = missingSpans.count();
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001471 for (int index = 0; index < missingCount; ++index) {
caryclark@google.com570863f2013-09-16 15:55:01 +00001472 MissingSpan& missing = missingSpans[index];
1473 switch (missing.fCommand) {
1474 case MissingSpan::kNoAction:
1475 break;
1476 case MissingSpan::kAddMissing:
1477 addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt);
1478 break;
1479 case MissingSpan::kRemoveNear: {
1480 SkOpSegment* segment = missing.fSegment;
1481 int count = segment->count();
1482 for (int inner = 0; inner < count; ++inner) {
1483 const SkOpSpan& span = segment->span(inner);
1484 if (span.fT != missing.fT && span.fOther != missing.fOther) {
1485 continue;
1486 }
1487 SkASSERT(span.fNear);
1488 SkOpSegment* other = span.fOther;
1489 int otherCount = other->count();
1490 for (int otherIndex = 0; otherIndex < otherCount; ++otherIndex) {
1491 const SkOpSpan& otherSpan = other->span(otherIndex);
1492 if (otherSpan.fT == span.fOtherT && otherSpan.fOther == segment
1493 && otherSpan.fOtherT == span.fT) {
1494 if (otherSpan.fDone) {
1495 other->fDoneSpans--;
1496 }
1497 other->fTs.remove(otherIndex);
1498 // FIXME: remove may leave a tiny dangling -- recompute tiny w/index
1499 break;
1500 }
1501 }
1502 if (span.fDone) {
1503 segment->fDoneSpans--;
1504 }
1505 segment->fTs.remove(inner);
1506 // FIXME: remove may leave a tiny dangling -- recompute tiny w/index
1507 break;
1508 }
1509 break;
1510 }
1511 case MissingSpan::kZeroSpan: {
1512 SkOpSegment* segment = missing.fSegment;
1513 int count = segment->count();
1514 for (int inner = 0; inner < count; ++inner) {
1515 SkOpSpan& span = segment->fTs[inner];
1516 if (span.fT < missing.fT) {
1517 continue;
1518 }
1519 if (span.fT >= missing.fEndT) {
1520 break;
1521 }
1522 span.fWindValue = span.fOppValue = 0;
1523 if (!span.fDone) {
1524 span.fDone = true;
1525 ++segment->fDoneSpans;
1526 }
1527 }
1528 break;
1529 }
1530 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001531 }
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001532 fixOtherTIndex();
caryclark@google.com570863f2013-09-16 15:55:01 +00001533 // OPTIMIZATION: this may fix indices more than once. Build an array of unique segments to
1534 // avoid this
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001535 for (int index = 0; index < missingCount; ++index) {
caryclark@google.com570863f2013-09-16 15:55:01 +00001536 const MissingSpan& missing = missingSpans[index];
1537 switch (missing.fCommand) {
1538 case MissingSpan::kNoAction:
1539 break;
1540 case MissingSpan::kAddMissing:
1541 missing.fOther->fixOtherTIndex();
1542 break;
1543 case MissingSpan::kRemoveNear:
1544 missing.fSegment->fixOtherTIndex();
1545 missing.fOther->fixOtherTIndex();
1546 break;
1547 case MissingSpan::kZeroSpan:
1548 break;
1549 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001550 }
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001551 debugValidate();
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001552}
1553
caryclark@google.com570863f2013-09-16 15:55:01 +00001554bool SkOpSegment::checkSmall(int index) const {
1555 if (fTs[index].fSmall) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001556 return true;
1557 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001558 double tBase = fTs[index].fT;
1559 while (index > 0 && precisely_negative(tBase - fTs[--index].fT))
1560 ;
1561 return fTs[index].fSmall;
1562}
1563
1564// if pair of spans on either side of tiny have the same end point and mid point, mark
1565// them as parallel
1566// OPTIMIZATION : mark the segment to note that some span is tiny
1567void SkOpSegment::checkTiny() {
1568 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
1569 SkOpSpan* thisSpan = fTs.begin() - 1;
1570 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be tiny
1571 while (++thisSpan < endSpan) {
1572 if (!thisSpan->fTiny) {
1573 continue;
1574 }
1575 SkOpSpan* nextSpan = thisSpan + 1;
1576 double thisT = thisSpan->fT;
1577 double nextT = nextSpan->fT;
1578 if (thisT == nextT) {
1579 continue;
1580 }
1581 SkASSERT(thisT < nextT);
1582 SkASSERT(thisSpan->fPt == nextSpan->fPt);
1583 SkOpSegment* thisOther = thisSpan->fOther;
1584 SkOpSegment* nextOther = nextSpan->fOther;
1585 int oIndex = thisSpan->fOtherIndex;
1586 for (int oStep = -1; oStep <= 1; oStep += 2) {
1587 int oEnd = thisOther->nextExactSpan(oIndex, oStep);
1588 if (oEnd < 0) {
1589 continue;
1590 }
1591 const SkOpSpan& oSpan = thisOther->span(oEnd);
1592 int nIndex = nextSpan->fOtherIndex;
1593 for (int nStep = -1; nStep <= 1; nStep += 2) {
1594 int nEnd = nextOther->nextExactSpan(nIndex, nStep);
1595 if (nEnd < 0) {
1596 continue;
1597 }
1598 const SkOpSpan& nSpan = nextOther->span(nEnd);
1599 if (oSpan.fPt != nSpan.fPt) {
1600 continue;
1601 }
1602 double oMidT = (thisSpan->fOtherT + oSpan.fT) / 2;
1603 const SkPoint& oPt = thisOther->ptAtT(oMidT);
1604 double nMidT = (nextSpan->fOtherT + nSpan.fT) / 2;
1605 const SkPoint& nPt = nextOther->ptAtT(nMidT);
1606 if (!AlmostEqualUlps(oPt, nPt)) {
1607 continue;
1608 }
1609#if DEBUG_CHECK_TINY
1610 SkDebugf("%s [%d] add coincidence [%d] [%d]\n", __FUNCTION__, fID,
1611 thisOther->fID, nextOther->fID);
1612#endif
1613 // this segment is missing a entry that the other contains
1614 // remember so we can add the missing one and recompute the indices
1615 MissingSpan& missing = missingSpans.push_back();
1616 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
1617 missing.fCommand = MissingSpan::kAddMissing;
1618 missing.fSegment = thisOther;
1619 missing.fT = thisSpan->fOtherT;
1620 missing.fOther = nextOther;
1621 missing.fOtherT = nextSpan->fOtherT;
1622 missing.fPt = thisSpan->fPt;
1623 }
1624 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001625 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001626 int missingCount = missingSpans.count();
1627 if (!missingCount) {
1628 return;
1629 }
1630 for (int index = 0; index < missingCount; ++index) {
1631 MissingSpan& missing = missingSpans[index];
1632 missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt);
1633 }
1634 for (int index = 0; index < missingCount; ++index) {
1635 MissingSpan& missing = missingSpans[index];
1636 missing.fSegment->fixOtherTIndex();
1637 missing.fOther->fixOtherTIndex();
1638 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001639}
1640
1641/*
1642 The M and S variable name parts stand for the operators.
1643 Mi stands for Minuend (see wiki subtraction, analogous to difference)
1644 Su stands for Subtrahend
1645 The Opp variable name part designates that the value is for the Opposite operator.
1646 Opposite values result from combining coincident spans.
1647 */
1648SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
1649 bool* unsortable, SkPathOp op, const int xorMiMask,
1650 const int xorSuMask) {
1651 const int startIndex = *nextStart;
1652 const int endIndex = *nextEnd;
1653 SkASSERT(startIndex != endIndex);
1654 SkDEBUGCODE(const int count = fTs.count());
1655 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
1656 const int step = SkSign32(endIndex - startIndex);
1657 const int end = nextExactSpan(startIndex, step);
1658 SkASSERT(end >= 0);
1659 SkOpSpan* endSpan = &fTs[end];
1660 SkOpSegment* other;
1661 if (isSimple(end)) {
1662 // mark the smaller of startIndex, endIndex done, and all adjacent
1663 // spans with the same T value (but not 'other' spans)
1664#if DEBUG_WINDING
1665 SkDebugf("%s simple\n", __FUNCTION__);
1666#endif
1667 int min = SkMin32(startIndex, endIndex);
1668 if (fTs[min].fDone) {
1669 return NULL;
1670 }
1671 markDoneBinary(min);
1672 other = endSpan->fOther;
1673 *nextStart = endSpan->fOtherIndex;
1674 double startT = other->fTs[*nextStart].fT;
1675 *nextEnd = *nextStart;
1676 do {
1677 *nextEnd += step;
caryclark@google.com570863f2013-09-16 15:55:01 +00001678 } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
caryclark@google.com07393ca2013-04-08 11:47:37 +00001679 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001680 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001681 *unsortable = true;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001682 return NULL;
1683 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001684 return other;
1685 }
1686 // more than one viable candidate -- measure angles to find best
caryclark@google.comd892bd82013-06-17 14:10:36 +00001687 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001688 SkASSERT(startIndex - endIndex != 0);
1689 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
caryclark@google.comd892bd82013-06-17 14:10:36 +00001690 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.com570863f2013-09-16 15:55:01 +00001691 int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp, &angles, &sorted);
1692 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001693 int angleCount = angles.count();
1694 int firstIndex = findStartingEdge(sorted, startIndex, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001695 SkASSERT(!sortable || firstIndex >= 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001696#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001697 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001698#endif
1699 if (!sortable) {
1700 *unsortable = true;
1701 return NULL;
1702 }
1703 SkASSERT(sorted[firstIndex]->segment() == this);
1704#if DEBUG_WINDING
1705 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
1706 sorted[firstIndex]->sign());
1707#endif
1708 int sumMiWinding = updateWinding(endIndex, startIndex);
1709 int sumSuWinding = updateOppWinding(endIndex, startIndex);
1710 if (operand()) {
1711 SkTSwap<int>(sumMiWinding, sumSuWinding);
1712 }
1713 int nextIndex = firstIndex + 1;
1714 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1715 const SkOpAngle* foundAngle = NULL;
1716 bool foundDone = false;
1717 // iterate through the angle, and compute everyone's winding
1718 SkOpSegment* nextSegment;
1719 int activeCount = 0;
1720 do {
1721 SkASSERT(nextIndex != firstIndex);
1722 if (nextIndex == angleCount) {
1723 nextIndex = 0;
1724 }
1725 const SkOpAngle* nextAngle = sorted[nextIndex];
1726 nextSegment = nextAngle->segment();
1727 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1728 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
1729 nextAngle->end(), op, &sumMiWinding, &sumSuWinding,
1730 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1731 if (activeAngle) {
1732 ++activeCount;
1733 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001734 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001735 *unsortable = true;
1736 return NULL;
1737 }
1738 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +00001739 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001740 }
1741 }
1742 if (nextSegment->done()) {
1743 continue;
1744 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001745 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001746 continue;
1747 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001748 if (!activeAngle) {
1749 nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextAngle->end());
1750 }
1751 SkOpSpan* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001752 if (last) {
1753 *chase->append() = last;
1754#if DEBUG_WINDING
caryclark@google.com570863f2013-09-16 15:55:01 +00001755 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
1756 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
1757 last->fSmall);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001758#endif
1759 }
1760 } while (++nextIndex != lastIndex);
1761 markDoneBinary(SkMin32(startIndex, endIndex));
1762 if (!foundAngle) {
1763 return NULL;
1764 }
1765 *nextStart = foundAngle->start();
1766 *nextEnd = foundAngle->end();
1767 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001768#if DEBUG_WINDING
1769 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1770 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1771 #endif
1772 return nextSegment;
1773}
1774
1775SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart,
1776 int* nextEnd, bool* unsortable) {
1777 const int startIndex = *nextStart;
1778 const int endIndex = *nextEnd;
1779 SkASSERT(startIndex != endIndex);
1780 SkDEBUGCODE(const int count = fTs.count());
1781 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
1782 const int step = SkSign32(endIndex - startIndex);
1783 const int end = nextExactSpan(startIndex, step);
1784 SkASSERT(end >= 0);
1785 SkOpSpan* endSpan = &fTs[end];
1786 SkOpSegment* other;
1787 if (isSimple(end)) {
1788 // mark the smaller of startIndex, endIndex done, and all adjacent
1789 // spans with the same T value (but not 'other' spans)
1790#if DEBUG_WINDING
1791 SkDebugf("%s simple\n", __FUNCTION__);
1792#endif
1793 int min = SkMin32(startIndex, endIndex);
1794 if (fTs[min].fDone) {
1795 return NULL;
1796 }
1797 markDoneUnary(min);
1798 other = endSpan->fOther;
1799 *nextStart = endSpan->fOtherIndex;
1800 double startT = other->fTs[*nextStart].fT;
1801 *nextEnd = *nextStart;
1802 do {
1803 *nextEnd += step;
caryclark@google.com570863f2013-09-16 15:55:01 +00001804 } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
caryclark@google.com07393ca2013-04-08 11:47:37 +00001805 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
caryclark@google.com570863f2013-09-16 15:55:01 +00001806 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
1807 *unsortable = true;
1808 return NULL;
1809 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001810 return other;
1811 }
1812 // more than one viable candidate -- measure angles to find best
caryclark@google.comd892bd82013-06-17 14:10:36 +00001813 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001814 SkASSERT(startIndex - endIndex != 0);
1815 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
caryclark@google.comd892bd82013-06-17 14:10:36 +00001816 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.com570863f2013-09-16 15:55:01 +00001817 int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryWinding, &angles, &sorted);
1818 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001819 int angleCount = angles.count();
1820 int firstIndex = findStartingEdge(sorted, startIndex, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001821 SkASSERT(!sortable || firstIndex >= 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001822#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001823 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001824#endif
1825 if (!sortable) {
1826 *unsortable = true;
1827 return NULL;
1828 }
1829 SkASSERT(sorted[firstIndex]->segment() == this);
1830#if DEBUG_WINDING
1831 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
1832 sorted[firstIndex]->sign());
1833#endif
1834 int sumWinding = updateWinding(endIndex, startIndex);
1835 int nextIndex = firstIndex + 1;
1836 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1837 const SkOpAngle* foundAngle = NULL;
1838 bool foundDone = false;
1839 // iterate through the angle, and compute everyone's winding
1840 SkOpSegment* nextSegment;
1841 int activeCount = 0;
1842 do {
1843 SkASSERT(nextIndex != firstIndex);
1844 if (nextIndex == angleCount) {
1845 nextIndex = 0;
1846 }
1847 const SkOpAngle* nextAngle = sorted[nextIndex];
1848 nextSegment = nextAngle->segment();
1849 int maxWinding;
1850 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
1851 &maxWinding, &sumWinding);
1852 if (activeAngle) {
1853 ++activeCount;
1854 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001855 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001856 *unsortable = true;
1857 return NULL;
1858 }
1859 foundAngle = nextAngle;
1860 foundDone = nextSegment->done(nextAngle);
1861 }
1862 }
1863 if (nextSegment->done()) {
1864 continue;
1865 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001866 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001867 continue;
1868 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001869 if (!activeAngle) {
1870 nextSegment->markAndChaseDoneUnary(nextAngle->start(), nextAngle->end());
1871 }
1872 SkOpSpan* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001873 if (last) {
1874 *chase->append() = last;
1875#if DEBUG_WINDING
caryclark@google.com570863f2013-09-16 15:55:01 +00001876 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
1877 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
1878 last->fSmall);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001879#endif
1880 }
1881 } while (++nextIndex != lastIndex);
1882 markDoneUnary(SkMin32(startIndex, endIndex));
1883 if (!foundAngle) {
1884 return NULL;
1885 }
1886 *nextStart = foundAngle->start();
1887 *nextEnd = foundAngle->end();
1888 nextSegment = foundAngle->segment();
1889#if DEBUG_WINDING
1890 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1891 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1892 #endif
1893 return nextSegment;
1894}
1895
1896SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsortable) {
1897 const int startIndex = *nextStart;
1898 const int endIndex = *nextEnd;
1899 SkASSERT(startIndex != endIndex);
1900 SkDEBUGCODE(int count = fTs.count());
caryclark@google.com570863f2013-09-16 15:55:01 +00001901 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001902 int step = SkSign32(endIndex - startIndex);
1903 int end = nextExactSpan(startIndex, step);
1904 SkASSERT(end >= 0);
1905 SkOpSpan* endSpan = &fTs[end];
1906 SkOpSegment* other;
1907 if (isSimple(end)) {
1908#if DEBUG_WINDING
1909 SkDebugf("%s simple\n", __FUNCTION__);
1910#endif
1911 int min = SkMin32(startIndex, endIndex);
1912 if (fTs[min].fDone) {
1913 return NULL;
1914 }
1915 markDone(min, 1);
1916 other = endSpan->fOther;
1917 *nextStart = endSpan->fOtherIndex;
1918 double startT = other->fTs[*nextStart].fT;
1919 // FIXME: I don't know why the logic here is difference from the winding case
1920 SkDEBUGCODE(bool firstLoop = true;)
1921 if ((approximately_less_than_zero(startT) && step < 0)
1922 || (approximately_greater_than_one(startT) && step > 0)) {
1923 step = -step;
1924 SkDEBUGCODE(firstLoop = false;)
1925 }
1926 do {
1927 *nextEnd = *nextStart;
1928 do {
1929 *nextEnd += step;
caryclark@google.com570863f2013-09-16 15:55:01 +00001930 } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
caryclark@google.com07393ca2013-04-08 11:47:37 +00001931 if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) {
1932 break;
1933 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001934 SkASSERT(firstLoop);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001935 SkDEBUGCODE(firstLoop = false;)
1936 step = -step;
1937 } while (true);
1938 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
1939 return other;
1940 }
caryclark@google.comd892bd82013-06-17 14:10:36 +00001941 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001942 SkASSERT(startIndex - endIndex != 0);
1943 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
caryclark@google.comd892bd82013-06-17 14:10:36 +00001944 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.com570863f2013-09-16 15:55:01 +00001945 int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryXor, &angles, &sorted);
1946 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001947 int angleCount = angles.count();
1948 int firstIndex = findStartingEdge(sorted, startIndex, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001949 SkASSERT(!sortable || firstIndex >= 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001950#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001951 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001952#endif
caryclark@google.com570863f2013-09-16 15:55:01 +00001953 if (!sortable) {
1954 *unsortable = true;
1955 return NULL;
1956 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001957 SkASSERT(sorted[firstIndex]->segment() == this);
caryclark@google.com570863f2013-09-16 15:55:01 +00001958#if DEBUG_WINDING
1959 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
1960 sorted[firstIndex]->sign());
1961#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00001962 int nextIndex = firstIndex + 1;
1963 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1964 const SkOpAngle* foundAngle = NULL;
1965 bool foundDone = false;
1966 SkOpSegment* nextSegment;
1967 int activeCount = 0;
1968 do {
1969 SkASSERT(nextIndex != firstIndex);
1970 if (nextIndex == angleCount) {
1971 nextIndex = 0;
1972 }
1973 const SkOpAngle* nextAngle = sorted[nextIndex];
1974 nextSegment = nextAngle->segment();
1975 ++activeCount;
1976 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001977 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001978 *unsortable = true;
1979 return NULL;
1980 }
1981 foundAngle = nextAngle;
1982 foundDone = nextSegment->done(nextAngle);
1983 }
1984 if (nextSegment->done()) {
1985 continue;
1986 }
1987 } while (++nextIndex != lastIndex);
1988 markDone(SkMin32(startIndex, endIndex), 1);
1989 if (!foundAngle) {
1990 return NULL;
1991 }
1992 *nextStart = foundAngle->start();
1993 *nextEnd = foundAngle->end();
1994 nextSegment = foundAngle->segment();
1995#if DEBUG_WINDING
1996 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1997 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1998 #endif
1999 return nextSegment;
2000}
2001
caryclark@google.comd892bd82013-06-17 14:10:36 +00002002int SkOpSegment::findStartingEdge(const SkTArray<SkOpAngle*, true>& sorted, int start, int end) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002003 int angleCount = sorted.count();
2004 int firstIndex = -1;
2005 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2006 const SkOpAngle* angle = sorted[angleIndex];
2007 if (angle->segment() == this && angle->start() == end &&
2008 angle->end() == start) {
2009 firstIndex = angleIndex;
2010 break;
2011 }
2012 }
2013 return firstIndex;
2014}
2015
caryclark@google.com07393ca2013-04-08 11:47:37 +00002016// FIXME: either:
2017// a) mark spans with either end unsortable as done, or
2018// b) rewrite findTop / findTopSegment / findTopContour to iterate further
2019// when encountering an unsortable span
2020
2021// OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2022// and use more concise logic like the old edge walker code?
2023// FIXME: this needs to deal with coincident edges
2024SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable,
2025 bool onlySortable) {
2026 // iterate through T intersections and return topmost
2027 // topmost tangent from y-min to first pt is closer to horizontal
2028 SkASSERT(!done());
2029 int firstT = -1;
2030 /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT);
2031 if (firstT < 0) {
2032 *unsortable = true;
2033 firstT = 0;
2034 while (fTs[firstT].fDone) {
2035 SkASSERT(firstT < fTs.count());
2036 ++firstT;
2037 }
2038 *tIndexPtr = firstT;
2039 *endIndexPtr = nextExactSpan(firstT, 1);
2040 return this;
2041 }
2042 // sort the edges to find the leftmost
2043 int step = 1;
2044 int end = nextSpan(firstT, step);
2045 if (end == -1) {
2046 step = -1;
2047 end = nextSpan(firstT, step);
2048 SkASSERT(end != -1);
2049 }
2050 // if the topmost T is not on end, or is three-way or more, find left
2051 // look for left-ness from tLeft to firstT (matching y of other)
caryclark@google.comd892bd82013-06-17 14:10:36 +00002052 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002053 SkASSERT(firstT - end != 0);
2054 addTwoAngles(end, firstT, &angles);
caryclark@google.com570863f2013-09-16 15:55:01 +00002055 if (!buildAngles(firstT, &angles, true) && onlySortable) {
2056// *unsortable = true;
2057// return NULL;
2058 }
caryclark@google.comd892bd82013-06-17 14:10:36 +00002059 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002060 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMayBeUnordered_SortAngleKind);
caryclark@google.com570863f2013-09-16 15:55:01 +00002061 if (onlySortable && !sortable) {
2062 *unsortable = true;
2063 return NULL;
2064 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002065 int first = SK_MaxS32;
2066 SkScalar top = SK_ScalarMax;
2067 int count = sorted.count();
2068 for (int index = 0; index < count; ++index) {
2069 const SkOpAngle* angle = sorted[index];
caryclark@google.com570863f2013-09-16 15:55:01 +00002070 if (onlySortable && angle->unorderable()) {
2071 continue;
2072 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002073 SkOpSegment* next = angle->segment();
2074 SkPathOpsBounds bounds;
2075 next->subDivideBounds(angle->end(), angle->start(), &bounds);
2076 if (approximately_greater(top, bounds.fTop)) {
2077 top = bounds.fTop;
2078 first = index;
2079 }
2080 }
2081 SkASSERT(first < SK_MaxS32);
2082#if DEBUG_SORT // || DEBUG_SWAP_TOP
caryclark@google.com07e97fc2013-07-08 17:17:02 +00002083 sorted[first]->segment()->debugShowSort(__FUNCTION__, sorted, first, 0, 0, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002084#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00002085 // skip edges that have already been processed
2086 firstT = first - 1;
2087 SkOpSegment* leftSegment;
2088 do {
2089 if (++firstT == count) {
2090 firstT = 0;
2091 }
2092 const SkOpAngle* angle = sorted[firstT];
2093 SkASSERT(!onlySortable || !angle->unsortable());
2094 leftSegment = angle->segment();
2095 *tIndexPtr = angle->end();
2096 *endIndexPtr = angle->start();
2097 } while (leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone);
2098 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
2099 const int tIndex = *tIndexPtr;
2100 const int endIndex = *endIndexPtr;
2101 if (!leftSegment->clockwise(tIndex, endIndex)) {
2102 bool swap = !leftSegment->monotonicInY(tIndex, endIndex)
2103 && !leftSegment->serpentine(tIndex, endIndex);
2104 #if DEBUG_SWAP_TOP
2105 SkDebugf("%s swap=%d serpentine=%d containedByEnds=%d monotonic=%d\n", __FUNCTION__,
2106 swap,
2107 leftSegment->serpentine(tIndex, endIndex),
2108 leftSegment->controlsContainedByEnds(tIndex, endIndex),
2109 leftSegment->monotonicInY(tIndex, endIndex));
2110 #endif
2111 if (swap) {
2112 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first
2113 // sorted but merely the first not already processed (i.e., not done)
2114 SkTSwap(*tIndexPtr, *endIndexPtr);
2115 }
2116 }
2117 }
2118 SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny);
2119 return leftSegment;
2120}
2121
2122// FIXME: not crazy about this
2123// when the intersections are performed, the other index is into an
2124// incomplete array. As the array grows, the indices become incorrect
2125// while the following fixes the indices up again, it isn't smart about
2126// skipping segments whose indices are already correct
2127// assuming we leave the code that wrote the index in the first place
caryclark@google.com570863f2013-09-16 15:55:01 +00002128// FIXME: if called after remove, this needs to correct tiny
caryclark@google.com07393ca2013-04-08 11:47:37 +00002129void SkOpSegment::fixOtherTIndex() {
2130 int iCount = fTs.count();
2131 for (int i = 0; i < iCount; ++i) {
2132 SkOpSpan& iSpan = fTs[i];
2133 double oT = iSpan.fOtherT;
2134 SkOpSegment* other = iSpan.fOther;
2135 int oCount = other->fTs.count();
caryclark@google.com4fdbb222013-07-23 15:27:41 +00002136 SkDEBUGCODE(iSpan.fOtherIndex = -1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002137 for (int o = 0; o < oCount; ++o) {
2138 SkOpSpan& oSpan = other->fTs[o];
2139 if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan.fT) {
2140 iSpan.fOtherIndex = o;
caryclark@google.com4fdbb222013-07-23 15:27:41 +00002141 oSpan.fOtherIndex = i;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002142 break;
2143 }
2144 }
caryclark@google.com4fdbb222013-07-23 15:27:41 +00002145 SkASSERT(iSpan.fOtherIndex >= 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002146 }
2147}
2148
2149void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
2150 fDoneSpans = 0;
2151 fOperand = operand;
2152 fXor = evenOdd;
2153 fPts = pts;
2154 fVerb = verb;
2155}
2156
2157void SkOpSegment::initWinding(int start, int end) {
2158 int local = spanSign(start, end);
2159 int oppLocal = oppSign(start, end);
2160 (void) markAndChaseWinding(start, end, local, oppLocal);
2161 // OPTIMIZATION: the reverse mark and chase could skip the first marking
2162 (void) markAndChaseWinding(end, start, local, oppLocal);
2163}
2164
2165/*
2166when we start with a vertical intersect, we try to use the dx to determine if the edge is to
2167the left or the right of vertical. This determines if we need to add the span's
2168sign or not. However, this isn't enough.
2169If the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed.
2170If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
2171from has the same x direction as this span, the winding should change. If the dx is opposite, then
2172the same winding is shared by both.
2173*/
2174void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkScalar hitDx,
2175 int oppWind, SkScalar hitOppDx) {
2176 SkASSERT(hitDx || !winding);
reed@google.com277c3f82013-05-31 15:17:50 +00002177 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002178 SkASSERT(dx);
2179 int windVal = windValue(SkMin32(start, end));
2180#if DEBUG_WINDING_AT_T
2181 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
2182 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
2183#endif
2184 if (!winding) {
2185 winding = dx < 0 ? windVal : -windVal;
2186 } else if (winding * dx < 0) {
2187 int sideWind = winding + (dx < 0 ? windVal : -windVal);
2188 if (abs(winding) < abs(sideWind)) {
2189 winding = sideWind;
2190 }
2191 }
2192#if DEBUG_WINDING_AT_T
2193 SkDebugf(" winding=%d\n", winding);
2194#endif
2195 SkDEBUGCODE(int oppLocal = oppSign(start, end));
2196 SkASSERT(hitOppDx || !oppWind || !oppLocal);
2197 int oppWindVal = oppValue(SkMin32(start, end));
2198 if (!oppWind) {
2199 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
2200 } else if (hitOppDx * dx >= 0) {
2201 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
2202 if (abs(oppWind) < abs(oppSideWind)) {
2203 oppWind = oppSideWind;
2204 }
2205 }
2206 (void) markAndChaseWinding(start, end, winding, oppWind);
2207}
2208
caryclark@google.com07393ca2013-04-08 11:47:37 +00002209// OPTIMIZE: successive calls could start were the last leaves off
2210// or calls could specialize to walk forwards or backwards
2211bool SkOpSegment::isMissing(double startT) const {
2212 size_t tCount = fTs.count();
2213 for (size_t index = 0; index < tCount; ++index) {
2214 if (approximately_zero(startT - fTs[index].fT)) {
2215 return false;
2216 }
2217 }
2218 return true;
2219}
2220
2221bool SkOpSegment::isSimple(int end) const {
2222 int count = fTs.count();
2223 if (count == 2) {
2224 return true;
2225 }
2226 double t = fTs[end].fT;
2227 if (approximately_less_than_zero(t)) {
2228 return !approximately_less_than_zero(fTs[1].fT);
2229 }
2230 if (approximately_greater_than_one(t)) {
2231 return !approximately_greater_than_one(fTs[count - 2].fT);
2232 }
2233 return false;
2234}
2235
2236// this span is excluded by the winding rule -- chase the ends
2237// as long as they are unambiguous to mark connections as done
2238// and give them the same winding value
2239SkOpSpan* SkOpSegment::markAndChaseDone(int index, int endIndex, int winding) {
2240 int step = SkSign32(endIndex - index);
2241 int min = SkMin32(index, endIndex);
2242 markDone(min, winding);
2243 SkOpSpan* last;
2244 SkOpSegment* other = this;
2245 while ((other = other->nextChase(&index, step, &min, &last))) {
2246 other->markDone(min, winding);
2247 }
2248 return last;
2249}
2250
2251SkOpSpan* SkOpSegment::markAndChaseDoneBinary(const SkOpAngle* angle, int winding, int oppWinding) {
2252 int index = angle->start();
2253 int endIndex = angle->end();
2254 int step = SkSign32(endIndex - index);
2255 int min = SkMin32(index, endIndex);
2256 markDoneBinary(min, winding, oppWinding);
2257 SkOpSpan* last;
2258 SkOpSegment* other = this;
2259 while ((other = other->nextChase(&index, step, &min, &last))) {
2260 other->markDoneBinary(min, winding, oppWinding);
2261 }
2262 return last;
2263}
2264
2265SkOpSpan* SkOpSegment::markAndChaseDoneBinary(int index, int endIndex) {
2266 int step = SkSign32(endIndex - index);
2267 int min = SkMin32(index, endIndex);
2268 markDoneBinary(min);
2269 SkOpSpan* last;
2270 SkOpSegment* other = this;
2271 while ((other = other->nextChase(&index, step, &min, &last))) {
2272 if (other->done()) {
2273 return NULL;
2274 }
2275 other->markDoneBinary(min);
2276 }
2277 return last;
2278}
2279
2280SkOpSpan* SkOpSegment::markAndChaseDoneUnary(int index, int endIndex) {
2281 int step = SkSign32(endIndex - index);
2282 int min = SkMin32(index, endIndex);
2283 markDoneUnary(min);
2284 SkOpSpan* last;
2285 SkOpSegment* other = this;
2286 while ((other = other->nextChase(&index, step, &min, &last))) {
2287 if (other->done()) {
2288 return NULL;
2289 }
2290 other->markDoneUnary(min);
2291 }
2292 return last;
2293}
2294
2295SkOpSpan* SkOpSegment::markAndChaseDoneUnary(const SkOpAngle* angle, int winding) {
2296 int index = angle->start();
2297 int endIndex = angle->end();
2298 return markAndChaseDone(index, endIndex, winding);
2299}
2300
2301SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, const int winding) {
2302 int index = angle->start();
2303 int endIndex = angle->end();
2304 int step = SkSign32(endIndex - index);
2305 int min = SkMin32(index, endIndex);
2306 markWinding(min, winding);
2307 SkOpSpan* last;
2308 SkOpSegment* other = this;
2309 while ((other = other->nextChase(&index, step, &min, &last))) {
2310 if (other->fTs[min].fWindSum != SK_MinS32) {
2311 SkASSERT(other->fTs[min].fWindSum == winding);
2312 return NULL;
2313 }
2314 other->markWinding(min, winding);
2315 }
2316 return last;
2317}
2318
2319SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
2320 int min = SkMin32(index, endIndex);
2321 int step = SkSign32(endIndex - index);
2322 markWinding(min, winding, oppWinding);
2323 SkOpSpan* last;
2324 SkOpSegment* other = this;
2325 while ((other = other->nextChase(&index, step, &min, &last))) {
2326 if (other->fTs[min].fWindSum != SK_MinS32) {
2327 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
2328 return NULL;
2329 }
2330 other->markWinding(min, winding, oppWinding);
2331 }
2332 return last;
2333}
2334
2335SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding) {
2336 int start = angle->start();
2337 int end = angle->end();
2338 return markAndChaseWinding(start, end, winding, oppWinding);
2339}
2340
2341SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, bool activeAngle,
2342 const SkOpAngle* angle) {
2343 SkASSERT(angle->segment() == this);
2344 if (UseInnerWinding(maxWinding, sumWinding)) {
2345 maxWinding = sumWinding;
2346 }
2347 SkOpSpan* last;
2348 if (activeAngle) {
2349 last = markAndChaseWinding(angle, maxWinding);
2350 } else {
2351 last = markAndChaseDoneUnary(angle, maxWinding);
2352 }
caryclark@google.com570863f2013-09-16 15:55:01 +00002353#if DEBUG_WINDING
2354 if (last) {
2355 SkDebugf("%s last id=%d windSum=%d small=%d\n", __FUNCTION__,
2356 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
2357 last->fSmall);
2358 }
2359#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00002360 return last;
2361}
2362
2363SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
2364 int oppSumWinding, bool activeAngle, const SkOpAngle* angle) {
2365 SkASSERT(angle->segment() == this);
2366 if (UseInnerWinding(maxWinding, sumWinding)) {
2367 maxWinding = sumWinding;
2368 }
2369 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
2370 oppMaxWinding = oppSumWinding;
2371 }
2372 SkOpSpan* last;
2373 if (activeAngle) {
2374 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
2375 } else {
2376 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
2377 }
caryclark@google.com570863f2013-09-16 15:55:01 +00002378#if DEBUG_WINDING
2379 if (last) {
2380 SkDebugf("%s last id=%d windSum=%d small=%d\n", __FUNCTION__,
2381 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
2382 last->fSmall);
2383 }
2384#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00002385 return last;
2386}
2387
2388// FIXME: this should also mark spans with equal (x,y)
2389// This may be called when the segment is already marked done. While this
2390// wastes time, it shouldn't do any more than spin through the T spans.
2391// OPTIMIZATION: abort on first done found (assuming that this code is
2392// always called to mark segments done).
2393void SkOpSegment::markDone(int index, int winding) {
2394 // SkASSERT(!done());
2395 SkASSERT(winding);
2396 double referenceT = fTs[index].fT;
2397 int lesser = index;
2398 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2399 markOneDone(__FUNCTION__, lesser, winding);
2400 }
2401 do {
2402 markOneDone(__FUNCTION__, index, winding);
2403 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2404}
2405
2406void SkOpSegment::markDoneBinary(int index, int winding, int oppWinding) {
2407 // SkASSERT(!done());
2408 SkASSERT(winding || oppWinding);
2409 double referenceT = fTs[index].fT;
2410 int lesser = index;
2411 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2412 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
2413 }
2414 do {
2415 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
2416 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2417}
2418
2419void SkOpSegment::markDoneBinary(int index) {
2420 double referenceT = fTs[index].fT;
2421 int lesser = index;
2422 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2423 markOneDoneBinary(__FUNCTION__, lesser);
2424 }
2425 do {
2426 markOneDoneBinary(__FUNCTION__, index);
2427 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2428}
2429
2430void SkOpSegment::markDoneUnary(int index) {
2431 double referenceT = fTs[index].fT;
2432 int lesser = index;
2433 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2434 markOneDoneUnary(__FUNCTION__, lesser);
2435 }
2436 do {
2437 markOneDoneUnary(__FUNCTION__, index);
2438 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2439}
2440
2441void SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) {
2442 SkOpSpan* span = markOneWinding(funName, tIndex, winding);
2443 if (!span) {
2444 return;
2445 }
2446 span->fDone = true;
2447 fDoneSpans++;
2448}
2449
2450void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) {
2451 SkOpSpan* span = verifyOneWinding(funName, tIndex);
2452 if (!span) {
2453 return;
2454 }
2455 span->fDone = true;
2456 fDoneSpans++;
2457}
2458
2459void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
2460 SkOpSpan* span = markOneWinding(funName, tIndex, winding, oppWinding);
2461 if (!span) {
2462 return;
2463 }
2464 span->fDone = true;
2465 fDoneSpans++;
2466}
2467
2468void SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) {
2469 SkOpSpan* span = verifyOneWindingU(funName, tIndex);
2470 if (!span) {
2471 return;
2472 }
2473 span->fDone = true;
2474 fDoneSpans++;
2475}
2476
2477SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding) {
2478 SkOpSpan& span = fTs[tIndex];
2479 if (span.fDone) {
2480 return NULL;
2481 }
2482#if DEBUG_MARK_DONE
2483 debugShowNewWinding(funName, span, winding);
2484#endif
2485 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com570863f2013-09-16 15:55:01 +00002486 SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002487 span.fWindSum = winding;
2488 return &span;
2489}
2490
2491SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding,
2492 int oppWinding) {
2493 SkOpSpan& span = fTs[tIndex];
2494 if (span.fDone) {
2495 return NULL;
2496 }
2497#if DEBUG_MARK_DONE
2498 debugShowNewWinding(funName, span, winding, oppWinding);
2499#endif
2500 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
caryclark@google.com570863f2013-09-16 15:55:01 +00002501 SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002502 span.fWindSum = winding;
2503 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00002504 SkASSERT(abs(oppWinding) <= SkPathOpsDebug::gMaxWindSum);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002505 span.fOppSum = oppWinding;
2506 return &span;
2507}
2508
2509// from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
2510bool SkOpSegment::clockwise(int tStart, int tEnd) const {
2511 SkASSERT(fVerb != SkPath::kLine_Verb);
2512 SkPoint edge[4];
2513 subDivide(tStart, tEnd, edge);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002514 int points = SkPathOpsVerbToPoints(fVerb);
2515 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002516 if (fVerb == SkPath::kCubic_Verb) {
2517 SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY);
2518 if (edge[1].fY < lesser && edge[2].fY < lesser) {
2519 SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1].fY} }};
2520 SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3].fY} }};
2521 if (SkIntersections::Test(tangent1, tangent2)) {
2522 SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2523 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY);
2524 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY);
2525 return sum <= 0;
2526 }
2527 }
2528 }
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002529 for (int idx = 0; idx < points; ++idx){
caryclark@google.com07393ca2013-04-08 11:47:37 +00002530 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
2531 }
2532 return sum <= 0;
2533}
2534
2535bool SkOpSegment::monotonicInY(int tStart, int tEnd) const {
2536 if (fVerb == SkPath::kLine_Verb) {
2537 return false;
2538 }
2539 if (fVerb == SkPath::kQuad_Verb) {
2540 SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2541 return dst.monotonicInY();
2542 }
2543 SkASSERT(fVerb == SkPath::kCubic_Verb);
2544 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2545 return dst.monotonicInY();
2546}
2547
2548bool SkOpSegment::serpentine(int tStart, int tEnd) const {
2549 if (fVerb != SkPath::kCubic_Verb) {
2550 return false;
2551 }
2552 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2553 return dst.serpentine();
2554}
2555
2556SkOpSpan* SkOpSegment::verifyOneWinding(const char* funName, int tIndex) {
2557 SkOpSpan& span = fTs[tIndex];
2558 if (span.fDone) {
2559 return NULL;
2560 }
2561#if DEBUG_MARK_DONE
2562 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
2563#endif
2564 SkASSERT(span.fWindSum != SK_MinS32);
2565 SkASSERT(span.fOppSum != SK_MinS32);
2566 return &span;
2567}
2568
2569SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) {
2570 SkOpSpan& span = fTs[tIndex];
2571 if (span.fDone) {
2572 return NULL;
2573 }
2574#if DEBUG_MARK_DONE
2575 debugShowNewWinding(funName, span, span.fWindSum);
2576#endif
2577 SkASSERT(span.fWindSum != SK_MinS32);
2578 return &span;
2579}
2580
2581// note that just because a span has one end that is unsortable, that's
2582// not enough to mark it done. The other end may be sortable, allowing the
2583// span to be added.
2584// FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
2585void SkOpSegment::markUnsortable(int start, int end) {
2586 SkOpSpan* span = &fTs[start];
2587 if (start < end) {
2588#if DEBUG_UNSORTABLE
2589 debugShowNewWinding(__FUNCTION__, *span, 0);
2590#endif
2591 span->fUnsortableStart = true;
2592 } else {
2593 --span;
2594#if DEBUG_UNSORTABLE
2595 debugShowNewWinding(__FUNCTION__, *span, 0);
2596#endif
2597 span->fUnsortableEnd = true;
2598 }
2599 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
2600 return;
2601 }
2602 span->fDone = true;
2603 fDoneSpans++;
2604}
2605
2606void SkOpSegment::markWinding(int index, int winding) {
2607// SkASSERT(!done());
2608 SkASSERT(winding);
2609 double referenceT = fTs[index].fT;
2610 int lesser = index;
2611 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2612 markOneWinding(__FUNCTION__, lesser, winding);
2613 }
2614 do {
2615 markOneWinding(__FUNCTION__, index, winding);
2616 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2617}
2618
2619void SkOpSegment::markWinding(int index, int winding, int oppWinding) {
2620// SkASSERT(!done());
2621 SkASSERT(winding || oppWinding);
2622 double referenceT = fTs[index].fT;
2623 int lesser = index;
2624 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2625 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
2626 }
2627 do {
2628 markOneWinding(__FUNCTION__, index, winding, oppWinding);
2629 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2630}
2631
2632void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) {
2633 int nextDoorWind = SK_MaxS32;
2634 int nextOppWind = SK_MaxS32;
2635 if (tIndex > 0) {
2636 const SkOpSpan& below = fTs[tIndex - 1];
2637 if (approximately_negative(t - below.fT)) {
2638 nextDoorWind = below.fWindValue;
2639 nextOppWind = below.fOppValue;
2640 }
2641 }
2642 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
2643 const SkOpSpan& above = fTs[tIndex + 1];
2644 if (approximately_negative(above.fT - t)) {
2645 nextDoorWind = above.fWindValue;
2646 nextOppWind = above.fOppValue;
2647 }
2648 }
2649 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
2650 const SkOpSpan& below = fTs[tIndex - 1];
2651 nextDoorWind = below.fWindValue;
2652 nextOppWind = below.fOppValue;
2653 }
2654 if (nextDoorWind != SK_MaxS32) {
2655 SkOpSpan& newSpan = fTs[tIndex];
2656 newSpan.fWindValue = nextDoorWind;
2657 newSpan.fOppValue = nextOppWind;
2658 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
2659 newSpan.fDone = true;
2660 ++fDoneSpans;
2661 }
2662 }
2663}
2664
caryclark@google.com570863f2013-09-16 15:55:01 +00002665double SkOpSegment::missingNear(double t, const SkOpSegment* other, const SkPoint& startPt,
2666 const SkPoint& endPt) const {
2667 int count = this->count();
2668 for (int index = 0; index < count; ++index) {
2669 const SkOpSpan& span = this->span(index);
2670 if (span.fOther == other && span.fPt == startPt) {
2671 double midT = (t + span.fT) / 2;
2672 if (betweenPoints(midT, startPt, endPt)) {
2673 return span.fT;
2674 }
2675 }
2676 }
2677 return -1;
2678}
2679
caryclark@google.com07393ca2013-04-08 11:47:37 +00002680// return span if when chasing, two or more radiating spans are not done
2681// OPTIMIZATION: ? multiple spans is detected when there is only one valid
2682// candidate and the remaining spans have windValue == 0 (canceled by
2683// coincidence). The coincident edges could either be removed altogether,
2684// or this code could be more complicated in detecting this case. Worth it?
2685bool SkOpSegment::multipleSpans(int end) const {
2686 return end > 0 && end < fTs.count() - 1;
2687}
2688
2689bool SkOpSegment::nextCandidate(int* start, int* end) const {
2690 while (fTs[*end].fDone) {
2691 if (fTs[*end].fT == 1) {
2692 return false;
2693 }
2694 ++(*end);
2695 }
2696 *start = *end;
2697 *end = nextExactSpan(*start, 1);
2698 return true;
2699}
2700
2701SkOpSegment* SkOpSegment::nextChase(int* index, const int step, int* min, SkOpSpan** last) {
2702 int end = nextExactSpan(*index, step);
2703 SkASSERT(end >= 0);
caryclark@google.com570863f2013-09-16 15:55:01 +00002704 if (fTs[end].fSmall) {
2705 *last = NULL;
2706 return NULL;
2707 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002708 if (multipleSpans(end)) {
2709 *last = &fTs[end];
2710 return NULL;
2711 }
2712 const SkOpSpan& endSpan = fTs[end];
2713 SkOpSegment* other = endSpan.fOther;
2714 *index = endSpan.fOtherIndex;
fmalita@google.com22eb7942013-05-01 20:35:51 +00002715 SkASSERT(*index >= 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002716 int otherEnd = other->nextExactSpan(*index, step);
2717 SkASSERT(otherEnd >= 0);
2718 *min = SkMin32(*index, otherEnd);
caryclark@google.com570863f2013-09-16 15:55:01 +00002719 if (other->fTs[*min].fSmall) {
caryclark@google.coma5e55922013-05-07 18:51:31 +00002720 *last = NULL;
2721 return NULL;
2722 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002723 return other;
2724}
2725
2726// This has callers for two different situations: one establishes the end
2727// of the current span, and one establishes the beginning of the next span
2728// (thus the name). When this is looking for the end of the current span,
2729// coincidence is found when the beginning Ts contain -step and the end
2730// contains step. When it is looking for the beginning of the next, the
2731// first Ts found can be ignored and the last Ts should contain -step.
2732// OPTIMIZATION: probably should split into two functions
2733int SkOpSegment::nextSpan(int from, int step) const {
2734 const SkOpSpan& fromSpan = fTs[from];
2735 int count = fTs.count();
2736 int to = from;
2737 while (step > 0 ? ++to < count : --to >= 0) {
2738 const SkOpSpan& span = fTs[to];
2739 if (approximately_zero(span.fT - fromSpan.fT)) {
2740 continue;
2741 }
2742 return to;
2743 }
2744 return -1;
2745}
2746
2747// FIXME
2748// this returns at any difference in T, vs. a preset minimum. It may be
2749// that all callers to nextSpan should use this instead.
caryclark@google.com07393ca2013-04-08 11:47:37 +00002750int SkOpSegment::nextExactSpan(int from, int step) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002751 int to = from;
caryclark@google.com570863f2013-09-16 15:55:01 +00002752 if (step < 0) {
2753 const SkOpSpan& fromSpan = fTs[from];
2754 while (--to >= 0) {
2755 const SkOpSpan& span = fTs[to];
2756 if (precisely_negative(fromSpan.fT - span.fT) || span.fTiny) {
2757 continue;
2758 }
2759 return to;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002760 }
caryclark@google.com570863f2013-09-16 15:55:01 +00002761 } else {
2762 while (fTs[from].fTiny) {
2763 from++;
2764 }
2765 const SkOpSpan& fromSpan = fTs[from];
2766 int count = fTs.count();
2767 while (++to < count) {
2768 const SkOpSpan& span = fTs[to];
2769 if (precisely_negative(span.fT - fromSpan.fT)) {
2770 continue;
2771 }
2772 return to;
2773 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002774 }
2775 return -1;
2776}
2777
2778void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
2779 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) {
2780 int deltaSum = spanSign(index, endIndex);
2781 int oppDeltaSum = oppSign(index, endIndex);
2782 if (operand()) {
2783 *maxWinding = *sumSuWinding;
2784 *sumWinding = *sumSuWinding -= deltaSum;
2785 *oppMaxWinding = *sumMiWinding;
2786 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
2787 } else {
2788 *maxWinding = *sumMiWinding;
2789 *sumWinding = *sumMiWinding -= deltaSum;
2790 *oppMaxWinding = *sumSuWinding;
2791 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
2792 }
caryclark@google.com570863f2013-09-16 15:55:01 +00002793 SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum);
2794 SkASSERT(abs(*oppSumWinding) <= SkPathOpsDebug::gMaxWindSum);
2795}
2796
2797void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding,
2798 int* maxWinding, int* sumWinding) {
2799 int deltaSum = spanSign(index, endIndex);
2800 *maxWinding = *sumMiWinding;
2801 *sumWinding = *sumMiWinding -= deltaSum;
2802 SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002803}
2804
2805// This marks all spans unsortable so that this info is available for early
2806// exclusion in find top and others. This could be optimized to only mark
2807// adjacent spans that unsortable. However, this makes it difficult to later
2808// determine starting points for edge detection in find top and the like.
caryclark@google.comd892bd82013-06-17 14:10:36 +00002809bool SkOpSegment::SortAngles(const SkTArray<SkOpAngle, true>& angles,
2810 SkTArray<SkOpAngle*, true>* angleList,
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002811 SortAngleKind orderKind) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002812 bool sortable = true;
2813 int angleCount = angles.count();
2814 int angleIndex;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002815 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2816 const SkOpAngle& angle = angles[angleIndex];
caryclark@google.comd892bd82013-06-17 14:10:36 +00002817 angleList->push_back(const_cast<SkOpAngle*>(&angle));
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002818#if DEBUG_ANGLE
2819 (*(angleList->end() - 1))->setID(angleIndex);
2820#endif
2821 sortable &= !(angle.unsortable() || (orderKind == kMustBeOrdered_SortAngleKind
2822 && angle.unorderable()));
caryclark@google.com07393ca2013-04-08 11:47:37 +00002823 }
2824 if (sortable) {
caryclark@google.com7dfbb072013-04-22 14:37:05 +00002825 SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002826 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002827 if (angles[angleIndex].unsortable() || (orderKind == kMustBeOrdered_SortAngleKind
2828 && angles[angleIndex].unorderable())) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002829 sortable = false;
2830 break;
2831 }
2832 }
2833 }
2834 if (!sortable) {
2835 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2836 const SkOpAngle& angle = angles[angleIndex];
2837 angle.segment()->markUnsortable(angle.start(), angle.end());
2838 }
2839 }
2840 return sortable;
2841}
2842
caryclark@google.com570863f2013-09-16 15:55:01 +00002843// set segments to unsortable if angle is unsortable, but do not set all angles
2844// note that for a simple 4 way crossing, two of the edges may be orderable even though
2845// two edges are too short to be orderable.
2846// perhaps some classes of unsortable angles should make all shared angles unsortable, but
2847// simple lines that have tiny crossings are always sortable on the large ends
2848// OPTIMIZATION: check earlier when angles are added to input if any are unsortable
2849// may make sense then to mark all segments in angle sweep as unsortableStart/unsortableEnd
2850// solely for the purpose of short-circuiting future angle building around this center
2851bool SkOpSegment::SortAngles2(const SkTArray<SkOpAngle, true>& angles,
2852 SkTArray<SkOpAngle*, true>* angleList) {
2853 int angleCount = angles.count();
2854 int angleIndex;
2855 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2856 const SkOpAngle& angle = angles[angleIndex];
2857 if (angle.unsortable()) {
2858 return false;
2859 }
2860 angleList->push_back(const_cast<SkOpAngle*>(&angle));
2861#if DEBUG_ANGLE
2862 (*(angleList->end() - 1))->setID(angleIndex);
2863#endif
2864 }
2865 SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1);
2866 // at this point angles are sorted but individually may not be orderable
2867 // this means that only adjcent orderable segments may transfer winding
2868 return true;
2869}
2870
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002871// return true if midpoints were computed
2872bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const {
2873 SkASSERT(start != end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002874 edge[0] = fTs[start].fPt;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002875 int points = SkPathOpsVerbToPoints(fVerb);
2876 edge[points] = fTs[end].fPt;
2877 if (fVerb == SkPath::kLine_Verb) {
2878 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002879 }
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002880 double startT = fTs[start].fT;
2881 double endT = fTs[end].fT;
2882 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
2883 // don't compute midpoints if we already have them
2884 if (fVerb == SkPath::kQuad_Verb) {
2885 edge[1] = fPts[1];
2886 return false;
2887 }
2888 SkASSERT(fVerb == SkPath::kCubic_Verb);
2889 if (start < end) {
2890 edge[1] = fPts[1];
2891 edge[2] = fPts[2];
2892 return false;
2893 }
2894 edge[1] = fPts[2];
2895 edge[2] = fPts[1];
2896 return false;
2897 }
2898 const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[points].fY }};
2899 if (fVerb == SkPath::kQuad_Verb) {
2900 edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
2901 } else {
2902 SkASSERT(fVerb == SkPath::kCubic_Verb);
2903 SkDPoint ctrl[2];
2904 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
2905 edge[1] = ctrl[0].asSkPoint();
2906 edge[2] = ctrl[1].asSkPoint();
2907 }
2908 return true;
2909}
2910
2911// return true if midpoints were computed
2912bool SkOpSegment::subDivide(int start, int end, SkDCubic* result) const {
2913 SkASSERT(start != end);
2914 (*result)[0].set(fTs[start].fPt);
2915 int points = SkPathOpsVerbToPoints(fVerb);
2916 (*result)[points].set(fTs[end].fPt);
2917 if (fVerb == SkPath::kLine_Verb) {
2918 return false;
2919 }
2920 double startT = fTs[start].fT;
2921 double endT = fTs[end].fT;
2922 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
2923 // don't compute midpoints if we already have them
2924 if (fVerb == SkPath::kQuad_Verb) {
2925 (*result)[1].set(fPts[1]);
2926 return false;
2927 }
2928 SkASSERT(fVerb == SkPath::kCubic_Verb);
2929 if (start < end) {
2930 (*result)[1].set(fPts[1]);
2931 (*result)[2].set(fPts[2]);
2932 return false;
2933 }
2934 (*result)[1].set(fPts[2]);
2935 (*result)[2].set(fPts[1]);
2936 return false;
2937 }
2938 if (fVerb == SkPath::kQuad_Verb) {
2939 (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], startT, endT);
2940 } else {
2941 SkASSERT(fVerb == SkPath::kCubic_Verb);
2942 SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*result)[1]);
2943 }
2944 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002945}
2946
2947void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const {
2948 SkPoint edge[4];
2949 subDivide(start, end, edge);
reed@google.com277c3f82013-05-31 15:17:50 +00002950 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002951}
2952
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002953bool SkOpSegment::isTiny(const SkOpAngle* angle) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002954 int start = angle->start();
2955 int end = angle->end();
2956 const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
2957 return mSpan.fTiny;
2958}
2959
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002960bool SkOpSegment::isTiny(int index) const {
2961 return fTs[index].fTiny;
2962}
2963
caryclark@google.com570863f2013-09-16 15:55:01 +00002964void SkOpSegment::TrackOutsidePair(SkTArray<SkPoint, true>* outsidePts, const SkPoint& endPt,
2965 const SkPoint& startPt) {
2966 int outCount = outsidePts->count();
2967 if (outCount == 0 || endPt != (*outsidePts)[outCount - 2]) {
2968 outsidePts->push_back(endPt);
2969 outsidePts->push_back(startPt);
2970 }
2971}
2972
2973void SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoint& startPt) {
2974 int outCount = outsidePts->count();
2975 if (outCount == 0 || startPt != (*outsidePts)[outCount - 1]) {
2976 outsidePts->push_back(startPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002977 }
2978}
2979
2980void SkOpSegment::undoneSpan(int* start, int* end) {
2981 size_t tCount = fTs.count();
2982 size_t index;
2983 for (index = 0; index < tCount; ++index) {
2984 if (!fTs[index].fDone) {
2985 break;
2986 }
2987 }
2988 SkASSERT(index < tCount - 1);
2989 *start = index;
2990 double startT = fTs[index].fT;
2991 while (approximately_negative(fTs[++index].fT - startT))
2992 SkASSERT(index < tCount);
2993 SkASSERT(index < tCount);
2994 *end = index;
2995}
2996
2997int SkOpSegment::updateOppWinding(int index, int endIndex) const {
2998 int lesser = SkMin32(index, endIndex);
2999 int oppWinding = oppSum(lesser);
3000 int oppSpanWinding = oppSign(index, endIndex);
3001 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
3002 && oppWinding != SK_MaxS32) {
3003 oppWinding -= oppSpanWinding;
3004 }
3005 return oppWinding;
3006}
3007
3008int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
3009 int startIndex = angle->start();
3010 int endIndex = angle->end();
3011 return updateOppWinding(endIndex, startIndex);
3012}
3013
3014int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
3015 int startIndex = angle->start();
3016 int endIndex = angle->end();
3017 return updateOppWinding(startIndex, endIndex);
3018}
3019
3020int SkOpSegment::updateWinding(int index, int endIndex) const {
3021 int lesser = SkMin32(index, endIndex);
3022 int winding = windSum(lesser);
3023 int spanWinding = spanSign(index, endIndex);
caryclark@google.com570863f2013-09-16 15:55:01 +00003024 if (winding && UseInnerWinding(winding - spanWinding, winding)
3025 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00003026 winding -= spanWinding;
3027 }
3028 return winding;
3029}
3030
3031int SkOpSegment::updateWinding(const SkOpAngle* angle) const {
3032 int startIndex = angle->start();
3033 int endIndex = angle->end();
3034 return updateWinding(endIndex, startIndex);
3035}
3036
caryclark@google.com570863f2013-09-16 15:55:01 +00003037int SkOpSegment::updateWindingReverse(int index, int endIndex) const {
3038 int lesser = SkMin32(index, endIndex);
3039 int winding = windSum(lesser);
3040 int spanWinding = spanSign(endIndex, index);
3041 if (winding && UseInnerWindingReverse(winding - spanWinding, winding)
3042 && winding != SK_MaxS32) {
3043 winding -= spanWinding;
3044 }
3045 return winding;
3046}
3047
caryclark@google.com07393ca2013-04-08 11:47:37 +00003048int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const {
3049 int startIndex = angle->start();
3050 int endIndex = angle->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00003051 return updateWindingReverse(endIndex, startIndex);
3052}
3053
3054// OPTIMIZATION: does the following also work, and is it any faster?
3055// return outerWinding * innerWinding > 0
3056// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
3057bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
3058 SkASSERT(outerWinding != SK_MaxS32);
3059 SkASSERT(innerWinding != SK_MaxS32);
3060 int absOut = abs(outerWinding);
3061 int absIn = abs(innerWinding);
3062 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
3063 return result;
3064}
3065
3066bool SkOpSegment::UseInnerWindingReverse(int outerWinding, int innerWinding) {
3067 SkASSERT(outerWinding != SK_MaxS32);
3068 SkASSERT(innerWinding != SK_MaxS32);
3069 int absOut = abs(outerWinding);
3070 int absIn = abs(innerWinding);
3071 bool result = absOut == absIn ? true : absOut < absIn;
3072 return result;
caryclark@google.com07393ca2013-04-08 11:47:37 +00003073}
3074
3075int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const {
3076 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
3077 return SK_MinS32;
3078 }
3079 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
3080 SkASSERT(winding != SK_MinS32);
3081 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
3082#if DEBUG_WINDING_AT_T
3083 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
3084#endif
3085 // see if a + change in T results in a +/- change in X (compute x'(T))
reed@google.com277c3f82013-05-31 15:17:50 +00003086 *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
caryclark@google.com07393ca2013-04-08 11:47:37 +00003087 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
3088 *dx = fPts[2].fX - fPts[1].fX - *dx;
3089 }
3090 if (*dx == 0) {
3091#if DEBUG_WINDING_AT_T
3092 SkDebugf(" dx=0 winding=SK_MinS32\n");
3093#endif
3094 return SK_MinS32;
3095 }
skia.committer@gmail.coma4aced42013-07-09 07:00:56 +00003096 if (windVal < 0) { // reverse sign if opp contour traveled in reverse
caryclark@google.com07e97fc2013-07-08 17:17:02 +00003097 *dx = -*dx;
3098 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00003099 if (winding * *dx > 0) { // if same signs, result is negative
3100 winding += *dx > 0 ? -windVal : windVal;
3101 }
3102#if DEBUG_WINDING_AT_T
3103 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding);
3104#endif
3105 return winding;
3106}
3107
3108int SkOpSegment::windSum(const SkOpAngle* angle) const {
3109 int start = angle->start();
3110 int end = angle->end();
3111 int index = SkMin32(start, end);
3112 return windSum(index);
3113}
3114
3115int SkOpSegment::windValue(const SkOpAngle* angle) const {
3116 int start = angle->start();
3117 int end = angle->end();
3118 int index = SkMin32(start, end);
3119 return windValue(index);
3120}
3121
3122int SkOpSegment::windValueAt(double t) const {
3123 int count = fTs.count();
3124 for (int index = 0; index < count; ++index) {
3125 if (fTs[index].fT == t) {
3126 return fTs[index].fWindValue;
3127 }
3128 }
3129 SkASSERT(0);
3130 return 0;
3131}
3132
3133void SkOpSegment::zeroSpan(SkOpSpan* span) {
caryclark@google.coma5e55922013-05-07 18:51:31 +00003134 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003135 span->fWindValue = 0;
3136 span->fOppValue = 0;
3137 SkASSERT(!span->fDone);
3138 span->fDone = true;
3139 ++fDoneSpans;
3140}
skia.committer@gmail.com32840172013-04-09 07:01:27 +00003141
caryclark@google.com07393ca2013-04-08 11:47:37 +00003142#if DEBUG_SWAP_TOP
3143bool SkOpSegment::controlsContainedByEnds(int tStart, int tEnd) const {
3144 if (fVerb != SkPath::kCubic_Verb) {
3145 return false;
3146 }
3147 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
3148 return dst.controlsContainedByEnds();
3149}
3150#endif
3151
3152#if DEBUG_CONCIDENT
3153// SkASSERT if pair has not already been added
3154void SkOpSegment::debugAddTPair(double t, const SkOpSegment& other, double otherT) const {
3155 for (int i = 0; i < fTs.count(); ++i) {
3156 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
3157 return;
3158 }
3159 }
3160 SkASSERT(0);
3161}
3162#endif
3163
3164#if DEBUG_CONCIDENT
3165void SkOpSegment::debugShowTs() const {
3166 SkDebugf("%s id=%d", __FUNCTION__, fID);
3167 int lastWind = -1;
3168 int lastOpp = -1;
3169 double lastT = -1;
3170 int i;
3171 for (i = 0; i < fTs.count(); ++i) {
3172 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
3173 || lastOpp != fTs[i].fOppValue;
3174 if (change && lastWind >= 0) {
3175 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3176 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3177 }
3178 if (change) {
3179 SkDebugf(" [o=%d", fTs[i].fOther->fID);
3180 lastWind = fTs[i].fWindValue;
3181 lastOpp = fTs[i].fOppValue;
3182 lastT = fTs[i].fT;
3183 } else {
3184 SkDebugf(",%d", fTs[i].fOther->fID);
3185 }
3186 }
3187 if (i <= 0) {
3188 return;
3189 }
3190 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
3191 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
3192 if (fOperand) {
3193 SkDebugf(" operand");
3194 }
3195 if (done()) {
3196 SkDebugf(" done");
3197 }
3198 SkDebugf("\n");
3199}
3200#endif
3201
caryclark@google.coma5e55922013-05-07 18:51:31 +00003202#if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
caryclark@google.com07393ca2013-04-08 11:47:37 +00003203void SkOpSegment::debugShowActiveSpans() const {
caryclark@google.com4fdbb222013-07-23 15:27:41 +00003204 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00003205 if (done()) {
3206 return;
3207 }
3208#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3209 int lastId = -1;
3210 double lastT = -1;
3211#endif
3212 for (int i = 0; i < fTs.count(); ++i) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00003213 if (fTs[i].fDone) {
3214 continue;
3215 }
caryclark@google.coma5e55922013-05-07 18:51:31 +00003216 SkASSERT(i < fTs.count() - 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003217#if DEBUG_ACTIVE_SPANS_SHORT_FORM
3218 if (lastId == fID && lastT == fTs[i].fT) {
3219 continue;
3220 }
3221 lastId = fID;
3222 lastT = fTs[i].fT;
3223#endif
3224 SkDebugf("%s id=%d", __FUNCTION__, fID);
3225 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
reed@google.com277c3f82013-05-31 15:17:50 +00003226 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00003227 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3228 }
3229 const SkOpSpan* span = &fTs[i];
3230 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", span->fT, xAtT(span), yAtT(span));
3231 int iEnd = i + 1;
3232 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) {
3233 ++iEnd;
3234 }
3235 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT);
3236 const SkOpSegment* other = fTs[i].fOther;
3237 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
3238 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
3239 if (fTs[i].fWindSum == SK_MinS32) {
3240 SkDebugf("?");
3241 } else {
3242 SkDebugf("%d", fTs[i].fWindSum);
3243 }
3244 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
3245 }
3246}
3247#endif
3248
3249
3250#if DEBUG_MARK_DONE || DEBUG_UNSORTABLE
3251void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding) {
3252 const SkPoint& pt = xyAtT(&span);
3253 SkDebugf("%s id=%d", fun, fID);
3254 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
reed@google.com277c3f82013-05-31 15:17:50 +00003255 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00003256 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3257 }
3258 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3259 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3260 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d windSum=",
3261 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
3262 (&span)[1].fT, winding);
3263 if (span.fWindSum == SK_MinS32) {
3264 SkDebugf("?");
3265 } else {
3266 SkDebugf("%d", span.fWindSum);
3267 }
3268 SkDebugf(" windValue=%d\n", span.fWindValue);
3269}
3270
3271void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding,
3272 int oppWinding) {
3273 const SkPoint& pt = xyAtT(&span);
3274 SkDebugf("%s id=%d", fun, fID);
3275 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
reed@google.com277c3f82013-05-31 15:17:50 +00003276 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00003277 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
3278 }
3279 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
3280 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
3281 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d newOppSum=%d oppSum=",
3282 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
3283 (&span)[1].fT, winding, oppWinding);
3284 if (span.fOppSum == SK_MinS32) {
3285 SkDebugf("?");
3286 } else {
3287 SkDebugf("%d", span.fOppSum);
3288 }
3289 SkDebugf(" windSum=");
3290 if (span.fWindSum == SK_MinS32) {
3291 SkDebugf("?");
3292 } else {
3293 SkDebugf("%d", span.fWindSum);
3294 }
3295 SkDebugf(" windValue=%d\n", span.fWindValue);
3296}
3297#endif
3298
3299#if DEBUG_SORT || DEBUG_SWAP_TOP
caryclark@google.comd892bd82013-06-17 14:10:36 +00003300void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles,
3301 int first, const int contourWinding,
caryclark@google.com07e97fc2013-07-08 17:17:02 +00003302 const int oppContourWinding, bool sortable) const {
caryclark@google.com570863f2013-09-16 15:55:01 +00003303 if (--SkPathOpsDebug::gSortCount < 0) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00003304 return;
3305 }
caryclark@google.com570863f2013-09-16 15:55:01 +00003306 if (!sortable) {
3307 if (angles.count() == 0) {
3308 return;
3309 }
3310 if (first < 0) {
3311 first = 0;
3312 }
3313 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00003314 SkASSERT(angles[first]->segment() == this);
caryclark@google.com07e97fc2013-07-08 17:17:02 +00003315 SkASSERT(!sortable || angles.count() > 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003316 int lastSum = contourWinding;
3317 int oppLastSum = oppContourWinding;
3318 const SkOpAngle* firstAngle = angles[first];
3319 int windSum = lastSum - spanSign(firstAngle);
3320 int oppoSign = oppSign(firstAngle);
3321 int oppWindSum = oppLastSum - oppoSign;
caryclark@google.com570863f2013-09-16 15:55:01 +00003322 #define WIND_AS_STRING(x) char x##Str[12]; \
3323 if (!SkPathOpsDebug::ValidWind(x)) strcpy(x##Str, "?"); \
3324 else SK_SNPRINTF(x##Str, sizeof(x##Str), "%d", x)
caryclark@google.com07393ca2013-04-08 11:47:37 +00003325 WIND_AS_STRING(contourWinding);
3326 WIND_AS_STRING(oppContourWinding);
3327 SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FUNCTION__,
3328 contourWindingStr, oppContourWindingStr, spanSign(angles[first]));
3329 int index = first;
3330 bool firstTime = true;
3331 do {
3332 const SkOpAngle& angle = *angles[index];
3333 const SkOpSegment& segment = *angle.segment();
3334 int start = angle.start();
3335 int end = angle.end();
3336 const SkOpSpan& sSpan = segment.fTs[start];
3337 const SkOpSpan& eSpan = segment.fTs[end];
3338 const SkOpSpan& mSpan = segment.fTs[SkMin32(start, end)];
3339 bool opp = segment.fOperand ^ fOperand;
3340 if (!firstTime) {
3341 oppoSign = segment.oppSign(&angle);
3342 if (opp) {
3343 oppLastSum = oppWindSum;
3344 oppWindSum -= segment.spanSign(&angle);
3345 if (oppoSign) {
3346 lastSum = windSum;
3347 windSum -= oppoSign;
3348 }
3349 } else {
3350 lastSum = windSum;
3351 windSum -= segment.spanSign(&angle);
3352 if (oppoSign) {
3353 oppLastSum = oppWindSum;
3354 oppWindSum -= oppoSign;
3355 }
3356 }
3357 }
3358 SkDebugf("%s [%d] %s", __FUNCTION__, index,
3359 angle.unsortable() ? "*** UNSORTABLE *** " : "");
caryclark@google.comcffbcc32013-06-04 17:59:42 +00003360 #if DEBUG_SORT_COMPACT
3361 SkDebugf("id=%d %s start=%d (%1.9g,%1.9g) end=%d (%1.9g,%1.9g)",
reed@google.com277c3f82013-05-31 15:17:50 +00003362 segment.fID, kLVerbStr[SkPathOpsVerbToPoints(segment.fVerb)],
caryclark@google.com07393ca2013-04-08 11:47:37 +00003363 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
3364 segment.xAtT(&eSpan), segment.yAtT(&eSpan));
3365 #else
3366 switch (segment.fVerb) {
3367 case SkPath::kLine_Verb:
3368 SkDebugf(LINE_DEBUG_STR, LINE_DEBUG_DATA(segment.fPts));
3369 break;
3370 case SkPath::kQuad_Verb:
3371 SkDebugf(QUAD_DEBUG_STR, QUAD_DEBUG_DATA(segment.fPts));
3372 break;
3373 case SkPath::kCubic_Verb:
3374 SkDebugf(CUBIC_DEBUG_STR, CUBIC_DEBUG_DATA(segment.fPts));
3375 break;
3376 default:
3377 SkASSERT(0);
3378 }
3379 SkDebugf(" tStart=%1.9g tEnd=%1.9g", sSpan.fT, eSpan.fT);
3380 #endif
3381 SkDebugf(" sign=%d windValue=%d windSum=", angle.sign(), mSpan.fWindValue);
caryclark@google.com570863f2013-09-16 15:55:01 +00003382 SkPathOpsDebug::WindingPrintf(mSpan.fWindSum);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003383 int last, wind;
3384 if (opp) {
3385 last = oppLastSum;
3386 wind = oppWindSum;
3387 } else {
3388 last = lastSum;
3389 wind = windSum;
3390 }
caryclark@google.com570863f2013-09-16 15:55:01 +00003391 bool useInner = SkPathOpsDebug::ValidWind(last) && SkPathOpsDebug::ValidWind(wind)
3392 && UseInnerWinding(last, wind);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003393 WIND_AS_STRING(last);
3394 WIND_AS_STRING(wind);
3395 WIND_AS_STRING(lastSum);
3396 WIND_AS_STRING(oppLastSum);
3397 WIND_AS_STRING(windSum);
3398 WIND_AS_STRING(oppWindSum);
3399 #undef WIND_AS_STRING
3400 if (!oppoSign) {
3401 SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr : lastStr);
3402 } else {
3403 SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : oppLastSumStr,
3404 opp ? windSumStr : oppWindSumStr);
3405 }
caryclark@google.com570863f2013-09-16 15:55:01 +00003406 SkDebugf(" done=%d unord=%d small=%d tiny=%d opp=%d\n",
3407 mSpan.fDone, angle.unorderable(), mSpan.fSmall, mSpan.fTiny, opp);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003408 ++index;
3409 if (index == angles.count()) {
3410 index = 0;
3411 }
3412 if (firstTime) {
3413 firstTime = false;
3414 }
3415 } while (index != first);
3416}
3417
caryclark@google.comd892bd82013-06-17 14:10:36 +00003418void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles,
caryclark@google.com07e97fc2013-07-08 17:17:02 +00003419 int first, bool sortable) {
caryclark@google.com570863f2013-09-16 15:55:01 +00003420 if (!sortable) {
3421 if (angles.count() == 0) {
3422 return;
3423 }
3424 if (first < 0) {
3425 first = 0;
3426 }
3427 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00003428 const SkOpAngle* firstAngle = angles[first];
3429 const SkOpSegment* segment = firstAngle->segment();
3430 int winding = segment->updateWinding(firstAngle);
3431 int oppWinding = segment->updateOppWinding(firstAngle);
caryclark@google.com07e97fc2013-07-08 17:17:02 +00003432 debugShowSort(fun, angles, first, winding, oppWinding, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003433}
3434
3435#endif
3436
3437#if DEBUG_SHOW_WINDING
3438int SkOpSegment::debugShowWindingValues(int slotCount, int ofInterest) const {
3439 if (!(1 << fID & ofInterest)) {
3440 return 0;
3441 }
3442 int sum = 0;
caryclark@google.comd892bd82013-06-17 14:10:36 +00003443 SkTArray<char, true> slots(slotCount * 2);
caryclark@google.com07393ca2013-04-08 11:47:37 +00003444 memset(slots.begin(), ' ', slotCount * 2);
3445 for (int i = 0; i < fTs.count(); ++i) {
3446 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
3447 // continue;
3448 // }
3449 sum += fTs[i].fWindValue;
3450 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
3451 sum += fTs[i].fOppValue;
3452 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
3453 }
3454 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
3455 slots.begin() + slotCount);
3456 return sum;
3457}
3458#endif
caryclark@google.com4fdbb222013-07-23 15:27:41 +00003459
3460void SkOpSegment::debugValidate() const {
3461#if DEBUG_VALIDATE
3462 int count = fTs.count();
3463 SkASSERT(count >= 2);
3464 SkASSERT(fTs[0].fT == 0);
3465 SkASSERT(fTs[count - 1].fT == 1);
3466 int done = 0;
3467 double t = -1;
3468 for (int i = 0; i < count; ++i) {
3469 const SkOpSpan& span = fTs[i];
3470 SkASSERT(t <= span.fT);
3471 t = span.fT;
3472 int otherIndex = span.fOtherIndex;
3473 const SkOpSegment* other = span.fOther;
3474 const SkOpSpan& otherSpan = other->fTs[otherIndex];
3475 SkASSERT(otherSpan.fPt == span.fPt);
3476 SkASSERT(otherSpan.fOtherT == t);
3477 SkASSERT(&fTs[i] == &otherSpan.fOther->fTs[otherSpan.fOtherIndex]);
3478 done += span.fDone;
3479 }
3480 SkASSERT(done == fDoneSpans);
3481#endif
3482}
caryclark@google.com570863f2013-09-16 15:55:01 +00003483
3484#ifdef SK_DEBUG
3485void SkOpSegment::dumpPts() const {
3486 int last = SkPathOpsVerbToPoints(fVerb);
3487 SkDebugf("{{");
3488 int index = 0;
3489 do {
3490 SkDPoint::DumpSkPoint(fPts[index]);
3491 SkDebugf(", ");
3492 } while (++index < last);
3493 SkDPoint::DumpSkPoint(fPts[index]);
3494 SkDebugf("}}\n");
3495}
3496
3497void SkOpSegment::dumpDPts() const {
3498 int count = SkPathOpsVerbToPoints(fVerb);
3499 SkDebugf("{{");
3500 int index = 0;
3501 do {
3502 SkDPoint dPt = {fPts[index].fX, fPts[index].fY};
3503 dPt.dump();
3504 if (index != count) {
3505 SkDebugf(", ");
3506 }
3507 } while (++index <= count);
3508 SkDebugf("}}\n");
3509}
3510
3511void SkOpSegment::dumpSpans() const {
3512 int count = this->count();
3513 for (int index = 0; index < count; ++index) {
3514 const SkOpSpan& span = this->span(index);
3515 SkDebugf("[%d] ", index);
3516 span.dump();
3517 }
3518}
3519#endif