Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: src/pathops/SkOpSegment.cpp

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

Powered by Google App Engine
This is Rietveld 408576698