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