blob: 5b2074995734ecccc454b77f6ecb9bb09fb486fa [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() {
1085#if 1
1086 return; // FIXME: suspect we will need the code below to make intersections consistent
1087#else
1088 SkTDArray<SkOpSpan> missingSpans;
1089 int count = fTs.count();
1090 for (int index = 0; index < count; ++index) {
1091 const SkOpSpan& span = fTs[index];
1092 const SkOpSegment* other = span.fOther;
1093 const SkOpSpan* otherSpan = &other->fTs[span.fOtherIndex];
1094 double otherT = otherSpan->fT;
1095 if (otherT != 0 && otherT != 1) {
1096 continue;
1097 }
1098 int peekStart = span.fOtherIndex;
1099 while (peekStart > 0) {
1100 const SkOpSpan* peeker = &other->fTs[peekStart - 1];
1101 if (peeker->fT != otherT) {
1102 break;
1103 }
1104 --peekStart;
1105 }
1106 int otherLast = other->fTs.count() - 1;
1107 int peekLast = span.fOtherIndex;
1108 while (peekLast < otherLast) {
1109 const SkOpSpan* peeker = &other->fTs[peekLast + 1];
1110 if (peeker->fT != otherT) {
1111 break;
1112 }
1113 ++peekLast;
1114 }
1115 if (peekStart == peekLast) {
1116 continue;
1117 }
1118 double t = span.fT;
1119 int tStart = index;
1120 while (tStart > 0 && t == fTs[tStart - 1].fT) {
1121 --tStart;
1122 }
1123 int tLast = index;
1124 int last = count - 1;
1125 while (tLast < last && t == fTs[tLast + 1].fT) {
1126 ++tLast;
1127 }
1128 for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) {
1129 if (peekIndex == span.fOtherIndex) {
1130 continue;
1131 }
1132 const SkOpSpan& peekSpan = other->fTs[peekIndex];
1133 SkOpSegment* match = peekSpan.fOther;
1134 const double matchT = peekSpan.fOtherT;
1135 for (int tIndex = tStart; tIndex <= tLast; ++tIndex) {
1136 const SkOpSpan& tSpan = fTs[tIndex];
1137 if (tSpan.fOther == match && tSpan.fOtherT == matchT) {
1138 goto nextPeeker;
1139 }
1140 }
1141 // this segment is missing a entry that the other contains
1142 // remember so we can add the missing one and recompute the indices
1143 SkOpSpan* missing = missingSpans.append();
1144 missing->fT = t;
1145 missing->fOther = match;
1146 missing->fOtherT = matchT;
1147 missing->fPt = peekSpan.fPt;
1148 }
1149nextPeeker:
1150 ;
1151 }
1152 int missingCount = missingSpans.count();
1153 for (int index = 0; index < missingCount; ++index) {
1154 const SkOpSpan& missing = missingSpans[index];
1155 addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt);
1156 }
1157 if (missingCount > 0) {
1158 fixOtherTIndex();
1159 }
1160#endif
1161}
1162
caryclark@google.com07393ca2013-04-08 11:47:37 +00001163bool SkOpSegment::equalPoints(int greaterTIndex, int lesserTIndex) {
1164 SkASSERT(greaterTIndex >= lesserTIndex);
1165 double greaterT = fTs[greaterTIndex].fT;
1166 double lesserT = fTs[lesserTIndex].fT;
1167 if (greaterT == lesserT) {
1168 return true;
1169 }
1170 if (!approximately_negative(greaterT - lesserT)) {
1171 return false;
1172 }
1173 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
1174}
1175
1176/*
1177 The M and S variable name parts stand for the operators.
1178 Mi stands for Minuend (see wiki subtraction, analogous to difference)
1179 Su stands for Subtrahend
1180 The Opp variable name part designates that the value is for the Opposite operator.
1181 Opposite values result from combining coincident spans.
1182 */
1183SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
1184 bool* unsortable, SkPathOp op, const int xorMiMask,
1185 const int xorSuMask) {
1186 const int startIndex = *nextStart;
1187 const int endIndex = *nextEnd;
1188 SkASSERT(startIndex != endIndex);
1189 SkDEBUGCODE(const int count = fTs.count());
1190 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
1191 const int step = SkSign32(endIndex - startIndex);
1192 const int end = nextExactSpan(startIndex, step);
1193 SkASSERT(end >= 0);
1194 SkOpSpan* endSpan = &fTs[end];
1195 SkOpSegment* other;
1196 if (isSimple(end)) {
1197 // mark the smaller of startIndex, endIndex done, and all adjacent
1198 // spans with the same T value (but not 'other' spans)
1199#if DEBUG_WINDING
1200 SkDebugf("%s simple\n", __FUNCTION__);
1201#endif
1202 int min = SkMin32(startIndex, endIndex);
1203 if (fTs[min].fDone) {
1204 return NULL;
1205 }
1206 markDoneBinary(min);
1207 other = endSpan->fOther;
1208 *nextStart = endSpan->fOtherIndex;
1209 double startT = other->fTs[*nextStart].fT;
1210 *nextEnd = *nextStart;
1211 do {
1212 *nextEnd += step;
1213 }
1214 while (precisely_zero(startT - other->fTs[*nextEnd].fT));
1215 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001216 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001217 *unsortable = true;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001218 return NULL;
1219 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001220 return other;
1221 }
1222 // more than one viable candidate -- measure angles to find best
caryclark@google.comd892bd82013-06-17 14:10:36 +00001223 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001224 SkASSERT(startIndex - endIndex != 0);
1225 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
1226 addTwoAngles(startIndex, end, &angles);
1227 buildAngles(end, &angles, true);
caryclark@google.comd892bd82013-06-17 14:10:36 +00001228 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001229 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_SortAngleKind);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001230 int angleCount = angles.count();
1231 int firstIndex = findStartingEdge(sorted, startIndex, end);
1232 SkASSERT(firstIndex >= 0);
1233#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001234 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001235#endif
1236 if (!sortable) {
1237 *unsortable = true;
1238 return NULL;
1239 }
1240 SkASSERT(sorted[firstIndex]->segment() == this);
1241#if DEBUG_WINDING
1242 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
1243 sorted[firstIndex]->sign());
1244#endif
1245 int sumMiWinding = updateWinding(endIndex, startIndex);
1246 int sumSuWinding = updateOppWinding(endIndex, startIndex);
1247 if (operand()) {
1248 SkTSwap<int>(sumMiWinding, sumSuWinding);
1249 }
1250 int nextIndex = firstIndex + 1;
1251 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1252 const SkOpAngle* foundAngle = NULL;
1253 bool foundDone = false;
1254 // iterate through the angle, and compute everyone's winding
1255 SkOpSegment* nextSegment;
1256 int activeCount = 0;
1257 do {
1258 SkASSERT(nextIndex != firstIndex);
1259 if (nextIndex == angleCount) {
1260 nextIndex = 0;
1261 }
1262 const SkOpAngle* nextAngle = sorted[nextIndex];
1263 nextSegment = nextAngle->segment();
1264 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1265 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
1266 nextAngle->end(), op, &sumMiWinding, &sumSuWinding,
1267 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1268 if (activeAngle) {
1269 ++activeCount;
1270 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001271 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001272 *unsortable = true;
1273 return NULL;
1274 }
1275 foundAngle = nextAngle;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001276 foundDone = nextSegment->done(nextAngle) && !nextSegment->isTiny(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001277 }
1278 }
1279 if (nextSegment->done()) {
1280 continue;
1281 }
1282 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
1283 continue;
1284 }
1285 SkOpSpan* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
1286 oppSumWinding, activeAngle, nextAngle);
1287 if (last) {
1288 *chase->append() = last;
1289#if DEBUG_WINDING
1290 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
1291 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
1292#endif
1293 }
1294 } while (++nextIndex != lastIndex);
1295 markDoneBinary(SkMin32(startIndex, endIndex));
1296 if (!foundAngle) {
1297 return NULL;
1298 }
1299 *nextStart = foundAngle->start();
1300 *nextEnd = foundAngle->end();
1301 nextSegment = foundAngle->segment();
1302
1303#if DEBUG_WINDING
1304 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1305 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1306 #endif
1307 return nextSegment;
1308}
1309
1310SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart,
1311 int* nextEnd, bool* unsortable) {
1312 const int startIndex = *nextStart;
1313 const int endIndex = *nextEnd;
1314 SkASSERT(startIndex != endIndex);
1315 SkDEBUGCODE(const int count = fTs.count());
1316 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
1317 const int step = SkSign32(endIndex - startIndex);
1318 const int end = nextExactSpan(startIndex, step);
1319 SkASSERT(end >= 0);
1320 SkOpSpan* endSpan = &fTs[end];
1321 SkOpSegment* other;
1322 if (isSimple(end)) {
1323 // mark the smaller of startIndex, endIndex done, and all adjacent
1324 // spans with the same T value (but not 'other' spans)
1325#if DEBUG_WINDING
1326 SkDebugf("%s simple\n", __FUNCTION__);
1327#endif
1328 int min = SkMin32(startIndex, endIndex);
1329 if (fTs[min].fDone) {
1330 return NULL;
1331 }
1332 markDoneUnary(min);
1333 other = endSpan->fOther;
1334 *nextStart = endSpan->fOtherIndex;
1335 double startT = other->fTs[*nextStart].fT;
1336 *nextEnd = *nextStart;
1337 do {
1338 *nextEnd += step;
1339 }
1340 while (precisely_zero(startT - other->fTs[*nextEnd].fT));
1341 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
1342 return other;
1343 }
1344 // more than one viable candidate -- measure angles to find best
caryclark@google.comd892bd82013-06-17 14:10:36 +00001345 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001346 SkASSERT(startIndex - endIndex != 0);
1347 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
1348 addTwoAngles(startIndex, end, &angles);
1349 buildAngles(end, &angles, true);
caryclark@google.comd892bd82013-06-17 14:10:36 +00001350 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001351 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_SortAngleKind);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001352 int angleCount = angles.count();
1353 int firstIndex = findStartingEdge(sorted, startIndex, end);
1354 SkASSERT(firstIndex >= 0);
1355#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001356 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001357#endif
1358 if (!sortable) {
1359 *unsortable = true;
1360 return NULL;
1361 }
1362 SkASSERT(sorted[firstIndex]->segment() == this);
1363#if DEBUG_WINDING
1364 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
1365 sorted[firstIndex]->sign());
1366#endif
1367 int sumWinding = updateWinding(endIndex, startIndex);
1368 int nextIndex = firstIndex + 1;
1369 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1370 const SkOpAngle* foundAngle = NULL;
1371 bool foundDone = false;
1372 // iterate through the angle, and compute everyone's winding
1373 SkOpSegment* nextSegment;
1374 int activeCount = 0;
1375 do {
1376 SkASSERT(nextIndex != firstIndex);
1377 if (nextIndex == angleCount) {
1378 nextIndex = 0;
1379 }
1380 const SkOpAngle* nextAngle = sorted[nextIndex];
1381 nextSegment = nextAngle->segment();
1382 int maxWinding;
1383 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
1384 &maxWinding, &sumWinding);
1385 if (activeAngle) {
1386 ++activeCount;
1387 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001388 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001389 *unsortable = true;
1390 return NULL;
1391 }
1392 foundAngle = nextAngle;
1393 foundDone = nextSegment->done(nextAngle);
1394 }
1395 }
1396 if (nextSegment->done()) {
1397 continue;
1398 }
1399 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
1400 continue;
1401 }
1402 SkOpSpan* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
1403 if (last) {
1404 *chase->append() = last;
1405#if DEBUG_WINDING
1406 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
1407 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
1408#endif
1409 }
1410 } while (++nextIndex != lastIndex);
1411 markDoneUnary(SkMin32(startIndex, endIndex));
1412 if (!foundAngle) {
1413 return NULL;
1414 }
1415 *nextStart = foundAngle->start();
1416 *nextEnd = foundAngle->end();
1417 nextSegment = foundAngle->segment();
1418#if DEBUG_WINDING
1419 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1420 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1421 #endif
1422 return nextSegment;
1423}
1424
1425SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsortable) {
1426 const int startIndex = *nextStart;
1427 const int endIndex = *nextEnd;
1428 SkASSERT(startIndex != endIndex);
1429 SkDEBUGCODE(int count = fTs.count());
1430 SkASSERT(startIndex < endIndex ? startIndex < count - 1
1431 : startIndex > 0);
1432 int step = SkSign32(endIndex - startIndex);
1433 int end = nextExactSpan(startIndex, step);
1434 SkASSERT(end >= 0);
1435 SkOpSpan* endSpan = &fTs[end];
1436 SkOpSegment* other;
1437 if (isSimple(end)) {
1438#if DEBUG_WINDING
1439 SkDebugf("%s simple\n", __FUNCTION__);
1440#endif
1441 int min = SkMin32(startIndex, endIndex);
1442 if (fTs[min].fDone) {
1443 return NULL;
1444 }
1445 markDone(min, 1);
1446 other = endSpan->fOther;
1447 *nextStart = endSpan->fOtherIndex;
1448 double startT = other->fTs[*nextStart].fT;
1449 // FIXME: I don't know why the logic here is difference from the winding case
1450 SkDEBUGCODE(bool firstLoop = true;)
1451 if ((approximately_less_than_zero(startT) && step < 0)
1452 || (approximately_greater_than_one(startT) && step > 0)) {
1453 step = -step;
1454 SkDEBUGCODE(firstLoop = false;)
1455 }
1456 do {
1457 *nextEnd = *nextStart;
1458 do {
1459 *nextEnd += step;
1460 }
1461 while (precisely_zero(startT - other->fTs[*nextEnd].fT));
1462 if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) {
1463 break;
1464 }
1465#ifdef SK_DEBUG
1466 SkASSERT(firstLoop);
1467#endif
1468 SkDEBUGCODE(firstLoop = false;)
1469 step = -step;
1470 } while (true);
1471 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
1472 return other;
1473 }
caryclark@google.comd892bd82013-06-17 14:10:36 +00001474 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001475 SkASSERT(startIndex - endIndex != 0);
1476 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
1477 addTwoAngles(startIndex, end, &angles);
1478 buildAngles(end, &angles, false);
caryclark@google.comd892bd82013-06-17 14:10:36 +00001479 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001480 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_SortAngleKind);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001481 if (!sortable) {
1482 *unsortable = true;
1483#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001484 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0,
1485 sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001486#endif
1487 return NULL;
1488 }
1489 int angleCount = angles.count();
1490 int firstIndex = findStartingEdge(sorted, startIndex, end);
1491 SkASSERT(firstIndex >= 0);
1492#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001493 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001494#endif
1495 SkASSERT(sorted[firstIndex]->segment() == this);
1496 int nextIndex = firstIndex + 1;
1497 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1498 const SkOpAngle* foundAngle = NULL;
1499 bool foundDone = false;
1500 SkOpSegment* nextSegment;
1501 int activeCount = 0;
1502 do {
1503 SkASSERT(nextIndex != firstIndex);
1504 if (nextIndex == angleCount) {
1505 nextIndex = 0;
1506 }
1507 const SkOpAngle* nextAngle = sorted[nextIndex];
1508 nextSegment = nextAngle->segment();
1509 ++activeCount;
1510 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001511 if (nextSegment->isTiny(nextAngle)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001512 *unsortable = true;
1513 return NULL;
1514 }
1515 foundAngle = nextAngle;
1516 foundDone = nextSegment->done(nextAngle);
1517 }
1518 if (nextSegment->done()) {
1519 continue;
1520 }
1521 } while (++nextIndex != lastIndex);
1522 markDone(SkMin32(startIndex, endIndex), 1);
1523 if (!foundAngle) {
1524 return NULL;
1525 }
1526 *nextStart = foundAngle->start();
1527 *nextEnd = foundAngle->end();
1528 nextSegment = foundAngle->segment();
1529#if DEBUG_WINDING
1530 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1531 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1532 #endif
1533 return nextSegment;
1534}
1535
caryclark@google.comd892bd82013-06-17 14:10:36 +00001536int SkOpSegment::findStartingEdge(const SkTArray<SkOpAngle*, true>& sorted, int start, int end) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001537 int angleCount = sorted.count();
1538 int firstIndex = -1;
1539 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
1540 const SkOpAngle* angle = sorted[angleIndex];
1541 if (angle->segment() == this && angle->start() == end &&
1542 angle->end() == start) {
1543 firstIndex = angleIndex;
1544 break;
1545 }
1546 }
1547 return firstIndex;
1548}
1549
1550// FIXME: this is tricky code; needs its own unit test
1551// note that fOtherIndex isn't computed yet, so it can't be used here
1552void SkOpSegment::findTooCloseToCall() {
1553 int count = fTs.count();
1554 if (count < 3) { // require t=0, x, 1 at minimum
1555 return;
1556 }
1557 int matchIndex = 0;
1558 int moCount;
1559 SkOpSpan* match;
1560 SkOpSegment* mOther;
1561 do {
1562 match = &fTs[matchIndex];
1563 mOther = match->fOther;
1564 // FIXME: allow quads, cubics to be near coincident?
1565 if (mOther->fVerb == SkPath::kLine_Verb) {
1566 moCount = mOther->fTs.count();
1567 if (moCount >= 3) {
1568 break;
1569 }
1570 }
1571 if (++matchIndex >= count) {
1572 return;
1573 }
1574 } while (true); // require t=0, x, 1 at minimum
1575 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
1576 const SkPoint* matchPt = &xyAtT(match);
1577 // look for a pair of nearby T values that map to the same (x,y) value
1578 // if found, see if the pair of other segments share a common point. If
1579 // so, the span from here to there is coincident.
1580 for (int index = matchIndex + 1; index < count; ++index) {
1581 SkOpSpan* test = &fTs[index];
1582 if (test->fDone) {
1583 continue;
1584 }
1585 SkOpSegment* tOther = test->fOther;
1586 if (tOther->fVerb != SkPath::kLine_Verb) {
1587 continue; // FIXME: allow quads, cubics to be near coincident?
1588 }
1589 int toCount = tOther->fTs.count();
1590 if (toCount < 3) { // require t=0, x, 1 at minimum
1591 continue;
1592 }
1593 const SkPoint* testPt = &xyAtT(test);
1594 if (*matchPt != *testPt) {
1595 matchIndex = index;
1596 moCount = toCount;
1597 match = test;
1598 mOther = tOther;
1599 matchPt = testPt;
1600 continue;
1601 }
1602 int moStart = -1;
1603 int moEnd = -1;
1604 double moStartT = 0;
1605 double moEndT = 0;
1606 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
1607 SkOpSpan& moSpan = mOther->fTs[moIndex];
1608 if (moSpan.fDone) {
1609 continue;
1610 }
1611 if (moSpan.fOther == this) {
1612 if (moSpan.fOtherT == match->fT) {
1613 moStart = moIndex;
1614 moStartT = moSpan.fT;
1615 }
1616 continue;
1617 }
1618 if (moSpan.fOther == tOther) {
1619 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
1620 moStart = -1;
1621 break;
1622 }
1623 SkASSERT(moEnd == -1);
1624 moEnd = moIndex;
1625 moEndT = moSpan.fT;
1626 }
1627 }
1628 if (moStart < 0 || moEnd < 0) {
1629 continue;
1630 }
1631 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
1632 if (approximately_equal(moStartT, moEndT)) {
1633 continue;
1634 }
1635 int toStart = -1;
1636 int toEnd = -1;
1637 double toStartT = 0;
1638 double toEndT = 0;
1639 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
1640 SkOpSpan& toSpan = tOther->fTs[toIndex];
1641 if (toSpan.fDone) {
1642 continue;
1643 }
1644 if (toSpan.fOther == this) {
1645 if (toSpan.fOtherT == test->fT) {
1646 toStart = toIndex;
1647 toStartT = toSpan.fT;
1648 }
1649 continue;
1650 }
1651 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
1652 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
1653 moStart = -1;
1654 break;
1655 }
1656 SkASSERT(toEnd == -1);
1657 toEnd = toIndex;
1658 toEndT = toSpan.fT;
1659 }
1660 }
1661 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
1662 if (toStart <= 0 || toEnd <= 0) {
1663 continue;
1664 }
1665 if (approximately_equal(toStartT, toEndT)) {
1666 continue;
1667 }
1668 // test to see if the segment between there and here is linear
1669 if (!mOther->isLinear(moStart, moEnd)
1670 || !tOther->isLinear(toStart, toEnd)) {
1671 continue;
1672 }
1673 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
1674 if (flipped) {
1675 mOther->addTCancel(moStartT, moEndT, tOther, toEndT, toStartT);
1676 } else {
1677 mOther->addTCoincident(moStartT, moEndT, tOther, toStartT, toEndT);
1678 }
1679 }
1680}
1681
1682// FIXME: either:
1683// a) mark spans with either end unsortable as done, or
1684// b) rewrite findTop / findTopSegment / findTopContour to iterate further
1685// when encountering an unsortable span
1686
1687// OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
1688// and use more concise logic like the old edge walker code?
1689// FIXME: this needs to deal with coincident edges
1690SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable,
1691 bool onlySortable) {
1692 // iterate through T intersections and return topmost
1693 // topmost tangent from y-min to first pt is closer to horizontal
1694 SkASSERT(!done());
1695 int firstT = -1;
1696 /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT);
1697 if (firstT < 0) {
1698 *unsortable = true;
1699 firstT = 0;
1700 while (fTs[firstT].fDone) {
1701 SkASSERT(firstT < fTs.count());
1702 ++firstT;
1703 }
1704 *tIndexPtr = firstT;
1705 *endIndexPtr = nextExactSpan(firstT, 1);
1706 return this;
1707 }
1708 // sort the edges to find the leftmost
1709 int step = 1;
1710 int end = nextSpan(firstT, step);
1711 if (end == -1) {
1712 step = -1;
1713 end = nextSpan(firstT, step);
1714 SkASSERT(end != -1);
1715 }
1716 // if the topmost T is not on end, or is three-way or more, find left
1717 // look for left-ness from tLeft to firstT (matching y of other)
caryclark@google.comd892bd82013-06-17 14:10:36 +00001718 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001719 SkASSERT(firstT - end != 0);
1720 addTwoAngles(end, firstT, &angles);
1721 buildAngles(firstT, &angles, true);
caryclark@google.comd892bd82013-06-17 14:10:36 +00001722 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001723 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMayBeUnordered_SortAngleKind);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001724 int first = SK_MaxS32;
1725 SkScalar top = SK_ScalarMax;
1726 int count = sorted.count();
1727 for (int index = 0; index < count; ++index) {
1728 const SkOpAngle* angle = sorted[index];
1729 SkOpSegment* next = angle->segment();
1730 SkPathOpsBounds bounds;
1731 next->subDivideBounds(angle->end(), angle->start(), &bounds);
1732 if (approximately_greater(top, bounds.fTop)) {
1733 top = bounds.fTop;
1734 first = index;
1735 }
1736 }
1737 SkASSERT(first < SK_MaxS32);
1738#if DEBUG_SORT // || DEBUG_SWAP_TOP
caryclark@google.com07e97fc2013-07-08 17:17:02 +00001739 sorted[first]->segment()->debugShowSort(__FUNCTION__, sorted, first, 0, 0, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001740#endif
1741 if (onlySortable && !sortable) {
1742 *unsortable = true;
1743 return NULL;
1744 }
1745 // skip edges that have already been processed
1746 firstT = first - 1;
1747 SkOpSegment* leftSegment;
1748 do {
1749 if (++firstT == count) {
1750 firstT = 0;
1751 }
1752 const SkOpAngle* angle = sorted[firstT];
1753 SkASSERT(!onlySortable || !angle->unsortable());
1754 leftSegment = angle->segment();
1755 *tIndexPtr = angle->end();
1756 *endIndexPtr = angle->start();
1757 } while (leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone);
1758 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
1759 const int tIndex = *tIndexPtr;
1760 const int endIndex = *endIndexPtr;
1761 if (!leftSegment->clockwise(tIndex, endIndex)) {
1762 bool swap = !leftSegment->monotonicInY(tIndex, endIndex)
1763 && !leftSegment->serpentine(tIndex, endIndex);
1764 #if DEBUG_SWAP_TOP
1765 SkDebugf("%s swap=%d serpentine=%d containedByEnds=%d monotonic=%d\n", __FUNCTION__,
1766 swap,
1767 leftSegment->serpentine(tIndex, endIndex),
1768 leftSegment->controlsContainedByEnds(tIndex, endIndex),
1769 leftSegment->monotonicInY(tIndex, endIndex));
1770 #endif
1771 if (swap) {
1772 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first
1773 // sorted but merely the first not already processed (i.e., not done)
1774 SkTSwap(*tIndexPtr, *endIndexPtr);
1775 }
1776 }
1777 }
1778 SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny);
1779 return leftSegment;
1780}
1781
1782// FIXME: not crazy about this
1783// when the intersections are performed, the other index is into an
1784// incomplete array. As the array grows, the indices become incorrect
1785// while the following fixes the indices up again, it isn't smart about
1786// skipping segments whose indices are already correct
1787// assuming we leave the code that wrote the index in the first place
1788void SkOpSegment::fixOtherTIndex() {
1789 int iCount = fTs.count();
1790 for (int i = 0; i < iCount; ++i) {
1791 SkOpSpan& iSpan = fTs[i];
1792 double oT = iSpan.fOtherT;
1793 SkOpSegment* other = iSpan.fOther;
1794 int oCount = other->fTs.count();
1795 for (int o = 0; o < oCount; ++o) {
1796 SkOpSpan& oSpan = other->fTs[o];
1797 if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan.fT) {
1798 iSpan.fOtherIndex = o;
1799 break;
1800 }
1801 }
1802 }
1803}
1804
1805void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
1806 fDoneSpans = 0;
1807 fOperand = operand;
1808 fXor = evenOdd;
1809 fPts = pts;
1810 fVerb = verb;
1811}
1812
1813void SkOpSegment::initWinding(int start, int end) {
1814 int local = spanSign(start, end);
1815 int oppLocal = oppSign(start, end);
1816 (void) markAndChaseWinding(start, end, local, oppLocal);
1817 // OPTIMIZATION: the reverse mark and chase could skip the first marking
1818 (void) markAndChaseWinding(end, start, local, oppLocal);
1819}
1820
1821/*
1822when we start with a vertical intersect, we try to use the dx to determine if the edge is to
1823the left or the right of vertical. This determines if we need to add the span's
1824sign or not. However, this isn't enough.
1825If the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed.
1826If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
1827from has the same x direction as this span, the winding should change. If the dx is opposite, then
1828the same winding is shared by both.
1829*/
1830void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkScalar hitDx,
1831 int oppWind, SkScalar hitOppDx) {
1832 SkASSERT(hitDx || !winding);
reed@google.com277c3f82013-05-31 15:17:50 +00001833 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001834 SkASSERT(dx);
1835 int windVal = windValue(SkMin32(start, end));
1836#if DEBUG_WINDING_AT_T
1837 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
1838 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
1839#endif
1840 if (!winding) {
1841 winding = dx < 0 ? windVal : -windVal;
1842 } else if (winding * dx < 0) {
1843 int sideWind = winding + (dx < 0 ? windVal : -windVal);
1844 if (abs(winding) < abs(sideWind)) {
1845 winding = sideWind;
1846 }
1847 }
1848#if DEBUG_WINDING_AT_T
1849 SkDebugf(" winding=%d\n", winding);
1850#endif
1851 SkDEBUGCODE(int oppLocal = oppSign(start, end));
1852 SkASSERT(hitOppDx || !oppWind || !oppLocal);
1853 int oppWindVal = oppValue(SkMin32(start, end));
1854 if (!oppWind) {
1855 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
1856 } else if (hitOppDx * dx >= 0) {
1857 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
1858 if (abs(oppWind) < abs(oppSideWind)) {
1859 oppWind = oppSideWind;
1860 }
1861 }
1862 (void) markAndChaseWinding(start, end, winding, oppWind);
1863}
1864
1865bool SkOpSegment::isLinear(int start, int end) const {
1866 if (fVerb == SkPath::kLine_Verb) {
1867 return true;
1868 }
1869 if (fVerb == SkPath::kQuad_Verb) {
1870 SkDQuad qPart = SkDQuad::SubDivide(fPts, fTs[start].fT, fTs[end].fT);
1871 return qPart.isLinear(0, 2);
1872 } else {
1873 SkASSERT(fVerb == SkPath::kCubic_Verb);
1874 SkDCubic cPart = SkDCubic::SubDivide(fPts, fTs[start].fT, fTs[end].fT);
1875 return cPart.isLinear(0, 3);
1876 }
1877}
1878
1879// OPTIMIZE: successive calls could start were the last leaves off
1880// or calls could specialize to walk forwards or backwards
1881bool SkOpSegment::isMissing(double startT) const {
1882 size_t tCount = fTs.count();
1883 for (size_t index = 0; index < tCount; ++index) {
1884 if (approximately_zero(startT - fTs[index].fT)) {
1885 return false;
1886 }
1887 }
1888 return true;
1889}
1890
1891bool SkOpSegment::isSimple(int end) const {
1892 int count = fTs.count();
1893 if (count == 2) {
1894 return true;
1895 }
1896 double t = fTs[end].fT;
1897 if (approximately_less_than_zero(t)) {
1898 return !approximately_less_than_zero(fTs[1].fT);
1899 }
1900 if (approximately_greater_than_one(t)) {
1901 return !approximately_greater_than_one(fTs[count - 2].fT);
1902 }
1903 return false;
1904}
1905
1906// this span is excluded by the winding rule -- chase the ends
1907// as long as they are unambiguous to mark connections as done
1908// and give them the same winding value
1909SkOpSpan* SkOpSegment::markAndChaseDone(int index, int endIndex, int winding) {
1910 int step = SkSign32(endIndex - index);
1911 int min = SkMin32(index, endIndex);
1912 markDone(min, winding);
1913 SkOpSpan* last;
1914 SkOpSegment* other = this;
1915 while ((other = other->nextChase(&index, step, &min, &last))) {
1916 other->markDone(min, winding);
1917 }
1918 return last;
1919}
1920
1921SkOpSpan* SkOpSegment::markAndChaseDoneBinary(const SkOpAngle* angle, int winding, int oppWinding) {
1922 int index = angle->start();
1923 int endIndex = angle->end();
1924 int step = SkSign32(endIndex - index);
1925 int min = SkMin32(index, endIndex);
1926 markDoneBinary(min, winding, oppWinding);
1927 SkOpSpan* last;
1928 SkOpSegment* other = this;
1929 while ((other = other->nextChase(&index, step, &min, &last))) {
1930 other->markDoneBinary(min, winding, oppWinding);
1931 }
1932 return last;
1933}
1934
1935SkOpSpan* SkOpSegment::markAndChaseDoneBinary(int index, int endIndex) {
1936 int step = SkSign32(endIndex - index);
1937 int min = SkMin32(index, endIndex);
1938 markDoneBinary(min);
1939 SkOpSpan* last;
1940 SkOpSegment* other = this;
1941 while ((other = other->nextChase(&index, step, &min, &last))) {
1942 if (other->done()) {
1943 return NULL;
1944 }
1945 other->markDoneBinary(min);
1946 }
1947 return last;
1948}
1949
1950SkOpSpan* SkOpSegment::markAndChaseDoneUnary(int index, int endIndex) {
1951 int step = SkSign32(endIndex - index);
1952 int min = SkMin32(index, endIndex);
1953 markDoneUnary(min);
1954 SkOpSpan* last;
1955 SkOpSegment* other = this;
1956 while ((other = other->nextChase(&index, step, &min, &last))) {
1957 if (other->done()) {
1958 return NULL;
1959 }
1960 other->markDoneUnary(min);
1961 }
1962 return last;
1963}
1964
1965SkOpSpan* SkOpSegment::markAndChaseDoneUnary(const SkOpAngle* angle, int winding) {
1966 int index = angle->start();
1967 int endIndex = angle->end();
1968 return markAndChaseDone(index, endIndex, winding);
1969}
1970
1971SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, const int winding) {
1972 int index = angle->start();
1973 int endIndex = angle->end();
1974 int step = SkSign32(endIndex - index);
1975 int min = SkMin32(index, endIndex);
1976 markWinding(min, winding);
1977 SkOpSpan* last;
1978 SkOpSegment* other = this;
1979 while ((other = other->nextChase(&index, step, &min, &last))) {
1980 if (other->fTs[min].fWindSum != SK_MinS32) {
1981 SkASSERT(other->fTs[min].fWindSum == winding);
1982 return NULL;
1983 }
1984 other->markWinding(min, winding);
1985 }
1986 return last;
1987}
1988
1989SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
1990 int min = SkMin32(index, endIndex);
1991 int step = SkSign32(endIndex - index);
1992 markWinding(min, winding, oppWinding);
1993 SkOpSpan* last;
1994 SkOpSegment* other = this;
1995 while ((other = other->nextChase(&index, step, &min, &last))) {
1996 if (other->fTs[min].fWindSum != SK_MinS32) {
1997 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
1998 return NULL;
1999 }
2000 other->markWinding(min, winding, oppWinding);
2001 }
2002 return last;
2003}
2004
2005SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding) {
2006 int start = angle->start();
2007 int end = angle->end();
2008 return markAndChaseWinding(start, end, winding, oppWinding);
2009}
2010
2011SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, bool activeAngle,
2012 const SkOpAngle* angle) {
2013 SkASSERT(angle->segment() == this);
2014 if (UseInnerWinding(maxWinding, sumWinding)) {
2015 maxWinding = sumWinding;
2016 }
2017 SkOpSpan* last;
2018 if (activeAngle) {
2019 last = markAndChaseWinding(angle, maxWinding);
2020 } else {
2021 last = markAndChaseDoneUnary(angle, maxWinding);
2022 }
2023 return last;
2024}
2025
2026SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
2027 int oppSumWinding, bool activeAngle, const SkOpAngle* angle) {
2028 SkASSERT(angle->segment() == this);
2029 if (UseInnerWinding(maxWinding, sumWinding)) {
2030 maxWinding = sumWinding;
2031 }
2032 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
2033 oppMaxWinding = oppSumWinding;
2034 }
2035 SkOpSpan* last;
2036 if (activeAngle) {
2037 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
2038 } else {
2039 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
2040 }
2041 return last;
2042}
2043
2044// FIXME: this should also mark spans with equal (x,y)
2045// This may be called when the segment is already marked done. While this
2046// wastes time, it shouldn't do any more than spin through the T spans.
2047// OPTIMIZATION: abort on first done found (assuming that this code is
2048// always called to mark segments done).
2049void SkOpSegment::markDone(int index, int winding) {
2050 // SkASSERT(!done());
2051 SkASSERT(winding);
2052 double referenceT = fTs[index].fT;
2053 int lesser = index;
2054 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2055 markOneDone(__FUNCTION__, lesser, winding);
2056 }
2057 do {
2058 markOneDone(__FUNCTION__, index, winding);
2059 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2060}
2061
2062void SkOpSegment::markDoneBinary(int index, int winding, int oppWinding) {
2063 // SkASSERT(!done());
2064 SkASSERT(winding || oppWinding);
2065 double referenceT = fTs[index].fT;
2066 int lesser = index;
2067 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2068 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
2069 }
2070 do {
2071 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
2072 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2073}
2074
2075void SkOpSegment::markDoneBinary(int index) {
2076 double referenceT = fTs[index].fT;
2077 int lesser = index;
2078 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2079 markOneDoneBinary(__FUNCTION__, lesser);
2080 }
2081 do {
2082 markOneDoneBinary(__FUNCTION__, index);
2083 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2084}
2085
2086void SkOpSegment::markDoneUnary(int index) {
2087 double referenceT = fTs[index].fT;
2088 int lesser = index;
2089 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2090 markOneDoneUnary(__FUNCTION__, lesser);
2091 }
2092 do {
2093 markOneDoneUnary(__FUNCTION__, index);
2094 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2095}
2096
2097void SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) {
2098 SkOpSpan* span = markOneWinding(funName, tIndex, winding);
2099 if (!span) {
2100 return;
2101 }
2102 span->fDone = true;
2103 fDoneSpans++;
2104}
2105
2106void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) {
2107 SkOpSpan* span = verifyOneWinding(funName, tIndex);
2108 if (!span) {
2109 return;
2110 }
2111 span->fDone = true;
2112 fDoneSpans++;
2113}
2114
2115void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
2116 SkOpSpan* span = markOneWinding(funName, tIndex, winding, oppWinding);
2117 if (!span) {
2118 return;
2119 }
2120 span->fDone = true;
2121 fDoneSpans++;
2122}
2123
2124void SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) {
2125 SkOpSpan* span = verifyOneWindingU(funName, tIndex);
2126 if (!span) {
2127 return;
2128 }
2129 span->fDone = true;
2130 fDoneSpans++;
2131}
2132
2133SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding) {
2134 SkOpSpan& span = fTs[tIndex];
2135 if (span.fDone) {
2136 return NULL;
2137 }
2138#if DEBUG_MARK_DONE
2139 debugShowNewWinding(funName, span, winding);
2140#endif
2141 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
2142#ifdef SK_DEBUG
2143 SkASSERT(abs(winding) <= gDebugMaxWindSum);
2144#endif
2145 span.fWindSum = winding;
2146 return &span;
2147}
2148
2149SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding,
2150 int oppWinding) {
2151 SkOpSpan& span = fTs[tIndex];
2152 if (span.fDone) {
2153 return NULL;
2154 }
2155#if DEBUG_MARK_DONE
2156 debugShowNewWinding(funName, span, winding, oppWinding);
2157#endif
2158 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
2159#ifdef SK_DEBUG
2160 SkASSERT(abs(winding) <= gDebugMaxWindSum);
2161#endif
2162 span.fWindSum = winding;
2163 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
2164#ifdef SK_DEBUG
2165 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
2166#endif
2167 span.fOppSum = oppWinding;
2168 return &span;
2169}
2170
2171// from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
2172bool SkOpSegment::clockwise(int tStart, int tEnd) const {
2173 SkASSERT(fVerb != SkPath::kLine_Verb);
2174 SkPoint edge[4];
2175 subDivide(tStart, tEnd, edge);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002176 int points = SkPathOpsVerbToPoints(fVerb);
2177 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002178 if (fVerb == SkPath::kCubic_Verb) {
2179 SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY);
2180 if (edge[1].fY < lesser && edge[2].fY < lesser) {
2181 SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1].fY} }};
2182 SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3].fY} }};
2183 if (SkIntersections::Test(tangent1, tangent2)) {
2184 SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2185 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY);
2186 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY);
2187 return sum <= 0;
2188 }
2189 }
2190 }
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002191 for (int idx = 0; idx < points; ++idx){
caryclark@google.com07393ca2013-04-08 11:47:37 +00002192 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
2193 }
2194 return sum <= 0;
2195}
2196
2197bool SkOpSegment::monotonicInY(int tStart, int tEnd) const {
2198 if (fVerb == SkPath::kLine_Verb) {
2199 return false;
2200 }
2201 if (fVerb == SkPath::kQuad_Verb) {
2202 SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2203 return dst.monotonicInY();
2204 }
2205 SkASSERT(fVerb == SkPath::kCubic_Verb);
2206 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2207 return dst.monotonicInY();
2208}
2209
2210bool SkOpSegment::serpentine(int tStart, int tEnd) const {
2211 if (fVerb != SkPath::kCubic_Verb) {
2212 return false;
2213 }
2214 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2215 return dst.serpentine();
2216}
2217
2218SkOpSpan* SkOpSegment::verifyOneWinding(const char* funName, int tIndex) {
2219 SkOpSpan& span = fTs[tIndex];
2220 if (span.fDone) {
2221 return NULL;
2222 }
2223#if DEBUG_MARK_DONE
2224 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
2225#endif
2226 SkASSERT(span.fWindSum != SK_MinS32);
2227 SkASSERT(span.fOppSum != SK_MinS32);
2228 return &span;
2229}
2230
2231SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) {
2232 SkOpSpan& span = fTs[tIndex];
2233 if (span.fDone) {
2234 return NULL;
2235 }
2236#if DEBUG_MARK_DONE
2237 debugShowNewWinding(funName, span, span.fWindSum);
2238#endif
2239 SkASSERT(span.fWindSum != SK_MinS32);
2240 return &span;
2241}
2242
2243// note that just because a span has one end that is unsortable, that's
2244// not enough to mark it done. The other end may be sortable, allowing the
2245// span to be added.
2246// FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
2247void SkOpSegment::markUnsortable(int start, int end) {
2248 SkOpSpan* span = &fTs[start];
2249 if (start < end) {
2250#if DEBUG_UNSORTABLE
2251 debugShowNewWinding(__FUNCTION__, *span, 0);
2252#endif
2253 span->fUnsortableStart = true;
2254 } else {
2255 --span;
2256#if DEBUG_UNSORTABLE
2257 debugShowNewWinding(__FUNCTION__, *span, 0);
2258#endif
2259 span->fUnsortableEnd = true;
2260 }
2261 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
2262 return;
2263 }
2264 span->fDone = true;
2265 fDoneSpans++;
2266}
2267
2268void SkOpSegment::markWinding(int index, int winding) {
2269// SkASSERT(!done());
2270 SkASSERT(winding);
2271 double referenceT = fTs[index].fT;
2272 int lesser = index;
2273 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2274 markOneWinding(__FUNCTION__, lesser, winding);
2275 }
2276 do {
2277 markOneWinding(__FUNCTION__, index, winding);
2278 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2279}
2280
2281void SkOpSegment::markWinding(int index, int winding, int oppWinding) {
2282// SkASSERT(!done());
2283 SkASSERT(winding || oppWinding);
2284 double referenceT = fTs[index].fT;
2285 int lesser = index;
2286 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2287 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
2288 }
2289 do {
2290 markOneWinding(__FUNCTION__, index, winding, oppWinding);
2291 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2292}
2293
2294void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) {
2295 int nextDoorWind = SK_MaxS32;
2296 int nextOppWind = SK_MaxS32;
2297 if (tIndex > 0) {
2298 const SkOpSpan& below = fTs[tIndex - 1];
2299 if (approximately_negative(t - below.fT)) {
2300 nextDoorWind = below.fWindValue;
2301 nextOppWind = below.fOppValue;
2302 }
2303 }
2304 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
2305 const SkOpSpan& above = fTs[tIndex + 1];
2306 if (approximately_negative(above.fT - t)) {
2307 nextDoorWind = above.fWindValue;
2308 nextOppWind = above.fOppValue;
2309 }
2310 }
2311 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
2312 const SkOpSpan& below = fTs[tIndex - 1];
2313 nextDoorWind = below.fWindValue;
2314 nextOppWind = below.fOppValue;
2315 }
2316 if (nextDoorWind != SK_MaxS32) {
2317 SkOpSpan& newSpan = fTs[tIndex];
2318 newSpan.fWindValue = nextDoorWind;
2319 newSpan.fOppValue = nextOppWind;
2320 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
2321 newSpan.fDone = true;
2322 ++fDoneSpans;
2323 }
2324 }
2325}
2326
2327// return span if when chasing, two or more radiating spans are not done
2328// OPTIMIZATION: ? multiple spans is detected when there is only one valid
2329// candidate and the remaining spans have windValue == 0 (canceled by
2330// coincidence). The coincident edges could either be removed altogether,
2331// or this code could be more complicated in detecting this case. Worth it?
2332bool SkOpSegment::multipleSpans(int end) const {
2333 return end > 0 && end < fTs.count() - 1;
2334}
2335
2336bool SkOpSegment::nextCandidate(int* start, int* end) const {
2337 while (fTs[*end].fDone) {
2338 if (fTs[*end].fT == 1) {
2339 return false;
2340 }
2341 ++(*end);
2342 }
2343 *start = *end;
2344 *end = nextExactSpan(*start, 1);
2345 return true;
2346}
2347
2348SkOpSegment* SkOpSegment::nextChase(int* index, const int step, int* min, SkOpSpan** last) {
2349 int end = nextExactSpan(*index, step);
2350 SkASSERT(end >= 0);
2351 if (multipleSpans(end)) {
2352 *last = &fTs[end];
2353 return NULL;
2354 }
2355 const SkOpSpan& endSpan = fTs[end];
2356 SkOpSegment* other = endSpan.fOther;
2357 *index = endSpan.fOtherIndex;
fmalita@google.com22eb7942013-05-01 20:35:51 +00002358 SkASSERT(*index >= 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002359 int otherEnd = other->nextExactSpan(*index, step);
2360 SkASSERT(otherEnd >= 0);
2361 *min = SkMin32(*index, otherEnd);
caryclark@google.coma5e55922013-05-07 18:51:31 +00002362 if (other->fTs[*min].fTiny) {
2363 *last = NULL;
2364 return NULL;
2365 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002366 return other;
2367}
2368
2369// This has callers for two different situations: one establishes the end
2370// of the current span, and one establishes the beginning of the next span
2371// (thus the name). When this is looking for the end of the current span,
2372// coincidence is found when the beginning Ts contain -step and the end
2373// contains step. When it is looking for the beginning of the next, the
2374// first Ts found can be ignored and the last Ts should contain -step.
2375// OPTIMIZATION: probably should split into two functions
2376int SkOpSegment::nextSpan(int from, int step) const {
2377 const SkOpSpan& fromSpan = fTs[from];
2378 int count = fTs.count();
2379 int to = from;
2380 while (step > 0 ? ++to < count : --to >= 0) {
2381 const SkOpSpan& span = fTs[to];
2382 if (approximately_zero(span.fT - fromSpan.fT)) {
2383 continue;
2384 }
2385 return to;
2386 }
2387 return -1;
2388}
2389
2390// FIXME
2391// this returns at any difference in T, vs. a preset minimum. It may be
2392// that all callers to nextSpan should use this instead.
2393// OPTIMIZATION splitting this into separate loops for up/down steps
2394// would allow using precisely_negative instead of precisely_zero
2395int SkOpSegment::nextExactSpan(int from, int step) const {
2396 const SkOpSpan& fromSpan = fTs[from];
2397 int count = fTs.count();
2398 int to = from;
2399 while (step > 0 ? ++to < count : --to >= 0) {
2400 const SkOpSpan& span = fTs[to];
2401 if (precisely_zero(span.fT - fromSpan.fT)) {
2402 continue;
2403 }
2404 return to;
2405 }
2406 return -1;
2407}
2408
2409void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
2410 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) {
2411 int deltaSum = spanSign(index, endIndex);
2412 int oppDeltaSum = oppSign(index, endIndex);
2413 if (operand()) {
2414 *maxWinding = *sumSuWinding;
2415 *sumWinding = *sumSuWinding -= deltaSum;
2416 *oppMaxWinding = *sumMiWinding;
2417 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
2418 } else {
2419 *maxWinding = *sumMiWinding;
2420 *sumWinding = *sumMiWinding -= deltaSum;
2421 *oppMaxWinding = *sumSuWinding;
2422 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
2423 }
2424}
2425
2426// This marks all spans unsortable so that this info is available for early
2427// exclusion in find top and others. This could be optimized to only mark
2428// adjacent spans that unsortable. However, this makes it difficult to later
2429// determine starting points for edge detection in find top and the like.
caryclark@google.comd892bd82013-06-17 14:10:36 +00002430bool SkOpSegment::SortAngles(const SkTArray<SkOpAngle, true>& angles,
2431 SkTArray<SkOpAngle*, true>* angleList,
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002432 SortAngleKind orderKind) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002433 bool sortable = true;
2434 int angleCount = angles.count();
2435 int angleIndex;
caryclark@google.comd892bd82013-06-17 14:10:36 +00002436// FIXME: caller needs to use SkTArray constructor with reserve count
2437// angleList->setReserve(angleCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002438 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2439 const SkOpAngle& angle = angles[angleIndex];
caryclark@google.comd892bd82013-06-17 14:10:36 +00002440 angleList->push_back(const_cast<SkOpAngle*>(&angle));
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002441#if DEBUG_ANGLE
2442 (*(angleList->end() - 1))->setID(angleIndex);
2443#endif
2444 sortable &= !(angle.unsortable() || (orderKind == kMustBeOrdered_SortAngleKind
2445 && angle.unorderable()));
caryclark@google.com07393ca2013-04-08 11:47:37 +00002446 }
2447 if (sortable) {
caryclark@google.com7dfbb072013-04-22 14:37:05 +00002448 SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002449 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002450 if (angles[angleIndex].unsortable() || (orderKind == kMustBeOrdered_SortAngleKind
2451 && angles[angleIndex].unorderable())) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002452 sortable = false;
2453 break;
2454 }
2455 }
2456 }
2457 if (!sortable) {
2458 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2459 const SkOpAngle& angle = angles[angleIndex];
2460 angle.segment()->markUnsortable(angle.start(), angle.end());
2461 }
2462 }
2463 return sortable;
2464}
2465
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002466// return true if midpoints were computed
2467bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const {
2468 SkASSERT(start != end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002469 edge[0] = fTs[start].fPt;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002470 int points = SkPathOpsVerbToPoints(fVerb);
2471 edge[points] = fTs[end].fPt;
2472 if (fVerb == SkPath::kLine_Verb) {
2473 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002474 }
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002475 double startT = fTs[start].fT;
2476 double endT = fTs[end].fT;
2477 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
2478 // don't compute midpoints if we already have them
2479 if (fVerb == SkPath::kQuad_Verb) {
2480 edge[1] = fPts[1];
2481 return false;
2482 }
2483 SkASSERT(fVerb == SkPath::kCubic_Verb);
2484 if (start < end) {
2485 edge[1] = fPts[1];
2486 edge[2] = fPts[2];
2487 return false;
2488 }
2489 edge[1] = fPts[2];
2490 edge[2] = fPts[1];
2491 return false;
2492 }
2493 const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[points].fY }};
2494 if (fVerb == SkPath::kQuad_Verb) {
2495 edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
2496 } else {
2497 SkASSERT(fVerb == SkPath::kCubic_Verb);
2498 SkDPoint ctrl[2];
2499 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
2500 edge[1] = ctrl[0].asSkPoint();
2501 edge[2] = ctrl[1].asSkPoint();
2502 }
2503 return true;
2504}
2505
2506// return true if midpoints were computed
2507bool SkOpSegment::subDivide(int start, int end, SkDCubic* result) const {
2508 SkASSERT(start != end);
2509 (*result)[0].set(fTs[start].fPt);
2510 int points = SkPathOpsVerbToPoints(fVerb);
2511 (*result)[points].set(fTs[end].fPt);
2512 if (fVerb == SkPath::kLine_Verb) {
2513 return false;
2514 }
2515 double startT = fTs[start].fT;
2516 double endT = fTs[end].fT;
2517 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
2518 // don't compute midpoints if we already have them
2519 if (fVerb == SkPath::kQuad_Verb) {
2520 (*result)[1].set(fPts[1]);
2521 return false;
2522 }
2523 SkASSERT(fVerb == SkPath::kCubic_Verb);
2524 if (start < end) {
2525 (*result)[1].set(fPts[1]);
2526 (*result)[2].set(fPts[2]);
2527 return false;
2528 }
2529 (*result)[1].set(fPts[2]);
2530 (*result)[2].set(fPts[1]);
2531 return false;
2532 }
2533 if (fVerb == SkPath::kQuad_Verb) {
2534 (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], startT, endT);
2535 } else {
2536 SkASSERT(fVerb == SkPath::kCubic_Verb);
2537 SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*result)[1]);
2538 }
2539 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002540}
2541
2542void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const {
2543 SkPoint edge[4];
2544 subDivide(start, end, edge);
reed@google.com277c3f82013-05-31 15:17:50 +00002545 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002546}
2547
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002548bool SkOpSegment::isTiny(const SkOpAngle* angle) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002549 int start = angle->start();
2550 int end = angle->end();
2551 const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
2552 return mSpan.fTiny;
2553}
2554
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002555bool SkOpSegment::isTiny(int index) const {
2556 return fTs[index].fTiny;
2557}
2558
caryclark@google.comd892bd82013-06-17 14:10:36 +00002559void SkOpSegment::TrackOutside(SkTArray<double, true>* outsideTs, double end, double start) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002560 int outCount = outsideTs->count();
2561 if (outCount == 0 || !approximately_negative(end - (*outsideTs)[outCount - 2])) {
caryclark@google.comd892bd82013-06-17 14:10:36 +00002562 outsideTs->push_back(end);
2563 outsideTs->push_back(start);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002564 }
2565}
2566
2567void SkOpSegment::undoneSpan(int* start, int* end) {
2568 size_t tCount = fTs.count();
2569 size_t index;
2570 for (index = 0; index < tCount; ++index) {
2571 if (!fTs[index].fDone) {
2572 break;
2573 }
2574 }
2575 SkASSERT(index < tCount - 1);
2576 *start = index;
2577 double startT = fTs[index].fT;
2578 while (approximately_negative(fTs[++index].fT - startT))
2579 SkASSERT(index < tCount);
2580 SkASSERT(index < tCount);
2581 *end = index;
2582}
2583
2584int SkOpSegment::updateOppWinding(int index, int endIndex) const {
2585 int lesser = SkMin32(index, endIndex);
2586 int oppWinding = oppSum(lesser);
2587 int oppSpanWinding = oppSign(index, endIndex);
2588 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
2589 && oppWinding != SK_MaxS32) {
2590 oppWinding -= oppSpanWinding;
2591 }
2592 return oppWinding;
2593}
2594
2595int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
2596 int startIndex = angle->start();
2597 int endIndex = angle->end();
2598 return updateOppWinding(endIndex, startIndex);
2599}
2600
2601int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
2602 int startIndex = angle->start();
2603 int endIndex = angle->end();
2604 return updateOppWinding(startIndex, endIndex);
2605}
2606
2607int SkOpSegment::updateWinding(int index, int endIndex) const {
2608 int lesser = SkMin32(index, endIndex);
2609 int winding = windSum(lesser);
2610 int spanWinding = spanSign(index, endIndex);
2611 if (winding && UseInnerWinding(winding - spanWinding, winding) && winding != SK_MaxS32) {
2612 winding -= spanWinding;
2613 }
2614 return winding;
2615}
2616
2617int SkOpSegment::updateWinding(const SkOpAngle* angle) const {
2618 int startIndex = angle->start();
2619 int endIndex = angle->end();
2620 return updateWinding(endIndex, startIndex);
2621}
2622
2623int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const {
2624 int startIndex = angle->start();
2625 int endIndex = angle->end();
2626 return updateWinding(startIndex, endIndex);
2627}
2628
2629int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const {
2630 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
2631 return SK_MinS32;
2632 }
2633 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
2634 SkASSERT(winding != SK_MinS32);
2635 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
2636#if DEBUG_WINDING_AT_T
2637 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
2638#endif
2639 // see if a + change in T results in a +/- change in X (compute x'(T))
reed@google.com277c3f82013-05-31 15:17:50 +00002640 *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002641 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
2642 *dx = fPts[2].fX - fPts[1].fX - *dx;
2643 }
2644 if (*dx == 0) {
2645#if DEBUG_WINDING_AT_T
2646 SkDebugf(" dx=0 winding=SK_MinS32\n");
2647#endif
2648 return SK_MinS32;
2649 }
skia.committer@gmail.coma4aced42013-07-09 07:00:56 +00002650 if (windVal < 0) { // reverse sign if opp contour traveled in reverse
caryclark@google.com07e97fc2013-07-08 17:17:02 +00002651 *dx = -*dx;
2652 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002653 if (winding * *dx > 0) { // if same signs, result is negative
2654 winding += *dx > 0 ? -windVal : windVal;
2655 }
2656#if DEBUG_WINDING_AT_T
2657 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding);
2658#endif
2659 return winding;
2660}
2661
2662int SkOpSegment::windSum(const SkOpAngle* angle) const {
2663 int start = angle->start();
2664 int end = angle->end();
2665 int index = SkMin32(start, end);
2666 return windSum(index);
2667}
2668
2669int SkOpSegment::windValue(const SkOpAngle* angle) const {
2670 int start = angle->start();
2671 int end = angle->end();
2672 int index = SkMin32(start, end);
2673 return windValue(index);
2674}
2675
2676int SkOpSegment::windValueAt(double t) const {
2677 int count = fTs.count();
2678 for (int index = 0; index < count; ++index) {
2679 if (fTs[index].fT == t) {
2680 return fTs[index].fWindValue;
2681 }
2682 }
2683 SkASSERT(0);
2684 return 0;
2685}
2686
2687void SkOpSegment::zeroSpan(SkOpSpan* span) {
caryclark@google.coma5e55922013-05-07 18:51:31 +00002688 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002689 span->fWindValue = 0;
2690 span->fOppValue = 0;
2691 SkASSERT(!span->fDone);
2692 span->fDone = true;
2693 ++fDoneSpans;
2694}
skia.committer@gmail.com32840172013-04-09 07:01:27 +00002695
caryclark@google.com07393ca2013-04-08 11:47:37 +00002696#if DEBUG_SWAP_TOP
2697bool SkOpSegment::controlsContainedByEnds(int tStart, int tEnd) const {
2698 if (fVerb != SkPath::kCubic_Verb) {
2699 return false;
2700 }
2701 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2702 return dst.controlsContainedByEnds();
2703}
2704#endif
2705
2706#if DEBUG_CONCIDENT
2707// SkASSERT if pair has not already been added
2708void SkOpSegment::debugAddTPair(double t, const SkOpSegment& other, double otherT) const {
2709 for (int i = 0; i < fTs.count(); ++i) {
2710 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
2711 return;
2712 }
2713 }
2714 SkASSERT(0);
2715}
2716#endif
2717
2718#if DEBUG_CONCIDENT
2719void SkOpSegment::debugShowTs() const {
2720 SkDebugf("%s id=%d", __FUNCTION__, fID);
2721 int lastWind = -1;
2722 int lastOpp = -1;
2723 double lastT = -1;
2724 int i;
2725 for (i = 0; i < fTs.count(); ++i) {
2726 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
2727 || lastOpp != fTs[i].fOppValue;
2728 if (change && lastWind >= 0) {
2729 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
2730 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
2731 }
2732 if (change) {
2733 SkDebugf(" [o=%d", fTs[i].fOther->fID);
2734 lastWind = fTs[i].fWindValue;
2735 lastOpp = fTs[i].fOppValue;
2736 lastT = fTs[i].fT;
2737 } else {
2738 SkDebugf(",%d", fTs[i].fOther->fID);
2739 }
2740 }
2741 if (i <= 0) {
2742 return;
2743 }
2744 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
2745 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
2746 if (fOperand) {
2747 SkDebugf(" operand");
2748 }
2749 if (done()) {
2750 SkDebugf(" done");
2751 }
2752 SkDebugf("\n");
2753}
2754#endif
2755
caryclark@google.coma5e55922013-05-07 18:51:31 +00002756#if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
caryclark@google.com07393ca2013-04-08 11:47:37 +00002757void SkOpSegment::debugShowActiveSpans() const {
2758 if (done()) {
2759 return;
2760 }
2761#if DEBUG_ACTIVE_SPANS_SHORT_FORM
2762 int lastId = -1;
2763 double lastT = -1;
2764#endif
2765 for (int i = 0; i < fTs.count(); ++i) {
2766 SkASSERT(&fTs[i] == &fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOther->
2767 fTs[fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOtherIndex]);
2768 if (fTs[i].fDone) {
2769 continue;
2770 }
caryclark@google.coma5e55922013-05-07 18:51:31 +00002771 SkASSERT(i < fTs.count() - 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002772#if DEBUG_ACTIVE_SPANS_SHORT_FORM
2773 if (lastId == fID && lastT == fTs[i].fT) {
2774 continue;
2775 }
2776 lastId = fID;
2777 lastT = fTs[i].fT;
2778#endif
2779 SkDebugf("%s id=%d", __FUNCTION__, fID);
2780 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
reed@google.com277c3f82013-05-31 15:17:50 +00002781 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002782 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
2783 }
2784 const SkOpSpan* span = &fTs[i];
2785 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", span->fT, xAtT(span), yAtT(span));
2786 int iEnd = i + 1;
2787 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) {
2788 ++iEnd;
2789 }
2790 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT);
2791 const SkOpSegment* other = fTs[i].fOther;
2792 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
2793 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
2794 if (fTs[i].fWindSum == SK_MinS32) {
2795 SkDebugf("?");
2796 } else {
2797 SkDebugf("%d", fTs[i].fWindSum);
2798 }
2799 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
2800 }
2801}
2802#endif
2803
2804
2805#if DEBUG_MARK_DONE || DEBUG_UNSORTABLE
2806void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding) {
2807 const SkPoint& pt = xyAtT(&span);
2808 SkDebugf("%s id=%d", fun, fID);
2809 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
reed@google.com277c3f82013-05-31 15:17:50 +00002810 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002811 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
2812 }
2813 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
2814 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
2815 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d windSum=",
2816 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
2817 (&span)[1].fT, winding);
2818 if (span.fWindSum == SK_MinS32) {
2819 SkDebugf("?");
2820 } else {
2821 SkDebugf("%d", span.fWindSum);
2822 }
2823 SkDebugf(" windValue=%d\n", span.fWindValue);
2824}
2825
2826void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding,
2827 int oppWinding) {
2828 const SkPoint& pt = xyAtT(&span);
2829 SkDebugf("%s id=%d", fun, fID);
2830 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
reed@google.com277c3f82013-05-31 15:17:50 +00002831 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002832 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
2833 }
2834 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
2835 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
2836 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d newOppSum=%d oppSum=",
2837 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
2838 (&span)[1].fT, winding, oppWinding);
2839 if (span.fOppSum == SK_MinS32) {
2840 SkDebugf("?");
2841 } else {
2842 SkDebugf("%d", span.fOppSum);
2843 }
2844 SkDebugf(" windSum=");
2845 if (span.fWindSum == SK_MinS32) {
2846 SkDebugf("?");
2847 } else {
2848 SkDebugf("%d", span.fWindSum);
2849 }
2850 SkDebugf(" windValue=%d\n", span.fWindValue);
2851}
2852#endif
2853
2854#if DEBUG_SORT || DEBUG_SWAP_TOP
caryclark@google.comd892bd82013-06-17 14:10:36 +00002855void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles,
2856 int first, const int contourWinding,
caryclark@google.com07e97fc2013-07-08 17:17:02 +00002857 const int oppContourWinding, bool sortable) const {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002858 if (--gDebugSortCount < 0) {
2859 return;
2860 }
2861 SkASSERT(angles[first]->segment() == this);
caryclark@google.com07e97fc2013-07-08 17:17:02 +00002862 SkASSERT(!sortable || angles.count() > 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002863 int lastSum = contourWinding;
2864 int oppLastSum = oppContourWinding;
2865 const SkOpAngle* firstAngle = angles[first];
2866 int windSum = lastSum - spanSign(firstAngle);
2867 int oppoSign = oppSign(firstAngle);
2868 int oppWindSum = oppLastSum - oppoSign;
2869 #define WIND_AS_STRING(x) char x##Str[12]; if (!valid_wind(x)) strcpy(x##Str, "?"); \
caryclark@google.comad65a3e2013-04-15 19:13:59 +00002870 else SK_SNPRINTF(x##Str, sizeof(x##Str), "%d", x)
caryclark@google.com07393ca2013-04-08 11:47:37 +00002871 WIND_AS_STRING(contourWinding);
2872 WIND_AS_STRING(oppContourWinding);
2873 SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FUNCTION__,
2874 contourWindingStr, oppContourWindingStr, spanSign(angles[first]));
2875 int index = first;
2876 bool firstTime = true;
2877 do {
2878 const SkOpAngle& angle = *angles[index];
2879 const SkOpSegment& segment = *angle.segment();
2880 int start = angle.start();
2881 int end = angle.end();
2882 const SkOpSpan& sSpan = segment.fTs[start];
2883 const SkOpSpan& eSpan = segment.fTs[end];
2884 const SkOpSpan& mSpan = segment.fTs[SkMin32(start, end)];
2885 bool opp = segment.fOperand ^ fOperand;
2886 if (!firstTime) {
2887 oppoSign = segment.oppSign(&angle);
2888 if (opp) {
2889 oppLastSum = oppWindSum;
2890 oppWindSum -= segment.spanSign(&angle);
2891 if (oppoSign) {
2892 lastSum = windSum;
2893 windSum -= oppoSign;
2894 }
2895 } else {
2896 lastSum = windSum;
2897 windSum -= segment.spanSign(&angle);
2898 if (oppoSign) {
2899 oppLastSum = oppWindSum;
2900 oppWindSum -= oppoSign;
2901 }
2902 }
2903 }
2904 SkDebugf("%s [%d] %s", __FUNCTION__, index,
2905 angle.unsortable() ? "*** UNSORTABLE *** " : "");
caryclark@google.comcffbcc32013-06-04 17:59:42 +00002906 #if DEBUG_SORT_COMPACT
2907 SkDebugf("id=%d %s start=%d (%1.9g,%1.9g) end=%d (%1.9g,%1.9g)",
reed@google.com277c3f82013-05-31 15:17:50 +00002908 segment.fID, kLVerbStr[SkPathOpsVerbToPoints(segment.fVerb)],
caryclark@google.com07393ca2013-04-08 11:47:37 +00002909 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
2910 segment.xAtT(&eSpan), segment.yAtT(&eSpan));
2911 #else
2912 switch (segment.fVerb) {
2913 case SkPath::kLine_Verb:
2914 SkDebugf(LINE_DEBUG_STR, LINE_DEBUG_DATA(segment.fPts));
2915 break;
2916 case SkPath::kQuad_Verb:
2917 SkDebugf(QUAD_DEBUG_STR, QUAD_DEBUG_DATA(segment.fPts));
2918 break;
2919 case SkPath::kCubic_Verb:
2920 SkDebugf(CUBIC_DEBUG_STR, CUBIC_DEBUG_DATA(segment.fPts));
2921 break;
2922 default:
2923 SkASSERT(0);
2924 }
2925 SkDebugf(" tStart=%1.9g tEnd=%1.9g", sSpan.fT, eSpan.fT);
2926 #endif
2927 SkDebugf(" sign=%d windValue=%d windSum=", angle.sign(), mSpan.fWindValue);
caryclark@google.com03610322013-04-18 15:58:21 +00002928 winding_printf(mSpan.fWindSum);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002929 int last, wind;
2930 if (opp) {
2931 last = oppLastSum;
2932 wind = oppWindSum;
2933 } else {
2934 last = lastSum;
2935 wind = windSum;
2936 }
2937 bool useInner = valid_wind(last) && valid_wind(wind) && UseInnerWinding(last, wind);
2938 WIND_AS_STRING(last);
2939 WIND_AS_STRING(wind);
2940 WIND_AS_STRING(lastSum);
2941 WIND_AS_STRING(oppLastSum);
2942 WIND_AS_STRING(windSum);
2943 WIND_AS_STRING(oppWindSum);
2944 #undef WIND_AS_STRING
2945 if (!oppoSign) {
2946 SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr : lastStr);
2947 } else {
2948 SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : oppLastSumStr,
2949 opp ? windSumStr : oppWindSumStr);
2950 }
2951 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
caryclark@google.comad65a3e2013-04-15 19:13:59 +00002952#if 0 && DEBUG_ANGLE
caryclark@google.com07393ca2013-04-08 11:47:37 +00002953 angle.debugShow(segment.xyAtT(&sSpan));
2954#endif
2955 ++index;
2956 if (index == angles.count()) {
2957 index = 0;
2958 }
2959 if (firstTime) {
2960 firstTime = false;
2961 }
2962 } while (index != first);
2963}
2964
caryclark@google.comd892bd82013-06-17 14:10:36 +00002965void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles,
caryclark@google.com07e97fc2013-07-08 17:17:02 +00002966 int first, bool sortable) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00002967 const SkOpAngle* firstAngle = angles[first];
2968 const SkOpSegment* segment = firstAngle->segment();
2969 int winding = segment->updateWinding(firstAngle);
2970 int oppWinding = segment->updateOppWinding(firstAngle);
caryclark@google.com07e97fc2013-07-08 17:17:02 +00002971 debugShowSort(fun, angles, first, winding, oppWinding, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002972}
2973
2974#endif
2975
2976#if DEBUG_SHOW_WINDING
2977int SkOpSegment::debugShowWindingValues(int slotCount, int ofInterest) const {
2978 if (!(1 << fID & ofInterest)) {
2979 return 0;
2980 }
2981 int sum = 0;
caryclark@google.comd892bd82013-06-17 14:10:36 +00002982 SkTArray<char, true> slots(slotCount * 2);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002983 memset(slots.begin(), ' ', slotCount * 2);
2984 for (int i = 0; i < fTs.count(); ++i) {
2985 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
2986 // continue;
2987 // }
2988 sum += fTs[i].fWindValue;
2989 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
2990 sum += fTs[i].fOppValue;
2991 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
2992 }
2993 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
2994 slots.begin() + slotCount);
2995 return sum;
2996}
2997#endif