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