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