blob: 7e69bb835b478d27e630a738811f84d840760428 [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.comd892bd82013-06-17 14:10:36 +000035enum { kOutsideTrackedTCount = 16 }; // FIXME: determine what this should be
36
caryclark@google.com07393ca2013-04-08 11:47:37 +000037// OPTIMIZATION: does the following also work, and is it any faster?
38// return outerWinding * innerWinding > 0
39// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
40bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
41 SkASSERT(outerWinding != SK_MaxS32);
42 SkASSERT(innerWinding != SK_MaxS32);
43 int absOut = abs(outerWinding);
44 int absIn = abs(innerWinding);
45 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
46 return result;
47}
48
caryclark@google.comd892bd82013-06-17 14:10:36 +000049bool SkOpSegment::activeAngle(int index, int* done, SkTArray<SkOpAngle, true>* angles) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000050 if (activeAngleInner(index, done, angles)) {
51 return true;
52 }
53 int lesser = index;
54 while (--lesser >= 0 && equalPoints(index, lesser)) {
55 if (activeAngleOther(lesser, done, angles)) {
56 return true;
57 }
58 }
59 lesser = index;
60 do {
61 if (activeAngleOther(index, done, angles)) {
62 return true;
63 }
64 } while (++index < fTs.count() && equalPoints(index, lesser));
65 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__,
190 kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
191#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.comfa2aeee2013-07-15 13:29:13 +0000212#if 0 && DEBUG_ANGLE // computed pt and actual pt may differ by more than approx eq
caryclark@google.comd892bd82013-06-17 14:10:36 +0000213 SkTArray<SkOpAngle, true>& angles = *anglesPtr;
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000214 if (angles.count() > 1) {
215 const SkOpSegment* aSeg = angles[0].segment();
216 int aStart = angles[0].start();
217 if (!aSeg->fTs[aStart].fTiny) {
218 const SkPoint& angle0Pt = aSeg->xyAtT(aStart);
219 SkDPoint newPt = (*CurveDPointAtT[SkPathOpsVerbToPoints(aSeg->fVerb)])(aSeg->fPts,
220 aSeg->fTs[aStart].fT);
221#if ONE_OFF_DEBUG
222 SkDebugf("%s t1=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g)\n", __FUNCTION__,
223 aSeg->fTs[aStart].fT, newPt.fX, newPt.fY, angle0Pt.fX, angle0Pt.fY);
224#endif
225 SkASSERT(newPt.approximatelyEqual(angle0Pt));
caryclark@google.com03610322013-04-18 15:58:21 +0000226 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000227 }
228#endif
caryclark@google.comd892bd82013-06-17 14:10:36 +0000229 angle.set(this, start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000230}
231
232void SkOpSegment::addCancelOutsides(double tStart, double oStart, SkOpSegment* other, double oEnd) {
233 int tIndex = -1;
234 int tCount = fTs.count();
235 int oIndex = -1;
236 int oCount = other->fTs.count();
237 do {
238 ++tIndex;
239 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
240 int tIndexStart = tIndex;
241 do {
242 ++oIndex;
243 } while (!approximately_negative(oStart - other->fTs[oIndex].fT) && oIndex < oCount);
244 int oIndexStart = oIndex;
245 double nextT;
246 do {
247 nextT = fTs[++tIndex].fT;
248 } while (nextT < 1 && approximately_negative(nextT - tStart));
249 double oNextT;
250 do {
251 oNextT = other->fTs[++oIndex].fT;
252 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
253 // at this point, spans before and after are at:
254 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
255 // if tIndexStart == 0, no prior span
256 // if nextT == 1, no following span
257
258 // advance the span with zero winding
259 // if the following span exists (not past the end, non-zero winding)
260 // connect the two edges
261 if (!fTs[tIndexStart].fWindValue) {
262 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
263#if DEBUG_CONCIDENT
264 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
265 __FUNCTION__, fID, other->fID, tIndexStart - 1,
266 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
267 xyAtT(tIndexStart).fY);
268#endif
269 addTPair(fTs[tIndexStart].fT, other, other->fTs[oIndex].fT, false,
270 fTs[tIndexStart].fPt);
271 }
272 if (nextT < 1 && fTs[tIndex].fWindValue) {
273#if DEBUG_CONCIDENT
274 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
275 __FUNCTION__, fID, other->fID, tIndex,
276 fTs[tIndex].fT, xyAtT(tIndex).fX,
277 xyAtT(tIndex).fY);
278#endif
279 addTPair(fTs[tIndex].fT, other, other->fTs[oIndexStart].fT, false, fTs[tIndex].fPt);
280 }
281 } else {
282 SkASSERT(!other->fTs[oIndexStart].fWindValue);
283 if (oIndexStart > 0 && other->fTs[oIndexStart - 1].fWindValue) {
284#if DEBUG_CONCIDENT
285 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
286 __FUNCTION__, fID, other->fID, oIndexStart - 1,
287 other->fTs[oIndexStart].fT, other->xyAtT(oIndexStart).fX,
288 other->xyAtT(oIndexStart).fY);
289 other->debugAddTPair(other->fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
290#endif
291 }
292 if (oNextT < 1 && other->fTs[oIndex].fWindValue) {
293#if DEBUG_CONCIDENT
294 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
295 __FUNCTION__, fID, other->fID, oIndex,
296 other->fTs[oIndex].fT, other->xyAtT(oIndex).fX,
297 other->xyAtT(oIndex).fY);
298 other->debugAddTPair(other->fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
299#endif
300 }
301 }
302}
303
caryclark@google.comd892bd82013-06-17 14:10:36 +0000304void SkOpSegment::addCoinOutsides(const SkTArray<double, true>& outsideTs, SkOpSegment* other,
caryclark@google.com07393ca2013-04-08 11:47:37 +0000305 double oEnd) {
306 // walk this to outsideTs[0]
307 // walk other to outsideTs[1]
308 // if either is > 0, add a pointer to the other, copying adjacent winding
309 int tIndex = -1;
310 int oIndex = -1;
311 double tStart = outsideTs[0];
312 double oStart = outsideTs[1];
313 do {
314 ++tIndex;
315 } while (!approximately_negative(tStart - fTs[tIndex].fT));
316 SkPoint ptStart = fTs[tIndex].fPt;
317 do {
318 ++oIndex;
319 } while (!approximately_negative(oStart - other->fTs[oIndex].fT));
320 if (tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) {
321 addTPair(tStart, other, oStart, false, ptStart);
322 }
323 tStart = fTs[tIndex].fT;
324 oStart = other->fTs[oIndex].fT;
325 do {
326 double nextT;
327 do {
328 nextT = fTs[++tIndex].fT;
329 } while (approximately_negative(nextT - tStart));
330 tStart = nextT;
331 ptStart = fTs[tIndex].fPt;
332 do {
333 nextT = other->fTs[++oIndex].fT;
334 } while (approximately_negative(nextT - oStart));
335 oStart = nextT;
336 if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) {
337 break;
338 }
339 addTPair(tStart, other, oStart, false, ptStart);
340 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
341}
342
343void SkOpSegment::addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
344 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
345 fBounds.setCubicBounds(pts);
346}
347
348void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active) const {
349 SkPoint edge[4];
350 const SkPoint* ePtr;
351 int lastT = fTs.count() - 1;
352 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
353 ePtr = fPts;
354 } else {
355 // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
356 subDivide(start, end, edge);
357 ePtr = edge;
358 }
359 if (active) {
360 bool reverse = ePtr == fPts && start != 0;
361 if (reverse) {
reed@google.com277c3f82013-05-31 15:17:50 +0000362 path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000363 switch (fVerb) {
364 case SkPath::kLine_Verb:
365 path->deferredLine(ePtr[0]);
366 break;
367 case SkPath::kQuad_Verb:
368 path->quadTo(ePtr[1], ePtr[0]);
369 break;
370 case SkPath::kCubic_Verb:
371 path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
372 break;
373 default:
374 SkASSERT(0);
375 }
376 // return ePtr[0];
377 } else {
378 path->deferredMoveLine(ePtr[0]);
379 switch (fVerb) {
380 case SkPath::kLine_Verb:
381 path->deferredLine(ePtr[1]);
382 break;
383 case SkPath::kQuad_Verb:
384 path->quadTo(ePtr[1], ePtr[2]);
385 break;
386 case SkPath::kCubic_Verb:
387 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
388 break;
389 default:
390 SkASSERT(0);
391 }
392 }
393 }
reed@google.com277c3f82013-05-31 15:17:50 +0000394 // return ePtr[SkPathOpsVerbToPoints(fVerb)];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000395}
396
397void SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
398 init(pts, SkPath::kLine_Verb, operand, evenOdd);
399 fBounds.set(pts, 2);
400}
401
402// add 2 to edge or out of range values to get T extremes
403void SkOpSegment::addOtherT(int index, double otherT, int otherIndex) {
404 SkOpSpan& span = fTs[index];
caryclark@google.com03610322013-04-18 15:58:21 +0000405 if (precisely_zero(otherT)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000406 otherT = 0;
caryclark@google.com03610322013-04-18 15:58:21 +0000407 } else if (precisely_equal(otherT, 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000408 otherT = 1;
409 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000410 span.fOtherT = otherT;
411 span.fOtherIndex = otherIndex;
412}
413
414void SkOpSegment::addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
415 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
416 fBounds.setQuadBounds(pts);
417}
418
419 // Defer all coincident edge processing until
420 // after normal intersections have been computed
421
422// no need to be tricky; insert in normal T order
423// resolve overlapping ts when considering coincidence later
424
425 // add non-coincident intersection. Resulting edges are sorted in T.
426int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) {
caryclark@google.com03610322013-04-18 15:58:21 +0000427 if (precisely_zero(newT)) {
428 newT = 0;
429 } else if (precisely_equal(newT, 1)) {
430 newT = 1;
431 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000432 // FIXME: in the pathological case where there is a ton of intercepts,
433 // binary search?
434 int insertedAt = -1;
435 size_t tCount = fTs.count();
436 for (size_t index = 0; index < tCount; ++index) {
437 // OPTIMIZATION: if there are three or more identical Ts, then
438 // the fourth and following could be further insertion-sorted so
439 // that all the edges are clockwise or counterclockwise.
440 // This could later limit segment tests to the two adjacent
441 // neighbors, although it doesn't help with determining which
442 // circular direction to go in.
443 if (newT < fTs[index].fT) {
444 insertedAt = index;
445 break;
446 }
447 }
448 SkOpSpan* span;
449 if (insertedAt >= 0) {
450 span = fTs.insert(insertedAt);
451 } else {
452 insertedAt = tCount;
453 span = fTs.append();
454 }
455 span->fT = newT;
456 span->fOther = other;
457 span->fPt = pt;
caryclark@google.coma5e55922013-05-07 18:51:31 +0000458#if 0
459 // cubics, for instance, may not be exact enough to satisfy this check (e.g., cubicOp69d)
460 SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX)
461 && approximately_equal(xyAtT(newT).fY, pt.fY));
462#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000463 span->fWindSum = SK_MinS32;
464 span->fOppSum = SK_MinS32;
465 span->fWindValue = 1;
466 span->fOppValue = 0;
467 span->fTiny = false;
468 span->fLoop = false;
469 if ((span->fDone = newT == 1)) {
470 ++fDoneSpans;
471 }
472 span->fUnsortableStart = false;
473 span->fUnsortableEnd = false;
474 int less = -1;
475 while (&span[less + 1] - fTs.begin() > 0 && xyAtT(&span[less]) == xyAtT(span)) {
476 if (span[less].fDone) {
477 break;
478 }
479 double tInterval = newT - span[less].fT;
480 if (precisely_negative(tInterval)) {
481 break;
482 }
483 if (fVerb == SkPath::kCubic_Verb) {
484 double tMid = newT - tInterval / 2;
485 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid);
486 if (!midPt.approximatelyEqual(xyAtT(span))) {
487 break;
488 }
489 }
490 span[less].fTiny = true;
491 span[less].fDone = true;
492 if (approximately_negative(newT - span[less].fT)) {
493 if (approximately_greater_than_one(newT)) {
494 SkASSERT(&span[less] - fTs.begin() < fTs.count());
495 span[less].fUnsortableStart = true;
496 if (&span[less - 1] - fTs.begin() >= 0) {
497 span[less - 1].fUnsortableEnd = true;
498 }
499 }
500 if (approximately_less_than_zero(span[less].fT)) {
501 SkASSERT(&span[less + 1] - fTs.begin() < fTs.count());
502 SkASSERT(&span[less] - fTs.begin() >= 0);
503 span[less + 1].fUnsortableStart = true;
504 span[less].fUnsortableEnd = true;
505 }
506 }
507 ++fDoneSpans;
508 --less;
509 }
510 int more = 1;
511 while (fTs.end() - &span[more - 1] > 1 && xyAtT(&span[more]) == xyAtT(span)) {
512 if (span[more - 1].fDone) {
513 break;
514 }
515 double tEndInterval = span[more].fT - newT;
516 if (precisely_negative(tEndInterval)) {
517 break;
518 }
519 if (fVerb == SkPath::kCubic_Verb) {
520 double tMid = newT - tEndInterval / 2;
521 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid);
522 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
523 break;
524 }
525 }
526 span[more - 1].fTiny = true;
527 span[more - 1].fDone = true;
528 if (approximately_negative(span[more].fT - newT)) {
529 if (approximately_greater_than_one(span[more].fT)) {
530 span[more + 1].fUnsortableStart = true;
531 span[more].fUnsortableEnd = true;
532 }
533 if (approximately_less_than_zero(newT)) {
534 span[more].fUnsortableStart = true;
535 span[more - 1].fUnsortableEnd = true;
536 }
537 }
538 ++fDoneSpans;
539 ++more;
540 }
541 return insertedAt;
542}
543
544// set spans from start to end to decrement by one
545// note this walks other backwards
caryclark@google.coma5e55922013-05-07 18:51:31 +0000546// FIXME: there's probably an edge case that can be constructed where
caryclark@google.com07393ca2013-04-08 11:47:37 +0000547// two span in one segment are separated by float epsilon on one span but
548// not the other, if one segment is very small. For this
549// case the counts asserted below may or may not be enough to separate the
550// spans. Even if the counts work out, what if the spans aren't correctly
551// sorted? It feels better in such a case to match the span's other span
552// pointer since both coincident segments must contain the same spans.
caryclark@google.coma5e55922013-05-07 18:51:31 +0000553// FIXME? It seems that decrementing by one will fail for complex paths that
554// have three or more coincident edges. Shouldn't this subtract the difference
555// between the winding values?
caryclark@google.com07393ca2013-04-08 11:47:37 +0000556void SkOpSegment::addTCancel(double startT, double endT, SkOpSegment* other,
557 double oStartT, double oEndT) {
558 SkASSERT(!approximately_negative(endT - startT));
559 SkASSERT(!approximately_negative(oEndT - oStartT));
560 bool binary = fOperand != other->fOperand;
561 int index = 0;
562 while (!approximately_negative(startT - fTs[index].fT)) {
563 ++index;
564 }
565 int oIndex = other->fTs.count();
566 while (approximately_positive(other->fTs[--oIndex].fT - oEndT))
567 ;
568 double tRatio = (oEndT - oStartT) / (endT - startT);
569 SkOpSpan* test = &fTs[index];
570 SkOpSpan* oTest = &other->fTs[oIndex];
caryclark@google.comd892bd82013-06-17 14:10:36 +0000571 SkSTArray<kOutsideTrackedTCount, double, true> outsideTs;
572 SkSTArray<kOutsideTrackedTCount, double, true> oOutsideTs;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000573 do {
caryclark@google.coma5e55922013-05-07 18:51:31 +0000574 bool decrement = test->fWindValue && oTest->fWindValue;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000575 bool track = test->fWindValue || oTest->fWindValue;
caryclark@google.coma5e55922013-05-07 18:51:31 +0000576 bool bigger = test->fWindValue >= oTest->fWindValue;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000577 double testT = test->fT;
578 double oTestT = oTest->fT;
579 SkOpSpan* span = test;
580 do {
581 if (decrement) {
caryclark@google.coma5e55922013-05-07 18:51:31 +0000582 if (binary && bigger) {
583 span->fOppValue--;
584 } else {
585 decrementSpan(span);
586 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000587 } else if (track && span->fT < 1 && oTestT < 1) {
588 TrackOutside(&outsideTs, span->fT, oTestT);
589 }
590 span = &fTs[++index];
591 } while (approximately_negative(span->fT - testT));
592 SkOpSpan* oSpan = oTest;
593 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
594 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
595 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
596 while (approximately_negative(otherTMatchStart - oSpan->fT)
597 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
598 #ifdef SK_DEBUG
599 SkASSERT(originalWindValue == oSpan->fWindValue);
600 #endif
601 if (decrement) {
caryclark@google.coma5e55922013-05-07 18:51:31 +0000602 if (binary && !bigger) {
603 oSpan->fOppValue--;
604 } else {
605 other->decrementSpan(oSpan);
606 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000607 } else if (track && oSpan->fT < 1 && testT < 1) {
608 TrackOutside(&oOutsideTs, oSpan->fT, testT);
609 }
610 if (!oIndex) {
611 break;
612 }
613 oSpan = &other->fTs[--oIndex];
614 }
615 test = span;
616 oTest = oSpan;
617 } while (!approximately_negative(endT - test->fT));
618 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
619 // FIXME: determine if canceled edges need outside ts added
620 if (!done() && outsideTs.count()) {
621 double tStart = outsideTs[0];
622 double oStart = outsideTs[1];
623 addCancelOutsides(tStart, oStart, other, oEndT);
624 int count = outsideTs.count();
625 if (count > 2) {
626 double tStart = outsideTs[count - 2];
627 double oStart = outsideTs[count - 1];
628 addCancelOutsides(tStart, oStart, other, oEndT);
629 }
630 }
631 if (!other->done() && oOutsideTs.count()) {
632 double tStart = oOutsideTs[0];
633 double oStart = oOutsideTs[1];
634 other->addCancelOutsides(tStart, oStart, this, endT);
635 }
636}
637
638int SkOpSegment::addSelfT(SkOpSegment* other, const SkPoint& pt, double newT) {
639 int result = addT(other, pt, newT);
640 SkOpSpan* span = &fTs[result];
641 span->fLoop = true;
642 return result;
643}
644
645int SkOpSegment::addUnsortableT(SkOpSegment* other, bool start, const SkPoint& pt, double newT) {
646 int result = addT(other, pt, newT);
647 SkOpSpan* span = &fTs[result];
648 if (start) {
649 if (result > 0) {
650 span[result - 1].fUnsortableEnd = true;
651 }
652 span[result].fUnsortableStart = true;
653 } else {
654 span[result].fUnsortableEnd = true;
655 if (result + 1 < fTs.count()) {
656 span[result + 1].fUnsortableStart = true;
657 }
658 }
659 return result;
660}
661
662int SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool opp, int index,
caryclark@google.comd892bd82013-06-17 14:10:36 +0000663 SkTArray<double, true>* outsideTs) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000664 int oWindValue = oTest.fWindValue;
665 int oOppValue = oTest.fOppValue;
666 if (opp) {
667 SkTSwap<int>(oWindValue, oOppValue);
668 }
669 SkOpSpan* const test = &fTs[index];
670 SkOpSpan* end = test;
671 const double oStartT = oTest.fT;
672 do {
673 if (bumpSpan(end, oWindValue, oOppValue)) {
674 TrackOutside(outsideTs, end->fT, oStartT);
675 }
676 end = &fTs[++index];
677 } while (approximately_negative(end->fT - test->fT));
678 return index;
679}
680
681// because of the order in which coincidences are resolved, this and other
682// may not have the same intermediate points. Compute the corresponding
683// intermediate T values (using this as the master, other as the follower)
684// and walk other conditionally -- hoping that it catches up in the end
685int SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, double oEndT, int& oIndex,
caryclark@google.comd892bd82013-06-17 14:10:36 +0000686 SkTArray<double, true>* oOutsideTs) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000687 SkOpSpan* const oTest = &fTs[oIndex];
688 SkOpSpan* oEnd = oTest;
689 const double startT = test.fT;
690 const double oStartT = oTest->fT;
691 while (!approximately_negative(oEndT - oEnd->fT)
692 && approximately_negative(oEnd->fT - oStartT)) {
693 zeroSpan(oEnd);
694 TrackOutside(oOutsideTs, oEnd->fT, startT);
695 oEnd = &fTs[++oIndex];
696 }
697 return oIndex;
698}
699
700// FIXME: need to test this case:
701// contourA has two segments that are coincident
702// contourB has two segments that are coincident in the same place
703// each ends up with +2/0 pairs for winding count
704// since logic below doesn't transfer count (only increments/decrements) can this be
705// resolved to +4/0 ?
706
707// set spans from start to end to increment the greater by one and decrement
708// the lesser
709void SkOpSegment::addTCoincident(double startT, double endT, SkOpSegment* other, double oStartT,
710 double oEndT) {
711 SkASSERT(!approximately_negative(endT - startT));
712 SkASSERT(!approximately_negative(oEndT - oStartT));
713 bool opp = fOperand ^ other->fOperand;
714 int index = 0;
715 while (!approximately_negative(startT - fTs[index].fT)) {
716 ++index;
717 }
718 int oIndex = 0;
719 while (!approximately_negative(oStartT - other->fTs[oIndex].fT)) {
720 ++oIndex;
721 }
722 SkOpSpan* test = &fTs[index];
723 SkOpSpan* oTest = &other->fTs[oIndex];
caryclark@google.comd892bd82013-06-17 14:10:36 +0000724 SkSTArray<kOutsideTrackedTCount, double, true> outsideTs;
725 SkSTArray<kOutsideTrackedTCount, double, true> oOutsideTs;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000726 do {
727 // if either span has an opposite value and the operands don't match, resolve first
728 // SkASSERT(!test->fDone || !oTest->fDone);
729 if (test->fDone || oTest->fDone) {
730 index = advanceCoincidentThis(oTest, opp, index);
731 oIndex = other->advanceCoincidentOther(test, oEndT, oIndex);
732 } else {
733 index = bumpCoincidentThis(*oTest, opp, index, &outsideTs);
734 oIndex = other->bumpCoincidentOther(*test, oEndT, oIndex, &oOutsideTs);
735 }
736 test = &fTs[index];
737 oTest = &other->fTs[oIndex];
738 } while (!approximately_negative(endT - test->fT));
739 SkASSERT(approximately_negative(oTest->fT - oEndT));
740 SkASSERT(approximately_negative(oEndT - oTest->fT));
741 if (!done() && outsideTs.count()) {
742 addCoinOutsides(outsideTs, other, oEndT);
743 }
744 if (!other->done() && oOutsideTs.count()) {
745 other->addCoinOutsides(oOutsideTs, this, endT);
746 }
747}
748
749// FIXME: this doesn't prevent the same span from being added twice
750// fix in caller, SkASSERT here?
751void SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
752 const SkPoint& pt) {
753 int tCount = fTs.count();
754 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
755 const SkOpSpan& span = fTs[tIndex];
756 if (!approximately_negative(span.fT - t)) {
757 break;
758 }
759 if (approximately_negative(span.fT - t) && span.fOther == other
760 && approximately_equal(span.fOtherT, otherT)) {
761#if DEBUG_ADD_T_PAIR
762 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
763 __FUNCTION__, fID, t, other->fID, otherT);
764#endif
765 return;
766 }
767 }
768#if DEBUG_ADD_T_PAIR
769 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
770 __FUNCTION__, fID, t, other->fID, otherT);
771#endif
772 int insertedAt = addT(other, pt, t);
773 int otherInsertedAt = other->addT(this, pt, otherT);
774 addOtherT(insertedAt, otherT, otherInsertedAt);
775 other->addOtherT(otherInsertedAt, t, insertedAt);
776 matchWindingValue(insertedAt, t, borrowWind);
777 other->matchWindingValue(otherInsertedAt, otherT, borrowWind);
778}
779
caryclark@google.comd892bd82013-06-17 14:10:36 +0000780void SkOpSegment::addTwoAngles(int start, int end, SkTArray<SkOpAngle, true>* angles) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000781 // add edge leading into junction
782 int min = SkMin32(end, start);
caryclark@google.coma5e55922013-05-07 18:51:31 +0000783 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000784 addAngle(angles, end, start);
785 }
786 // add edge leading away from junction
787 int step = SkSign32(end - start);
788 int tIndex = nextExactSpan(end, step);
789 min = SkMin32(end, tIndex);
caryclark@google.coma5e55922013-05-07 18:51:31 +0000790 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000791 addAngle(angles, end, tIndex);
792 }
793}
794
795int SkOpSegment::advanceCoincidentThis(const SkOpSpan* oTest, bool opp, int index) {
796 SkOpSpan* const test = &fTs[index];
797 SkOpSpan* end;
798 do {
799 end = &fTs[++index];
800 } while (approximately_negative(end->fT - test->fT));
801 return index;
802}
803
804int SkOpSegment::advanceCoincidentOther(const SkOpSpan* test, double oEndT, int oIndex) {
805 SkOpSpan* const oTest = &fTs[oIndex];
806 SkOpSpan* oEnd = oTest;
807 const double oStartT = oTest->fT;
808 while (!approximately_negative(oEndT - oEnd->fT)
809 && approximately_negative(oEnd->fT - oStartT)) {
810 oEnd = &fTs[++oIndex];
811 }
812 return oIndex;
813}
814
815bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const {
816 if (lesser > greater) {
817 SkTSwap<int>(lesser, greater);
818 }
819 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
820}
821
caryclark@google.comd892bd82013-06-17 14:10:36 +0000822void SkOpSegment::buildAngles(int index, SkTArray<SkOpAngle, true>* angles, bool includeOpp) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000823 double referenceT = fTs[index].fT;
824 int lesser = index;
825 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
826 && precisely_negative(referenceT - fTs[lesser].fT)) {
827 buildAnglesInner(lesser, angles);
828 }
829 do {
830 buildAnglesInner(index, angles);
831 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
832 && precisely_negative(fTs[index].fT - referenceT));
833}
834
caryclark@google.comd892bd82013-06-17 14:10:36 +0000835void SkOpSegment::buildAnglesInner(int index, SkTArray<SkOpAngle, true>* angles) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000836 const SkOpSpan* span = &fTs[index];
837 SkOpSegment* other = span->fOther;
838// if there is only one live crossing, and no coincidence, continue
839// in the same direction
840// if there is coincidence, the only choice may be to reverse direction
841 // find edge on either side of intersection
842 int oIndex = span->fOtherIndex;
843 // if done == -1, prior span has already been processed
844 int step = 1;
845 int next = other->nextExactSpan(oIndex, step);
846 if (next < 0) {
847 step = -step;
848 next = other->nextExactSpan(oIndex, step);
849 }
850 // add candidate into and away from junction
851 other->addTwoAngles(next, oIndex, angles);
852}
853
854int SkOpSegment::computeSum(int startIndex, int endIndex, bool binary) {
caryclark@google.comd892bd82013-06-17 14:10:36 +0000855 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000856 addTwoAngles(startIndex, endIndex, &angles);
857 buildAngles(endIndex, &angles, false);
858 // OPTIMIZATION: check all angles to see if any have computed wind sum
859 // before sorting (early exit if none)
caryclark@google.comd892bd82013-06-17 14:10:36 +0000860 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000861 // FIXME?: Not sure if this sort must be ordered or if the relaxed ordering is OK ...
862 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_SortAngleKind);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000863#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000864 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000865#endif
866 if (!sortable) {
867 return SK_MinS32;
868 }
869 int angleCount = angles.count();
870 const SkOpAngle* angle;
871 const SkOpSegment* base;
872 int winding;
873 int oWinding;
874 int firstIndex = 0;
875 do {
876 angle = sorted[firstIndex];
877 base = angle->segment();
878 winding = base->windSum(angle);
879 if (winding != SK_MinS32) {
880 oWinding = base->oppSum(angle);
881 break;
882 }
883 if (++firstIndex == angleCount) {
884 return SK_MinS32;
885 }
886 } while (true);
887 // turn winding into contourWinding
888 int spanWinding = base->spanSign(angle);
889 bool inner = UseInnerWinding(winding + spanWinding, winding);
890#if DEBUG_WINDING
891 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
892 spanWinding, winding, angle->sign(), inner,
893 inner ? winding + spanWinding : winding);
894#endif
895 if (inner) {
896 winding += spanWinding;
897 }
898#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000899 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000900#endif
901 int nextIndex = firstIndex + 1;
902 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
903 winding -= base->spanSign(angle);
904 oWinding -= base->oppSign(angle);
905 do {
906 if (nextIndex == angleCount) {
907 nextIndex = 0;
908 }
909 angle = sorted[nextIndex];
910 SkOpSegment* segment = angle->segment();
911 bool opp = base->fOperand ^ segment->fOperand;
912 int maxWinding, oMaxWinding;
913 int spanSign = segment->spanSign(angle);
914 int oppoSign = segment->oppSign(angle);
915 if (opp) {
916 oMaxWinding = oWinding;
917 oWinding -= spanSign;
918 maxWinding = winding;
919 if (oppoSign) {
920 winding -= oppoSign;
921 }
922 } else {
923 maxWinding = winding;
924 winding -= spanSign;
925 oMaxWinding = oWinding;
926 if (oppoSign) {
927 oWinding -= oppoSign;
928 }
929 }
930 if (segment->windSum(angle) == SK_MinS32) {
931 if (opp) {
932 if (UseInnerWinding(oMaxWinding, oWinding)) {
933 oMaxWinding = oWinding;
934 }
935 if (oppoSign && UseInnerWinding(maxWinding, winding)) {
936 maxWinding = winding;
937 }
caryclark@google.coma5e55922013-05-07 18:51:31 +0000938#ifdef SK_DEBUG
939 SkASSERT(abs(maxWinding) <= gDebugMaxWindSum);
940 SkASSERT(abs(oMaxWinding) <= gDebugMaxWindSum);
941#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000942 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
943 } else {
944 if (UseInnerWinding(maxWinding, winding)) {
945 maxWinding = winding;
946 }
947 if (oppoSign && UseInnerWinding(oMaxWinding, oWinding)) {
948 oMaxWinding = oWinding;
949 }
caryclark@google.coma5e55922013-05-07 18:51:31 +0000950#ifdef SK_DEBUG
951 SkASSERT(abs(maxWinding) <= gDebugMaxWindSum);
952 SkASSERT(abs(binary ? oMaxWinding : 0) <= gDebugMaxWindSum);
953#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000954 (void) segment->markAndChaseWinding(angle, maxWinding,
955 binary ? oMaxWinding : 0);
956 }
957 }
958 } while (++nextIndex != lastIndex);
959 int minIndex = SkMin32(startIndex, endIndex);
960 return windSum(minIndex);
961}
962
963int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT,
964 bool* hitSomething, double mid, bool opp, bool current) const {
965 SkScalar bottom = fBounds.fBottom;
966 int bestTIndex = -1;
967 if (bottom <= *bestY) {
968 return bestTIndex;
969 }
970 SkScalar top = fBounds.fTop;
971 if (top >= basePt.fY) {
972 return bestTIndex;
973 }
974 if (fBounds.fLeft > basePt.fX) {
975 return bestTIndex;
976 }
977 if (fBounds.fRight < basePt.fX) {
978 return bestTIndex;
979 }
980 if (fBounds.fLeft == fBounds.fRight) {
981 // if vertical, and directly above test point, wait for another one
982 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
983 }
984 // intersect ray starting at basePt with edge
985 SkIntersections intersections;
986 // OPTIMIZE: use specialty function that intersects ray with curve,
987 // returning t values only for curve (we don't care about t on ray)
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000988 int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)])
989 (fPts, top, bottom, basePt.fX, false);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000990 if (pts == 0 || (current && pts == 1)) {
991 return bestTIndex;
992 }
993 if (current) {
994 SkASSERT(pts > 1);
995 int closestIdx = 0;
996 double closest = fabs(intersections[0][0] - mid);
997 for (int idx = 1; idx < pts; ++idx) {
998 double test = fabs(intersections[0][idx] - mid);
999 if (closest > test) {
1000 closestIdx = idx;
1001 closest = test;
1002 }
1003 }
1004 intersections.quickRemoveOne(closestIdx, --pts);
1005 }
1006 double bestT = -1;
1007 for (int index = 0; index < pts; ++index) {
1008 double foundT = intersections[0][index];
1009 if (approximately_less_than_zero(foundT)
1010 || approximately_greater_than_one(foundT)) {
1011 continue;
1012 }
reed@google.com277c3f82013-05-31 15:17:50 +00001013 SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fY;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001014 if (approximately_negative(testY - *bestY)
1015 || approximately_negative(basePt.fY - testY)) {
1016 continue;
1017 }
1018 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
1019 return SK_MinS32; // if the intersection is edge on, wait for another one
1020 }
1021 if (fVerb > SkPath::kLine_Verb) {
reed@google.com277c3f82013-05-31 15:17:50 +00001022 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fX;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001023 if (approximately_zero(dx)) {
1024 return SK_MinS32; // hit vertical, wait for another one
1025 }
1026 }
1027 *bestY = testY;
1028 bestT = foundT;
1029 }
1030 if (bestT < 0) {
1031 return bestTIndex;
1032 }
1033 SkASSERT(bestT >= 0);
1034 SkASSERT(bestT <= 1);
1035 int start;
1036 int end = 0;
1037 do {
1038 start = end;
1039 end = nextSpan(start, 1);
1040 } while (fTs[end].fT < bestT);
1041 // FIXME: see next candidate for a better pattern to find the next start/end pair
1042 while (start + 1 < end && fTs[start].fDone) {
1043 ++start;
1044 }
1045 if (!isCanceled(start)) {
1046 *hitT = bestT;
1047 bestTIndex = start;
1048 *hitSomething = true;
1049 }
1050 return bestTIndex;
1051}
1052
1053void SkOpSegment::decrementSpan(SkOpSpan* span) {
1054 SkASSERT(span->fWindValue > 0);
1055 if (--(span->fWindValue) == 0) {
1056 if (!span->fOppValue && !span->fDone) {
1057 span->fDone = true;
1058 ++fDoneSpans;
1059 }
1060 }
1061}
1062
1063bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) {
1064 SkASSERT(!span->fDone);
1065 span->fWindValue += windDelta;
1066 SkASSERT(span->fWindValue >= 0);
1067 span->fOppValue += oppDelta;
1068 SkASSERT(span->fOppValue >= 0);
1069 if (fXor) {
1070 span->fWindValue &= 1;
1071 }
1072 if (fOppXor) {
1073 span->fOppValue &= 1;
1074 }
1075 if (!span->fWindValue && !span->fOppValue) {
1076 span->fDone = true;
1077 ++fDoneSpans;
1078 return true;
1079 }
1080 return false;
1081}
1082
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001083// look to see if the curve end intersects an intermediary that intersects the other
1084void SkOpSegment::checkEnds() {
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001085 debugValidate();
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001086 SkTDArray<SkOpSpan> missingSpans;
1087 int count = fTs.count();
1088 for (int index = 0; index < count; ++index) {
1089 const SkOpSpan& span = fTs[index];
1090 const SkOpSegment* other = span.fOther;
1091 const SkOpSpan* otherSpan = &other->fTs[span.fOtherIndex];
1092 double otherT = otherSpan->fT;
1093 if (otherT != 0 && otherT != 1) {
1094 continue;
1095 }
1096 int peekStart = span.fOtherIndex;
1097 while (peekStart > 0) {
1098 const SkOpSpan* peeker = &other->fTs[peekStart - 1];
1099 if (peeker->fT != otherT) {
1100 break;
1101 }
1102 --peekStart;
1103 }
1104 int otherLast = other->fTs.count() - 1;
1105 int peekLast = span.fOtherIndex;
1106 while (peekLast < otherLast) {
1107 const SkOpSpan* peeker = &other->fTs[peekLast + 1];
1108 if (peeker->fT != otherT) {
1109 break;
1110 }
1111 ++peekLast;
1112 }
1113 if (peekStart == peekLast) {
1114 continue;
1115 }
1116 double t = span.fT;
1117 int tStart = index;
1118 while (tStart > 0 && t == fTs[tStart - 1].fT) {
1119 --tStart;
1120 }
1121 int tLast = index;
1122 int last = count - 1;
1123 while (tLast < last && t == fTs[tLast + 1].fT) {
1124 ++tLast;
1125 }
1126 for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) {
1127 if (peekIndex == span.fOtherIndex) {
1128 continue;
1129 }
1130 const SkOpSpan& peekSpan = other->fTs[peekIndex];
1131 SkOpSegment* match = peekSpan.fOther;
1132 const double matchT = peekSpan.fOtherT;
1133 for (int tIndex = tStart; tIndex <= tLast; ++tIndex) {
1134 const SkOpSpan& tSpan = fTs[tIndex];
1135 if (tSpan.fOther == match && tSpan.fOtherT == matchT) {
1136 goto nextPeeker;
1137 }
1138 }
1139 // this segment is missing a entry that the other contains
1140 // remember so we can add the missing one and recompute the indices
1141 SkOpSpan* missing = missingSpans.append();
1142 missing->fT = t;
1143 missing->fOther = match;
1144 missing->fOtherT = matchT;
1145 missing->fPt = peekSpan.fPt;
1146 }
1147nextPeeker:
1148 ;
1149 }
1150 int missingCount = missingSpans.count();
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001151 if (missingCount == 0) {
1152 return;
1153 }
1154 debugValidate();
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001155 for (int index = 0; index < missingCount; ++index) {
1156 const SkOpSpan& missing = missingSpans[index];
1157 addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt);
1158 }
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001159 fixOtherTIndex();
1160 for (int index = 0; index < missingCount; ++index) {
1161 const SkOpSpan& missing = missingSpans[index];
1162 missing.fOther->fixOtherTIndex();
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001163 }
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001164 debugValidate();
caryclark@google.comfa2aeee2013-07-15 13:29:13 +00001165}
1166
caryclark@google.com07393ca2013-04-08 11:47:37 +00001167bool SkOpSegment::equalPoints(int greaterTIndex, int lesserTIndex) {
1168 SkASSERT(greaterTIndex >= lesserTIndex);
1169 double greaterT = fTs[greaterTIndex].fT;
1170 double lesserT = fTs[lesserTIndex].fT;
1171 if (greaterT == lesserT) {
1172 return true;
1173 }
1174 if (!approximately_negative(greaterT - lesserT)) {
1175 return false;
1176 }
1177 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
1178}
1179
1180/*
1181 The M and S variable name parts stand for the operators.
1182 Mi stands for Minuend (see wiki subtraction, analogous to difference)
1183 Su stands for Subtrahend
1184 The Opp variable name part designates that the value is for the Opposite operator.
1185 Opposite values result from combining coincident spans.
1186 */
1187SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
1188 bool* unsortable, SkPathOp op, const int xorMiMask,
1189 const int xorSuMask) {
1190 const int startIndex = *nextStart;
1191 const int endIndex = *nextEnd;
1192 SkASSERT(startIndex != endIndex);
1193 SkDEBUGCODE(const int count = fTs.count());
1194 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
1195 const int step = SkSign32(endIndex - startIndex);
1196 const int end = nextExactSpan(startIndex, step);
1197 SkASSERT(end >= 0);
1198 SkOpSpan* endSpan = &fTs[end];
1199 SkOpSegment* other;
1200 if (isSimple(end)) {
1201 // mark the smaller of startIndex, endIndex done, and all adjacent
1202 // spans with the same T value (but not 'other' spans)
1203#if DEBUG_WINDING
1204 SkDebugf("%s simple\n", __FUNCTION__);
1205#endif
1206 int min = SkMin32(startIndex, endIndex);
1207 if (fTs[min].fDone) {
1208 return NULL;
1209 }
1210 markDoneBinary(min);
1211 other = endSpan->fOther;
1212 *nextStart = endSpan->fOtherIndex;
1213 double startT = other->fTs[*nextStart].fT;
1214 *nextEnd = *nextStart;
1215 do {
1216 *nextEnd += step;
1217 }
1218 while (precisely_zero(startT - other->fTs[*nextEnd].fT));
1219 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001220 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001221 *unsortable = true;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001222 return NULL;
1223 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001224 return other;
1225 }
1226 // more than one viable candidate -- measure angles to find best
caryclark@google.comd892bd82013-06-17 14:10:36 +00001227 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001228 SkASSERT(startIndex - endIndex != 0);
1229 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
1230 addTwoAngles(startIndex, end, &angles);
1231 buildAngles(end, &angles, true);
caryclark@google.comd892bd82013-06-17 14:10:36 +00001232 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001233 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_SortAngleKind);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001234 int angleCount = angles.count();
1235 int firstIndex = findStartingEdge(sorted, startIndex, end);
1236 SkASSERT(firstIndex >= 0);
1237#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001238 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001239#endif
1240 if (!sortable) {
1241 *unsortable = true;
1242 return NULL;
1243 }
1244 SkASSERT(sorted[firstIndex]->segment() == this);
1245#if DEBUG_WINDING
1246 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
1247 sorted[firstIndex]->sign());
1248#endif
1249 int sumMiWinding = updateWinding(endIndex, startIndex);
1250 int sumSuWinding = updateOppWinding(endIndex, startIndex);
1251 if (operand()) {
1252 SkTSwap<int>(sumMiWinding, sumSuWinding);
1253 }
1254 int nextIndex = firstIndex + 1;
1255 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1256 const SkOpAngle* foundAngle = NULL;
1257 bool foundDone = false;
1258 // iterate through the angle, and compute everyone's winding
1259 SkOpSegment* nextSegment;
1260 int activeCount = 0;
1261 do {
1262 SkASSERT(nextIndex != firstIndex);
1263 if (nextIndex == angleCount) {
1264 nextIndex = 0;
1265 }
1266 const SkOpAngle* nextAngle = sorted[nextIndex];
1267 nextSegment = nextAngle->segment();
1268 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1269 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
1270 nextAngle->end(), op, &sumMiWinding, &sumSuWinding,
1271 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1272 if (activeAngle) {
1273 ++activeCount;
1274 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001275 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001276 *unsortable = true;
1277 return NULL;
1278 }
1279 foundAngle = nextAngle;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001280 foundDone = nextSegment->done(nextAngle) && !nextSegment->isTiny(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001281 }
1282 }
1283 if (nextSegment->done()) {
1284 continue;
1285 }
1286 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
1287 continue;
1288 }
1289 SkOpSpan* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
1290 oppSumWinding, activeAngle, nextAngle);
1291 if (last) {
1292 *chase->append() = last;
1293#if DEBUG_WINDING
1294 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
1295 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
1296#endif
1297 }
1298 } while (++nextIndex != lastIndex);
1299 markDoneBinary(SkMin32(startIndex, endIndex));
1300 if (!foundAngle) {
1301 return NULL;
1302 }
1303 *nextStart = foundAngle->start();
1304 *nextEnd = foundAngle->end();
1305 nextSegment = foundAngle->segment();
1306
1307#if DEBUG_WINDING
1308 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1309 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1310 #endif
1311 return nextSegment;
1312}
1313
1314SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart,
1315 int* nextEnd, bool* unsortable) {
1316 const int startIndex = *nextStart;
1317 const int endIndex = *nextEnd;
1318 SkASSERT(startIndex != endIndex);
1319 SkDEBUGCODE(const int count = fTs.count());
1320 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
1321 const int step = SkSign32(endIndex - startIndex);
1322 const int end = nextExactSpan(startIndex, step);
1323 SkASSERT(end >= 0);
1324 SkOpSpan* endSpan = &fTs[end];
1325 SkOpSegment* other;
1326 if (isSimple(end)) {
1327 // mark the smaller of startIndex, endIndex done, and all adjacent
1328 // spans with the same T value (but not 'other' spans)
1329#if DEBUG_WINDING
1330 SkDebugf("%s simple\n", __FUNCTION__);
1331#endif
1332 int min = SkMin32(startIndex, endIndex);
1333 if (fTs[min].fDone) {
1334 return NULL;
1335 }
1336 markDoneUnary(min);
1337 other = endSpan->fOther;
1338 *nextStart = endSpan->fOtherIndex;
1339 double startT = other->fTs[*nextStart].fT;
1340 *nextEnd = *nextStart;
1341 do {
1342 *nextEnd += step;
1343 }
1344 while (precisely_zero(startT - other->fTs[*nextEnd].fT));
1345 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
1346 return other;
1347 }
1348 // more than one viable candidate -- measure angles to find best
caryclark@google.comd892bd82013-06-17 14:10:36 +00001349 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001350 SkASSERT(startIndex - endIndex != 0);
1351 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
1352 addTwoAngles(startIndex, end, &angles);
1353 buildAngles(end, &angles, true);
caryclark@google.comd892bd82013-06-17 14:10:36 +00001354 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001355 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_SortAngleKind);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001356 int angleCount = angles.count();
1357 int firstIndex = findStartingEdge(sorted, startIndex, end);
1358 SkASSERT(firstIndex >= 0);
1359#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001360 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001361#endif
1362 if (!sortable) {
1363 *unsortable = true;
1364 return NULL;
1365 }
1366 SkASSERT(sorted[firstIndex]->segment() == this);
1367#if DEBUG_WINDING
1368 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
1369 sorted[firstIndex]->sign());
1370#endif
1371 int sumWinding = updateWinding(endIndex, startIndex);
1372 int nextIndex = firstIndex + 1;
1373 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1374 const SkOpAngle* foundAngle = NULL;
1375 bool foundDone = false;
1376 // iterate through the angle, and compute everyone's winding
1377 SkOpSegment* nextSegment;
1378 int activeCount = 0;
1379 do {
1380 SkASSERT(nextIndex != firstIndex);
1381 if (nextIndex == angleCount) {
1382 nextIndex = 0;
1383 }
1384 const SkOpAngle* nextAngle = sorted[nextIndex];
1385 nextSegment = nextAngle->segment();
1386 int maxWinding;
1387 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
1388 &maxWinding, &sumWinding);
1389 if (activeAngle) {
1390 ++activeCount;
1391 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001392 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001393 *unsortable = true;
1394 return NULL;
1395 }
1396 foundAngle = nextAngle;
1397 foundDone = nextSegment->done(nextAngle);
1398 }
1399 }
1400 if (nextSegment->done()) {
1401 continue;
1402 }
1403 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
1404 continue;
1405 }
1406 SkOpSpan* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
1407 if (last) {
1408 *chase->append() = last;
1409#if DEBUG_WINDING
1410 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
1411 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
1412#endif
1413 }
1414 } while (++nextIndex != lastIndex);
1415 markDoneUnary(SkMin32(startIndex, endIndex));
1416 if (!foundAngle) {
1417 return NULL;
1418 }
1419 *nextStart = foundAngle->start();
1420 *nextEnd = foundAngle->end();
1421 nextSegment = foundAngle->segment();
1422#if DEBUG_WINDING
1423 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1424 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1425 #endif
1426 return nextSegment;
1427}
1428
1429SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsortable) {
1430 const int startIndex = *nextStart;
1431 const int endIndex = *nextEnd;
1432 SkASSERT(startIndex != endIndex);
1433 SkDEBUGCODE(int count = fTs.count());
1434 SkASSERT(startIndex < endIndex ? startIndex < count - 1
1435 : startIndex > 0);
1436 int step = SkSign32(endIndex - startIndex);
1437 int end = nextExactSpan(startIndex, step);
1438 SkASSERT(end >= 0);
1439 SkOpSpan* endSpan = &fTs[end];
1440 SkOpSegment* other;
1441 if (isSimple(end)) {
1442#if DEBUG_WINDING
1443 SkDebugf("%s simple\n", __FUNCTION__);
1444#endif
1445 int min = SkMin32(startIndex, endIndex);
1446 if (fTs[min].fDone) {
1447 return NULL;
1448 }
1449 markDone(min, 1);
1450 other = endSpan->fOther;
1451 *nextStart = endSpan->fOtherIndex;
1452 double startT = other->fTs[*nextStart].fT;
1453 // FIXME: I don't know why the logic here is difference from the winding case
1454 SkDEBUGCODE(bool firstLoop = true;)
1455 if ((approximately_less_than_zero(startT) && step < 0)
1456 || (approximately_greater_than_one(startT) && step > 0)) {
1457 step = -step;
1458 SkDEBUGCODE(firstLoop = false;)
1459 }
1460 do {
1461 *nextEnd = *nextStart;
1462 do {
1463 *nextEnd += step;
1464 }
1465 while (precisely_zero(startT - other->fTs[*nextEnd].fT));
1466 if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) {
1467 break;
1468 }
1469#ifdef SK_DEBUG
1470 SkASSERT(firstLoop);
1471#endif
1472 SkDEBUGCODE(firstLoop = false;)
1473 step = -step;
1474 } while (true);
1475 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
1476 return other;
1477 }
caryclark@google.comd892bd82013-06-17 14:10:36 +00001478 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001479 SkASSERT(startIndex - endIndex != 0);
1480 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
1481 addTwoAngles(startIndex, end, &angles);
1482 buildAngles(end, &angles, false);
caryclark@google.comd892bd82013-06-17 14:10:36 +00001483 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001484 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_SortAngleKind);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001485 if (!sortable) {
1486 *unsortable = true;
1487#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001488 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0,
1489 sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001490#endif
1491 return NULL;
1492 }
1493 int angleCount = angles.count();
1494 int firstIndex = findStartingEdge(sorted, startIndex, end);
1495 SkASSERT(firstIndex >= 0);
1496#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001497 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001498#endif
1499 SkASSERT(sorted[firstIndex]->segment() == this);
1500 int nextIndex = firstIndex + 1;
1501 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1502 const SkOpAngle* foundAngle = NULL;
1503 bool foundDone = false;
1504 SkOpSegment* nextSegment;
1505 int activeCount = 0;
1506 do {
1507 SkASSERT(nextIndex != firstIndex);
1508 if (nextIndex == angleCount) {
1509 nextIndex = 0;
1510 }
1511 const SkOpAngle* nextAngle = sorted[nextIndex];
1512 nextSegment = nextAngle->segment();
1513 ++activeCount;
1514 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001515 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001516 *unsortable = true;
1517 return NULL;
1518 }
1519 foundAngle = nextAngle;
1520 foundDone = nextSegment->done(nextAngle);
1521 }
1522 if (nextSegment->done()) {
1523 continue;
1524 }
1525 } while (++nextIndex != lastIndex);
1526 markDone(SkMin32(startIndex, endIndex), 1);
1527 if (!foundAngle) {
1528 return NULL;
1529 }
1530 *nextStart = foundAngle->start();
1531 *nextEnd = foundAngle->end();
1532 nextSegment = foundAngle->segment();
1533#if DEBUG_WINDING
1534 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1535 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1536 #endif
1537 return nextSegment;
1538}
1539
caryclark@google.comd892bd82013-06-17 14:10:36 +00001540int SkOpSegment::findStartingEdge(const SkTArray<SkOpAngle*, true>& sorted, int start, int end) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001541 int angleCount = sorted.count();
1542 int firstIndex = -1;
1543 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
1544 const SkOpAngle* angle = sorted[angleIndex];
1545 if (angle->segment() == this && angle->start() == end &&
1546 angle->end() == start) {
1547 firstIndex = angleIndex;
1548 break;
1549 }
1550 }
1551 return firstIndex;
1552}
1553
1554// FIXME: this is tricky code; needs its own unit test
1555// note that fOtherIndex isn't computed yet, so it can't be used here
1556void SkOpSegment::findTooCloseToCall() {
1557 int count = fTs.count();
1558 if (count < 3) { // require t=0, x, 1 at minimum
1559 return;
1560 }
1561 int matchIndex = 0;
1562 int moCount;
1563 SkOpSpan* match;
1564 SkOpSegment* mOther;
1565 do {
1566 match = &fTs[matchIndex];
1567 mOther = match->fOther;
1568 // FIXME: allow quads, cubics to be near coincident?
1569 if (mOther->fVerb == SkPath::kLine_Verb) {
1570 moCount = mOther->fTs.count();
1571 if (moCount >= 3) {
1572 break;
1573 }
1574 }
1575 if (++matchIndex >= count) {
1576 return;
1577 }
1578 } while (true); // require t=0, x, 1 at minimum
1579 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
1580 const SkPoint* matchPt = &xyAtT(match);
1581 // look for a pair of nearby T values that map to the same (x,y) value
1582 // if found, see if the pair of other segments share a common point. If
1583 // so, the span from here to there is coincident.
1584 for (int index = matchIndex + 1; index < count; ++index) {
1585 SkOpSpan* test = &fTs[index];
1586 if (test->fDone) {
1587 continue;
1588 }
1589 SkOpSegment* tOther = test->fOther;
1590 if (tOther->fVerb != SkPath::kLine_Verb) {
1591 continue; // FIXME: allow quads, cubics to be near coincident?
1592 }
1593 int toCount = tOther->fTs.count();
1594 if (toCount < 3) { // require t=0, x, 1 at minimum
1595 continue;
1596 }
1597 const SkPoint* testPt = &xyAtT(test);
1598 if (*matchPt != *testPt) {
1599 matchIndex = index;
1600 moCount = toCount;
1601 match = test;
1602 mOther = tOther;
1603 matchPt = testPt;
1604 continue;
1605 }
1606 int moStart = -1;
1607 int moEnd = -1;
1608 double moStartT = 0;
1609 double moEndT = 0;
1610 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
1611 SkOpSpan& moSpan = mOther->fTs[moIndex];
1612 if (moSpan.fDone) {
1613 continue;
1614 }
1615 if (moSpan.fOther == this) {
1616 if (moSpan.fOtherT == match->fT) {
1617 moStart = moIndex;
1618 moStartT = moSpan.fT;
1619 }
1620 continue;
1621 }
1622 if (moSpan.fOther == tOther) {
1623 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
1624 moStart = -1;
1625 break;
1626 }
1627 SkASSERT(moEnd == -1);
1628 moEnd = moIndex;
1629 moEndT = moSpan.fT;
1630 }
1631 }
1632 if (moStart < 0 || moEnd < 0) {
1633 continue;
1634 }
1635 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
1636 if (approximately_equal(moStartT, moEndT)) {
1637 continue;
1638 }
1639 int toStart = -1;
1640 int toEnd = -1;
1641 double toStartT = 0;
1642 double toEndT = 0;
1643 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
1644 SkOpSpan& toSpan = tOther->fTs[toIndex];
1645 if (toSpan.fDone) {
1646 continue;
1647 }
1648 if (toSpan.fOther == this) {
1649 if (toSpan.fOtherT == test->fT) {
1650 toStart = toIndex;
1651 toStartT = toSpan.fT;
1652 }
1653 continue;
1654 }
1655 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
1656 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
1657 moStart = -1;
1658 break;
1659 }
1660 SkASSERT(toEnd == -1);
1661 toEnd = toIndex;
1662 toEndT = toSpan.fT;
1663 }
1664 }
1665 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
1666 if (toStart <= 0 || toEnd <= 0) {
1667 continue;
1668 }
1669 if (approximately_equal(toStartT, toEndT)) {
1670 continue;
1671 }
1672 // test to see if the segment between there and here is linear
1673 if (!mOther->isLinear(moStart, moEnd)
1674 || !tOther->isLinear(toStart, toEnd)) {
1675 continue;
1676 }
1677 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
1678 if (flipped) {
1679 mOther->addTCancel(moStartT, moEndT, tOther, toEndT, toStartT);
1680 } else {
1681 mOther->addTCoincident(moStartT, moEndT, tOther, toStartT, toEndT);
1682 }
1683 }
1684}
1685
1686// FIXME: either:
1687// a) mark spans with either end unsortable as done, or
1688// b) rewrite findTop / findTopSegment / findTopContour to iterate further
1689// when encountering an unsortable span
1690
1691// OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
1692// and use more concise logic like the old edge walker code?
1693// FIXME: this needs to deal with coincident edges
1694SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable,
1695 bool onlySortable) {
1696 // iterate through T intersections and return topmost
1697 // topmost tangent from y-min to first pt is closer to horizontal
1698 SkASSERT(!done());
1699 int firstT = -1;
1700 /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT);
1701 if (firstT < 0) {
1702 *unsortable = true;
1703 firstT = 0;
1704 while (fTs[firstT].fDone) {
1705 SkASSERT(firstT < fTs.count());
1706 ++firstT;
1707 }
1708 *tIndexPtr = firstT;
1709 *endIndexPtr = nextExactSpan(firstT, 1);
1710 return this;
1711 }
1712 // sort the edges to find the leftmost
1713 int step = 1;
1714 int end = nextSpan(firstT, step);
1715 if (end == -1) {
1716 step = -1;
1717 end = nextSpan(firstT, step);
1718 SkASSERT(end != -1);
1719 }
1720 // if the topmost T is not on end, or is three-way or more, find left
1721 // look for left-ness from tLeft to firstT (matching y of other)
caryclark@google.comd892bd82013-06-17 14:10:36 +00001722 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001723 SkASSERT(firstT - end != 0);
1724 addTwoAngles(end, firstT, &angles);
1725 buildAngles(firstT, &angles, true);
caryclark@google.comd892bd82013-06-17 14:10:36 +00001726 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001727 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMayBeUnordered_SortAngleKind);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001728 int first = SK_MaxS32;
1729 SkScalar top = SK_ScalarMax;
1730 int count = sorted.count();
1731 for (int index = 0; index < count; ++index) {
1732 const SkOpAngle* angle = sorted[index];
1733 SkOpSegment* next = angle->segment();
1734 SkPathOpsBounds bounds;
1735 next->subDivideBounds(angle->end(), angle->start(), &bounds);
1736 if (approximately_greater(top, bounds.fTop)) {
1737 top = bounds.fTop;
1738 first = index;
1739 }
1740 }
1741 SkASSERT(first < SK_MaxS32);
1742#if DEBUG_SORT // || DEBUG_SWAP_TOP
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001743 sorted[first]->segment()->debugShowSort(__FUNCTION__, sorted, first, 0, 0, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001744#endif
1745 if (onlySortable && !sortable) {
1746 *unsortable = true;
1747 return NULL;
1748 }
1749 // skip edges that have already been processed
1750 firstT = first - 1;
1751 SkOpSegment* leftSegment;
1752 do {
1753 if (++firstT == count) {
1754 firstT = 0;
1755 }
1756 const SkOpAngle* angle = sorted[firstT];
1757 SkASSERT(!onlySortable || !angle->unsortable());
1758 leftSegment = angle->segment();
1759 *tIndexPtr = angle->end();
1760 *endIndexPtr = angle->start();
1761 } while (leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone);
1762 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
1763 const int tIndex = *tIndexPtr;
1764 const int endIndex = *endIndexPtr;
1765 if (!leftSegment->clockwise(tIndex, endIndex)) {
1766 bool swap = !leftSegment->monotonicInY(tIndex, endIndex)
1767 && !leftSegment->serpentine(tIndex, endIndex);
1768 #if DEBUG_SWAP_TOP
1769 SkDebugf("%s swap=%d serpentine=%d containedByEnds=%d monotonic=%d\n", __FUNCTION__,
1770 swap,
1771 leftSegment->serpentine(tIndex, endIndex),
1772 leftSegment->controlsContainedByEnds(tIndex, endIndex),
1773 leftSegment->monotonicInY(tIndex, endIndex));
1774 #endif
1775 if (swap) {
1776 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first
1777 // sorted but merely the first not already processed (i.e., not done)
1778 SkTSwap(*tIndexPtr, *endIndexPtr);
1779 }
1780 }
1781 }
1782 SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny);
1783 return leftSegment;
1784}
1785
1786// FIXME: not crazy about this
1787// when the intersections are performed, the other index is into an
1788// incomplete array. As the array grows, the indices become incorrect
1789// while the following fixes the indices up again, it isn't smart about
1790// skipping segments whose indices are already correct
1791// assuming we leave the code that wrote the index in the first place
1792void SkOpSegment::fixOtherTIndex() {
1793 int iCount = fTs.count();
1794 for (int i = 0; i < iCount; ++i) {
1795 SkOpSpan& iSpan = fTs[i];
1796 double oT = iSpan.fOtherT;
1797 SkOpSegment* other = iSpan.fOther;
1798 int oCount = other->fTs.count();
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001799 SkDEBUGCODE(iSpan.fOtherIndex = -1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001800 for (int o = 0; o < oCount; ++o) {
1801 SkOpSpan& oSpan = other->fTs[o];
1802 if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan.fT) {
1803 iSpan.fOtherIndex = o;
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001804 oSpan.fOtherIndex = i;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001805 break;
1806 }
1807 }
caryclark@google.com4fdbb222013-07-23 15:27:41 +00001808 SkASSERT(iSpan.fOtherIndex >= 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001809 }
1810}
1811
1812void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
1813 fDoneSpans = 0;
1814 fOperand = operand;
1815 fXor = evenOdd;
1816 fPts = pts;
1817 fVerb = verb;
1818}
1819
1820void SkOpSegment::initWinding(int start, int end) {
1821 int local = spanSign(start, end);
1822 int oppLocal = oppSign(start, end);
1823 (void) markAndChaseWinding(start, end, local, oppLocal);
1824 // OPTIMIZATION: the reverse mark and chase could skip the first marking
1825 (void) markAndChaseWinding(end, start, local, oppLocal);
1826}
1827
1828/*
1829when we start with a vertical intersect, we try to use the dx to determine if the edge is to
1830the left or the right of vertical. This determines if we need to add the span's
1831sign or not. However, this isn't enough.
1832If the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed.
1833If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
1834from has the same x direction as this span, the winding should change. If the dx is opposite, then
1835the same winding is shared by both.
1836*/
1837void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkScalar hitDx,
1838 int oppWind, SkScalar hitOppDx) {
1839 SkASSERT(hitDx || !winding);
reed@google.com277c3f82013-05-31 15:17:50 +00001840 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001841 SkASSERT(dx);
1842 int windVal = windValue(SkMin32(start, end));
1843#if DEBUG_WINDING_AT_T
1844 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
1845 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
1846#endif
1847 if (!winding) {
1848 winding = dx < 0 ? windVal : -windVal;
1849 } else if (winding * dx < 0) {
1850 int sideWind = winding + (dx < 0 ? windVal : -windVal);
1851 if (abs(winding) < abs(sideWind)) {
1852 winding = sideWind;
1853 }
1854 }
1855#if DEBUG_WINDING_AT_T
1856 SkDebugf(" winding=%d\n", winding);
1857#endif
1858 SkDEBUGCODE(int oppLocal = oppSign(start, end));
1859 SkASSERT(hitOppDx || !oppWind || !oppLocal);
1860 int oppWindVal = oppValue(SkMin32(start, end));
1861 if (!oppWind) {
1862 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
1863 } else if (hitOppDx * dx >= 0) {
1864 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
1865 if (abs(oppWind) < abs(oppSideWind)) {
1866 oppWind = oppSideWind;
1867 }
1868 }
1869 (void) markAndChaseWinding(start, end, winding, oppWind);
1870}
1871
1872bool SkOpSegment::isLinear(int start, int end) const {
1873 if (fVerb == SkPath::kLine_Verb) {
1874 return true;
1875 }
1876 if (fVerb == SkPath::kQuad_Verb) {
1877 SkDQuad qPart = SkDQuad::SubDivide(fPts, fTs[start].fT, fTs[end].fT);
1878 return qPart.isLinear(0, 2);
1879 } else {
1880 SkASSERT(fVerb == SkPath::kCubic_Verb);
1881 SkDCubic cPart = SkDCubic::SubDivide(fPts, fTs[start].fT, fTs[end].fT);
1882 return cPart.isLinear(0, 3);
1883 }
1884}
1885
1886// OPTIMIZE: successive calls could start were the last leaves off
1887// or calls could specialize to walk forwards or backwards
1888bool SkOpSegment::isMissing(double startT) const {
1889 size_t tCount = fTs.count();
1890 for (size_t index = 0; index < tCount; ++index) {
1891 if (approximately_zero(startT - fTs[index].fT)) {
1892 return false;
1893 }
1894 }
1895 return true;
1896}
1897
1898bool SkOpSegment::isSimple(int end) const {
1899 int count = fTs.count();
1900 if (count == 2) {
1901 return true;
1902 }
1903 double t = fTs[end].fT;
1904 if (approximately_less_than_zero(t)) {
1905 return !approximately_less_than_zero(fTs[1].fT);
1906 }
1907 if (approximately_greater_than_one(t)) {
1908 return !approximately_greater_than_one(fTs[count - 2].fT);
1909 }
1910 return false;
1911}
1912
1913// this span is excluded by the winding rule -- chase the ends
1914// as long as they are unambiguous to mark connections as done
1915// and give them the same winding value
1916SkOpSpan* SkOpSegment::markAndChaseDone(int index, int endIndex, int winding) {
1917 int step = SkSign32(endIndex - index);
1918 int min = SkMin32(index, endIndex);
1919 markDone(min, winding);
1920 SkOpSpan* last;
1921 SkOpSegment* other = this;
1922 while ((other = other->nextChase(&index, step, &min, &last))) {
1923 other->markDone(min, winding);
1924 }
1925 return last;
1926}
1927
1928SkOpSpan* SkOpSegment::markAndChaseDoneBinary(const SkOpAngle* angle, int winding, int oppWinding) {
1929 int index = angle->start();
1930 int endIndex = angle->end();
1931 int step = SkSign32(endIndex - index);
1932 int min = SkMin32(index, endIndex);
1933 markDoneBinary(min, winding, oppWinding);
1934 SkOpSpan* last;
1935 SkOpSegment* other = this;
1936 while ((other = other->nextChase(&index, step, &min, &last))) {
1937 other->markDoneBinary(min, winding, oppWinding);
1938 }
1939 return last;
1940}
1941
1942SkOpSpan* SkOpSegment::markAndChaseDoneBinary(int index, int endIndex) {
1943 int step = SkSign32(endIndex - index);
1944 int min = SkMin32(index, endIndex);
1945 markDoneBinary(min);
1946 SkOpSpan* last;
1947 SkOpSegment* other = this;
1948 while ((other = other->nextChase(&index, step, &min, &last))) {
1949 if (other->done()) {
1950 return NULL;
1951 }
1952 other->markDoneBinary(min);
1953 }
1954 return last;
1955}
1956
1957SkOpSpan* SkOpSegment::markAndChaseDoneUnary(int index, int endIndex) {
1958 int step = SkSign32(endIndex - index);
1959 int min = SkMin32(index, endIndex);
1960 markDoneUnary(min);
1961 SkOpSpan* last;
1962 SkOpSegment* other = this;
1963 while ((other = other->nextChase(&index, step, &min, &last))) {
1964 if (other->done()) {
1965 return NULL;
1966 }
1967 other->markDoneUnary(min);
1968 }
1969 return last;
1970}
1971
1972SkOpSpan* SkOpSegment::markAndChaseDoneUnary(const SkOpAngle* angle, int winding) {
1973 int index = angle->start();
1974 int endIndex = angle->end();
1975 return markAndChaseDone(index, endIndex, winding);
1976}
1977
1978SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, const int winding) {
1979 int index = angle->start();
1980 int endIndex = angle->end();
1981 int step = SkSign32(endIndex - index);
1982 int min = SkMin32(index, endIndex);
1983 markWinding(min, winding);
1984 SkOpSpan* last;
1985 SkOpSegment* other = this;
1986 while ((other = other->nextChase(&index, step, &min, &last))) {
1987 if (other->fTs[min].fWindSum != SK_MinS32) {
1988 SkASSERT(other->fTs[min].fWindSum == winding);
1989 return NULL;
1990 }
1991 other->markWinding(min, winding);
1992 }
1993 return last;
1994}
1995
1996SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
1997 int min = SkMin32(index, endIndex);
1998 int step = SkSign32(endIndex - index);
1999 markWinding(min, winding, oppWinding);
2000 SkOpSpan* last;
2001 SkOpSegment* other = this;
2002 while ((other = other->nextChase(&index, step, &min, &last))) {
2003 if (other->fTs[min].fWindSum != SK_MinS32) {
2004 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
2005 return NULL;
2006 }
2007 other->markWinding(min, winding, oppWinding);
2008 }
2009 return last;
2010}
2011
2012SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding) {
2013 int start = angle->start();
2014 int end = angle->end();
2015 return markAndChaseWinding(start, end, winding, oppWinding);
2016}
2017
2018SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, bool activeAngle,
2019 const SkOpAngle* angle) {
2020 SkASSERT(angle->segment() == this);
2021 if (UseInnerWinding(maxWinding, sumWinding)) {
2022 maxWinding = sumWinding;
2023 }
2024 SkOpSpan* last;
2025 if (activeAngle) {
2026 last = markAndChaseWinding(angle, maxWinding);
2027 } else {
2028 last = markAndChaseDoneUnary(angle, maxWinding);
2029 }
2030 return last;
2031}
2032
2033SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
2034 int oppSumWinding, bool activeAngle, const SkOpAngle* angle) {
2035 SkASSERT(angle->segment() == this);
2036 if (UseInnerWinding(maxWinding, sumWinding)) {
2037 maxWinding = sumWinding;
2038 }
2039 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
2040 oppMaxWinding = oppSumWinding;
2041 }
2042 SkOpSpan* last;
2043 if (activeAngle) {
2044 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
2045 } else {
2046 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
2047 }
2048 return last;
2049}
2050
2051// FIXME: this should also mark spans with equal (x,y)
2052// This may be called when the segment is already marked done. While this
2053// wastes time, it shouldn't do any more than spin through the T spans.
2054// OPTIMIZATION: abort on first done found (assuming that this code is
2055// always called to mark segments done).
2056void SkOpSegment::markDone(int index, int winding) {
2057 // SkASSERT(!done());
2058 SkASSERT(winding);
2059 double referenceT = fTs[index].fT;
2060 int lesser = index;
2061 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2062 markOneDone(__FUNCTION__, lesser, winding);
2063 }
2064 do {
2065 markOneDone(__FUNCTION__, index, winding);
2066 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2067}
2068
2069void SkOpSegment::markDoneBinary(int index, int winding, int oppWinding) {
2070 // SkASSERT(!done());
2071 SkASSERT(winding || oppWinding);
2072 double referenceT = fTs[index].fT;
2073 int lesser = index;
2074 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2075 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
2076 }
2077 do {
2078 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
2079 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2080}
2081
2082void SkOpSegment::markDoneBinary(int index) {
2083 double referenceT = fTs[index].fT;
2084 int lesser = index;
2085 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2086 markOneDoneBinary(__FUNCTION__, lesser);
2087 }
2088 do {
2089 markOneDoneBinary(__FUNCTION__, index);
2090 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2091}
2092
2093void SkOpSegment::markDoneUnary(int index) {
2094 double referenceT = fTs[index].fT;
2095 int lesser = index;
2096 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2097 markOneDoneUnary(__FUNCTION__, lesser);
2098 }
2099 do {
2100 markOneDoneUnary(__FUNCTION__, index);
2101 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2102}
2103
2104void SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) {
2105 SkOpSpan* span = markOneWinding(funName, tIndex, winding);
2106 if (!span) {
2107 return;
2108 }
2109 span->fDone = true;
2110 fDoneSpans++;
2111}
2112
2113void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) {
2114 SkOpSpan* span = verifyOneWinding(funName, tIndex);
2115 if (!span) {
2116 return;
2117 }
2118 span->fDone = true;
2119 fDoneSpans++;
2120}
2121
2122void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
2123 SkOpSpan* span = markOneWinding(funName, tIndex, winding, oppWinding);
2124 if (!span) {
2125 return;
2126 }
2127 span->fDone = true;
2128 fDoneSpans++;
2129}
2130
2131void SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) {
2132 SkOpSpan* span = verifyOneWindingU(funName, tIndex);
2133 if (!span) {
2134 return;
2135 }
2136 span->fDone = true;
2137 fDoneSpans++;
2138}
2139
2140SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding) {
2141 SkOpSpan& span = fTs[tIndex];
2142 if (span.fDone) {
2143 return NULL;
2144 }
2145#if DEBUG_MARK_DONE
2146 debugShowNewWinding(funName, span, winding);
2147#endif
2148 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
2149#ifdef SK_DEBUG
2150 SkASSERT(abs(winding) <= gDebugMaxWindSum);
2151#endif
2152 span.fWindSum = winding;
2153 return &span;
2154}
2155
2156SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding,
2157 int oppWinding) {
2158 SkOpSpan& span = fTs[tIndex];
2159 if (span.fDone) {
2160 return NULL;
2161 }
2162#if DEBUG_MARK_DONE
2163 debugShowNewWinding(funName, span, winding, oppWinding);
2164#endif
2165 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
2166#ifdef SK_DEBUG
2167 SkASSERT(abs(winding) <= gDebugMaxWindSum);
2168#endif
2169 span.fWindSum = winding;
2170 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
2171#ifdef SK_DEBUG
2172 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
2173#endif
2174 span.fOppSum = oppWinding;
2175 return &span;
2176}
2177
2178// from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
2179bool SkOpSegment::clockwise(int tStart, int tEnd) const {
2180 SkASSERT(fVerb != SkPath::kLine_Verb);
2181 SkPoint edge[4];
2182 subDivide(tStart, tEnd, edge);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002183 int points = SkPathOpsVerbToPoints(fVerb);
2184 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002185 if (fVerb == SkPath::kCubic_Verb) {
2186 SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY);
2187 if (edge[1].fY < lesser && edge[2].fY < lesser) {
2188 SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1].fY} }};
2189 SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3].fY} }};
2190 if (SkIntersections::Test(tangent1, tangent2)) {
2191 SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2192 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY);
2193 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY);
2194 return sum <= 0;
2195 }
2196 }
2197 }
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002198 for (int idx = 0; idx < points; ++idx){
caryclark@google.com07393ca2013-04-08 11:47:37 +00002199 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
2200 }
2201 return sum <= 0;
2202}
2203
2204bool SkOpSegment::monotonicInY(int tStart, int tEnd) const {
2205 if (fVerb == SkPath::kLine_Verb) {
2206 return false;
2207 }
2208 if (fVerb == SkPath::kQuad_Verb) {
2209 SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2210 return dst.monotonicInY();
2211 }
2212 SkASSERT(fVerb == SkPath::kCubic_Verb);
2213 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2214 return dst.monotonicInY();
2215}
2216
2217bool SkOpSegment::serpentine(int tStart, int tEnd) const {
2218 if (fVerb != SkPath::kCubic_Verb) {
2219 return false;
2220 }
2221 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2222 return dst.serpentine();
2223}
2224
2225SkOpSpan* SkOpSegment::verifyOneWinding(const char* funName, int tIndex) {
2226 SkOpSpan& span = fTs[tIndex];
2227 if (span.fDone) {
2228 return NULL;
2229 }
2230#if DEBUG_MARK_DONE
2231 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
2232#endif
2233 SkASSERT(span.fWindSum != SK_MinS32);
2234 SkASSERT(span.fOppSum != SK_MinS32);
2235 return &span;
2236}
2237
2238SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) {
2239 SkOpSpan& span = fTs[tIndex];
2240 if (span.fDone) {
2241 return NULL;
2242 }
2243#if DEBUG_MARK_DONE
2244 debugShowNewWinding(funName, span, span.fWindSum);
2245#endif
2246 SkASSERT(span.fWindSum != SK_MinS32);
2247 return &span;
2248}
2249
2250// note that just because a span has one end that is unsortable, that's
2251// not enough to mark it done. The other end may be sortable, allowing the
2252// span to be added.
2253// FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
2254void SkOpSegment::markUnsortable(int start, int end) {
2255 SkOpSpan* span = &fTs[start];
2256 if (start < end) {
2257#if DEBUG_UNSORTABLE
2258 debugShowNewWinding(__FUNCTION__, *span, 0);
2259#endif
2260 span->fUnsortableStart = true;
2261 } else {
2262 --span;
2263#if DEBUG_UNSORTABLE
2264 debugShowNewWinding(__FUNCTION__, *span, 0);
2265#endif
2266 span->fUnsortableEnd = true;
2267 }
2268 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
2269 return;
2270 }
2271 span->fDone = true;
2272 fDoneSpans++;
2273}
2274
2275void SkOpSegment::markWinding(int index, int winding) {
2276// SkASSERT(!done());
2277 SkASSERT(winding);
2278 double referenceT = fTs[index].fT;
2279 int lesser = index;
2280 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2281 markOneWinding(__FUNCTION__, lesser, winding);
2282 }
2283 do {
2284 markOneWinding(__FUNCTION__, index, winding);
2285 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2286}
2287
2288void SkOpSegment::markWinding(int index, int winding, int oppWinding) {
2289// SkASSERT(!done());
2290 SkASSERT(winding || oppWinding);
2291 double referenceT = fTs[index].fT;
2292 int lesser = index;
2293 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2294 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
2295 }
2296 do {
2297 markOneWinding(__FUNCTION__, index, winding, oppWinding);
2298 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2299}
2300
2301void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) {
2302 int nextDoorWind = SK_MaxS32;
2303 int nextOppWind = SK_MaxS32;
2304 if (tIndex > 0) {
2305 const SkOpSpan& below = fTs[tIndex - 1];
2306 if (approximately_negative(t - below.fT)) {
2307 nextDoorWind = below.fWindValue;
2308 nextOppWind = below.fOppValue;
2309 }
2310 }
2311 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
2312 const SkOpSpan& above = fTs[tIndex + 1];
2313 if (approximately_negative(above.fT - t)) {
2314 nextDoorWind = above.fWindValue;
2315 nextOppWind = above.fOppValue;
2316 }
2317 }
2318 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
2319 const SkOpSpan& below = fTs[tIndex - 1];
2320 nextDoorWind = below.fWindValue;
2321 nextOppWind = below.fOppValue;
2322 }
2323 if (nextDoorWind != SK_MaxS32) {
2324 SkOpSpan& newSpan = fTs[tIndex];
2325 newSpan.fWindValue = nextDoorWind;
2326 newSpan.fOppValue = nextOppWind;
2327 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
2328 newSpan.fDone = true;
2329 ++fDoneSpans;
2330 }
2331 }
2332}
2333
2334// return span if when chasing, two or more radiating spans are not done
2335// OPTIMIZATION: ? multiple spans is detected when there is only one valid
2336// candidate and the remaining spans have windValue == 0 (canceled by
2337// coincidence). The coincident edges could either be removed altogether,
2338// or this code could be more complicated in detecting this case. Worth it?
2339bool SkOpSegment::multipleSpans(int end) const {
2340 return end > 0 && end < fTs.count() - 1;
2341}
2342
2343bool SkOpSegment::nextCandidate(int* start, int* end) const {
2344 while (fTs[*end].fDone) {
2345 if (fTs[*end].fT == 1) {
2346 return false;
2347 }
2348 ++(*end);
2349 }
2350 *start = *end;
2351 *end = nextExactSpan(*start, 1);
2352 return true;
2353}
2354
2355SkOpSegment* SkOpSegment::nextChase(int* index, const int step, int* min, SkOpSpan** last) {
2356 int end = nextExactSpan(*index, step);
2357 SkASSERT(end >= 0);
2358 if (multipleSpans(end)) {
2359 *last = &fTs[end];
2360 return NULL;
2361 }
2362 const SkOpSpan& endSpan = fTs[end];
2363 SkOpSegment* other = endSpan.fOther;
2364 *index = endSpan.fOtherIndex;
fmalita@google.com22eb7942013-05-01 20:35:51 +00002365 SkASSERT(*index >= 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002366 int otherEnd = other->nextExactSpan(*index, step);
2367 SkASSERT(otherEnd >= 0);
2368 *min = SkMin32(*index, otherEnd);
caryclark@google.coma5e55922013-05-07 18:51:31 +00002369 if (other->fTs[*min].fTiny) {
2370 *last = NULL;
2371 return NULL;
2372 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002373 return other;
2374}
2375
2376// This has callers for two different situations: one establishes the end
2377// of the current span, and one establishes the beginning of the next span
2378// (thus the name). When this is looking for the end of the current span,
2379// coincidence is found when the beginning Ts contain -step and the end
2380// contains step. When it is looking for the beginning of the next, the
2381// first Ts found can be ignored and the last Ts should contain -step.
2382// OPTIMIZATION: probably should split into two functions
2383int SkOpSegment::nextSpan(int from, int step) const {
2384 const SkOpSpan& fromSpan = fTs[from];
2385 int count = fTs.count();
2386 int to = from;
2387 while (step > 0 ? ++to < count : --to >= 0) {
2388 const SkOpSpan& span = fTs[to];
2389 if (approximately_zero(span.fT - fromSpan.fT)) {
2390 continue;
2391 }
2392 return to;
2393 }
2394 return -1;
2395}
2396
2397// FIXME
2398// this returns at any difference in T, vs. a preset minimum. It may be
2399// that all callers to nextSpan should use this instead.
2400// OPTIMIZATION splitting this into separate loops for up/down steps
2401// would allow using precisely_negative instead of precisely_zero
2402int SkOpSegment::nextExactSpan(int from, int step) const {
2403 const SkOpSpan& fromSpan = fTs[from];
2404 int count = fTs.count();
2405 int to = from;
2406 while (step > 0 ? ++to < count : --to >= 0) {
2407 const SkOpSpan& span = fTs[to];
2408 if (precisely_zero(span.fT - fromSpan.fT)) {
2409 continue;
2410 }
2411 return to;
2412 }
2413 return -1;
2414}
2415
2416void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
2417 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) {
2418 int deltaSum = spanSign(index, endIndex);
2419 int oppDeltaSum = oppSign(index, endIndex);
2420 if (operand()) {
2421 *maxWinding = *sumSuWinding;
2422 *sumWinding = *sumSuWinding -= deltaSum;
2423 *oppMaxWinding = *sumMiWinding;
2424 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
2425 } else {
2426 *maxWinding = *sumMiWinding;
2427 *sumWinding = *sumMiWinding -= deltaSum;
2428 *oppMaxWinding = *sumSuWinding;
2429 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
2430 }
2431}
2432
2433// This marks all spans unsortable so that this info is available for early
2434// exclusion in find top and others. This could be optimized to only mark
2435// adjacent spans that unsortable. However, this makes it difficult to later
2436// determine starting points for edge detection in find top and the like.
caryclark@google.comd892bd82013-06-17 14:10:36 +00002437bool SkOpSegment::SortAngles(const SkTArray<SkOpAngle, true>& angles,
2438 SkTArray<SkOpAngle*, true>* angleList,
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002439 SortAngleKind orderKind) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002440 bool sortable = true;
2441 int angleCount = angles.count();
2442 int angleIndex;
caryclark@google.comd892bd82013-06-17 14:10:36 +00002443// FIXME: caller needs to use SkTArray constructor with reserve count
2444// angleList->setReserve(angleCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002445 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2446 const SkOpAngle& angle = angles[angleIndex];
caryclark@google.comd892bd82013-06-17 14:10:36 +00002447 angleList->push_back(const_cast<SkOpAngle*>(&angle));
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002448#if DEBUG_ANGLE
2449 (*(angleList->end() - 1))->setID(angleIndex);
2450#endif
2451 sortable &= !(angle.unsortable() || (orderKind == kMustBeOrdered_SortAngleKind
2452 && angle.unorderable()));
caryclark@google.com07393ca2013-04-08 11:47:37 +00002453 }
2454 if (sortable) {
caryclark@google.com7dfbb072013-04-22 14:37:05 +00002455 SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002456 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002457 if (angles[angleIndex].unsortable() || (orderKind == kMustBeOrdered_SortAngleKind
2458 && angles[angleIndex].unorderable())) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002459 sortable = false;
2460 break;
2461 }
2462 }
2463 }
2464 if (!sortable) {
2465 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2466 const SkOpAngle& angle = angles[angleIndex];
2467 angle.segment()->markUnsortable(angle.start(), angle.end());
2468 }
2469 }
2470 return sortable;
2471}
2472
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002473// return true if midpoints were computed
2474bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const {
2475 SkASSERT(start != end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002476 edge[0] = fTs[start].fPt;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002477 int points = SkPathOpsVerbToPoints(fVerb);
2478 edge[points] = fTs[end].fPt;
2479 if (fVerb == SkPath::kLine_Verb) {
2480 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002481 }
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002482 double startT = fTs[start].fT;
2483 double endT = fTs[end].fT;
2484 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
2485 // don't compute midpoints if we already have them
2486 if (fVerb == SkPath::kQuad_Verb) {
2487 edge[1] = fPts[1];
2488 return false;
2489 }
2490 SkASSERT(fVerb == SkPath::kCubic_Verb);
2491 if (start < end) {
2492 edge[1] = fPts[1];
2493 edge[2] = fPts[2];
2494 return false;
2495 }
2496 edge[1] = fPts[2];
2497 edge[2] = fPts[1];
2498 return false;
2499 }
2500 const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[points].fY }};
2501 if (fVerb == SkPath::kQuad_Verb) {
2502 edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
2503 } else {
2504 SkASSERT(fVerb == SkPath::kCubic_Verb);
2505 SkDPoint ctrl[2];
2506 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
2507 edge[1] = ctrl[0].asSkPoint();
2508 edge[2] = ctrl[1].asSkPoint();
2509 }
2510 return true;
2511}
2512
2513// return true if midpoints were computed
2514bool SkOpSegment::subDivide(int start, int end, SkDCubic* result) const {
2515 SkASSERT(start != end);
2516 (*result)[0].set(fTs[start].fPt);
2517 int points = SkPathOpsVerbToPoints(fVerb);
2518 (*result)[points].set(fTs[end].fPt);
2519 if (fVerb == SkPath::kLine_Verb) {
2520 return false;
2521 }
2522 double startT = fTs[start].fT;
2523 double endT = fTs[end].fT;
2524 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
2525 // don't compute midpoints if we already have them
2526 if (fVerb == SkPath::kQuad_Verb) {
2527 (*result)[1].set(fPts[1]);
2528 return false;
2529 }
2530 SkASSERT(fVerb == SkPath::kCubic_Verb);
2531 if (start < end) {
2532 (*result)[1].set(fPts[1]);
2533 (*result)[2].set(fPts[2]);
2534 return false;
2535 }
2536 (*result)[1].set(fPts[2]);
2537 (*result)[2].set(fPts[1]);
2538 return false;
2539 }
2540 if (fVerb == SkPath::kQuad_Verb) {
2541 (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], startT, endT);
2542 } else {
2543 SkASSERT(fVerb == SkPath::kCubic_Verb);
2544 SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*result)[1]);
2545 }
2546 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002547}
2548
2549void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const {
2550 SkPoint edge[4];
2551 subDivide(start, end, edge);
reed@google.com277c3f82013-05-31 15:17:50 +00002552 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002553}
2554
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002555bool SkOpSegment::isTiny(const SkOpAngle* angle) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002556 int start = angle->start();
2557 int end = angle->end();
2558 const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
2559 return mSpan.fTiny;
2560}
2561
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002562bool SkOpSegment::isTiny(int index) const {
2563 return fTs[index].fTiny;
2564}
2565
caryclark@google.comd892bd82013-06-17 14:10:36 +00002566void SkOpSegment::TrackOutside(SkTArray<double, true>* outsideTs, double end, double start) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002567 int outCount = outsideTs->count();
2568 if (outCount == 0 || !approximately_negative(end - (*outsideTs)[outCount - 2])) {
caryclark@google.comd892bd82013-06-17 14:10:36 +00002569 outsideTs->push_back(end);
2570 outsideTs->push_back(start);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002571 }
2572}
2573
2574void SkOpSegment::undoneSpan(int* start, int* end) {
2575 size_t tCount = fTs.count();
2576 size_t index;
2577 for (index = 0; index < tCount; ++index) {
2578 if (!fTs[index].fDone) {
2579 break;
2580 }
2581 }
2582 SkASSERT(index < tCount - 1);
2583 *start = index;
2584 double startT = fTs[index].fT;
2585 while (approximately_negative(fTs[++index].fT - startT))
2586 SkASSERT(index < tCount);
2587 SkASSERT(index < tCount);
2588 *end = index;
2589}
2590
2591int SkOpSegment::updateOppWinding(int index, int endIndex) const {
2592 int lesser = SkMin32(index, endIndex);
2593 int oppWinding = oppSum(lesser);
2594 int oppSpanWinding = oppSign(index, endIndex);
2595 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
2596 && oppWinding != SK_MaxS32) {
2597 oppWinding -= oppSpanWinding;
2598 }
2599 return oppWinding;
2600}
2601
2602int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
2603 int startIndex = angle->start();
2604 int endIndex = angle->end();
2605 return updateOppWinding(endIndex, startIndex);
2606}
2607
2608int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
2609 int startIndex = angle->start();
2610 int endIndex = angle->end();
2611 return updateOppWinding(startIndex, endIndex);
2612}
2613
2614int SkOpSegment::updateWinding(int index, int endIndex) const {
2615 int lesser = SkMin32(index, endIndex);
2616 int winding = windSum(lesser);
2617 int spanWinding = spanSign(index, endIndex);
2618 if (winding && UseInnerWinding(winding - spanWinding, winding) && winding != SK_MaxS32) {
2619 winding -= spanWinding;
2620 }
2621 return winding;
2622}
2623
2624int SkOpSegment::updateWinding(const SkOpAngle* angle) const {
2625 int startIndex = angle->start();
2626 int endIndex = angle->end();
2627 return updateWinding(endIndex, startIndex);
2628}
2629
2630int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const {
2631 int startIndex = angle->start();
2632 int endIndex = angle->end();
2633 return updateWinding(startIndex, endIndex);
2634}
2635
2636int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const {
2637 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
2638 return SK_MinS32;
2639 }
2640 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
2641 SkASSERT(winding != SK_MinS32);
2642 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
2643#if DEBUG_WINDING_AT_T
2644 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
2645#endif
2646 // see if a + change in T results in a +/- change in X (compute x'(T))
reed@google.com277c3f82013-05-31 15:17:50 +00002647 *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002648 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
2649 *dx = fPts[2].fX - fPts[1].fX - *dx;
2650 }
2651 if (*dx == 0) {
2652#if DEBUG_WINDING_AT_T
2653 SkDebugf(" dx=0 winding=SK_MinS32\n");
2654#endif
2655 return SK_MinS32;
2656 }
skia.committer@gmail.coma4aced42013-07-09 07:00:56 +00002657 if (windVal < 0) { // reverse sign if opp contour traveled in reverse
caryclark@google.com07e97fc2013-07-08 17:17:02 +00002658 *dx = -*dx;
2659 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002660 if (winding * *dx > 0) { // if same signs, result is negative
2661 winding += *dx > 0 ? -windVal : windVal;
2662 }
2663#if DEBUG_WINDING_AT_T
2664 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding);
2665#endif
2666 return winding;
2667}
2668
2669int SkOpSegment::windSum(const SkOpAngle* angle) const {
2670 int start = angle->start();
2671 int end = angle->end();
2672 int index = SkMin32(start, end);
2673 return windSum(index);
2674}
2675
2676int SkOpSegment::windValue(const SkOpAngle* angle) const {
2677 int start = angle->start();
2678 int end = angle->end();
2679 int index = SkMin32(start, end);
2680 return windValue(index);
2681}
2682
2683int SkOpSegment::windValueAt(double t) const {
2684 int count = fTs.count();
2685 for (int index = 0; index < count; ++index) {
2686 if (fTs[index].fT == t) {
2687 return fTs[index].fWindValue;
2688 }
2689 }
2690 SkASSERT(0);
2691 return 0;
2692}
2693
2694void SkOpSegment::zeroSpan(SkOpSpan* span) {
caryclark@google.coma5e55922013-05-07 18:51:31 +00002695 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002696 span->fWindValue = 0;
2697 span->fOppValue = 0;
2698 SkASSERT(!span->fDone);
2699 span->fDone = true;
2700 ++fDoneSpans;
2701}
skia.committer@gmail.com32840172013-04-09 07:01:27 +00002702
caryclark@google.com07393ca2013-04-08 11:47:37 +00002703#if DEBUG_SWAP_TOP
2704bool SkOpSegment::controlsContainedByEnds(int tStart, int tEnd) const {
2705 if (fVerb != SkPath::kCubic_Verb) {
2706 return false;
2707 }
2708 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2709 return dst.controlsContainedByEnds();
2710}
2711#endif
2712
2713#if DEBUG_CONCIDENT
2714// SkASSERT if pair has not already been added
2715void SkOpSegment::debugAddTPair(double t, const SkOpSegment& other, double otherT) const {
2716 for (int i = 0; i < fTs.count(); ++i) {
2717 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
2718 return;
2719 }
2720 }
2721 SkASSERT(0);
2722}
2723#endif
2724
2725#if DEBUG_CONCIDENT
2726void SkOpSegment::debugShowTs() const {
2727 SkDebugf("%s id=%d", __FUNCTION__, fID);
2728 int lastWind = -1;
2729 int lastOpp = -1;
2730 double lastT = -1;
2731 int i;
2732 for (i = 0; i < fTs.count(); ++i) {
2733 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
2734 || lastOpp != fTs[i].fOppValue;
2735 if (change && lastWind >= 0) {
2736 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
2737 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
2738 }
2739 if (change) {
2740 SkDebugf(" [o=%d", fTs[i].fOther->fID);
2741 lastWind = fTs[i].fWindValue;
2742 lastOpp = fTs[i].fOppValue;
2743 lastT = fTs[i].fT;
2744 } else {
2745 SkDebugf(",%d", fTs[i].fOther->fID);
2746 }
2747 }
2748 if (i <= 0) {
2749 return;
2750 }
2751 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
2752 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
2753 if (fOperand) {
2754 SkDebugf(" operand");
2755 }
2756 if (done()) {
2757 SkDebugf(" done");
2758 }
2759 SkDebugf("\n");
2760}
2761#endif
2762
caryclark@google.coma5e55922013-05-07 18:51:31 +00002763#if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
caryclark@google.com07393ca2013-04-08 11:47:37 +00002764void SkOpSegment::debugShowActiveSpans() const {
caryclark@google.com4fdbb222013-07-23 15:27:41 +00002765 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00002766 if (done()) {
2767 return;
2768 }
2769#if DEBUG_ACTIVE_SPANS_SHORT_FORM
2770 int lastId = -1;
2771 double lastT = -1;
2772#endif
2773 for (int i = 0; i < fTs.count(); ++i) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002774 if (fTs[i].fDone) {
2775 continue;
2776 }
caryclark@google.coma5e55922013-05-07 18:51:31 +00002777 SkASSERT(i < fTs.count() - 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002778#if DEBUG_ACTIVE_SPANS_SHORT_FORM
2779 if (lastId == fID && lastT == fTs[i].fT) {
2780 continue;
2781 }
2782 lastId = fID;
2783 lastT = fTs[i].fT;
2784#endif
2785 SkDebugf("%s id=%d", __FUNCTION__, fID);
2786 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
reed@google.com277c3f82013-05-31 15:17:50 +00002787 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002788 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
2789 }
2790 const SkOpSpan* span = &fTs[i];
2791 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", span->fT, xAtT(span), yAtT(span));
2792 int iEnd = i + 1;
2793 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) {
2794 ++iEnd;
2795 }
2796 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT);
2797 const SkOpSegment* other = fTs[i].fOther;
2798 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
2799 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
2800 if (fTs[i].fWindSum == SK_MinS32) {
2801 SkDebugf("?");
2802 } else {
2803 SkDebugf("%d", fTs[i].fWindSum);
2804 }
2805 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
2806 }
2807}
2808#endif
2809
2810
2811#if DEBUG_MARK_DONE || DEBUG_UNSORTABLE
2812void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding) {
2813 const SkPoint& pt = xyAtT(&span);
2814 SkDebugf("%s id=%d", fun, fID);
2815 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
reed@google.com277c3f82013-05-31 15:17:50 +00002816 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002817 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
2818 }
2819 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
2820 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
2821 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d windSum=",
2822 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
2823 (&span)[1].fT, winding);
2824 if (span.fWindSum == SK_MinS32) {
2825 SkDebugf("?");
2826 } else {
2827 SkDebugf("%d", span.fWindSum);
2828 }
2829 SkDebugf(" windValue=%d\n", span.fWindValue);
2830}
2831
2832void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding,
2833 int oppWinding) {
2834 const SkPoint& pt = xyAtT(&span);
2835 SkDebugf("%s id=%d", fun, fID);
2836 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
reed@google.com277c3f82013-05-31 15:17:50 +00002837 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002838 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
2839 }
2840 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
2841 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
2842 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d newOppSum=%d oppSum=",
2843 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
2844 (&span)[1].fT, winding, oppWinding);
2845 if (span.fOppSum == SK_MinS32) {
2846 SkDebugf("?");
2847 } else {
2848 SkDebugf("%d", span.fOppSum);
2849 }
2850 SkDebugf(" windSum=");
2851 if (span.fWindSum == SK_MinS32) {
2852 SkDebugf("?");
2853 } else {
2854 SkDebugf("%d", span.fWindSum);
2855 }
2856 SkDebugf(" windValue=%d\n", span.fWindValue);
2857}
2858#endif
2859
2860#if DEBUG_SORT || DEBUG_SWAP_TOP
caryclark@google.comd892bd82013-06-17 14:10:36 +00002861void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles,
2862 int first, const int contourWinding,
caryclark@google.com07e97fc2013-07-08 17:17:02 +00002863 const int oppContourWinding, bool sortable) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002864 if (--gDebugSortCount < 0) {
2865 return;
2866 }
2867 SkASSERT(angles[first]->segment() == this);
caryclark@google.com07e97fc2013-07-08 17:17:02 +00002868 SkASSERT(!sortable || angles.count() > 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002869 int lastSum = contourWinding;
2870 int oppLastSum = oppContourWinding;
2871 const SkOpAngle* firstAngle = angles[first];
2872 int windSum = lastSum - spanSign(firstAngle);
2873 int oppoSign = oppSign(firstAngle);
2874 int oppWindSum = oppLastSum - oppoSign;
2875 #define WIND_AS_STRING(x) char x##Str[12]; if (!valid_wind(x)) strcpy(x##Str, "?"); \
caryclark@google.comad65a3e2013-04-15 19:13:59 +00002876 else SK_SNPRINTF(x##Str, sizeof(x##Str), "%d", x)
caryclark@google.com07393ca2013-04-08 11:47:37 +00002877 WIND_AS_STRING(contourWinding);
2878 WIND_AS_STRING(oppContourWinding);
2879 SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FUNCTION__,
2880 contourWindingStr, oppContourWindingStr, spanSign(angles[first]));
2881 int index = first;
2882 bool firstTime = true;
2883 do {
2884 const SkOpAngle& angle = *angles[index];
2885 const SkOpSegment& segment = *angle.segment();
2886 int start = angle.start();
2887 int end = angle.end();
2888 const SkOpSpan& sSpan = segment.fTs[start];
2889 const SkOpSpan& eSpan = segment.fTs[end];
2890 const SkOpSpan& mSpan = segment.fTs[SkMin32(start, end)];
2891 bool opp = segment.fOperand ^ fOperand;
2892 if (!firstTime) {
2893 oppoSign = segment.oppSign(&angle);
2894 if (opp) {
2895 oppLastSum = oppWindSum;
2896 oppWindSum -= segment.spanSign(&angle);
2897 if (oppoSign) {
2898 lastSum = windSum;
2899 windSum -= oppoSign;
2900 }
2901 } else {
2902 lastSum = windSum;
2903 windSum -= segment.spanSign(&angle);
2904 if (oppoSign) {
2905 oppLastSum = oppWindSum;
2906 oppWindSum -= oppoSign;
2907 }
2908 }
2909 }
2910 SkDebugf("%s [%d] %s", __FUNCTION__, index,
2911 angle.unsortable() ? "*** UNSORTABLE *** " : "");
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002912 #if DEBUG_SORT_COMPACT
2913 SkDebugf("id=%d %s start=%d (%1.9g,%1.9g) end=%d (%1.9g,%1.9g)",
reed@google.com277c3f82013-05-31 15:17:50 +00002914 segment.fID, kLVerbStr[SkPathOpsVerbToPoints(segment.fVerb)],
caryclark@google.com07393ca2013-04-08 11:47:37 +00002915 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
2916 segment.xAtT(&eSpan), segment.yAtT(&eSpan));
2917 #else
2918 switch (segment.fVerb) {
2919 case SkPath::kLine_Verb:
2920 SkDebugf(LINE_DEBUG_STR, LINE_DEBUG_DATA(segment.fPts));
2921 break;
2922 case SkPath::kQuad_Verb:
2923 SkDebugf(QUAD_DEBUG_STR, QUAD_DEBUG_DATA(segment.fPts));
2924 break;
2925 case SkPath::kCubic_Verb:
2926 SkDebugf(CUBIC_DEBUG_STR, CUBIC_DEBUG_DATA(segment.fPts));
2927 break;
2928 default:
2929 SkASSERT(0);
2930 }
2931 SkDebugf(" tStart=%1.9g tEnd=%1.9g", sSpan.fT, eSpan.fT);
2932 #endif
2933 SkDebugf(" sign=%d windValue=%d windSum=", angle.sign(), mSpan.fWindValue);
caryclark@google.com03610322013-04-18 15:58:21 +00002934 winding_printf(mSpan.fWindSum);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002935 int last, wind;
2936 if (opp) {
2937 last = oppLastSum;
2938 wind = oppWindSum;
2939 } else {
2940 last = lastSum;
2941 wind = windSum;
2942 }
2943 bool useInner = valid_wind(last) && valid_wind(wind) && UseInnerWinding(last, wind);
2944 WIND_AS_STRING(last);
2945 WIND_AS_STRING(wind);
2946 WIND_AS_STRING(lastSum);
2947 WIND_AS_STRING(oppLastSum);
2948 WIND_AS_STRING(windSum);
2949 WIND_AS_STRING(oppWindSum);
2950 #undef WIND_AS_STRING
2951 if (!oppoSign) {
2952 SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr : lastStr);
2953 } else {
2954 SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : oppLastSumStr,
2955 opp ? windSumStr : oppWindSumStr);
2956 }
2957 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.comad65a3e2013-04-15 19:13:59 +00002958#if 0 && DEBUG_ANGLE
caryclark@google.com07393ca2013-04-08 11:47:37 +00002959 angle.debugShow(segment.xyAtT(&sSpan));
2960#endif
2961 ++index;
2962 if (index == angles.count()) {
2963 index = 0;
2964 }
2965 if (firstTime) {
2966 firstTime = false;
2967 }
2968 } while (index != first);
2969}
2970
caryclark@google.comd892bd82013-06-17 14:10:36 +00002971void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles,
caryclark@google.com07e97fc2013-07-08 17:17:02 +00002972 int first, bool sortable) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002973 const SkOpAngle* firstAngle = angles[first];
2974 const SkOpSegment* segment = firstAngle->segment();
2975 int winding = segment->updateWinding(firstAngle);
2976 int oppWinding = segment->updateOppWinding(firstAngle);
caryclark@google.com07e97fc2013-07-08 17:17:02 +00002977 debugShowSort(fun, angles, first, winding, oppWinding, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002978}
2979
2980#endif
2981
2982#if DEBUG_SHOW_WINDING
2983int SkOpSegment::debugShowWindingValues(int slotCount, int ofInterest) const {
2984 if (!(1 << fID & ofInterest)) {
2985 return 0;
2986 }
2987 int sum = 0;
caryclark@google.comd892bd82013-06-17 14:10:36 +00002988 SkTArray<char, true> slots(slotCount * 2);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002989 memset(slots.begin(), ' ', slotCount * 2);
2990 for (int i = 0; i < fTs.count(); ++i) {
2991 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
2992 // continue;
2993 // }
2994 sum += fTs[i].fWindValue;
2995 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
2996 sum += fTs[i].fOppValue;
2997 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
2998 }
2999 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
3000 slots.begin() + slotCount);
3001 return sum;
3002}
3003#endif
caryclark@google.com4fdbb222013-07-23 15:27:41 +00003004
3005void SkOpSegment::debugValidate() const {
3006#if DEBUG_VALIDATE
3007 int count = fTs.count();
3008 SkASSERT(count >= 2);
3009 SkASSERT(fTs[0].fT == 0);
3010 SkASSERT(fTs[count - 1].fT == 1);
3011 int done = 0;
3012 double t = -1;
3013 for (int i = 0; i < count; ++i) {
3014 const SkOpSpan& span = fTs[i];
3015 SkASSERT(t <= span.fT);
3016 t = span.fT;
3017 int otherIndex = span.fOtherIndex;
3018 const SkOpSegment* other = span.fOther;
3019 const SkOpSpan& otherSpan = other->fTs[otherIndex];
3020 SkASSERT(otherSpan.fPt == span.fPt);
3021 SkASSERT(otherSpan.fOtherT == t);
3022 SkASSERT(&fTs[i] == &otherSpan.fOther->fTs[otherSpan.fOtherIndex]);
3023 done += span.fDone;
3024 }
3025 SkASSERT(done == fDoneSpans);
3026#endif
3027}