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