blob: 627b0af9d4575da7bfaeb408f0279f819088cfd7 [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"
10#include "TSearch.h"
11
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
21// FIXME: add support for kReverseDifference_Op
22static const bool gActiveEdge[kXOR_PathOp + 1][2][2][2][2] = {
23// miFrom=0 miFrom=1
24// miTo=0 miTo=1 miTo=0 miTo=1
25// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
26// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
27 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
28 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
29 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
30 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su
31};
32
33#undef F
34#undef T
35
36// OPTIMIZATION: does the following also work, and is it any faster?
37// return outerWinding * innerWinding > 0
38// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
39bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
40 SkASSERT(outerWinding != SK_MaxS32);
41 SkASSERT(innerWinding != SK_MaxS32);
42 int absOut = abs(outerWinding);
43 int absIn = abs(innerWinding);
44 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
45 return result;
46}
47
48bool SkOpSegment::activeAngle(int index, int* done, SkTDArray<SkOpAngle>* angles) {
49 if (activeAngleInner(index, done, angles)) {
50 return true;
51 }
52 int lesser = index;
53 while (--lesser >= 0 && equalPoints(index, lesser)) {
54 if (activeAngleOther(lesser, done, angles)) {
55 return true;
56 }
57 }
58 lesser = index;
59 do {
60 if (activeAngleOther(index, done, angles)) {
61 return true;
62 }
63 } while (++index < fTs.count() && equalPoints(index, lesser));
64 return false;
65}
66
67bool SkOpSegment::activeAngleOther(int index, int* done, SkTDArray<SkOpAngle>* angles) {
68 SkOpSpan* span = &fTs[index];
69 SkOpSegment* other = span->fOther;
70 int oIndex = span->fOtherIndex;
71 return other->activeAngleInner(oIndex, done, angles);
72}
73
74bool SkOpSegment::activeAngleInner(int index, int* done, SkTDArray<SkOpAngle>* angles) {
75 int next = nextExactSpan(index, 1);
76 if (next > 0) {
77 SkOpSpan& upSpan = fTs[index];
78 if (upSpan.fWindValue || upSpan.fOppValue) {
79 addAngle(angles, index, next);
80 if (upSpan.fDone || upSpan.fUnsortableEnd) {
81 (*done)++;
82 } else if (upSpan.fWindSum != SK_MinS32) {
83 return true;
84 }
85 } else if (!upSpan.fDone) {
86 upSpan.fDone = true;
87 fDoneSpans++;
88 }
89 }
90 int prev = nextExactSpan(index, -1);
91 // edge leading into junction
92 if (prev >= 0) {
93 SkOpSpan& downSpan = fTs[prev];
94 if (downSpan.fWindValue || downSpan.fOppValue) {
95 addAngle(angles, index, prev);
96 if (downSpan.fDone) {
97 (*done)++;
98 } else if (downSpan.fWindSum != SK_MinS32) {
99 return true;
100 }
101 } else if (!downSpan.fDone) {
102 downSpan.fDone = true;
103 fDoneSpans++;
104 }
105 }
106 return false;
107}
108
109SkPoint SkOpSegment::activeLeftTop(bool onlySortable, int* firstT) const {
110 SkASSERT(!done());
111 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
112 int count = fTs.count();
113 // see if either end is not done since we want smaller Y of the pair
114 bool lastDone = true;
115 bool lastUnsortable = false;
116 double lastT = -1;
117 for (int index = 0; index < count; ++index) {
118 const SkOpSpan& span = fTs[index];
119 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
120 goto next;
121 }
122 if (span.fDone && lastDone) {
123 goto next;
124 }
125 if (approximately_negative(span.fT - lastT)) {
126 goto next;
127 }
128 {
129 const SkPoint& xy = xyAtT(&span);
130 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
131 topPt = xy;
132 if (firstT) {
133 *firstT = index;
134 }
135 }
136 if (fVerb != SkPath::kLine_Verb && !lastDone) {
137 SkPoint curveTop = (*CurveTop[fVerb])(fPts, lastT, span.fT);
138 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
139 && topPt.fX > curveTop.fX)) {
140 topPt = curveTop;
141 if (firstT) {
142 *firstT = index;
143 }
144 }
145 }
146 lastT = span.fT;
147 }
148next:
149 lastDone = span.fDone;
150 lastUnsortable = span.fUnsortableEnd;
151 }
152 return topPt;
153}
154
155bool SkOpSegment::activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op) {
156 int sumMiWinding = updateWinding(endIndex, index);
157 int sumSuWinding = updateOppWinding(endIndex, index);
158 if (fOperand) {
159 SkTSwap<int>(sumMiWinding, sumSuWinding);
160 }
161 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
162 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, &sumMiWinding, &sumSuWinding,
163 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
164}
165
166bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op,
167 int* sumMiWinding, int* sumSuWinding,
168 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) {
169 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
170 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
171 bool miFrom;
172 bool miTo;
173 bool suFrom;
174 bool suTo;
175 if (operand()) {
176 miFrom = (*oppMaxWinding & xorMiMask) != 0;
177 miTo = (*oppSumWinding & xorMiMask) != 0;
178 suFrom = (*maxWinding & xorSuMask) != 0;
179 suTo = (*sumWinding & xorSuMask) != 0;
180 } else {
181 miFrom = (*maxWinding & xorMiMask) != 0;
182 miTo = (*sumWinding & xorMiMask) != 0;
183 suFrom = (*oppMaxWinding & xorSuMask) != 0;
184 suTo = (*oppSumWinding & xorSuMask) != 0;
185 }
186 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
187#if DEBUG_ACTIVE_OP
188 SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__,
189 kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
190#endif
191 return result;
192}
193
194bool SkOpSegment::activeWinding(int index, int endIndex) {
195 int sumWinding = updateWinding(endIndex, index);
196 int maxWinding;
197 return activeWinding(index, endIndex, &maxWinding, &sumWinding);
198}
199
200bool SkOpSegment::activeWinding(int index, int endIndex, int* maxWinding, int* sumWinding) {
201 setUpWinding(index, endIndex, maxWinding, sumWinding);
202 bool from = *maxWinding != 0;
203 bool to = *sumWinding != 0;
204 bool result = gUnaryActiveEdge[from][to];
205 return result;
206}
207
208void SkOpSegment::addAngle(SkTDArray<SkOpAngle>* anglesPtr, int start, int end) const {
209 SkASSERT(start != end);
210 SkOpAngle* angle = anglesPtr->append();
211#if DEBUG_ANGLE
212 SkTDArray<SkOpAngle>& angles = *anglesPtr;
213 if (angles.count() > 1 && !fTs[start].fTiny) {
214 SkPoint angle0Pt = (*CurvePointAtT[angles[0].verb()])(angles[0].pts(),
215 (*angles[0].spans())[angles[0].start()].fT);
216 SkPoint newPt = (*CurvePointAtT[fVerb])(fPts, fTs[start].fT);
217 SkASSERT(AlmostEqualUlps(angle0Pt.fX, newPt.fX));
218 SkASSERT(AlmostEqualUlps(angle0Pt.fY, newPt.fY));
219 }
220#endif
221 angle->set(fPts, fVerb, this, start, end, fTs);
222}
223
224void SkOpSegment::addCancelOutsides(double tStart, double oStart, SkOpSegment* other, double oEnd) {
225 int tIndex = -1;
226 int tCount = fTs.count();
227 int oIndex = -1;
228 int oCount = other->fTs.count();
229 do {
230 ++tIndex;
231 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount);
232 int tIndexStart = tIndex;
233 do {
234 ++oIndex;
235 } while (!approximately_negative(oStart - other->fTs[oIndex].fT) && oIndex < oCount);
236 int oIndexStart = oIndex;
237 double nextT;
238 do {
239 nextT = fTs[++tIndex].fT;
240 } while (nextT < 1 && approximately_negative(nextT - tStart));
241 double oNextT;
242 do {
243 oNextT = other->fTs[++oIndex].fT;
244 } while (oNextT < 1 && approximately_negative(oNextT - oStart));
245 // at this point, spans before and after are at:
246 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
247 // if tIndexStart == 0, no prior span
248 // if nextT == 1, no following span
249
250 // advance the span with zero winding
251 // if the following span exists (not past the end, non-zero winding)
252 // connect the two edges
253 if (!fTs[tIndexStart].fWindValue) {
254 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
255#if DEBUG_CONCIDENT
256 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
257 __FUNCTION__, fID, other->fID, tIndexStart - 1,
258 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
259 xyAtT(tIndexStart).fY);
260#endif
261 addTPair(fTs[tIndexStart].fT, other, other->fTs[oIndex].fT, false,
262 fTs[tIndexStart].fPt);
263 }
264 if (nextT < 1 && fTs[tIndex].fWindValue) {
265#if DEBUG_CONCIDENT
266 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
267 __FUNCTION__, fID, other->fID, tIndex,
268 fTs[tIndex].fT, xyAtT(tIndex).fX,
269 xyAtT(tIndex).fY);
270#endif
271 addTPair(fTs[tIndex].fT, other, other->fTs[oIndexStart].fT, false, fTs[tIndex].fPt);
272 }
273 } else {
274 SkASSERT(!other->fTs[oIndexStart].fWindValue);
275 if (oIndexStart > 0 && other->fTs[oIndexStart - 1].fWindValue) {
276#if DEBUG_CONCIDENT
277 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
278 __FUNCTION__, fID, other->fID, oIndexStart - 1,
279 other->fTs[oIndexStart].fT, other->xyAtT(oIndexStart).fX,
280 other->xyAtT(oIndexStart).fY);
281 other->debugAddTPair(other->fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
282#endif
283 }
284 if (oNextT < 1 && other->fTs[oIndex].fWindValue) {
285#if DEBUG_CONCIDENT
286 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
287 __FUNCTION__, fID, other->fID, oIndex,
288 other->fTs[oIndex].fT, other->xyAtT(oIndex).fX,
289 other->xyAtT(oIndex).fY);
290 other->debugAddTPair(other->fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
291#endif
292 }
293 }
294}
295
296void SkOpSegment::addCoinOutsides(const SkTDArray<double>& outsideTs, SkOpSegment* other,
297 double oEnd) {
298 // walk this to outsideTs[0]
299 // walk other to outsideTs[1]
300 // if either is > 0, add a pointer to the other, copying adjacent winding
301 int tIndex = -1;
302 int oIndex = -1;
303 double tStart = outsideTs[0];
304 double oStart = outsideTs[1];
305 do {
306 ++tIndex;
307 } while (!approximately_negative(tStart - fTs[tIndex].fT));
308 SkPoint ptStart = fTs[tIndex].fPt;
309 do {
310 ++oIndex;
311 } while (!approximately_negative(oStart - other->fTs[oIndex].fT));
312 if (tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) {
313 addTPair(tStart, other, oStart, false, ptStart);
314 }
315 tStart = fTs[tIndex].fT;
316 oStart = other->fTs[oIndex].fT;
317 do {
318 double nextT;
319 do {
320 nextT = fTs[++tIndex].fT;
321 } while (approximately_negative(nextT - tStart));
322 tStart = nextT;
323 ptStart = fTs[tIndex].fPt;
324 do {
325 nextT = other->fTs[++oIndex].fT;
326 } while (approximately_negative(nextT - oStart));
327 oStart = nextT;
328 if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) {
329 break;
330 }
331 addTPair(tStart, other, oStart, false, ptStart);
332 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
333}
334
335void SkOpSegment::addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
336 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
337 fBounds.setCubicBounds(pts);
338}
339
340void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active) const {
341 SkPoint edge[4];
342 const SkPoint* ePtr;
343 int lastT = fTs.count() - 1;
344 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
345 ePtr = fPts;
346 } else {
347 // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
348 subDivide(start, end, edge);
349 ePtr = edge;
350 }
351 if (active) {
352 bool reverse = ePtr == fPts && start != 0;
353 if (reverse) {
354 path->deferredMoveLine(ePtr[fVerb]);
355 switch (fVerb) {
356 case SkPath::kLine_Verb:
357 path->deferredLine(ePtr[0]);
358 break;
359 case SkPath::kQuad_Verb:
360 path->quadTo(ePtr[1], ePtr[0]);
361 break;
362 case SkPath::kCubic_Verb:
363 path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
364 break;
365 default:
366 SkASSERT(0);
367 }
368 // return ePtr[0];
369 } else {
370 path->deferredMoveLine(ePtr[0]);
371 switch (fVerb) {
372 case SkPath::kLine_Verb:
373 path->deferredLine(ePtr[1]);
374 break;
375 case SkPath::kQuad_Verb:
376 path->quadTo(ePtr[1], ePtr[2]);
377 break;
378 case SkPath::kCubic_Verb:
379 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
380 break;
381 default:
382 SkASSERT(0);
383 }
384 }
385 }
386 // return ePtr[fVerb];
387}
388
389void SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
390 init(pts, SkPath::kLine_Verb, operand, evenOdd);
391 fBounds.set(pts, 2);
392}
393
394// add 2 to edge or out of range values to get T extremes
395void SkOpSegment::addOtherT(int index, double otherT, int otherIndex) {
396 SkOpSpan& span = fTs[index];
397#if PIN_ADD_T
398 if (precisely_less_than_zero(otherT)) {
399 otherT = 0;
400 } else if (precisely_greater_than_one(otherT)) {
401 otherT = 1;
402 }
403#endif
404 span.fOtherT = otherT;
405 span.fOtherIndex = otherIndex;
406}
407
408void SkOpSegment::addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
409 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
410 fBounds.setQuadBounds(pts);
411}
412
413 // Defer all coincident edge processing until
414 // after normal intersections have been computed
415
416// no need to be tricky; insert in normal T order
417// resolve overlapping ts when considering coincidence later
418
419 // add non-coincident intersection. Resulting edges are sorted in T.
420int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) {
421 // FIXME: in the pathological case where there is a ton of intercepts,
422 // binary search?
423 int insertedAt = -1;
424 size_t tCount = fTs.count();
425 for (size_t index = 0; index < tCount; ++index) {
426 // OPTIMIZATION: if there are three or more identical Ts, then
427 // the fourth and following could be further insertion-sorted so
428 // that all the edges are clockwise or counterclockwise.
429 // This could later limit segment tests to the two adjacent
430 // neighbors, although it doesn't help with determining which
431 // circular direction to go in.
432 if (newT < fTs[index].fT) {
433 insertedAt = index;
434 break;
435 }
436 }
437 SkOpSpan* span;
438 if (insertedAt >= 0) {
439 span = fTs.insert(insertedAt);
440 } else {
441 insertedAt = tCount;
442 span = fTs.append();
443 }
444 span->fT = newT;
445 span->fOther = other;
446 span->fPt = pt;
447 span->fWindSum = SK_MinS32;
448 span->fOppSum = SK_MinS32;
449 span->fWindValue = 1;
450 span->fOppValue = 0;
451 span->fTiny = false;
452 span->fLoop = false;
453 if ((span->fDone = newT == 1)) {
454 ++fDoneSpans;
455 }
456 span->fUnsortableStart = false;
457 span->fUnsortableEnd = false;
458 int less = -1;
459 while (&span[less + 1] - fTs.begin() > 0 && xyAtT(&span[less]) == xyAtT(span)) {
460 if (span[less].fDone) {
461 break;
462 }
463 double tInterval = newT - span[less].fT;
464 if (precisely_negative(tInterval)) {
465 break;
466 }
467 if (fVerb == SkPath::kCubic_Verb) {
468 double tMid = newT - tInterval / 2;
469 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid);
470 if (!midPt.approximatelyEqual(xyAtT(span))) {
471 break;
472 }
473 }
474 span[less].fTiny = true;
475 span[less].fDone = true;
476 if (approximately_negative(newT - span[less].fT)) {
477 if (approximately_greater_than_one(newT)) {
478 SkASSERT(&span[less] - fTs.begin() < fTs.count());
479 span[less].fUnsortableStart = true;
480 if (&span[less - 1] - fTs.begin() >= 0) {
481 span[less - 1].fUnsortableEnd = true;
482 }
483 }
484 if (approximately_less_than_zero(span[less].fT)) {
485 SkASSERT(&span[less + 1] - fTs.begin() < fTs.count());
486 SkASSERT(&span[less] - fTs.begin() >= 0);
487 span[less + 1].fUnsortableStart = true;
488 span[less].fUnsortableEnd = true;
489 }
490 }
491 ++fDoneSpans;
492 --less;
493 }
494 int more = 1;
495 while (fTs.end() - &span[more - 1] > 1 && xyAtT(&span[more]) == xyAtT(span)) {
496 if (span[more - 1].fDone) {
497 break;
498 }
499 double tEndInterval = span[more].fT - newT;
500 if (precisely_negative(tEndInterval)) {
501 break;
502 }
503 if (fVerb == SkPath::kCubic_Verb) {
504 double tMid = newT - tEndInterval / 2;
505 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid);
506 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
507 break;
508 }
509 }
510 span[more - 1].fTiny = true;
511 span[more - 1].fDone = true;
512 if (approximately_negative(span[more].fT - newT)) {
513 if (approximately_greater_than_one(span[more].fT)) {
514 span[more + 1].fUnsortableStart = true;
515 span[more].fUnsortableEnd = true;
516 }
517 if (approximately_less_than_zero(newT)) {
518 span[more].fUnsortableStart = true;
519 span[more - 1].fUnsortableEnd = true;
520 }
521 }
522 ++fDoneSpans;
523 ++more;
524 }
525 return insertedAt;
526}
527
528// set spans from start to end to decrement by one
529// note this walks other backwards
530// FIMXE: there's probably an edge case that can be constructed where
531// two span in one segment are separated by float epsilon on one span but
532// not the other, if one segment is very small. For this
533// case the counts asserted below may or may not be enough to separate the
534// spans. Even if the counts work out, what if the spans aren't correctly
535// sorted? It feels better in such a case to match the span's other span
536// pointer since both coincident segments must contain the same spans.
537void SkOpSegment::addTCancel(double startT, double endT, SkOpSegment* other,
538 double oStartT, double oEndT) {
539 SkASSERT(!approximately_negative(endT - startT));
540 SkASSERT(!approximately_negative(oEndT - oStartT));
541 bool binary = fOperand != other->fOperand;
542 int index = 0;
543 while (!approximately_negative(startT - fTs[index].fT)) {
544 ++index;
545 }
546 int oIndex = other->fTs.count();
547 while (approximately_positive(other->fTs[--oIndex].fT - oEndT))
548 ;
549 double tRatio = (oEndT - oStartT) / (endT - startT);
550 SkOpSpan* test = &fTs[index];
551 SkOpSpan* oTest = &other->fTs[oIndex];
552 SkTDArray<double> outsideTs;
553 SkTDArray<double> oOutsideTs;
554 do {
555 bool decrement = test->fWindValue && oTest->fWindValue && !binary;
556 bool track = test->fWindValue || oTest->fWindValue;
557 double testT = test->fT;
558 double oTestT = oTest->fT;
559 SkOpSpan* span = test;
560 do {
561 if (decrement) {
562 decrementSpan(span);
563 } else if (track && span->fT < 1 && oTestT < 1) {
564 TrackOutside(&outsideTs, span->fT, oTestT);
565 }
566 span = &fTs[++index];
567 } while (approximately_negative(span->fT - testT));
568 SkOpSpan* oSpan = oTest;
569 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio;
570 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio;
571 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue);
572 while (approximately_negative(otherTMatchStart - oSpan->fT)
573 && !approximately_negative(otherTMatchEnd - oSpan->fT)) {
574 #ifdef SK_DEBUG
575 SkASSERT(originalWindValue == oSpan->fWindValue);
576 #endif
577 if (decrement) {
578 other->decrementSpan(oSpan);
579 } else if (track && oSpan->fT < 1 && testT < 1) {
580 TrackOutside(&oOutsideTs, oSpan->fT, testT);
581 }
582 if (!oIndex) {
583 break;
584 }
585 oSpan = &other->fTs[--oIndex];
586 }
587 test = span;
588 oTest = oSpan;
589 } while (!approximately_negative(endT - test->fT));
590 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT));
591 // FIXME: determine if canceled edges need outside ts added
592 if (!done() && outsideTs.count()) {
593 double tStart = outsideTs[0];
594 double oStart = outsideTs[1];
595 addCancelOutsides(tStart, oStart, other, oEndT);
596 int count = outsideTs.count();
597 if (count > 2) {
598 double tStart = outsideTs[count - 2];
599 double oStart = outsideTs[count - 1];
600 addCancelOutsides(tStart, oStart, other, oEndT);
601 }
602 }
603 if (!other->done() && oOutsideTs.count()) {
604 double tStart = oOutsideTs[0];
605 double oStart = oOutsideTs[1];
606 other->addCancelOutsides(tStart, oStart, this, endT);
607 }
608}
609
610int SkOpSegment::addSelfT(SkOpSegment* other, const SkPoint& pt, double newT) {
611 int result = addT(other, pt, newT);
612 SkOpSpan* span = &fTs[result];
613 span->fLoop = true;
614 return result;
615}
616
617int SkOpSegment::addUnsortableT(SkOpSegment* other, bool start, const SkPoint& pt, double newT) {
618 int result = addT(other, pt, newT);
619 SkOpSpan* span = &fTs[result];
620 if (start) {
621 if (result > 0) {
622 span[result - 1].fUnsortableEnd = true;
623 }
624 span[result].fUnsortableStart = true;
625 } else {
626 span[result].fUnsortableEnd = true;
627 if (result + 1 < fTs.count()) {
628 span[result + 1].fUnsortableStart = true;
629 }
630 }
631 return result;
632}
633
634int SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool opp, int index,
635 SkTDArray<double>* outsideTs) {
636 int oWindValue = oTest.fWindValue;
637 int oOppValue = oTest.fOppValue;
638 if (opp) {
639 SkTSwap<int>(oWindValue, oOppValue);
640 }
641 SkOpSpan* const test = &fTs[index];
642 SkOpSpan* end = test;
643 const double oStartT = oTest.fT;
644 do {
645 if (bumpSpan(end, oWindValue, oOppValue)) {
646 TrackOutside(outsideTs, end->fT, oStartT);
647 }
648 end = &fTs[++index];
649 } while (approximately_negative(end->fT - test->fT));
650 return index;
651}
652
653// because of the order in which coincidences are resolved, this and other
654// may not have the same intermediate points. Compute the corresponding
655// intermediate T values (using this as the master, other as the follower)
656// and walk other conditionally -- hoping that it catches up in the end
657int SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, double oEndT, int& oIndex,
658 SkTDArray<double>* oOutsideTs) {
659 SkOpSpan* const oTest = &fTs[oIndex];
660 SkOpSpan* oEnd = oTest;
661 const double startT = test.fT;
662 const double oStartT = oTest->fT;
663 while (!approximately_negative(oEndT - oEnd->fT)
664 && approximately_negative(oEnd->fT - oStartT)) {
665 zeroSpan(oEnd);
666 TrackOutside(oOutsideTs, oEnd->fT, startT);
667 oEnd = &fTs[++oIndex];
668 }
669 return oIndex;
670}
671
672// FIXME: need to test this case:
673// contourA has two segments that are coincident
674// contourB has two segments that are coincident in the same place
675// each ends up with +2/0 pairs for winding count
676// since logic below doesn't transfer count (only increments/decrements) can this be
677// resolved to +4/0 ?
678
679// set spans from start to end to increment the greater by one and decrement
680// the lesser
681void SkOpSegment::addTCoincident(double startT, double endT, SkOpSegment* other, double oStartT,
682 double oEndT) {
683 SkASSERT(!approximately_negative(endT - startT));
684 SkASSERT(!approximately_negative(oEndT - oStartT));
685 bool opp = fOperand ^ other->fOperand;
686 int index = 0;
687 while (!approximately_negative(startT - fTs[index].fT)) {
688 ++index;
689 }
690 int oIndex = 0;
691 while (!approximately_negative(oStartT - other->fTs[oIndex].fT)) {
692 ++oIndex;
693 }
694 SkOpSpan* test = &fTs[index];
695 SkOpSpan* oTest = &other->fTs[oIndex];
696 SkTDArray<double> outsideTs;
697 SkTDArray<double> oOutsideTs;
698 do {
699 // if either span has an opposite value and the operands don't match, resolve first
700 // SkASSERT(!test->fDone || !oTest->fDone);
701 if (test->fDone || oTest->fDone) {
702 index = advanceCoincidentThis(oTest, opp, index);
703 oIndex = other->advanceCoincidentOther(test, oEndT, oIndex);
704 } else {
705 index = bumpCoincidentThis(*oTest, opp, index, &outsideTs);
706 oIndex = other->bumpCoincidentOther(*test, oEndT, oIndex, &oOutsideTs);
707 }
708 test = &fTs[index];
709 oTest = &other->fTs[oIndex];
710 } while (!approximately_negative(endT - test->fT));
711 SkASSERT(approximately_negative(oTest->fT - oEndT));
712 SkASSERT(approximately_negative(oEndT - oTest->fT));
713 if (!done() && outsideTs.count()) {
714 addCoinOutsides(outsideTs, other, oEndT);
715 }
716 if (!other->done() && oOutsideTs.count()) {
717 other->addCoinOutsides(oOutsideTs, this, endT);
718 }
719}
720
721// FIXME: this doesn't prevent the same span from being added twice
722// fix in caller, SkASSERT here?
723void SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
724 const SkPoint& pt) {
725 int tCount = fTs.count();
726 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
727 const SkOpSpan& span = fTs[tIndex];
728 if (!approximately_negative(span.fT - t)) {
729 break;
730 }
731 if (approximately_negative(span.fT - t) && span.fOther == other
732 && approximately_equal(span.fOtherT, otherT)) {
733#if DEBUG_ADD_T_PAIR
734 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
735 __FUNCTION__, fID, t, other->fID, otherT);
736#endif
737 return;
738 }
739 }
740#if DEBUG_ADD_T_PAIR
741 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
742 __FUNCTION__, fID, t, other->fID, otherT);
743#endif
744 int insertedAt = addT(other, pt, t);
745 int otherInsertedAt = other->addT(this, pt, otherT);
746 addOtherT(insertedAt, otherT, otherInsertedAt);
747 other->addOtherT(otherInsertedAt, t, insertedAt);
748 matchWindingValue(insertedAt, t, borrowWind);
749 other->matchWindingValue(otherInsertedAt, otherT, borrowWind);
750}
751
752void SkOpSegment::addTwoAngles(int start, int end, SkTDArray<SkOpAngle>* angles) const {
753 // add edge leading into junction
754 int min = SkMin32(end, start);
755 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) {
756 addAngle(angles, end, start);
757 }
758 // add edge leading away from junction
759 int step = SkSign32(end - start);
760 int tIndex = nextExactSpan(end, step);
761 min = SkMin32(end, tIndex);
762 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) {
763 addAngle(angles, end, tIndex);
764 }
765}
766
767int SkOpSegment::advanceCoincidentThis(const SkOpSpan* oTest, bool opp, int index) {
768 SkOpSpan* const test = &fTs[index];
769 SkOpSpan* end;
770 do {
771 end = &fTs[++index];
772 } while (approximately_negative(end->fT - test->fT));
773 return index;
774}
775
776int SkOpSegment::advanceCoincidentOther(const SkOpSpan* test, double oEndT, int oIndex) {
777 SkOpSpan* const oTest = &fTs[oIndex];
778 SkOpSpan* oEnd = oTest;
779 const double oStartT = oTest->fT;
780 while (!approximately_negative(oEndT - oEnd->fT)
781 && approximately_negative(oEnd->fT - oStartT)) {
782 oEnd = &fTs[++oIndex];
783 }
784 return oIndex;
785}
786
787bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const {
788 if (lesser > greater) {
789 SkTSwap<int>(lesser, greater);
790 }
791 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
792}
793
794void SkOpSegment::buildAngles(int index, SkTDArray<SkOpAngle>* angles, bool includeOpp) const {
795 double referenceT = fTs[index].fT;
796 int lesser = index;
797 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
798 && precisely_negative(referenceT - fTs[lesser].fT)) {
799 buildAnglesInner(lesser, angles);
800 }
801 do {
802 buildAnglesInner(index, angles);
803 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
804 && precisely_negative(fTs[index].fT - referenceT));
805}
806
807void SkOpSegment::buildAnglesInner(int index, SkTDArray<SkOpAngle>* angles) const {
808 const SkOpSpan* span = &fTs[index];
809 SkOpSegment* other = span->fOther;
810// if there is only one live crossing, and no coincidence, continue
811// in the same direction
812// if there is coincidence, the only choice may be to reverse direction
813 // find edge on either side of intersection
814 int oIndex = span->fOtherIndex;
815 // if done == -1, prior span has already been processed
816 int step = 1;
817 int next = other->nextExactSpan(oIndex, step);
818 if (next < 0) {
819 step = -step;
820 next = other->nextExactSpan(oIndex, step);
821 }
822 // add candidate into and away from junction
823 other->addTwoAngles(next, oIndex, angles);
824}
825
826int SkOpSegment::computeSum(int startIndex, int endIndex, bool binary) {
827 SkTDArray<SkOpAngle> angles;
828 addTwoAngles(startIndex, endIndex, &angles);
829 buildAngles(endIndex, &angles, false);
830 // OPTIMIZATION: check all angles to see if any have computed wind sum
831 // before sorting (early exit if none)
832 SkTDArray<SkOpAngle*> sorted;
833 bool sortable = SortAngles(angles, &sorted);
834#if DEBUG_SORT
835 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
836#endif
837 if (!sortable) {
838 return SK_MinS32;
839 }
840 int angleCount = angles.count();
841 const SkOpAngle* angle;
842 const SkOpSegment* base;
843 int winding;
844 int oWinding;
845 int firstIndex = 0;
846 do {
847 angle = sorted[firstIndex];
848 base = angle->segment();
849 winding = base->windSum(angle);
850 if (winding != SK_MinS32) {
851 oWinding = base->oppSum(angle);
852 break;
853 }
854 if (++firstIndex == angleCount) {
855 return SK_MinS32;
856 }
857 } while (true);
858 // turn winding into contourWinding
859 int spanWinding = base->spanSign(angle);
860 bool inner = UseInnerWinding(winding + spanWinding, winding);
861#if DEBUG_WINDING
862 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
863 spanWinding, winding, angle->sign(), inner,
864 inner ? winding + spanWinding : winding);
865#endif
866 if (inner) {
867 winding += spanWinding;
868 }
869#if DEBUG_SORT
870 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
871#endif
872 int nextIndex = firstIndex + 1;
873 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
874 winding -= base->spanSign(angle);
875 oWinding -= base->oppSign(angle);
876 do {
877 if (nextIndex == angleCount) {
878 nextIndex = 0;
879 }
880 angle = sorted[nextIndex];
881 SkOpSegment* segment = angle->segment();
882 bool opp = base->fOperand ^ segment->fOperand;
883 int maxWinding, oMaxWinding;
884 int spanSign = segment->spanSign(angle);
885 int oppoSign = segment->oppSign(angle);
886 if (opp) {
887 oMaxWinding = oWinding;
888 oWinding -= spanSign;
889 maxWinding = winding;
890 if (oppoSign) {
891 winding -= oppoSign;
892 }
893 } else {
894 maxWinding = winding;
895 winding -= spanSign;
896 oMaxWinding = oWinding;
897 if (oppoSign) {
898 oWinding -= oppoSign;
899 }
900 }
901 if (segment->windSum(angle) == SK_MinS32) {
902 if (opp) {
903 if (UseInnerWinding(oMaxWinding, oWinding)) {
904 oMaxWinding = oWinding;
905 }
906 if (oppoSign && UseInnerWinding(maxWinding, winding)) {
907 maxWinding = winding;
908 }
909 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding);
910 } else {
911 if (UseInnerWinding(maxWinding, winding)) {
912 maxWinding = winding;
913 }
914 if (oppoSign && UseInnerWinding(oMaxWinding, oWinding)) {
915 oMaxWinding = oWinding;
916 }
917 (void) segment->markAndChaseWinding(angle, maxWinding,
918 binary ? oMaxWinding : 0);
919 }
920 }
921 } while (++nextIndex != lastIndex);
922 int minIndex = SkMin32(startIndex, endIndex);
923 return windSum(minIndex);
924}
925
926int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT,
927 bool* hitSomething, double mid, bool opp, bool current) const {
928 SkScalar bottom = fBounds.fBottom;
929 int bestTIndex = -1;
930 if (bottom <= *bestY) {
931 return bestTIndex;
932 }
933 SkScalar top = fBounds.fTop;
934 if (top >= basePt.fY) {
935 return bestTIndex;
936 }
937 if (fBounds.fLeft > basePt.fX) {
938 return bestTIndex;
939 }
940 if (fBounds.fRight < basePt.fX) {
941 return bestTIndex;
942 }
943 if (fBounds.fLeft == fBounds.fRight) {
944 // if vertical, and directly above test point, wait for another one
945 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
946 }
947 // intersect ray starting at basePt with edge
948 SkIntersections intersections;
949 // OPTIMIZE: use specialty function that intersects ray with curve,
950 // returning t values only for curve (we don't care about t on ray)
951 int pts = (intersections.*CurveVertical[fVerb])(fPts, top, bottom, basePt.fX, false);
952 if (pts == 0 || (current && pts == 1)) {
953 return bestTIndex;
954 }
955 if (current) {
956 SkASSERT(pts > 1);
957 int closestIdx = 0;
958 double closest = fabs(intersections[0][0] - mid);
959 for (int idx = 1; idx < pts; ++idx) {
960 double test = fabs(intersections[0][idx] - mid);
961 if (closest > test) {
962 closestIdx = idx;
963 closest = test;
964 }
965 }
966 intersections.quickRemoveOne(closestIdx, --pts);
967 }
968 double bestT = -1;
969 for (int index = 0; index < pts; ++index) {
970 double foundT = intersections[0][index];
971 if (approximately_less_than_zero(foundT)
972 || approximately_greater_than_one(foundT)) {
973 continue;
974 }
975 SkScalar testY = (*CurvePointAtT[fVerb])(fPts, foundT).fY;
976 if (approximately_negative(testY - *bestY)
977 || approximately_negative(basePt.fY - testY)) {
978 continue;
979 }
980 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
981 return SK_MinS32; // if the intersection is edge on, wait for another one
982 }
983 if (fVerb > SkPath::kLine_Verb) {
984 SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, foundT).fX;
985 if (approximately_zero(dx)) {
986 return SK_MinS32; // hit vertical, wait for another one
987 }
988 }
989 *bestY = testY;
990 bestT = foundT;
991 }
992 if (bestT < 0) {
993 return bestTIndex;
994 }
995 SkASSERT(bestT >= 0);
996 SkASSERT(bestT <= 1);
997 int start;
998 int end = 0;
999 do {
1000 start = end;
1001 end = nextSpan(start, 1);
1002 } while (fTs[end].fT < bestT);
1003 // FIXME: see next candidate for a better pattern to find the next start/end pair
1004 while (start + 1 < end && fTs[start].fDone) {
1005 ++start;
1006 }
1007 if (!isCanceled(start)) {
1008 *hitT = bestT;
1009 bestTIndex = start;
1010 *hitSomething = true;
1011 }
1012 return bestTIndex;
1013}
1014
1015void SkOpSegment::decrementSpan(SkOpSpan* span) {
1016 SkASSERT(span->fWindValue > 0);
1017 if (--(span->fWindValue) == 0) {
1018 if (!span->fOppValue && !span->fDone) {
1019 span->fDone = true;
1020 ++fDoneSpans;
1021 }
1022 }
1023}
1024
1025bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) {
1026 SkASSERT(!span->fDone);
1027 span->fWindValue += windDelta;
1028 SkASSERT(span->fWindValue >= 0);
1029 span->fOppValue += oppDelta;
1030 SkASSERT(span->fOppValue >= 0);
1031 if (fXor) {
1032 span->fWindValue &= 1;
1033 }
1034 if (fOppXor) {
1035 span->fOppValue &= 1;
1036 }
1037 if (!span->fWindValue && !span->fOppValue) {
1038 span->fDone = true;
1039 ++fDoneSpans;
1040 return true;
1041 }
1042 return false;
1043}
1044
1045bool SkOpSegment::equalPoints(int greaterTIndex, int lesserTIndex) {
1046 SkASSERT(greaterTIndex >= lesserTIndex);
1047 double greaterT = fTs[greaterTIndex].fT;
1048 double lesserT = fTs[lesserTIndex].fT;
1049 if (greaterT == lesserT) {
1050 return true;
1051 }
1052 if (!approximately_negative(greaterT - lesserT)) {
1053 return false;
1054 }
1055 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
1056}
1057
1058/*
1059 The M and S variable name parts stand for the operators.
1060 Mi stands for Minuend (see wiki subtraction, analogous to difference)
1061 Su stands for Subtrahend
1062 The Opp variable name part designates that the value is for the Opposite operator.
1063 Opposite values result from combining coincident spans.
1064 */
1065SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
1066 bool* unsortable, SkPathOp op, const int xorMiMask,
1067 const int xorSuMask) {
1068 const int startIndex = *nextStart;
1069 const int endIndex = *nextEnd;
1070 SkASSERT(startIndex != endIndex);
1071 SkDEBUGCODE(const int count = fTs.count());
1072 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
1073 const int step = SkSign32(endIndex - startIndex);
1074 const int end = nextExactSpan(startIndex, step);
1075 SkASSERT(end >= 0);
1076 SkOpSpan* endSpan = &fTs[end];
1077 SkOpSegment* other;
1078 if (isSimple(end)) {
1079 // mark the smaller of startIndex, endIndex done, and all adjacent
1080 // spans with the same T value (but not 'other' spans)
1081#if DEBUG_WINDING
1082 SkDebugf("%s simple\n", __FUNCTION__);
1083#endif
1084 int min = SkMin32(startIndex, endIndex);
1085 if (fTs[min].fDone) {
1086 return NULL;
1087 }
1088 markDoneBinary(min);
1089 other = endSpan->fOther;
1090 *nextStart = endSpan->fOtherIndex;
1091 double startT = other->fTs[*nextStart].fT;
1092 *nextEnd = *nextStart;
1093 do {
1094 *nextEnd += step;
1095 }
1096 while (precisely_zero(startT - other->fTs[*nextEnd].fT));
1097 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
1098 return other;
1099 }
1100 // more than one viable candidate -- measure angles to find best
1101 SkTDArray<SkOpAngle> angles;
1102 SkASSERT(startIndex - endIndex != 0);
1103 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
1104 addTwoAngles(startIndex, end, &angles);
1105 buildAngles(end, &angles, true);
1106 SkTDArray<SkOpAngle*> sorted;
1107 bool sortable = SortAngles(angles, &sorted);
1108 int angleCount = angles.count();
1109 int firstIndex = findStartingEdge(sorted, startIndex, end);
1110 SkASSERT(firstIndex >= 0);
1111#if DEBUG_SORT
1112 debugShowSort(__FUNCTION__, sorted, firstIndex);
1113#endif
1114 if (!sortable) {
1115 *unsortable = true;
1116 return NULL;
1117 }
1118 SkASSERT(sorted[firstIndex]->segment() == this);
1119#if DEBUG_WINDING
1120 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex,
1121 sorted[firstIndex]->sign());
1122#endif
1123 int sumMiWinding = updateWinding(endIndex, startIndex);
1124 int sumSuWinding = updateOppWinding(endIndex, startIndex);
1125 if (operand()) {
1126 SkTSwap<int>(sumMiWinding, sumSuWinding);
1127 }
1128 int nextIndex = firstIndex + 1;
1129 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1130 const SkOpAngle* foundAngle = NULL;
1131 bool foundDone = false;
1132 // iterate through the angle, and compute everyone's winding
1133 SkOpSegment* nextSegment;
1134 int activeCount = 0;
1135 do {
1136 SkASSERT(nextIndex != firstIndex);
1137 if (nextIndex == angleCount) {
1138 nextIndex = 0;
1139 }
1140 const SkOpAngle* nextAngle = sorted[nextIndex];
1141 nextSegment = nextAngle->segment();
1142 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
1143 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
1144 nextAngle->end(), op, &sumMiWinding, &sumSuWinding,
1145 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1146 if (activeAngle) {
1147 ++activeCount;
1148 if (!foundAngle || (foundDone && activeCount & 1)) {
1149 if (nextSegment->tiny(nextAngle)) {
1150 *unsortable = true;
1151 return NULL;
1152 }
1153 foundAngle = nextAngle;
1154 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
1155 }
1156 }
1157 if (nextSegment->done()) {
1158 continue;
1159 }
1160 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
1161 continue;
1162 }
1163 SkOpSpan* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding,
1164 oppSumWinding, activeAngle, nextAngle);
1165 if (last) {
1166 *chase->append() = last;
1167#if DEBUG_WINDING
1168 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
1169 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
1170#endif
1171 }
1172 } while (++nextIndex != lastIndex);
1173 markDoneBinary(SkMin32(startIndex, endIndex));
1174 if (!foundAngle) {
1175 return NULL;
1176 }
1177 *nextStart = foundAngle->start();
1178 *nextEnd = foundAngle->end();
1179 nextSegment = foundAngle->segment();
1180
1181#if DEBUG_WINDING
1182 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1183 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1184 #endif
1185 return nextSegment;
1186}
1187
1188SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart,
1189 int* nextEnd, bool* unsortable) {
1190 const int startIndex = *nextStart;
1191 const int endIndex = *nextEnd;
1192 SkASSERT(startIndex != endIndex);
1193 SkDEBUGCODE(const int count = fTs.count());
1194 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
1195 const int step = SkSign32(endIndex - startIndex);
1196 const int end = nextExactSpan(startIndex, step);
1197 SkASSERT(end >= 0);
1198 SkOpSpan* endSpan = &fTs[end];
1199 SkOpSegment* other;
1200 if (isSimple(end)) {
1201 // mark the smaller of startIndex, endIndex done, and all adjacent
1202 // spans with the same T value (but not 'other' spans)
1203#if DEBUG_WINDING
1204 SkDebugf("%s simple\n", __FUNCTION__);
1205#endif
1206 int min = SkMin32(startIndex, endIndex);
1207 if (fTs[min].fDone) {
1208 return NULL;
1209 }
1210 markDoneUnary(min);
1211 other = endSpan->fOther;
1212 *nextStart = endSpan->fOtherIndex;
1213 double startT = other->fTs[*nextStart].fT;
1214 *nextEnd = *nextStart;
1215 do {
1216 *nextEnd += step;
1217 }
1218 while (precisely_zero(startT - other->fTs[*nextEnd].fT));
1219 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
1220 return other;
1221 }
1222 // more than one viable candidate -- measure angles to find best
1223 SkTDArray<SkOpAngle> angles;
1224 SkASSERT(startIndex - endIndex != 0);
1225 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
1226 addTwoAngles(startIndex, end, &angles);
1227 buildAngles(end, &angles, true);
1228 SkTDArray<SkOpAngle*> sorted;
1229 bool sortable = SortAngles(angles, &sorted);
1230 int angleCount = angles.count();
1231 int firstIndex = findStartingEdge(sorted, startIndex, end);
1232 SkASSERT(firstIndex >= 0);
1233#if DEBUG_SORT
1234 debugShowSort(__FUNCTION__, sorted, firstIndex);
1235#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 sumWinding = updateWinding(endIndex, startIndex);
1246 int nextIndex = firstIndex + 1;
1247 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1248 const SkOpAngle* foundAngle = NULL;
1249 bool foundDone = false;
1250 // iterate through the angle, and compute everyone's winding
1251 SkOpSegment* nextSegment;
1252 int activeCount = 0;
1253 do {
1254 SkASSERT(nextIndex != firstIndex);
1255 if (nextIndex == angleCount) {
1256 nextIndex = 0;
1257 }
1258 const SkOpAngle* nextAngle = sorted[nextIndex];
1259 nextSegment = nextAngle->segment();
1260 int maxWinding;
1261 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
1262 &maxWinding, &sumWinding);
1263 if (activeAngle) {
1264 ++activeCount;
1265 if (!foundAngle || (foundDone && activeCount & 1)) {
1266 if (nextSegment->tiny(nextAngle)) {
1267 *unsortable = true;
1268 return NULL;
1269 }
1270 foundAngle = nextAngle;
1271 foundDone = nextSegment->done(nextAngle);
1272 }
1273 }
1274 if (nextSegment->done()) {
1275 continue;
1276 }
1277 if (nextSegment->windSum(nextAngle) != SK_MinS32) {
1278 continue;
1279 }
1280 SkOpSpan* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle);
1281 if (last) {
1282 *chase->append() = last;
1283#if DEBUG_WINDING
1284 SkDebugf("%s chase.append id=%d\n", __FUNCTION__,
1285 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
1286#endif
1287 }
1288 } while (++nextIndex != lastIndex);
1289 markDoneUnary(SkMin32(startIndex, endIndex));
1290 if (!foundAngle) {
1291 return NULL;
1292 }
1293 *nextStart = foundAngle->start();
1294 *nextEnd = foundAngle->end();
1295 nextSegment = foundAngle->segment();
1296#if DEBUG_WINDING
1297 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1298 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1299 #endif
1300 return nextSegment;
1301}
1302
1303SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsortable) {
1304 const int startIndex = *nextStart;
1305 const int endIndex = *nextEnd;
1306 SkASSERT(startIndex != endIndex);
1307 SkDEBUGCODE(int count = fTs.count());
1308 SkASSERT(startIndex < endIndex ? startIndex < count - 1
1309 : startIndex > 0);
1310 int step = SkSign32(endIndex - startIndex);
1311 int end = nextExactSpan(startIndex, step);
1312 SkASSERT(end >= 0);
1313 SkOpSpan* endSpan = &fTs[end];
1314 SkOpSegment* other;
1315 if (isSimple(end)) {
1316#if DEBUG_WINDING
1317 SkDebugf("%s simple\n", __FUNCTION__);
1318#endif
1319 int min = SkMin32(startIndex, endIndex);
1320 if (fTs[min].fDone) {
1321 return NULL;
1322 }
1323 markDone(min, 1);
1324 other = endSpan->fOther;
1325 *nextStart = endSpan->fOtherIndex;
1326 double startT = other->fTs[*nextStart].fT;
1327 // FIXME: I don't know why the logic here is difference from the winding case
1328 SkDEBUGCODE(bool firstLoop = true;)
1329 if ((approximately_less_than_zero(startT) && step < 0)
1330 || (approximately_greater_than_one(startT) && step > 0)) {
1331 step = -step;
1332 SkDEBUGCODE(firstLoop = false;)
1333 }
1334 do {
1335 *nextEnd = *nextStart;
1336 do {
1337 *nextEnd += step;
1338 }
1339 while (precisely_zero(startT - other->fTs[*nextEnd].fT));
1340 if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) {
1341 break;
1342 }
1343#ifdef SK_DEBUG
1344 SkASSERT(firstLoop);
1345#endif
1346 SkDEBUGCODE(firstLoop = false;)
1347 step = -step;
1348 } while (true);
1349 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
1350 return other;
1351 }
1352 SkTDArray<SkOpAngle> angles;
1353 SkASSERT(startIndex - endIndex != 0);
1354 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
1355 addTwoAngles(startIndex, end, &angles);
1356 buildAngles(end, &angles, false);
1357 SkTDArray<SkOpAngle*> sorted;
1358 bool sortable = SortAngles(angles, &sorted);
1359 if (!sortable) {
1360 *unsortable = true;
1361#if DEBUG_SORT
1362 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0);
1363#endif
1364 return NULL;
1365 }
1366 int angleCount = angles.count();
1367 int firstIndex = findStartingEdge(sorted, startIndex, end);
1368 SkASSERT(firstIndex >= 0);
1369#if DEBUG_SORT
1370 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
1371#endif
1372 SkASSERT(sorted[firstIndex]->segment() == this);
1373 int nextIndex = firstIndex + 1;
1374 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
1375 const SkOpAngle* foundAngle = NULL;
1376 bool foundDone = false;
1377 SkOpSegment* nextSegment;
1378 int activeCount = 0;
1379 do {
1380 SkASSERT(nextIndex != firstIndex);
1381 if (nextIndex == angleCount) {
1382 nextIndex = 0;
1383 }
1384 const SkOpAngle* nextAngle = sorted[nextIndex];
1385 nextSegment = nextAngle->segment();
1386 ++activeCount;
1387 if (!foundAngle || (foundDone && activeCount & 1)) {
1388 if (nextSegment->tiny(nextAngle)) {
1389 *unsortable = true;
1390 return NULL;
1391 }
1392 foundAngle = nextAngle;
1393 foundDone = nextSegment->done(nextAngle);
1394 }
1395 if (nextSegment->done()) {
1396 continue;
1397 }
1398 } while (++nextIndex != lastIndex);
1399 markDone(SkMin32(startIndex, endIndex), 1);
1400 if (!foundAngle) {
1401 return NULL;
1402 }
1403 *nextStart = foundAngle->start();
1404 *nextEnd = foundAngle->end();
1405 nextSegment = foundAngle->segment();
1406#if DEBUG_WINDING
1407 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1408 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1409 #endif
1410 return nextSegment;
1411}
1412
1413int SkOpSegment::findStartingEdge(const SkTDArray<SkOpAngle*>& sorted, int start, int end) {
1414 int angleCount = sorted.count();
1415 int firstIndex = -1;
1416 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
1417 const SkOpAngle* angle = sorted[angleIndex];
1418 if (angle->segment() == this && angle->start() == end &&
1419 angle->end() == start) {
1420 firstIndex = angleIndex;
1421 break;
1422 }
1423 }
1424 return firstIndex;
1425}
1426
1427// FIXME: this is tricky code; needs its own unit test
1428// note that fOtherIndex isn't computed yet, so it can't be used here
1429void SkOpSegment::findTooCloseToCall() {
1430 int count = fTs.count();
1431 if (count < 3) { // require t=0, x, 1 at minimum
1432 return;
1433 }
1434 int matchIndex = 0;
1435 int moCount;
1436 SkOpSpan* match;
1437 SkOpSegment* mOther;
1438 do {
1439 match = &fTs[matchIndex];
1440 mOther = match->fOther;
1441 // FIXME: allow quads, cubics to be near coincident?
1442 if (mOther->fVerb == SkPath::kLine_Verb) {
1443 moCount = mOther->fTs.count();
1444 if (moCount >= 3) {
1445 break;
1446 }
1447 }
1448 if (++matchIndex >= count) {
1449 return;
1450 }
1451 } while (true); // require t=0, x, 1 at minimum
1452 // OPTIMIZATION: defer matchPt until qualifying toCount is found?
1453 const SkPoint* matchPt = &xyAtT(match);
1454 // look for a pair of nearby T values that map to the same (x,y) value
1455 // if found, see if the pair of other segments share a common point. If
1456 // so, the span from here to there is coincident.
1457 for (int index = matchIndex + 1; index < count; ++index) {
1458 SkOpSpan* test = &fTs[index];
1459 if (test->fDone) {
1460 continue;
1461 }
1462 SkOpSegment* tOther = test->fOther;
1463 if (tOther->fVerb != SkPath::kLine_Verb) {
1464 continue; // FIXME: allow quads, cubics to be near coincident?
1465 }
1466 int toCount = tOther->fTs.count();
1467 if (toCount < 3) { // require t=0, x, 1 at minimum
1468 continue;
1469 }
1470 const SkPoint* testPt = &xyAtT(test);
1471 if (*matchPt != *testPt) {
1472 matchIndex = index;
1473 moCount = toCount;
1474 match = test;
1475 mOther = tOther;
1476 matchPt = testPt;
1477 continue;
1478 }
1479 int moStart = -1;
1480 int moEnd = -1;
1481 double moStartT = 0;
1482 double moEndT = 0;
1483 for (int moIndex = 0; moIndex < moCount; ++moIndex) {
1484 SkOpSpan& moSpan = mOther->fTs[moIndex];
1485 if (moSpan.fDone) {
1486 continue;
1487 }
1488 if (moSpan.fOther == this) {
1489 if (moSpan.fOtherT == match->fT) {
1490 moStart = moIndex;
1491 moStartT = moSpan.fT;
1492 }
1493 continue;
1494 }
1495 if (moSpan.fOther == tOther) {
1496 if (tOther->windValueAt(moSpan.fOtherT) == 0) {
1497 moStart = -1;
1498 break;
1499 }
1500 SkASSERT(moEnd == -1);
1501 moEnd = moIndex;
1502 moEndT = moSpan.fT;
1503 }
1504 }
1505 if (moStart < 0 || moEnd < 0) {
1506 continue;
1507 }
1508 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test
1509 if (approximately_equal(moStartT, moEndT)) {
1510 continue;
1511 }
1512 int toStart = -1;
1513 int toEnd = -1;
1514 double toStartT = 0;
1515 double toEndT = 0;
1516 for (int toIndex = 0; toIndex < toCount; ++toIndex) {
1517 SkOpSpan& toSpan = tOther->fTs[toIndex];
1518 if (toSpan.fDone) {
1519 continue;
1520 }
1521 if (toSpan.fOther == this) {
1522 if (toSpan.fOtherT == test->fT) {
1523 toStart = toIndex;
1524 toStartT = toSpan.fT;
1525 }
1526 continue;
1527 }
1528 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) {
1529 if (mOther->windValueAt(toSpan.fOtherT) == 0) {
1530 moStart = -1;
1531 break;
1532 }
1533 SkASSERT(toEnd == -1);
1534 toEnd = toIndex;
1535 toEndT = toSpan.fT;
1536 }
1537 }
1538 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test
1539 if (toStart <= 0 || toEnd <= 0) {
1540 continue;
1541 }
1542 if (approximately_equal(toStartT, toEndT)) {
1543 continue;
1544 }
1545 // test to see if the segment between there and here is linear
1546 if (!mOther->isLinear(moStart, moEnd)
1547 || !tOther->isLinear(toStart, toEnd)) {
1548 continue;
1549 }
1550 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1;
1551 if (flipped) {
1552 mOther->addTCancel(moStartT, moEndT, tOther, toEndT, toStartT);
1553 } else {
1554 mOther->addTCoincident(moStartT, moEndT, tOther, toStartT, toEndT);
1555 }
1556 }
1557}
1558
1559// FIXME: either:
1560// a) mark spans with either end unsortable as done, or
1561// b) rewrite findTop / findTopSegment / findTopContour to iterate further
1562// when encountering an unsortable span
1563
1564// OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
1565// and use more concise logic like the old edge walker code?
1566// FIXME: this needs to deal with coincident edges
1567SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable,
1568 bool onlySortable) {
1569 // iterate through T intersections and return topmost
1570 // topmost tangent from y-min to first pt is closer to horizontal
1571 SkASSERT(!done());
1572 int firstT = -1;
1573 /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT);
1574 if (firstT < 0) {
1575 *unsortable = true;
1576 firstT = 0;
1577 while (fTs[firstT].fDone) {
1578 SkASSERT(firstT < fTs.count());
1579 ++firstT;
1580 }
1581 *tIndexPtr = firstT;
1582 *endIndexPtr = nextExactSpan(firstT, 1);
1583 return this;
1584 }
1585 // sort the edges to find the leftmost
1586 int step = 1;
1587 int end = nextSpan(firstT, step);
1588 if (end == -1) {
1589 step = -1;
1590 end = nextSpan(firstT, step);
1591 SkASSERT(end != -1);
1592 }
1593 // if the topmost T is not on end, or is three-way or more, find left
1594 // look for left-ness from tLeft to firstT (matching y of other)
1595 SkTDArray<SkOpAngle> angles;
1596 SkASSERT(firstT - end != 0);
1597 addTwoAngles(end, firstT, &angles);
1598 buildAngles(firstT, &angles, true);
1599 SkTDArray<SkOpAngle*> sorted;
1600 bool sortable = SortAngles(angles, &sorted);
1601 int first = SK_MaxS32;
1602 SkScalar top = SK_ScalarMax;
1603 int count = sorted.count();
1604 for (int index = 0; index < count; ++index) {
1605 const SkOpAngle* angle = sorted[index];
1606 SkOpSegment* next = angle->segment();
1607 SkPathOpsBounds bounds;
1608 next->subDivideBounds(angle->end(), angle->start(), &bounds);
1609 if (approximately_greater(top, bounds.fTop)) {
1610 top = bounds.fTop;
1611 first = index;
1612 }
1613 }
1614 SkASSERT(first < SK_MaxS32);
1615#if DEBUG_SORT // || DEBUG_SWAP_TOP
1616 sorted[first]->segment()->debugShowSort(__FUNCTION__, sorted, first, 0, 0);
1617#endif
1618 if (onlySortable && !sortable) {
1619 *unsortable = true;
1620 return NULL;
1621 }
1622 // skip edges that have already been processed
1623 firstT = first - 1;
1624 SkOpSegment* leftSegment;
1625 do {
1626 if (++firstT == count) {
1627 firstT = 0;
1628 }
1629 const SkOpAngle* angle = sorted[firstT];
1630 SkASSERT(!onlySortable || !angle->unsortable());
1631 leftSegment = angle->segment();
1632 *tIndexPtr = angle->end();
1633 *endIndexPtr = angle->start();
1634 } while (leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone);
1635 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
1636 const int tIndex = *tIndexPtr;
1637 const int endIndex = *endIndexPtr;
1638 if (!leftSegment->clockwise(tIndex, endIndex)) {
1639 bool swap = !leftSegment->monotonicInY(tIndex, endIndex)
1640 && !leftSegment->serpentine(tIndex, endIndex);
1641 #if DEBUG_SWAP_TOP
1642 SkDebugf("%s swap=%d serpentine=%d containedByEnds=%d monotonic=%d\n", __FUNCTION__,
1643 swap,
1644 leftSegment->serpentine(tIndex, endIndex),
1645 leftSegment->controlsContainedByEnds(tIndex, endIndex),
1646 leftSegment->monotonicInY(tIndex, endIndex));
1647 #endif
1648 if (swap) {
1649 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first
1650 // sorted but merely the first not already processed (i.e., not done)
1651 SkTSwap(*tIndexPtr, *endIndexPtr);
1652 }
1653 }
1654 }
1655 SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny);
1656 return leftSegment;
1657}
1658
1659// FIXME: not crazy about this
1660// when the intersections are performed, the other index is into an
1661// incomplete array. As the array grows, the indices become incorrect
1662// while the following fixes the indices up again, it isn't smart about
1663// skipping segments whose indices are already correct
1664// assuming we leave the code that wrote the index in the first place
1665void SkOpSegment::fixOtherTIndex() {
1666 int iCount = fTs.count();
1667 for (int i = 0; i < iCount; ++i) {
1668 SkOpSpan& iSpan = fTs[i];
1669 double oT = iSpan.fOtherT;
1670 SkOpSegment* other = iSpan.fOther;
1671 int oCount = other->fTs.count();
1672 for (int o = 0; o < oCount; ++o) {
1673 SkOpSpan& oSpan = other->fTs[o];
1674 if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan.fT) {
1675 iSpan.fOtherIndex = o;
1676 break;
1677 }
1678 }
1679 }
1680}
1681
1682void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
1683 fDoneSpans = 0;
1684 fOperand = operand;
1685 fXor = evenOdd;
1686 fPts = pts;
1687 fVerb = verb;
1688}
1689
1690void SkOpSegment::initWinding(int start, int end) {
1691 int local = spanSign(start, end);
1692 int oppLocal = oppSign(start, end);
1693 (void) markAndChaseWinding(start, end, local, oppLocal);
1694 // OPTIMIZATION: the reverse mark and chase could skip the first marking
1695 (void) markAndChaseWinding(end, start, local, oppLocal);
1696}
1697
1698/*
1699when we start with a vertical intersect, we try to use the dx to determine if the edge is to
1700the left or the right of vertical. This determines if we need to add the span's
1701sign or not. However, this isn't enough.
1702If the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed.
1703If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
1704from has the same x direction as this span, the winding should change. If the dx is opposite, then
1705the same winding is shared by both.
1706*/
1707void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkScalar hitDx,
1708 int oppWind, SkScalar hitOppDx) {
1709 SkASSERT(hitDx || !winding);
1710 SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, tHit).fX;
1711 SkASSERT(dx);
1712 int windVal = windValue(SkMin32(start, end));
1713#if DEBUG_WINDING_AT_T
1714 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding,
1715 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
1716#endif
1717 if (!winding) {
1718 winding = dx < 0 ? windVal : -windVal;
1719 } else if (winding * dx < 0) {
1720 int sideWind = winding + (dx < 0 ? windVal : -windVal);
1721 if (abs(winding) < abs(sideWind)) {
1722 winding = sideWind;
1723 }
1724 }
1725#if DEBUG_WINDING_AT_T
1726 SkDebugf(" winding=%d\n", winding);
1727#endif
1728 SkDEBUGCODE(int oppLocal = oppSign(start, end));
1729 SkASSERT(hitOppDx || !oppWind || !oppLocal);
1730 int oppWindVal = oppValue(SkMin32(start, end));
1731 if (!oppWind) {
1732 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
1733 } else if (hitOppDx * dx >= 0) {
1734 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
1735 if (abs(oppWind) < abs(oppSideWind)) {
1736 oppWind = oppSideWind;
1737 }
1738 }
1739 (void) markAndChaseWinding(start, end, winding, oppWind);
1740}
1741
1742bool SkOpSegment::isLinear(int start, int end) const {
1743 if (fVerb == SkPath::kLine_Verb) {
1744 return true;
1745 }
1746 if (fVerb == SkPath::kQuad_Verb) {
1747 SkDQuad qPart = SkDQuad::SubDivide(fPts, fTs[start].fT, fTs[end].fT);
1748 return qPart.isLinear(0, 2);
1749 } else {
1750 SkASSERT(fVerb == SkPath::kCubic_Verb);
1751 SkDCubic cPart = SkDCubic::SubDivide(fPts, fTs[start].fT, fTs[end].fT);
1752 return cPart.isLinear(0, 3);
1753 }
1754}
1755
1756// OPTIMIZE: successive calls could start were the last leaves off
1757// or calls could specialize to walk forwards or backwards
1758bool SkOpSegment::isMissing(double startT) const {
1759 size_t tCount = fTs.count();
1760 for (size_t index = 0; index < tCount; ++index) {
1761 if (approximately_zero(startT - fTs[index].fT)) {
1762 return false;
1763 }
1764 }
1765 return true;
1766}
1767
1768bool SkOpSegment::isSimple(int end) const {
1769 int count = fTs.count();
1770 if (count == 2) {
1771 return true;
1772 }
1773 double t = fTs[end].fT;
1774 if (approximately_less_than_zero(t)) {
1775 return !approximately_less_than_zero(fTs[1].fT);
1776 }
1777 if (approximately_greater_than_one(t)) {
1778 return !approximately_greater_than_one(fTs[count - 2].fT);
1779 }
1780 return false;
1781}
1782
1783// this span is excluded by the winding rule -- chase the ends
1784// as long as they are unambiguous to mark connections as done
1785// and give them the same winding value
1786SkOpSpan* SkOpSegment::markAndChaseDone(int index, int endIndex, int winding) {
1787 int step = SkSign32(endIndex - index);
1788 int min = SkMin32(index, endIndex);
1789 markDone(min, winding);
1790 SkOpSpan* last;
1791 SkOpSegment* other = this;
1792 while ((other = other->nextChase(&index, step, &min, &last))) {
1793 other->markDone(min, winding);
1794 }
1795 return last;
1796}
1797
1798SkOpSpan* SkOpSegment::markAndChaseDoneBinary(const SkOpAngle* angle, int winding, int oppWinding) {
1799 int index = angle->start();
1800 int endIndex = angle->end();
1801 int step = SkSign32(endIndex - index);
1802 int min = SkMin32(index, endIndex);
1803 markDoneBinary(min, winding, oppWinding);
1804 SkOpSpan* last;
1805 SkOpSegment* other = this;
1806 while ((other = other->nextChase(&index, step, &min, &last))) {
1807 other->markDoneBinary(min, winding, oppWinding);
1808 }
1809 return last;
1810}
1811
1812SkOpSpan* SkOpSegment::markAndChaseDoneBinary(int index, int endIndex) {
1813 int step = SkSign32(endIndex - index);
1814 int min = SkMin32(index, endIndex);
1815 markDoneBinary(min);
1816 SkOpSpan* last;
1817 SkOpSegment* other = this;
1818 while ((other = other->nextChase(&index, step, &min, &last))) {
1819 if (other->done()) {
1820 return NULL;
1821 }
1822 other->markDoneBinary(min);
1823 }
1824 return last;
1825}
1826
1827SkOpSpan* SkOpSegment::markAndChaseDoneUnary(int index, int endIndex) {
1828 int step = SkSign32(endIndex - index);
1829 int min = SkMin32(index, endIndex);
1830 markDoneUnary(min);
1831 SkOpSpan* last;
1832 SkOpSegment* other = this;
1833 while ((other = other->nextChase(&index, step, &min, &last))) {
1834 if (other->done()) {
1835 return NULL;
1836 }
1837 other->markDoneUnary(min);
1838 }
1839 return last;
1840}
1841
1842SkOpSpan* SkOpSegment::markAndChaseDoneUnary(const SkOpAngle* angle, int winding) {
1843 int index = angle->start();
1844 int endIndex = angle->end();
1845 return markAndChaseDone(index, endIndex, winding);
1846}
1847
1848SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, const int winding) {
1849 int index = angle->start();
1850 int endIndex = angle->end();
1851 int step = SkSign32(endIndex - index);
1852 int min = SkMin32(index, endIndex);
1853 markWinding(min, winding);
1854 SkOpSpan* last;
1855 SkOpSegment* other = this;
1856 while ((other = other->nextChase(&index, step, &min, &last))) {
1857 if (other->fTs[min].fWindSum != SK_MinS32) {
1858 SkASSERT(other->fTs[min].fWindSum == winding);
1859 return NULL;
1860 }
1861 other->markWinding(min, winding);
1862 }
1863 return last;
1864}
1865
1866SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
1867 int min = SkMin32(index, endIndex);
1868 int step = SkSign32(endIndex - index);
1869 markWinding(min, winding, oppWinding);
1870 SkOpSpan* last;
1871 SkOpSegment* other = this;
1872 while ((other = other->nextChase(&index, step, &min, &last))) {
1873 if (other->fTs[min].fWindSum != SK_MinS32) {
1874 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
1875 return NULL;
1876 }
1877 other->markWinding(min, winding, oppWinding);
1878 }
1879 return last;
1880}
1881
1882SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding) {
1883 int start = angle->start();
1884 int end = angle->end();
1885 return markAndChaseWinding(start, end, winding, oppWinding);
1886}
1887
1888SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, bool activeAngle,
1889 const SkOpAngle* angle) {
1890 SkASSERT(angle->segment() == this);
1891 if (UseInnerWinding(maxWinding, sumWinding)) {
1892 maxWinding = sumWinding;
1893 }
1894 SkOpSpan* last;
1895 if (activeAngle) {
1896 last = markAndChaseWinding(angle, maxWinding);
1897 } else {
1898 last = markAndChaseDoneUnary(angle, maxWinding);
1899 }
1900 return last;
1901}
1902
1903SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
1904 int oppSumWinding, bool activeAngle, const SkOpAngle* angle) {
1905 SkASSERT(angle->segment() == this);
1906 if (UseInnerWinding(maxWinding, sumWinding)) {
1907 maxWinding = sumWinding;
1908 }
1909 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
1910 oppMaxWinding = oppSumWinding;
1911 }
1912 SkOpSpan* last;
1913 if (activeAngle) {
1914 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
1915 } else {
1916 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding);
1917 }
1918 return last;
1919}
1920
1921// FIXME: this should also mark spans with equal (x,y)
1922// This may be called when the segment is already marked done. While this
1923// wastes time, it shouldn't do any more than spin through the T spans.
1924// OPTIMIZATION: abort on first done found (assuming that this code is
1925// always called to mark segments done).
1926void SkOpSegment::markDone(int index, int winding) {
1927 // SkASSERT(!done());
1928 SkASSERT(winding);
1929 double referenceT = fTs[index].fT;
1930 int lesser = index;
1931 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
1932 markOneDone(__FUNCTION__, lesser, winding);
1933 }
1934 do {
1935 markOneDone(__FUNCTION__, index, winding);
1936 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
1937}
1938
1939void SkOpSegment::markDoneBinary(int index, int winding, int oppWinding) {
1940 // SkASSERT(!done());
1941 SkASSERT(winding || oppWinding);
1942 double referenceT = fTs[index].fT;
1943 int lesser = index;
1944 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
1945 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding);
1946 }
1947 do {
1948 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding);
1949 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
1950}
1951
1952void SkOpSegment::markDoneBinary(int index) {
1953 double referenceT = fTs[index].fT;
1954 int lesser = index;
1955 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
1956 markOneDoneBinary(__FUNCTION__, lesser);
1957 }
1958 do {
1959 markOneDoneBinary(__FUNCTION__, index);
1960 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
1961}
1962
1963void SkOpSegment::markDoneUnary(int index) {
1964 double referenceT = fTs[index].fT;
1965 int lesser = index;
1966 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
1967 markOneDoneUnary(__FUNCTION__, lesser);
1968 }
1969 do {
1970 markOneDoneUnary(__FUNCTION__, index);
1971 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
1972}
1973
1974void SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) {
1975 SkOpSpan* span = markOneWinding(funName, tIndex, winding);
1976 if (!span) {
1977 return;
1978 }
1979 span->fDone = true;
1980 fDoneSpans++;
1981}
1982
1983void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) {
1984 SkOpSpan* span = verifyOneWinding(funName, tIndex);
1985 if (!span) {
1986 return;
1987 }
1988 span->fDone = true;
1989 fDoneSpans++;
1990}
1991
1992void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) {
1993 SkOpSpan* span = markOneWinding(funName, tIndex, winding, oppWinding);
1994 if (!span) {
1995 return;
1996 }
1997 span->fDone = true;
1998 fDoneSpans++;
1999}
2000
2001void SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) {
2002 SkOpSpan* span = verifyOneWindingU(funName, tIndex);
2003 if (!span) {
2004 return;
2005 }
2006 span->fDone = true;
2007 fDoneSpans++;
2008}
2009
2010SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding) {
2011 SkOpSpan& span = fTs[tIndex];
2012 if (span.fDone) {
2013 return NULL;
2014 }
2015#if DEBUG_MARK_DONE
2016 debugShowNewWinding(funName, span, winding);
2017#endif
2018 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
2019#ifdef SK_DEBUG
2020 SkASSERT(abs(winding) <= gDebugMaxWindSum);
2021#endif
2022 span.fWindSum = winding;
2023 return &span;
2024}
2025
2026SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding,
2027 int oppWinding) {
2028 SkOpSpan& span = fTs[tIndex];
2029 if (span.fDone) {
2030 return NULL;
2031 }
2032#if DEBUG_MARK_DONE
2033 debugShowNewWinding(funName, span, winding, oppWinding);
2034#endif
2035 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
2036#ifdef SK_DEBUG
2037 SkASSERT(abs(winding) <= gDebugMaxWindSum);
2038#endif
2039 span.fWindSum = winding;
2040 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
2041#ifdef SK_DEBUG
2042 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
2043#endif
2044 span.fOppSum = oppWinding;
2045 return &span;
2046}
2047
2048// from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
2049bool SkOpSegment::clockwise(int tStart, int tEnd) const {
2050 SkASSERT(fVerb != SkPath::kLine_Verb);
2051 SkPoint edge[4];
2052 subDivide(tStart, tEnd, edge);
2053 double sum = (edge[0].fX - edge[fVerb].fX) * (edge[0].fY + edge[fVerb].fY);
2054 if (fVerb == SkPath::kCubic_Verb) {
2055 SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY);
2056 if (edge[1].fY < lesser && edge[2].fY < lesser) {
2057 SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1].fY} }};
2058 SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3].fY} }};
2059 if (SkIntersections::Test(tangent1, tangent2)) {
2060 SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2061 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY);
2062 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY);
2063 return sum <= 0;
2064 }
2065 }
2066 }
2067 for (int idx = 0; idx < fVerb; ++idx){
2068 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
2069 }
2070 return sum <= 0;
2071}
2072
2073bool SkOpSegment::monotonicInY(int tStart, int tEnd) const {
2074 if (fVerb == SkPath::kLine_Verb) {
2075 return false;
2076 }
2077 if (fVerb == SkPath::kQuad_Verb) {
2078 SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2079 return dst.monotonicInY();
2080 }
2081 SkASSERT(fVerb == SkPath::kCubic_Verb);
2082 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2083 return dst.monotonicInY();
2084}
2085
2086bool SkOpSegment::serpentine(int tStart, int tEnd) const {
2087 if (fVerb != SkPath::kCubic_Verb) {
2088 return false;
2089 }
2090 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2091 return dst.serpentine();
2092}
2093
2094SkOpSpan* SkOpSegment::verifyOneWinding(const char* funName, int tIndex) {
2095 SkOpSpan& span = fTs[tIndex];
2096 if (span.fDone) {
2097 return NULL;
2098 }
2099#if DEBUG_MARK_DONE
2100 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
2101#endif
2102 SkASSERT(span.fWindSum != SK_MinS32);
2103 SkASSERT(span.fOppSum != SK_MinS32);
2104 return &span;
2105}
2106
2107SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) {
2108 SkOpSpan& span = fTs[tIndex];
2109 if (span.fDone) {
2110 return NULL;
2111 }
2112#if DEBUG_MARK_DONE
2113 debugShowNewWinding(funName, span, span.fWindSum);
2114#endif
2115 SkASSERT(span.fWindSum != SK_MinS32);
2116 return &span;
2117}
2118
2119// note that just because a span has one end that is unsortable, that's
2120// not enough to mark it done. The other end may be sortable, allowing the
2121// span to be added.
2122// FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
2123void SkOpSegment::markUnsortable(int start, int end) {
2124 SkOpSpan* span = &fTs[start];
2125 if (start < end) {
2126#if DEBUG_UNSORTABLE
2127 debugShowNewWinding(__FUNCTION__, *span, 0);
2128#endif
2129 span->fUnsortableStart = true;
2130 } else {
2131 --span;
2132#if DEBUG_UNSORTABLE
2133 debugShowNewWinding(__FUNCTION__, *span, 0);
2134#endif
2135 span->fUnsortableEnd = true;
2136 }
2137 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
2138 return;
2139 }
2140 span->fDone = true;
2141 fDoneSpans++;
2142}
2143
2144void SkOpSegment::markWinding(int index, int winding) {
2145// SkASSERT(!done());
2146 SkASSERT(winding);
2147 double referenceT = fTs[index].fT;
2148 int lesser = index;
2149 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2150 markOneWinding(__FUNCTION__, lesser, winding);
2151 }
2152 do {
2153 markOneWinding(__FUNCTION__, index, winding);
2154 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2155}
2156
2157void SkOpSegment::markWinding(int index, int winding, int oppWinding) {
2158// SkASSERT(!done());
2159 SkASSERT(winding || oppWinding);
2160 double referenceT = fTs[index].fT;
2161 int lesser = index;
2162 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
2163 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
2164 }
2165 do {
2166 markOneWinding(__FUNCTION__, index, winding, oppWinding);
2167 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
2168}
2169
2170void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) {
2171 int nextDoorWind = SK_MaxS32;
2172 int nextOppWind = SK_MaxS32;
2173 if (tIndex > 0) {
2174 const SkOpSpan& below = fTs[tIndex - 1];
2175 if (approximately_negative(t - below.fT)) {
2176 nextDoorWind = below.fWindValue;
2177 nextOppWind = below.fOppValue;
2178 }
2179 }
2180 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
2181 const SkOpSpan& above = fTs[tIndex + 1];
2182 if (approximately_negative(above.fT - t)) {
2183 nextDoorWind = above.fWindValue;
2184 nextOppWind = above.fOppValue;
2185 }
2186 }
2187 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
2188 const SkOpSpan& below = fTs[tIndex - 1];
2189 nextDoorWind = below.fWindValue;
2190 nextOppWind = below.fOppValue;
2191 }
2192 if (nextDoorWind != SK_MaxS32) {
2193 SkOpSpan& newSpan = fTs[tIndex];
2194 newSpan.fWindValue = nextDoorWind;
2195 newSpan.fOppValue = nextOppWind;
2196 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
2197 newSpan.fDone = true;
2198 ++fDoneSpans;
2199 }
2200 }
2201}
2202
2203// return span if when chasing, two or more radiating spans are not done
2204// OPTIMIZATION: ? multiple spans is detected when there is only one valid
2205// candidate and the remaining spans have windValue == 0 (canceled by
2206// coincidence). The coincident edges could either be removed altogether,
2207// or this code could be more complicated in detecting this case. Worth it?
2208bool SkOpSegment::multipleSpans(int end) const {
2209 return end > 0 && end < fTs.count() - 1;
2210}
2211
2212bool SkOpSegment::nextCandidate(int* start, int* end) const {
2213 while (fTs[*end].fDone) {
2214 if (fTs[*end].fT == 1) {
2215 return false;
2216 }
2217 ++(*end);
2218 }
2219 *start = *end;
2220 *end = nextExactSpan(*start, 1);
2221 return true;
2222}
2223
2224SkOpSegment* SkOpSegment::nextChase(int* index, const int step, int* min, SkOpSpan** last) {
2225 int end = nextExactSpan(*index, step);
2226 SkASSERT(end >= 0);
2227 if (multipleSpans(end)) {
2228 *last = &fTs[end];
2229 return NULL;
2230 }
2231 const SkOpSpan& endSpan = fTs[end];
2232 SkOpSegment* other = endSpan.fOther;
2233 *index = endSpan.fOtherIndex;
2234 SkASSERT(index >= 0);
2235 int otherEnd = other->nextExactSpan(*index, step);
2236 SkASSERT(otherEnd >= 0);
2237 *min = SkMin32(*index, otherEnd);
2238 return other;
2239}
2240
2241// This has callers for two different situations: one establishes the end
2242// of the current span, and one establishes the beginning of the next span
2243// (thus the name). When this is looking for the end of the current span,
2244// coincidence is found when the beginning Ts contain -step and the end
2245// contains step. When it is looking for the beginning of the next, the
2246// first Ts found can be ignored and the last Ts should contain -step.
2247// OPTIMIZATION: probably should split into two functions
2248int SkOpSegment::nextSpan(int from, int step) const {
2249 const SkOpSpan& fromSpan = fTs[from];
2250 int count = fTs.count();
2251 int to = from;
2252 while (step > 0 ? ++to < count : --to >= 0) {
2253 const SkOpSpan& span = fTs[to];
2254 if (approximately_zero(span.fT - fromSpan.fT)) {
2255 continue;
2256 }
2257 return to;
2258 }
2259 return -1;
2260}
2261
2262// FIXME
2263// this returns at any difference in T, vs. a preset minimum. It may be
2264// that all callers to nextSpan should use this instead.
2265// OPTIMIZATION splitting this into separate loops for up/down steps
2266// would allow using precisely_negative instead of precisely_zero
2267int SkOpSegment::nextExactSpan(int from, int step) const {
2268 const SkOpSpan& fromSpan = fTs[from];
2269 int count = fTs.count();
2270 int to = from;
2271 while (step > 0 ? ++to < count : --to >= 0) {
2272 const SkOpSpan& span = fTs[to];
2273 if (precisely_zero(span.fT - fromSpan.fT)) {
2274 continue;
2275 }
2276 return to;
2277 }
2278 return -1;
2279}
2280
2281void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
2282 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) {
2283 int deltaSum = spanSign(index, endIndex);
2284 int oppDeltaSum = oppSign(index, endIndex);
2285 if (operand()) {
2286 *maxWinding = *sumSuWinding;
2287 *sumWinding = *sumSuWinding -= deltaSum;
2288 *oppMaxWinding = *sumMiWinding;
2289 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
2290 } else {
2291 *maxWinding = *sumMiWinding;
2292 *sumWinding = *sumMiWinding -= deltaSum;
2293 *oppMaxWinding = *sumSuWinding;
2294 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
2295 }
2296}
2297
2298// This marks all spans unsortable so that this info is available for early
2299// exclusion in find top and others. This could be optimized to only mark
2300// adjacent spans that unsortable. However, this makes it difficult to later
2301// determine starting points for edge detection in find top and the like.
2302bool SkOpSegment::SortAngles(const SkTDArray<SkOpAngle>& angles,
2303 SkTDArray<SkOpAngle*>* angleList) {
2304 bool sortable = true;
2305 int angleCount = angles.count();
2306 int angleIndex;
2307 angleList->setReserve(angleCount);
2308 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2309 const SkOpAngle& angle = angles[angleIndex];
2310 *angleList->append() = const_cast<SkOpAngle*>(&angle);
2311 sortable &= !angle.unsortable();
2312 }
2313 if (sortable) {
2314 QSort<SkOpAngle>(angleList->begin(), angleList->end() - 1);
2315 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2316 if (angles[angleIndex].unsortable()) {
2317 sortable = false;
2318 break;
2319 }
2320 }
2321 }
2322 if (!sortable) {
2323 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
2324 const SkOpAngle& angle = angles[angleIndex];
2325 angle.segment()->markUnsortable(angle.start(), angle.end());
2326 }
2327 }
2328 return sortable;
2329}
2330
2331void SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const {
2332 edge[0] = fTs[start].fPt;
2333 edge[fVerb] = fTs[end].fPt;
2334 if (fVerb == SkPath::kQuad_Verb || fVerb == SkPath::kCubic_Verb) {
2335 SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[fVerb].fX, edge[fVerb].fY }};
2336 if (fVerb == SkPath::kQuad_Verb) {
2337 edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], fTs[start].fT,
2338 fTs[end].fT).asSkPoint();
2339 } else {
2340 SkDCubic::SubDivide(fPts, sub[0], sub[1], fTs[start].fT, fTs[end].fT, sub);
2341 edge[1] = sub[0].asSkPoint();
2342 edge[2] = sub[1].asSkPoint();
2343 }
2344 }
2345}
2346
2347void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const {
2348 SkPoint edge[4];
2349 subDivide(start, end, edge);
2350 (bounds->*SetCurveBounds[fVerb])(edge);
2351}
2352
2353bool SkOpSegment::tiny(const SkOpAngle* angle) const {
2354 int start = angle->start();
2355 int end = angle->end();
2356 const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
2357 return mSpan.fTiny;
2358}
2359
2360void SkOpSegment::TrackOutside(SkTDArray<double>* outsideTs, double end, double start) {
2361 int outCount = outsideTs->count();
2362 if (outCount == 0 || !approximately_negative(end - (*outsideTs)[outCount - 2])) {
2363 *outsideTs->append() = end;
2364 *outsideTs->append() = start;
2365 }
2366}
2367
2368void SkOpSegment::undoneSpan(int* start, int* end) {
2369 size_t tCount = fTs.count();
2370 size_t index;
2371 for (index = 0; index < tCount; ++index) {
2372 if (!fTs[index].fDone) {
2373 break;
2374 }
2375 }
2376 SkASSERT(index < tCount - 1);
2377 *start = index;
2378 double startT = fTs[index].fT;
2379 while (approximately_negative(fTs[++index].fT - startT))
2380 SkASSERT(index < tCount);
2381 SkASSERT(index < tCount);
2382 *end = index;
2383}
2384
2385int SkOpSegment::updateOppWinding(int index, int endIndex) const {
2386 int lesser = SkMin32(index, endIndex);
2387 int oppWinding = oppSum(lesser);
2388 int oppSpanWinding = oppSign(index, endIndex);
2389 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
2390 && oppWinding != SK_MaxS32) {
2391 oppWinding -= oppSpanWinding;
2392 }
2393 return oppWinding;
2394}
2395
2396int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
2397 int startIndex = angle->start();
2398 int endIndex = angle->end();
2399 return updateOppWinding(endIndex, startIndex);
2400}
2401
2402int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
2403 int startIndex = angle->start();
2404 int endIndex = angle->end();
2405 return updateOppWinding(startIndex, endIndex);
2406}
2407
2408int SkOpSegment::updateWinding(int index, int endIndex) const {
2409 int lesser = SkMin32(index, endIndex);
2410 int winding = windSum(lesser);
2411 int spanWinding = spanSign(index, endIndex);
2412 if (winding && UseInnerWinding(winding - spanWinding, winding) && winding != SK_MaxS32) {
2413 winding -= spanWinding;
2414 }
2415 return winding;
2416}
2417
2418int SkOpSegment::updateWinding(const SkOpAngle* angle) const {
2419 int startIndex = angle->start();
2420 int endIndex = angle->end();
2421 return updateWinding(endIndex, startIndex);
2422}
2423
2424int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const {
2425 int startIndex = angle->start();
2426 int endIndex = angle->end();
2427 return updateWinding(startIndex, endIndex);
2428}
2429
2430int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const {
2431 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
2432 return SK_MinS32;
2433 }
2434 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
2435 SkASSERT(winding != SK_MinS32);
2436 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
2437#if DEBUG_WINDING_AT_T
2438 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
2439#endif
2440 // see if a + change in T results in a +/- change in X (compute x'(T))
2441 *dx = (*CurveSlopeAtT[fVerb])(fPts, tHit).fX;
2442 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
2443 *dx = fPts[2].fX - fPts[1].fX - *dx;
2444 }
2445 if (*dx == 0) {
2446#if DEBUG_WINDING_AT_T
2447 SkDebugf(" dx=0 winding=SK_MinS32\n");
2448#endif
2449 return SK_MinS32;
2450 }
2451 if (winding * *dx > 0) { // if same signs, result is negative
2452 winding += *dx > 0 ? -windVal : windVal;
2453 }
2454#if DEBUG_WINDING_AT_T
2455 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding);
2456#endif
2457 return winding;
2458}
2459
2460int SkOpSegment::windSum(const SkOpAngle* angle) const {
2461 int start = angle->start();
2462 int end = angle->end();
2463 int index = SkMin32(start, end);
2464 return windSum(index);
2465}
2466
2467int SkOpSegment::windValue(const SkOpAngle* angle) const {
2468 int start = angle->start();
2469 int end = angle->end();
2470 int index = SkMin32(start, end);
2471 return windValue(index);
2472}
2473
2474int SkOpSegment::windValueAt(double t) const {
2475 int count = fTs.count();
2476 for (int index = 0; index < count; ++index) {
2477 if (fTs[index].fT == t) {
2478 return fTs[index].fWindValue;
2479 }
2480 }
2481 SkASSERT(0);
2482 return 0;
2483}
2484
2485void SkOpSegment::zeroSpan(SkOpSpan* span) {
2486 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0);
2487 span->fWindValue = 0;
2488 span->fOppValue = 0;
2489 SkASSERT(!span->fDone);
2490 span->fDone = true;
2491 ++fDoneSpans;
2492}
2493
2494#if DEBUG_SWAP_TOP
2495bool SkOpSegment::controlsContainedByEnds(int tStart, int tEnd) const {
2496 if (fVerb != SkPath::kCubic_Verb) {
2497 return false;
2498 }
2499 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
2500 return dst.controlsContainedByEnds();
2501}
2502#endif
2503
2504#if DEBUG_CONCIDENT
2505// SkASSERT if pair has not already been added
2506void SkOpSegment::debugAddTPair(double t, const SkOpSegment& other, double otherT) const {
2507 for (int i = 0; i < fTs.count(); ++i) {
2508 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
2509 return;
2510 }
2511 }
2512 SkASSERT(0);
2513}
2514#endif
2515
2516#if DEBUG_CONCIDENT
2517void SkOpSegment::debugShowTs() const {
2518 SkDebugf("%s id=%d", __FUNCTION__, fID);
2519 int lastWind = -1;
2520 int lastOpp = -1;
2521 double lastT = -1;
2522 int i;
2523 for (i = 0; i < fTs.count(); ++i) {
2524 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue
2525 || lastOpp != fTs[i].fOppValue;
2526 if (change && lastWind >= 0) {
2527 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
2528 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
2529 }
2530 if (change) {
2531 SkDebugf(" [o=%d", fTs[i].fOther->fID);
2532 lastWind = fTs[i].fWindValue;
2533 lastOpp = fTs[i].fOppValue;
2534 lastT = fTs[i].fT;
2535 } else {
2536 SkDebugf(",%d", fTs[i].fOther->fID);
2537 }
2538 }
2539 if (i <= 0) {
2540 return;
2541 }
2542 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]",
2543 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp);
2544 if (fOperand) {
2545 SkDebugf(" operand");
2546 }
2547 if (done()) {
2548 SkDebugf(" done");
2549 }
2550 SkDebugf("\n");
2551}
2552#endif
2553
2554#if DEBUG_ACTIVE_SPANS
2555void SkOpSegment::debugShowActiveSpans() const {
2556 if (done()) {
2557 return;
2558 }
2559#if DEBUG_ACTIVE_SPANS_SHORT_FORM
2560 int lastId = -1;
2561 double lastT = -1;
2562#endif
2563 for (int i = 0; i < fTs.count(); ++i) {
2564 SkASSERT(&fTs[i] == &fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOther->
2565 fTs[fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOtherIndex]);
2566 if (fTs[i].fDone) {
2567 continue;
2568 }
2569#if DEBUG_ACTIVE_SPANS_SHORT_FORM
2570 if (lastId == fID && lastT == fTs[i].fT) {
2571 continue;
2572 }
2573 lastId = fID;
2574 lastT = fTs[i].fT;
2575#endif
2576 SkDebugf("%s id=%d", __FUNCTION__, fID);
2577 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
2578 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
2579 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
2580 }
2581 const SkOpSpan* span = &fTs[i];
2582 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", span->fT, xAtT(span), yAtT(span));
2583 int iEnd = i + 1;
2584 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) {
2585 ++iEnd;
2586 }
2587 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT);
2588 const SkOpSegment* other = fTs[i].fOther;
2589 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
2590 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
2591 if (fTs[i].fWindSum == SK_MinS32) {
2592 SkDebugf("?");
2593 } else {
2594 SkDebugf("%d", fTs[i].fWindSum);
2595 }
2596 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue);
2597 }
2598}
2599#endif
2600
2601
2602#if DEBUG_MARK_DONE || DEBUG_UNSORTABLE
2603void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding) {
2604 const SkPoint& pt = xyAtT(&span);
2605 SkDebugf("%s id=%d", fun, fID);
2606 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
2607 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
2608 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
2609 }
2610 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
2611 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
2612 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d windSum=",
2613 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
2614 (&span)[1].fT, winding);
2615 if (span.fWindSum == SK_MinS32) {
2616 SkDebugf("?");
2617 } else {
2618 SkDebugf("%d", span.fWindSum);
2619 }
2620 SkDebugf(" windValue=%d\n", span.fWindValue);
2621}
2622
2623void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding,
2624 int oppWinding) {
2625 const SkPoint& pt = xyAtT(&span);
2626 SkDebugf("%s id=%d", fun, fID);
2627 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
2628 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
2629 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
2630 }
2631 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
2632 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
2633 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d newOppSum=%d oppSum=",
2634 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
2635 (&span)[1].fT, winding, oppWinding);
2636 if (span.fOppSum == SK_MinS32) {
2637 SkDebugf("?");
2638 } else {
2639 SkDebugf("%d", span.fOppSum);
2640 }
2641 SkDebugf(" windSum=");
2642 if (span.fWindSum == SK_MinS32) {
2643 SkDebugf("?");
2644 } else {
2645 SkDebugf("%d", span.fWindSum);
2646 }
2647 SkDebugf(" windValue=%d\n", span.fWindValue);
2648}
2649#endif
2650
2651#if DEBUG_SORT || DEBUG_SWAP_TOP
2652void SkOpSegment::debugShowSort(const char* fun, const SkTDArray<SkOpAngle*>& angles, int first,
2653 const int contourWinding, const int oppContourWinding) const {
2654 if (--gDebugSortCount < 0) {
2655 return;
2656 }
2657 SkASSERT(angles[first]->segment() == this);
2658 SkASSERT(angles.count() > 1);
2659 int lastSum = contourWinding;
2660 int oppLastSum = oppContourWinding;
2661 const SkOpAngle* firstAngle = angles[first];
2662 int windSum = lastSum - spanSign(firstAngle);
2663 int oppoSign = oppSign(firstAngle);
2664 int oppWindSum = oppLastSum - oppoSign;
2665 #define WIND_AS_STRING(x) char x##Str[12]; if (!valid_wind(x)) strcpy(x##Str, "?"); \
2666 else snprintf(x##Str, sizeof(x##Str), "%d", x)
2667 WIND_AS_STRING(contourWinding);
2668 WIND_AS_STRING(oppContourWinding);
2669 SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FUNCTION__,
2670 contourWindingStr, oppContourWindingStr, spanSign(angles[first]));
2671 int index = first;
2672 bool firstTime = true;
2673 do {
2674 const SkOpAngle& angle = *angles[index];
2675 const SkOpSegment& segment = *angle.segment();
2676 int start = angle.start();
2677 int end = angle.end();
2678 const SkOpSpan& sSpan = segment.fTs[start];
2679 const SkOpSpan& eSpan = segment.fTs[end];
2680 const SkOpSpan& mSpan = segment.fTs[SkMin32(start, end)];
2681 bool opp = segment.fOperand ^ fOperand;
2682 if (!firstTime) {
2683 oppoSign = segment.oppSign(&angle);
2684 if (opp) {
2685 oppLastSum = oppWindSum;
2686 oppWindSum -= segment.spanSign(&angle);
2687 if (oppoSign) {
2688 lastSum = windSum;
2689 windSum -= oppoSign;
2690 }
2691 } else {
2692 lastSum = windSum;
2693 windSum -= segment.spanSign(&angle);
2694 if (oppoSign) {
2695 oppLastSum = oppWindSum;
2696 oppWindSum -= oppoSign;
2697 }
2698 }
2699 }
2700 SkDebugf("%s [%d] %s", __FUNCTION__, index,
2701 angle.unsortable() ? "*** UNSORTABLE *** " : "");
2702 #if COMPACT_DEBUG_SORT
2703 SkDebugf("id=%d %s start=%d (%1.9g,%,1.9g) end=%d (%1.9g,%,1.9g)",
2704 segment.fID, kLVerbStr[segment.fVerb],
2705 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
2706 segment.xAtT(&eSpan), segment.yAtT(&eSpan));
2707 #else
2708 switch (segment.fVerb) {
2709 case SkPath::kLine_Verb:
2710 SkDebugf(LINE_DEBUG_STR, LINE_DEBUG_DATA(segment.fPts));
2711 break;
2712 case SkPath::kQuad_Verb:
2713 SkDebugf(QUAD_DEBUG_STR, QUAD_DEBUG_DATA(segment.fPts));
2714 break;
2715 case SkPath::kCubic_Verb:
2716 SkDebugf(CUBIC_DEBUG_STR, CUBIC_DEBUG_DATA(segment.fPts));
2717 break;
2718 default:
2719 SkASSERT(0);
2720 }
2721 SkDebugf(" tStart=%1.9g tEnd=%1.9g", sSpan.fT, eSpan.fT);
2722 #endif
2723 SkDebugf(" sign=%d windValue=%d windSum=", angle.sign(), mSpan.fWindValue);
2724 #ifdef SK_DEBUG
2725 winding_printf(mSpan.fWindSum);
2726 #endif
2727 int last, wind;
2728 if (opp) {
2729 last = oppLastSum;
2730 wind = oppWindSum;
2731 } else {
2732 last = lastSum;
2733 wind = windSum;
2734 }
2735 bool useInner = valid_wind(last) && valid_wind(wind) && UseInnerWinding(last, wind);
2736 WIND_AS_STRING(last);
2737 WIND_AS_STRING(wind);
2738 WIND_AS_STRING(lastSum);
2739 WIND_AS_STRING(oppLastSum);
2740 WIND_AS_STRING(windSum);
2741 WIND_AS_STRING(oppWindSum);
2742 #undef WIND_AS_STRING
2743 if (!oppoSign) {
2744 SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr : lastStr);
2745 } else {
2746 SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : oppLastSumStr,
2747 opp ? windSumStr : oppWindSumStr);
2748 }
2749 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
2750#if false && DEBUG_ANGLE
2751 angle.debugShow(segment.xyAtT(&sSpan));
2752#endif
2753 ++index;
2754 if (index == angles.count()) {
2755 index = 0;
2756 }
2757 if (firstTime) {
2758 firstTime = false;
2759 }
2760 } while (index != first);
2761}
2762
2763void SkOpSegment::debugShowSort(const char* fun, const SkTDArray<SkOpAngle*>& angles, int first) {
2764 const SkOpAngle* firstAngle = angles[first];
2765 const SkOpSegment* segment = firstAngle->segment();
2766 int winding = segment->updateWinding(firstAngle);
2767 int oppWinding = segment->updateOppWinding(firstAngle);
2768 debugShowSort(fun, angles, first, winding, oppWinding);
2769}
2770
2771#endif
2772
2773#if DEBUG_SHOW_WINDING
2774int SkOpSegment::debugShowWindingValues(int slotCount, int ofInterest) const {
2775 if (!(1 << fID & ofInterest)) {
2776 return 0;
2777 }
2778 int sum = 0;
2779 SkTDArray<char> slots;
2780 slots.setCount(slotCount * 2);
2781 memset(slots.begin(), ' ', slotCount * 2);
2782 for (int i = 0; i < fTs.count(); ++i) {
2783 // if (!(1 << fTs[i].fOther->fID & ofInterest)) {
2784 // continue;
2785 // }
2786 sum += fTs[i].fWindValue;
2787 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue);
2788 sum += fTs[i].fOppValue;
2789 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue);
2790 }
2791 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount,
2792 slots.begin() + slotCount);
2793 return sum;
2794}
2795#endif