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 "SkOpCoincidence.h"
8 #include "SkOpContour.h"
9 #include "SkOpSegment.h"
10 #include "SkPathWriter.h"
11 #include "SkPointPriv.h"
12
13 /*
14 After computing raw intersections, post process all segments to:
15 - find small collections of points that can be collapsed to a single point
16 - find missing intersections to resolve differences caused by different algorithms
17
18 Consider segments containing tiny or small intervals. Consider coincident segments
19 because coincidence finds intersections through distance measurement that non-coincident
20 intersection tests cannot.
21 */
22
23 #define F (false) // discard the edge
24 #define T (true) // keep the edge
25
26 static const bool gUnaryActiveEdge[2][2] = {
27 // from=0 from=1
28 // to=0,1 to=0,1
29 {F, T}, {T, F},
30 };
31
32 static const bool gActiveEdge[kXOR_SkPathOp + 1][2][2][2][2] = {
33 // miFrom=0 miFrom=1
34 // miTo=0 miTo=1 miTo=0 miTo=1
35 // suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
36 // suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
37 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
38 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
39 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
40 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su
41 };
42
43 #undef F
44 #undef T
45
activeAngle(SkOpSpanBase * start,SkOpSpanBase ** startPtr,SkOpSpanBase ** endPtr,bool * done)46 SkOpAngle* SkOpSegment::activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr,
47 SkOpSpanBase** endPtr, bool* done) {
48 if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done)) {
49 return result;
50 }
51 if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done)) {
52 return result;
53 }
54 return nullptr;
55 }
56
activeAngleInner(SkOpSpanBase * start,SkOpSpanBase ** startPtr,SkOpSpanBase ** endPtr,bool * done)57 SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** startPtr,
58 SkOpSpanBase** endPtr, bool* done) {
59 SkOpSpan* upSpan = start->upCastable();
60 if (upSpan) {
61 if (upSpan->windValue() || upSpan->oppValue()) {
62 SkOpSpanBase* next = upSpan->next();
63 if (!*endPtr) {
64 *startPtr = start;
65 *endPtr = next;
66 }
67 if (!upSpan->done()) {
68 if (upSpan->windSum() != SK_MinS32) {
69 return spanToAngle(start, next);
70 }
71 *done = false;
72 }
73 } else {
74 SkASSERT(upSpan->done());
75 }
76 }
77 SkOpSpan* downSpan = start->prev();
78 // edge leading into junction
79 if (downSpan) {
80 if (downSpan->windValue() || downSpan->oppValue()) {
81 if (!*endPtr) {
82 *startPtr = start;
83 *endPtr = downSpan;
84 }
85 if (!downSpan->done()) {
86 if (downSpan->windSum() != SK_MinS32) {
87 return spanToAngle(start, downSpan);
88 }
89 *done = false;
90 }
91 } else {
92 SkASSERT(downSpan->done());
93 }
94 }
95 return nullptr;
96 }
97
activeAngleOther(SkOpSpanBase * start,SkOpSpanBase ** startPtr,SkOpSpanBase ** endPtr,bool * done)98 SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** startPtr,
99 SkOpSpanBase** endPtr, bool* done) {
100 SkOpPtT* oPtT = start->ptT()->next();
101 SkOpSegment* other = oPtT->segment();
102 SkOpSpanBase* oSpan = oPtT->span();
103 return other->activeAngleInner(oSpan, startPtr, endPtr, done);
104 }
105
activeOp(SkOpSpanBase * start,SkOpSpanBase * end,int xorMiMask,int xorSuMask,SkPathOp op)106 bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xorSuMask,
107 SkPathOp op) {
108 int sumMiWinding = this->updateWinding(end, start);
109 int sumSuWinding = this->updateOppWinding(end, start);
110 #if DEBUG_LIMIT_WIND_SUM
111 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM);
112 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM);
113 #endif
114 if (this->operand()) {
115 SkTSwap<int>(sumMiWinding, sumSuWinding);
116 }
117 return this->activeOp(xorMiMask, xorSuMask, start, end, op, &sumMiWinding, &sumSuWinding);
118 }
119
activeOp(int xorMiMask,int xorSuMask,SkOpSpanBase * start,SkOpSpanBase * end,SkPathOp op,int * sumMiWinding,int * sumSuWinding)120 bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end,
121 SkPathOp op, int* sumMiWinding, int* sumSuWinding) {
122 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
123 this->setUpWindings(start, end, sumMiWinding, sumSuWinding,
124 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
125 bool miFrom;
126 bool miTo;
127 bool suFrom;
128 bool suTo;
129 if (operand()) {
130 miFrom = (oppMaxWinding & xorMiMask) != 0;
131 miTo = (oppSumWinding & xorMiMask) != 0;
132 suFrom = (maxWinding & xorSuMask) != 0;
133 suTo = (sumWinding & xorSuMask) != 0;
134 } else {
135 miFrom = (maxWinding & xorMiMask) != 0;
136 miTo = (sumWinding & xorMiMask) != 0;
137 suFrom = (oppMaxWinding & xorSuMask) != 0;
138 suTo = (oppSumWinding & xorSuMask) != 0;
139 }
140 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
141 #if DEBUG_ACTIVE_OP
142 SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n",
143 __FUNCTION__, debugID(), start->t(), end->t(),
144 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
145 #endif
146 return result;
147 }
148
activeWinding(SkOpSpanBase * start,SkOpSpanBase * end)149 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
150 int sumWinding = updateWinding(end, start);
151 return activeWinding(start, end, &sumWinding);
152 }
153
activeWinding(SkOpSpanBase * start,SkOpSpanBase * end,int * sumWinding)154 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding) {
155 int maxWinding;
156 setUpWinding(start, end, &maxWinding, sumWinding);
157 bool from = maxWinding != 0;
158 bool to = *sumWinding != 0;
159 bool result = gUnaryActiveEdge[from][to];
160 return result;
161 }
162
addCurveTo(const SkOpSpanBase * start,const SkOpSpanBase * end,SkPathWriter * path) const163 bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
164 SkPathWriter* path) const {
165 FAIL_IF(start->starter(end)->alreadyAdded());
166 SkDCurveSweep curvePart;
167 start->segment()->subDivide(start, end, &curvePart.fCurve);
168 curvePart.setCurveHullSweep(fVerb);
169 SkPath::Verb verb = curvePart.isCurve() ? fVerb : SkPath::kLine_Verb;
170 path->deferredMove(start->ptT());
171 switch (verb) {
172 case SkPath::kLine_Verb:
173 FAIL_IF(!path->deferredLine(end->ptT()));
174 break;
175 case SkPath::kQuad_Verb:
176 path->quadTo(curvePart.fCurve.fQuad[1].asSkPoint(), end->ptT());
177 break;
178 case SkPath::kConic_Verb:
179 path->conicTo(curvePart.fCurve.fConic[1].asSkPoint(), end->ptT(),
180 curvePart.fCurve.fConic.fWeight);
181 break;
182 case SkPath::kCubic_Verb:
183 path->cubicTo(curvePart.fCurve.fCubic[1].asSkPoint(),
184 curvePart.fCurve.fCubic[2].asSkPoint(), end->ptT());
185 break;
186 default:
187 SkASSERT(0);
188 }
189 return true;
190 }
191
existing(double t,const SkOpSegment * opp) const192 const SkOpPtT* SkOpSegment::existing(double t, const SkOpSegment* opp) const {
193 const SkOpSpanBase* test = &fHead;
194 const SkOpPtT* testPtT;
195 SkPoint pt = this->ptAtT(t);
196 do {
197 testPtT = test->ptT();
198 if (testPtT->fT == t) {
199 break;
200 }
201 if (!this->match(testPtT, this, t, pt)) {
202 if (t < testPtT->fT) {
203 return nullptr;
204 }
205 continue;
206 }
207 if (!opp) {
208 return testPtT;
209 }
210 const SkOpPtT* loop = testPtT->next();
211 while (loop != testPtT) {
212 if (loop->segment() == this && loop->fT == t && loop->fPt == pt) {
213 goto foundMatch;
214 }
215 loop = loop->next();
216 }
217 return nullptr;
218 } while ((test = test->upCast()->next()));
219 foundMatch:
220 return opp && !test->contains(opp) ? nullptr : testPtT;
221 }
222
223 // break the span so that the coincident part does not change the angle of the remainder
addExpanded(double newT,const SkOpSpanBase * test,bool * startOver)224 bool SkOpSegment::addExpanded(double newT, const SkOpSpanBase* test, bool* startOver) {
225 if (this->contains(newT)) {
226 return true;
227 }
228 this->globalState()->resetAllocatedOpSpan();
229 FAIL_IF(!between(0, newT, 1));
230 SkOpPtT* newPtT = this->addT(newT);
231 *startOver |= this->globalState()->allocatedOpSpan();
232 if (!newPtT) {
233 return false;
234 }
235 newPtT->fPt = this->ptAtT(newT);
236 SkOpPtT* oppPrev = test->ptT()->oppPrev(newPtT);
237 if (oppPrev) {
238 // const cast away to change linked list; pt/t values stays unchanged
239 SkOpSpanBase* writableTest = const_cast<SkOpSpanBase*>(test);
240 writableTest->mergeMatches(newPtT->span());
241 writableTest->ptT()->addOpp(newPtT, oppPrev);
242 writableTest->checkForCollapsedCoincidence();
243 }
244 return true;
245 }
246
247 // Please keep this in sync with debugAddT()
addT(double t,const SkPoint & pt)248 SkOpPtT* SkOpSegment::addT(double t, const SkPoint& pt) {
249 debugValidate();
250 SkOpSpanBase* spanBase = &fHead;
251 do {
252 SkOpPtT* result = spanBase->ptT();
253 if (t == result->fT || (!zero_or_one(t) && this->match(result, this, t, pt))) {
254 spanBase->bumpSpanAdds();
255 return result;
256 }
257 if (t < result->fT) {
258 SkOpSpan* prev = result->span()->prev();
259 FAIL_WITH_NULL_IF(!prev);
260 // marks in global state that new op span has been allocated
261 SkOpSpan* span = this->insert(prev);
262 span->init(this, prev, t, pt);
263 this->debugValidate();
264 #if DEBUG_ADD_T
265 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
266 span->segment()->debugID(), span->debugID());
267 #endif
268 span->bumpSpanAdds();
269 return span->ptT();
270 }
271 FAIL_WITH_NULL_IF(spanBase == &fTail);
272 } while ((spanBase = spanBase->upCast()->next()));
273 SkASSERT(0);
274 return nullptr; // we never get here, but need this to satisfy compiler
275 }
276
addT(double t)277 SkOpPtT* SkOpSegment::addT(double t) {
278 return addT(t, this->ptAtT(t));
279 }
280
calcAngles()281 void SkOpSegment::calcAngles() {
282 bool activePrior = !fHead.isCanceled();
283 if (activePrior && !fHead.simple()) {
284 addStartSpan();
285 }
286 SkOpSpan* prior = &fHead;
287 SkOpSpanBase* spanBase = fHead.next();
288 while (spanBase != &fTail) {
289 if (activePrior) {
290 SkOpAngle* priorAngle = this->globalState()->allocator()->make<SkOpAngle>();
291 priorAngle->set(spanBase, prior);
292 spanBase->setFromAngle(priorAngle);
293 }
294 SkOpSpan* span = spanBase->upCast();
295 bool active = !span->isCanceled();
296 SkOpSpanBase* next = span->next();
297 if (active) {
298 SkOpAngle* angle = this->globalState()->allocator()->make<SkOpAngle>();
299 angle->set(span, next);
300 span->setToAngle(angle);
301 }
302 activePrior = active;
303 prior = span;
304 spanBase = next;
305 }
306 if (activePrior && !fTail.simple()) {
307 addEndSpan();
308 }
309 }
310
311 // Please keep this in sync with debugClearAll()
clearAll()312 void SkOpSegment::clearAll() {
313 SkOpSpan* span = &fHead;
314 do {
315 this->clearOne(span);
316 } while ((span = span->next()->upCastable()));
317 this->globalState()->coincidence()->release(this);
318 }
319
320 // Please keep this in sync with debugClearOne()
clearOne(SkOpSpan * span)321 void SkOpSegment::clearOne(SkOpSpan* span) {
322 span->setWindValue(0);
323 span->setOppValue(0);
324 this->markDone(span);
325 }
326
collapsed(double s,double e) const327 bool SkOpSegment::collapsed(double s, double e) const {
328 const SkOpSpanBase* span = &fHead;
329 do {
330 if (span->collapsed(s, e)) {
331 return true;
332 }
333 } while (span->upCastable() && (span = span->upCast()->next()));
334 return false;
335 }
336
ComputeOneSum(const SkOpAngle * baseAngle,SkOpAngle * nextAngle,SkOpAngle::IncludeType includeType)337 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
338 SkOpAngle::IncludeType includeType) {
339 SkOpSegment* baseSegment = baseAngle->segment();
340 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
341 int sumSuWinding;
342 bool binary = includeType >= SkOpAngle::kBinarySingle;
343 if (binary) {
344 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
345 if (baseSegment->operand()) {
346 SkTSwap<int>(sumMiWinding, sumSuWinding);
347 }
348 }
349 SkOpSegment* nextSegment = nextAngle->segment();
350 int maxWinding, sumWinding;
351 SkOpSpanBase* last;
352 if (binary) {
353 int oppMaxWinding, oppSumWinding;
354 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
355 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
356 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
357 nextAngle);
358 } else {
359 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
360 &maxWinding, &sumWinding);
361 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
362 }
363 nextAngle->setLastMarked(last);
364 }
365
ComputeOneSumReverse(SkOpAngle * baseAngle,SkOpAngle * nextAngle,SkOpAngle::IncludeType includeType)366 void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
367 SkOpAngle::IncludeType includeType) {
368 SkOpSegment* baseSegment = baseAngle->segment();
369 int sumMiWinding = baseSegment->updateWinding(baseAngle);
370 int sumSuWinding;
371 bool binary = includeType >= SkOpAngle::kBinarySingle;
372 if (binary) {
373 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
374 if (baseSegment->operand()) {
375 SkTSwap<int>(sumMiWinding, sumSuWinding);
376 }
377 }
378 SkOpSegment* nextSegment = nextAngle->segment();
379 int maxWinding, sumWinding;
380 SkOpSpanBase* last;
381 if (binary) {
382 int oppMaxWinding, oppSumWinding;
383 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
384 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
385 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
386 nextAngle);
387 } else {
388 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
389 &maxWinding, &sumWinding);
390 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
391 }
392 nextAngle->setLastMarked(last);
393 }
394
395 // at this point, the span is already ordered, or unorderable
computeSum(SkOpSpanBase * start,SkOpSpanBase * end,SkOpAngle::IncludeType includeType)396 int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
397 SkOpAngle::IncludeType includeType) {
398 SkASSERT(includeType != SkOpAngle::kUnaryXor);
399 SkOpAngle* firstAngle = this->spanToAngle(end, start);
400 if (nullptr == firstAngle || nullptr == firstAngle->next()) {
401 return SK_NaN32;
402 }
403 // if all angles have a computed winding,
404 // or if no adjacent angles are orderable,
405 // or if adjacent orderable angles have no computed winding,
406 // there's nothing to do
407 // if two orderable angles are adjacent, and both are next to orderable angles,
408 // and one has winding computed, transfer to the other
409 SkOpAngle* baseAngle = nullptr;
410 bool tryReverse = false;
411 // look for counterclockwise transfers
412 SkOpAngle* angle = firstAngle->previous();
413 SkOpAngle* next = angle->next();
414 firstAngle = next;
415 do {
416 SkOpAngle* prior = angle;
417 angle = next;
418 next = angle->next();
419 SkASSERT(prior->next() == angle);
420 SkASSERT(angle->next() == next);
421 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
422 baseAngle = nullptr;
423 continue;
424 }
425 int testWinding = angle->starter()->windSum();
426 if (SK_MinS32 != testWinding) {
427 baseAngle = angle;
428 tryReverse = true;
429 continue;
430 }
431 if (baseAngle) {
432 ComputeOneSum(baseAngle, angle, includeType);
433 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
434 }
435 } while (next != firstAngle);
436 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
437 firstAngle = baseAngle;
438 tryReverse = true;
439 }
440 if (tryReverse) {
441 baseAngle = nullptr;
442 SkOpAngle* prior = firstAngle;
443 do {
444 angle = prior;
445 prior = angle->previous();
446 SkASSERT(prior->next() == angle);
447 next = angle->next();
448 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
449 baseAngle = nullptr;
450 continue;
451 }
452 int testWinding = angle->starter()->windSum();
453 if (SK_MinS32 != testWinding) {
454 baseAngle = angle;
455 continue;
456 }
457 if (baseAngle) {
458 ComputeOneSumReverse(baseAngle, angle, includeType);
459 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
460 }
461 } while (prior != firstAngle);
462 }
463 return start->starter(end)->windSum();
464 }
465
contains(double newT) const466 bool SkOpSegment::contains(double newT) const {
467 const SkOpSpanBase* spanBase = &fHead;
468 do {
469 if (spanBase->ptT()->contains(this, newT)) {
470 return true;
471 }
472 if (spanBase == &fTail) {
473 break;
474 }
475 spanBase = spanBase->upCast()->next();
476 } while (true);
477 return false;
478 }
479
release(const SkOpSpan * span)480 void SkOpSegment::release(const SkOpSpan* span) {
481 if (span->done()) {
482 --fDoneCount;
483 }
484 --fCount;
485 SkOPASSERT(fCount >= fDoneCount);
486 }
487
488 #if DEBUG_ANGLE
489 // called only by debugCheckNearCoincidence
distSq(double t,const SkOpAngle * oppAngle) const490 double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
491 SkDPoint testPt = this->dPtAtT(t);
492 SkDLine testPerp = {{ testPt, testPt }};
493 SkDVector slope = this->dSlopeAtT(t);
494 testPerp[1].fX += slope.fY;
495 testPerp[1].fY -= slope.fX;
496 SkIntersections i;
497 const SkOpSegment* oppSegment = oppAngle->segment();
498 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
499 double closestDistSq = SK_ScalarInfinity;
500 for (int index = 0; index < i.used(); ++index) {
501 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
502 continue;
503 }
504 double testDistSq = testPt.distanceSquared(i.pt(index));
505 if (closestDistSq > testDistSq) {
506 closestDistSq = testDistSq;
507 }
508 }
509 return closestDistSq;
510 }
511 #endif
512
513 /*
514 The M and S variable name parts stand for the operators.
515 Mi stands for Minuend (see wiki subtraction, analogous to difference)
516 Su stands for Subtrahend
517 The Opp variable name part designates that the value is for the Opposite operator.
518 Opposite values result from combining coincident spans.
519 */
findNextOp(SkTDArray<SkOpSpanBase * > * chase,SkOpSpanBase ** nextStart,SkOpSpanBase ** nextEnd,bool * unsortable,SkPathOp op,int xorMiMask,int xorSuMask)520 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
521 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) {
522 SkOpSpanBase* start = *nextStart;
523 SkOpSpanBase* end = *nextEnd;
524 SkASSERT(start != end);
525 int step = start->step(end);
526 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
527 if (other) {
528 // mark the smaller of startIndex, endIndex done, and all adjacent
529 // spans with the same T value (but not 'other' spans)
530 #if DEBUG_WINDING
531 SkDebugf("%s simple\n", __FUNCTION__);
532 #endif
533 SkOpSpan* startSpan = start->starter(end);
534 if (startSpan->done()) {
535 return nullptr;
536 }
537 markDone(startSpan);
538 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
539 return other;
540 }
541 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
542 SkASSERT(endNear == end); // is this ever not end?
543 SkASSERT(endNear);
544 SkASSERT(start != endNear);
545 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
546 // more than one viable candidate -- measure angles to find best
547 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
548 bool sortable = calcWinding != SK_NaN32;
549 if (!sortable) {
550 *unsortable = true;
551 markDone(start->starter(end));
552 return nullptr;
553 }
554 SkOpAngle* angle = this->spanToAngle(end, start);
555 if (angle->unorderable()) {
556 *unsortable = true;
557 markDone(start->starter(end));
558 return nullptr;
559 }
560 #if DEBUG_SORT
561 SkDebugf("%s\n", __FUNCTION__);
562 angle->debugLoop();
563 #endif
564 int sumMiWinding = updateWinding(end, start);
565 if (sumMiWinding == SK_MinS32) {
566 *unsortable = true;
567 markDone(start->starter(end));
568 return nullptr;
569 }
570 int sumSuWinding = updateOppWinding(end, start);
571 if (operand()) {
572 SkTSwap<int>(sumMiWinding, sumSuWinding);
573 }
574 SkOpAngle* nextAngle = angle->next();
575 const SkOpAngle* foundAngle = nullptr;
576 bool foundDone = false;
577 // iterate through the angle, and compute everyone's winding
578 SkOpSegment* nextSegment;
579 int activeCount = 0;
580 do {
581 nextSegment = nextAngle->segment();
582 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
583 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
584 if (activeAngle) {
585 ++activeCount;
586 if (!foundAngle || (foundDone && activeCount & 1)) {
587 foundAngle = nextAngle;
588 foundDone = nextSegment->done(nextAngle);
589 }
590 }
591 if (nextSegment->done()) {
592 continue;
593 }
594 if (!activeAngle) {
595 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
596 }
597 SkOpSpanBase* last = nextAngle->lastMarked();
598 if (last) {
599 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
600 *chase->append() = last;
601 #if DEBUG_WINDING
602 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
603 last->segment()->debugID(), last->debugID());
604 if (!last->final()) {
605 SkDebugf(" windSum=%d", last->upCast()->windSum());
606 }
607 SkDebugf("\n");
608 #endif
609 }
610 } while ((nextAngle = nextAngle->next()) != angle);
611 start->segment()->markDone(start->starter(end));
612 if (!foundAngle) {
613 return nullptr;
614 }
615 *nextStart = foundAngle->start();
616 *nextEnd = foundAngle->end();
617 nextSegment = foundAngle->segment();
618 #if DEBUG_WINDING
619 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
620 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
621 #endif
622 return nextSegment;
623 }
624
findNextWinding(SkTDArray<SkOpSpanBase * > * chase,SkOpSpanBase ** nextStart,SkOpSpanBase ** nextEnd,bool * unsortable)625 SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
626 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
627 SkOpSpanBase* start = *nextStart;
628 SkOpSpanBase* end = *nextEnd;
629 SkASSERT(start != end);
630 int step = start->step(end);
631 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
632 if (other) {
633 // mark the smaller of startIndex, endIndex done, and all adjacent
634 // spans with the same T value (but not 'other' spans)
635 #if DEBUG_WINDING
636 SkDebugf("%s simple\n", __FUNCTION__);
637 #endif
638 SkOpSpan* startSpan = start->starter(end);
639 if (startSpan->done()) {
640 return nullptr;
641 }
642 markDone(startSpan);
643 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
644 return other;
645 }
646 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
647 SkASSERT(endNear == end); // is this ever not end?
648 SkASSERT(endNear);
649 SkASSERT(start != endNear);
650 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
651 // more than one viable candidate -- measure angles to find best
652 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
653 bool sortable = calcWinding != SK_NaN32;
654 if (!sortable) {
655 *unsortable = true;
656 markDone(start->starter(end));
657 return nullptr;
658 }
659 SkOpAngle* angle = this->spanToAngle(end, start);
660 if (angle->unorderable()) {
661 *unsortable = true;
662 markDone(start->starter(end));
663 return nullptr;
664 }
665 #if DEBUG_SORT
666 SkDebugf("%s\n", __FUNCTION__);
667 angle->debugLoop();
668 #endif
669 int sumWinding = updateWinding(end, start);
670 SkOpAngle* nextAngle = angle->next();
671 const SkOpAngle* foundAngle = nullptr;
672 bool foundDone = false;
673 // iterate through the angle, and compute everyone's winding
674 SkOpSegment* nextSegment;
675 int activeCount = 0;
676 do {
677 nextSegment = nextAngle->segment();
678 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
679 &sumWinding);
680 if (activeAngle) {
681 ++activeCount;
682 if (!foundAngle || (foundDone && activeCount & 1)) {
683 foundAngle = nextAngle;
684 foundDone = nextSegment->done(nextAngle);
685 }
686 }
687 if (nextSegment->done()) {
688 continue;
689 }
690 if (!activeAngle) {
691 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
692 }
693 SkOpSpanBase* last = nextAngle->lastMarked();
694 if (last) {
695 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
696 *chase->append() = last;
697 #if DEBUG_WINDING
698 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
699 last->segment()->debugID(), last->debugID());
700 if (!last->final()) {
701 SkDebugf(" windSum=%d", last->upCast()->windSum());
702 }
703 SkDebugf("\n");
704 #endif
705 }
706 } while ((nextAngle = nextAngle->next()) != angle);
707 start->segment()->markDone(start->starter(end));
708 if (!foundAngle) {
709 return nullptr;
710 }
711 *nextStart = foundAngle->start();
712 *nextEnd = foundAngle->end();
713 nextSegment = foundAngle->segment();
714 #if DEBUG_WINDING
715 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
716 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
717 #endif
718 return nextSegment;
719 }
720
findNextXor(SkOpSpanBase ** nextStart,SkOpSpanBase ** nextEnd,bool * unsortable)721 SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
722 bool* unsortable) {
723 SkOpSpanBase* start = *nextStart;
724 SkOpSpanBase* end = *nextEnd;
725 SkASSERT(start != end);
726 int step = start->step(end);
727 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
728 if (other) {
729 // mark the smaller of startIndex, endIndex done, and all adjacent
730 // spans with the same T value (but not 'other' spans)
731 #if DEBUG_WINDING
732 SkDebugf("%s simple\n", __FUNCTION__);
733 #endif
734 SkOpSpan* startSpan = start->starter(end);
735 if (startSpan->done()) {
736 return nullptr;
737 }
738 markDone(startSpan);
739 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
740 return other;
741 }
742 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
743 : (*nextStart)->prev());
744 SkASSERT(endNear == end); // is this ever not end?
745 SkASSERT(endNear);
746 SkASSERT(start != endNear);
747 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
748 SkOpAngle* angle = this->spanToAngle(end, start);
749 if (!angle || angle->unorderable()) {
750 *unsortable = true;
751 markDone(start->starter(end));
752 return nullptr;
753 }
754 #if DEBUG_SORT
755 SkDebugf("%s\n", __FUNCTION__);
756 angle->debugLoop();
757 #endif
758 SkOpAngle* nextAngle = angle->next();
759 const SkOpAngle* foundAngle = nullptr;
760 bool foundDone = false;
761 // iterate through the angle, and compute everyone's winding
762 SkOpSegment* nextSegment;
763 int activeCount = 0;
764 do {
765 nextSegment = nextAngle->segment();
766 ++activeCount;
767 if (!foundAngle || (foundDone && activeCount & 1)) {
768 foundAngle = nextAngle;
769 if (!(foundDone = nextSegment->done(nextAngle))) {
770 break;
771 }
772 }
773 nextAngle = nextAngle->next();
774 } while (nextAngle != angle);
775 start->segment()->markDone(start->starter(end));
776 if (!foundAngle) {
777 return nullptr;
778 }
779 *nextStart = foundAngle->start();
780 *nextEnd = foundAngle->end();
781 nextSegment = foundAngle->segment();
782 #if DEBUG_WINDING
783 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
784 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
785 #endif
786 return nextSegment;
787 }
788
globalState() const789 SkOpGlobalState* SkOpSegment::globalState() const {
790 return contour()->globalState();
791 }
792
init(SkPoint pts[],SkScalar weight,SkOpContour * contour,SkPath::Verb verb)793 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
794 fContour = contour;
795 fNext = nullptr;
796 fPts = pts;
797 fWeight = weight;
798 fVerb = verb;
799 fCount = 0;
800 fDoneCount = 0;
801 fVisited = false;
802 SkOpSpan* zeroSpan = &fHead;
803 zeroSpan->init(this, nullptr, 0, fPts[0]);
804 SkOpSpanBase* oneSpan = &fTail;
805 zeroSpan->setNext(oneSpan);
806 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
807 SkDEBUGCODE(fID = globalState()->nextSegmentID());
808 }
809
isClose(double t,const SkOpSegment * opp) const810 bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
811 SkDPoint cPt = this->dPtAtT(t);
812 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
813 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
814 SkIntersections i;
815 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
816 int used = i.used();
817 for (int index = 0; index < used; ++index) {
818 if (cPt.roughlyEqual(i.pt(index))) {
819 return true;
820 }
821 }
822 return false;
823 }
824
isXor() const825 bool SkOpSegment::isXor() const {
826 return fContour->isXor();
827 }
828
markAllDone()829 void SkOpSegment::markAllDone() {
830 SkOpSpan* span = this->head();
831 do {
832 this->markDone(span);
833 } while ((span = span->next()->upCastable()));
834 }
835
markAndChaseDone(SkOpSpanBase * start,SkOpSpanBase * end)836 SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) {
837 int step = start->step(end);
838 SkOpSpan* minSpan = start->starter(end);
839 markDone(minSpan);
840 SkOpSpanBase* last = nullptr;
841 SkOpSegment* other = this;
842 SkOpSpan* priorDone = nullptr;
843 SkOpSpan* lastDone = nullptr;
844 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
845 if (other->done()) {
846 SkASSERT(!last);
847 break;
848 }
849 if (lastDone == minSpan || priorDone == minSpan) {
850 return nullptr;
851 }
852 other->markDone(minSpan);
853 priorDone = lastDone;
854 lastDone = minSpan;
855 }
856 return last;
857 }
858
markAndChaseWinding(SkOpSpanBase * start,SkOpSpanBase * end,int winding,SkOpSpanBase ** lastPtr)859 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
860 SkOpSpanBase** lastPtr) {
861 SkOpSpan* spanStart = start->starter(end);
862 int step = start->step(end);
863 bool success = markWinding(spanStart, winding);
864 SkOpSpanBase* last = nullptr;
865 SkOpSegment* other = this;
866 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
867 if (spanStart->windSum() != SK_MinS32) {
868 // SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive?
869 SkASSERT(!last);
870 break;
871 }
872 (void) other->markWinding(spanStart, winding);
873 }
874 if (lastPtr) {
875 *lastPtr = last;
876 }
877 return success;
878 }
879
markAndChaseWinding(SkOpSpanBase * start,SkOpSpanBase * end,int winding,int oppWinding,SkOpSpanBase ** lastPtr)880 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
881 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
882 SkOpSpan* spanStart = start->starter(end);
883 int step = start->step(end);
884 bool success = markWinding(spanStart, winding, oppWinding);
885 SkOpSpanBase* last = nullptr;
886 SkOpSegment* other = this;
887 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
888 if (spanStart->windSum() != SK_MinS32) {
889 if (this->operand() == other->operand()) {
890 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
891 this->globalState()->setWindingFailed();
892 return false;
893 }
894 } else {
895 SkASSERT(spanStart->windSum() == oppWinding);
896 SkASSERT(spanStart->oppSum() == winding);
897 }
898 SkASSERT(!last);
899 break;
900 }
901 if (this->operand() == other->operand()) {
902 (void) other->markWinding(spanStart, winding, oppWinding);
903 } else {
904 (void) other->markWinding(spanStart, oppWinding, winding);
905 }
906 }
907 if (lastPtr) {
908 *lastPtr = last;
909 }
910 return success;
911 }
912
markAngle(int maxWinding,int sumWinding,const SkOpAngle * angle)913 SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
914 SkASSERT(angle->segment() == this);
915 if (UseInnerWinding(maxWinding, sumWinding)) {
916 maxWinding = sumWinding;
917 }
918 SkOpSpanBase* last;
919 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
920 #if DEBUG_WINDING
921 if (last) {
922 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
923 last->segment()->debugID(), last->debugID());
924 if (!last->final()) {
925 SkDebugf(" windSum=");
926 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
927 }
928 SkDebugf("\n");
929 }
930 #endif
931 return last;
932 }
933
markAngle(int maxWinding,int sumWinding,int oppMaxWinding,int oppSumWinding,const SkOpAngle * angle)934 SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
935 int oppSumWinding, const SkOpAngle* angle) {
936 SkASSERT(angle->segment() == this);
937 if (UseInnerWinding(maxWinding, sumWinding)) {
938 maxWinding = sumWinding;
939 }
940 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
941 oppMaxWinding = oppSumWinding;
942 }
943 SkOpSpanBase* last = nullptr;
944 // caller doesn't require that this marks anything
945 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
946 #if DEBUG_WINDING
947 if (last) {
948 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
949 last->segment()->debugID(), last->debugID());
950 if (!last->final()) {
951 SkDebugf(" windSum=");
952 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
953 }
954 SkDebugf(" \n");
955 }
956 #endif
957 return last;
958 }
959
markDone(SkOpSpan * span)960 void SkOpSegment::markDone(SkOpSpan* span) {
961 SkASSERT(this == span->segment());
962 if (span->done()) {
963 return;
964 }
965 #if DEBUG_MARK_DONE
966 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
967 #endif
968 span->setDone(true);
969 ++fDoneCount;
970 debugValidate();
971 }
972
markWinding(SkOpSpan * span,int winding)973 bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
974 SkASSERT(this == span->segment());
975 SkASSERT(winding);
976 if (span->done()) {
977 return false;
978 }
979 #if DEBUG_MARK_DONE
980 debugShowNewWinding(__FUNCTION__, span, winding);
981 #endif
982 span->setWindSum(winding);
983 debugValidate();
984 return true;
985 }
986
markWinding(SkOpSpan * span,int winding,int oppWinding)987 bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
988 SkASSERT(this == span->segment());
989 SkASSERT(winding || oppWinding);
990 if (span->done()) {
991 return false;
992 }
993 #if DEBUG_MARK_DONE
994 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
995 #endif
996 span->setWindSum(winding);
997 span->setOppSum(oppWinding);
998 debugValidate();
999 return true;
1000 }
1001
match(const SkOpPtT * base,const SkOpSegment * testParent,double testT,const SkPoint & testPt) const1002 bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
1003 const SkPoint& testPt) const {
1004 SkASSERT(this == base->segment());
1005 if (this == testParent) {
1006 if (precisely_equal(base->fT, testT)) {
1007 return true;
1008 }
1009 }
1010 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1011 return false;
1012 }
1013 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
1014 }
1015
set_last(SkOpSpanBase ** last,SkOpSpanBase * endSpan)1016 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1017 if (last) {
1018 *last = endSpan;
1019 }
1020 return nullptr;
1021 }
1022
nextChase(SkOpSpanBase ** startPtr,int * stepPtr,SkOpSpan ** minPtr,SkOpSpanBase ** last) const1023 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1024 SkOpSpanBase** last) const {
1025 SkOpSpanBase* origStart = *startPtr;
1026 int step = *stepPtr;
1027 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1028 SkASSERT(endSpan);
1029 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1030 SkOpSpanBase* foundSpan;
1031 SkOpSpanBase* otherEnd;
1032 SkOpSegment* other;
1033 if (angle == nullptr) {
1034 if (endSpan->t() != 0 && endSpan->t() != 1) {
1035 return nullptr;
1036 }
1037 SkOpPtT* otherPtT = endSpan->ptT()->next();
1038 other = otherPtT->segment();
1039 foundSpan = otherPtT->span();
1040 otherEnd = step > 0
1041 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1042 : foundSpan->prev();
1043 } else {
1044 int loopCount = angle->loopCount();
1045 if (loopCount > 2) {
1046 return set_last(last, endSpan);
1047 }
1048 const SkOpAngle* next = angle->next();
1049 if (nullptr == next) {
1050 return nullptr;
1051 }
1052 #if DEBUG_WINDING
1053 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
1054 && !next->segment()->contour()->isXor()) {
1055 SkDebugf("%s mismatched signs\n", __FUNCTION__);
1056 }
1057 #endif
1058 other = next->segment();
1059 foundSpan = endSpan = next->start();
1060 otherEnd = next->end();
1061 }
1062 if (!otherEnd) {
1063 return nullptr;
1064 }
1065 int foundStep = foundSpan->step(otherEnd);
1066 if (*stepPtr != foundStep) {
1067 return set_last(last, endSpan);
1068 }
1069 SkASSERT(*startPtr);
1070 // SkASSERT(otherEnd >= 0);
1071 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1072 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1073 if (foundMin->windValue() != origMin->windValue()
1074 || foundMin->oppValue() != origMin->oppValue()) {
1075 return set_last(last, endSpan);
1076 }
1077 *startPtr = foundSpan;
1078 *stepPtr = foundStep;
1079 if (minPtr) {
1080 *minPtr = foundMin;
1081 }
1082 return other;
1083 }
1084
1085 // Please keep this in sync with DebugClearVisited()
ClearVisited(SkOpSpanBase * span)1086 void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
1087 // reset visited flag back to false
1088 do {
1089 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1090 while ((ptT = ptT->next()) != stopPtT) {
1091 SkOpSegment* opp = ptT->segment();
1092 opp->resetVisited();
1093 }
1094 } while (!span->final() && (span = span->upCast()->next()));
1095 }
1096
1097 // Please keep this in sync with debugMissingCoincidence()
1098 // look for pairs of undetected coincident curves
1099 // assumes that segments going in have visited flag clear
1100 // Even though pairs of curves correct detect coincident runs, a run may be missed
1101 // if the coincidence is a product of multiple intersections. For instance, given
1102 // curves A, B, and C:
1103 // A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1104 // the end of C that the intersection is replaced with the end of C.
1105 // Even though A-B correctly do not detect an intersection at point 2,
1106 // the resulting run from point 1 to point 2 is coincident on A and B.
missingCoincidence()1107 bool SkOpSegment::missingCoincidence() {
1108 if (this->done()) {
1109 return false;
1110 }
1111 SkOpSpan* prior = nullptr;
1112 SkOpSpanBase* spanBase = &fHead;
1113 bool result = false;
1114 do {
1115 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
1116 SkOPASSERT(ptT->span() == spanBase);
1117 while ((ptT = ptT->next()) != spanStopPtT) {
1118 if (ptT->deleted()) {
1119 continue;
1120 }
1121 SkOpSegment* opp = ptT->span()->segment();
1122 if (opp->done()) {
1123 continue;
1124 }
1125 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1126 if (!opp->visited()) {
1127 continue;
1128 }
1129 if (spanBase == &fHead) {
1130 continue;
1131 }
1132 if (ptT->segment() == this) {
1133 continue;
1134 }
1135 SkOpSpan* span = spanBase->upCastable();
1136 // FIXME?: this assumes that if the opposite segment is coincident then no more
1137 // coincidence needs to be detected. This may not be true.
1138 if (span && span->containsCoincidence(opp)) {
1139 continue;
1140 }
1141 if (spanBase->containsCoinEnd(opp)) {
1142 continue;
1143 }
1144 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
1145 // find prior span containing opp segment
1146 SkOpSegment* priorOpp = nullptr;
1147 SkOpSpan* priorTest = spanBase->prev();
1148 while (!priorOpp && priorTest) {
1149 priorStopPtT = priorPtT = priorTest->ptT();
1150 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
1151 if (priorPtT->deleted()) {
1152 continue;
1153 }
1154 SkOpSegment* segment = priorPtT->span()->segment();
1155 if (segment == opp) {
1156 prior = priorTest;
1157 priorOpp = opp;
1158 break;
1159 }
1160 }
1161 priorTest = priorTest->prev();
1162 }
1163 if (!priorOpp) {
1164 continue;
1165 }
1166 if (priorPtT == ptT) {
1167 continue;
1168 }
1169 SkOpPtT* oppStart = prior->ptT();
1170 SkOpPtT* oppEnd = spanBase->ptT();
1171 bool swapped = priorPtT->fT > ptT->fT;
1172 if (swapped) {
1173 SkTSwap(priorPtT, ptT);
1174 SkTSwap(oppStart, oppEnd);
1175 }
1176 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1177 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1178 SkOpPtT* rootPtT = ptT->span()->ptT();
1179 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1180 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1181 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1182 goto swapBack;
1183 }
1184 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
1185 // mark coincidence
1186 #if DEBUG_COINCIDENCE_VERBOSE
1187 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1188 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1189 rootOppEnd->debugID());
1190 #endif
1191 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1192 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
1193 }
1194 #if DEBUG_COINCIDENCE
1195 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1196 #endif
1197 result = true;
1198 }
1199 swapBack:
1200 if (swapped) {
1201 SkTSwap(priorPtT, ptT);
1202 }
1203 }
1204 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
1205 ClearVisited(&fHead);
1206 return result;
1207 }
1208
1209 // please keep this in sync with debugMoveMultiples()
1210 // if a span has more than one intersection, merge the other segments' span as needed
moveMultiples()1211 bool SkOpSegment::moveMultiples() {
1212 debugValidate();
1213 SkOpSpanBase* test = &fHead;
1214 do {
1215 int addCount = test->spanAddsCount();
1216 // FAIL_IF(addCount < 1);
1217 if (addCount <= 1) {
1218 continue;
1219 }
1220 SkOpPtT* startPtT = test->ptT();
1221 SkOpPtT* testPtT = startPtT;
1222 do { // iterate through all spans associated with start
1223 SkOpSpanBase* oppSpan = testPtT->span();
1224 if (oppSpan->spanAddsCount() == addCount) {
1225 continue;
1226 }
1227 if (oppSpan->deleted()) {
1228 continue;
1229 }
1230 SkOpSegment* oppSegment = oppSpan->segment();
1231 if (oppSegment == this) {
1232 continue;
1233 }
1234 // find range of spans to consider merging
1235 SkOpSpanBase* oppPrev = oppSpan;
1236 SkOpSpanBase* oppFirst = oppSpan;
1237 while ((oppPrev = oppPrev->prev())) {
1238 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1239 break;
1240 }
1241 if (oppPrev->spanAddsCount() == addCount) {
1242 continue;
1243 }
1244 if (oppPrev->deleted()) {
1245 continue;
1246 }
1247 oppFirst = oppPrev;
1248 }
1249 SkOpSpanBase* oppNext = oppSpan;
1250 SkOpSpanBase* oppLast = oppSpan;
1251 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
1252 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1253 break;
1254 }
1255 if (oppNext->spanAddsCount() == addCount) {
1256 continue;
1257 }
1258 if (oppNext->deleted()) {
1259 continue;
1260 }
1261 oppLast = oppNext;
1262 }
1263 if (oppFirst == oppLast) {
1264 continue;
1265 }
1266 SkOpSpanBase* oppTest = oppFirst;
1267 do {
1268 if (oppTest == oppSpan) {
1269 continue;
1270 }
1271 // check to see if the candidate meets specific criteria:
1272 // it contains spans of segments in test's loop but not including 'this'
1273 SkOpPtT* oppStartPtT = oppTest->ptT();
1274 SkOpPtT* oppPtT = oppStartPtT;
1275 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1276 SkOpSegment* oppPtTSegment = oppPtT->segment();
1277 if (oppPtTSegment == this) {
1278 goto tryNextSpan;
1279 }
1280 SkOpPtT* matchPtT = startPtT;
1281 do {
1282 if (matchPtT->segment() == oppPtTSegment) {
1283 goto foundMatch;
1284 }
1285 } while ((matchPtT = matchPtT->next()) != startPtT);
1286 goto tryNextSpan;
1287 foundMatch: // merge oppTest and oppSpan
1288 oppSegment->debugValidate();
1289 oppTest->mergeMatches(oppSpan);
1290 oppTest->addOpp(oppSpan);
1291 oppSegment->debugValidate();
1292 goto checkNextSpan;
1293 }
1294 tryNextSpan:
1295 ;
1296 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1297 } while ((testPtT = testPtT->next()) != startPtT);
1298 checkNextSpan:
1299 ;
1300 } while ((test = test->final() ? nullptr : test->upCast()->next()));
1301 debugValidate();
1302 return true;
1303 }
1304
1305 // adjacent spans may have points close by
spansNearby(const SkOpSpanBase * refSpan,const SkOpSpanBase * checkSpan,bool * found) const1306 bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan,
1307 bool* found) const {
1308 const SkOpPtT* refHead = refSpan->ptT();
1309 const SkOpPtT* checkHead = checkSpan->ptT();
1310 // if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
1311 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
1312 #if DEBUG_COINCIDENCE
1313 // verify that no combination of points are close
1314 const SkOpPtT* dBugRef = refHead;
1315 do {
1316 const SkOpPtT* dBugCheck = checkHead;
1317 do {
1318 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
1319 dBugCheck = dBugCheck->next();
1320 } while (dBugCheck != checkHead);
1321 dBugRef = dBugRef->next();
1322 } while (dBugRef != refHead);
1323 #endif
1324 *found = false;
1325 return true;
1326 }
1327 // check only unique points
1328 SkScalar distSqBest = SK_ScalarMax;
1329 const SkOpPtT* refBest = nullptr;
1330 const SkOpPtT* checkBest = nullptr;
1331 const SkOpPtT* ref = refHead;
1332 do {
1333 if (ref->deleted()) {
1334 continue;
1335 }
1336 while (ref->ptAlreadySeen(refHead)) {
1337 ref = ref->next();
1338 if (ref == refHead) {
1339 goto doneCheckingDistance;
1340 }
1341 }
1342 const SkOpPtT* check = checkHead;
1343 const SkOpSegment* refSeg = ref->segment();
1344 int escapeHatch = 100000; // defend against infinite loops
1345 do {
1346 if (check->deleted()) {
1347 continue;
1348 }
1349 while (check->ptAlreadySeen(checkHead)) {
1350 check = check->next();
1351 if (check == checkHead) {
1352 goto nextRef;
1353 }
1354 }
1355 SkScalar distSq = SkPointPriv::DistanceToSqd(ref->fPt, check->fPt);
1356 if (distSqBest > distSq && (refSeg != check->segment()
1357 || !refSeg->ptsDisjoint(*ref, *check))) {
1358 distSqBest = distSq;
1359 refBest = ref;
1360 checkBest = check;
1361 }
1362 if (--escapeHatch <= 0) {
1363 return false;
1364 }
1365 } while ((check = check->next()) != checkHead);
1366 nextRef:
1367 ;
1368 } while ((ref = ref->next()) != refHead);
1369 doneCheckingDistance:
1370 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
1371 checkBest->fPt);
1372 return true;
1373 }
1374
1375 // Please keep this function in sync with debugMoveNearby()
1376 // Move nearby t values and pts so they all hang off the same span. Alignment happens later.
moveNearby()1377 bool SkOpSegment::moveNearby() {
1378 debugValidate();
1379 // release undeleted spans pointing to this seg that are linked to the primary span
1380 SkOpSpanBase* spanBase = &fHead;
1381 int escapeHatch = 9999; // the largest count for a regular test is 50; for a fuzzer, 500
1382 do {
1383 SkOpPtT* ptT = spanBase->ptT();
1384 const SkOpPtT* headPtT = ptT;
1385 while ((ptT = ptT->next()) != headPtT) {
1386 if (!--escapeHatch) {
1387 return false;
1388 }
1389 SkOpSpanBase* test = ptT->span();
1390 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1391 && test->ptT() == ptT) {
1392 if (test->final()) {
1393 if (spanBase == &fHead) {
1394 this->clearAll();
1395 return true;
1396 }
1397 spanBase->upCast()->release(ptT);
1398 } else if (test->prev()) {
1399 test->upCast()->release(headPtT);
1400 }
1401 break;
1402 }
1403 }
1404 spanBase = spanBase->upCast()->next();
1405 } while (!spanBase->final());
1406 // This loop looks for adjacent spans which are near by
1407 spanBase = &fHead;
1408 do { // iterate through all spans associated with start
1409 SkOpSpanBase* test = spanBase->upCast()->next();
1410 bool found;
1411 if (!this->spansNearby(spanBase, test, &found)) {
1412 return false;
1413 }
1414 if (found) {
1415 if (test->final()) {
1416 if (spanBase->prev()) {
1417 test->merge(spanBase->upCast());
1418 } else {
1419 this->clearAll();
1420 return true;
1421 }
1422 } else {
1423 spanBase->merge(test->upCast());
1424 }
1425 }
1426 spanBase = test;
1427 } while (!spanBase->final());
1428 debugValidate();
1429 return true;
1430 }
1431
operand() const1432 bool SkOpSegment::operand() const {
1433 return fContour->operand();
1434 }
1435
oppXor() const1436 bool SkOpSegment::oppXor() const {
1437 return fContour->oppXor();
1438 }
1439
ptsDisjoint(double t1,const SkPoint & pt1,double t2,const SkPoint & pt2) const1440 bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1441 if (fVerb == SkPath::kLine_Verb) {
1442 return false;
1443 }
1444 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1445 // hits in two places with very different t values.
1446 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1447 // 'controls contained by ends' could avoid this check for common curves
1448 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1449 // on the other hand, the below check is relatively inexpensive
1450 double midT = (t1 + t2) / 2;
1451 SkPoint midPt = this->ptAtT(midT);
1452 double seDistSq = SkTMax(SkPointPriv::DistanceToSqd(pt1, pt2) * 2, FLT_EPSILON * 2);
1453 return SkPointPriv::DistanceToSqd(midPt, pt1) > seDistSq ||
1454 SkPointPriv::DistanceToSqd(midPt, pt2) > seDistSq;
1455 }
1456
setUpWindings(SkOpSpanBase * start,SkOpSpanBase * end,int * sumMiWinding,int * maxWinding,int * sumWinding)1457 void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1458 int* maxWinding, int* sumWinding) {
1459 int deltaSum = SpanSign(start, end);
1460 *maxWinding = *sumMiWinding;
1461 *sumWinding = *sumMiWinding -= deltaSum;
1462 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1463 }
1464
setUpWindings(SkOpSpanBase * start,SkOpSpanBase * end,int * sumMiWinding,int * sumSuWinding,int * maxWinding,int * sumWinding,int * oppMaxWinding,int * oppSumWinding)1465 void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1466 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1467 int* oppSumWinding) {
1468 int deltaSum = SpanSign(start, end);
1469 int oppDeltaSum = OppSign(start, end);
1470 if (operand()) {
1471 *maxWinding = *sumSuWinding;
1472 *sumWinding = *sumSuWinding -= deltaSum;
1473 *oppMaxWinding = *sumMiWinding;
1474 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1475 } else {
1476 *maxWinding = *sumMiWinding;
1477 *sumWinding = *sumMiWinding -= deltaSum;
1478 *oppMaxWinding = *sumSuWinding;
1479 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1480 }
1481 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1482 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
1483 }
1484
sortAngles()1485 bool SkOpSegment::sortAngles() {
1486 SkOpSpanBase* span = &this->fHead;
1487 do {
1488 SkOpAngle* fromAngle = span->fromAngle();
1489 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
1490 if (!fromAngle && !toAngle) {
1491 continue;
1492 }
1493 #if DEBUG_ANGLE
1494 bool wroteAfterHeader = false;
1495 #endif
1496 SkOpAngle* baseAngle = fromAngle;
1497 if (fromAngle && toAngle) {
1498 #if DEBUG_ANGLE
1499 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1500 span->debugID());
1501 wroteAfterHeader = true;
1502 #endif
1503 FAIL_IF(!fromAngle->insert(toAngle));
1504 } else if (!fromAngle) {
1505 baseAngle = toAngle;
1506 }
1507 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1508 do {
1509 SkOpSpanBase* oSpan = ptT->span();
1510 if (oSpan == span) {
1511 continue;
1512 }
1513 SkOpAngle* oAngle = oSpan->fromAngle();
1514 if (oAngle) {
1515 #if DEBUG_ANGLE
1516 if (!wroteAfterHeader) {
1517 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1518 span->t(), span->debugID());
1519 wroteAfterHeader = true;
1520 }
1521 #endif
1522 if (!oAngle->loopContains(baseAngle)) {
1523 baseAngle->insert(oAngle);
1524 }
1525 }
1526 if (!oSpan->final()) {
1527 oAngle = oSpan->upCast()->toAngle();
1528 if (oAngle) {
1529 #if DEBUG_ANGLE
1530 if (!wroteAfterHeader) {
1531 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1532 span->t(), span->debugID());
1533 wroteAfterHeader = true;
1534 }
1535 #endif
1536 if (!oAngle->loopContains(baseAngle)) {
1537 baseAngle->insert(oAngle);
1538 }
1539 }
1540 }
1541 } while ((ptT = ptT->next()) != stopPtT);
1542 if (baseAngle->loopCount() == 1) {
1543 span->setFromAngle(nullptr);
1544 if (toAngle) {
1545 span->upCast()->setToAngle(nullptr);
1546 }
1547 baseAngle = nullptr;
1548 }
1549 #if DEBUG_SORT
1550 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1551 #endif
1552 } while (!span->final() && (span = span->upCast()->next()));
1553 return true;
1554 }
1555
subDivide(const SkOpSpanBase * start,const SkOpSpanBase * end,SkDCurve * edge) const1556 bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
1557 SkDCurve* edge) const {
1558 SkASSERT(start != end);
1559 const SkOpPtT& startPtT = *start->ptT();
1560 const SkOpPtT& endPtT = *end->ptT();
1561 SkDEBUGCODE(edge->fVerb = fVerb);
1562 edge->fCubic[0].set(startPtT.fPt);
1563 int points = SkPathOpsVerbToPoints(fVerb);
1564 edge->fCubic[points].set(endPtT.fPt);
1565 if (fVerb == SkPath::kLine_Verb) {
1566 return false;
1567 }
1568 double startT = startPtT.fT;
1569 double endT = endPtT.fT;
1570 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1571 // don't compute midpoints if we already have them
1572 if (fVerb == SkPath::kQuad_Verb) {
1573 edge->fLine[1].set(fPts[1]);
1574 return false;
1575 }
1576 if (fVerb == SkPath::kConic_Verb) {
1577 edge->fConic[1].set(fPts[1]);
1578 edge->fConic.fWeight = fWeight;
1579 return false;
1580 }
1581 SkASSERT(fVerb == SkPath::kCubic_Verb);
1582 if (startT == 0) {
1583 edge->fCubic[1].set(fPts[1]);
1584 edge->fCubic[2].set(fPts[2]);
1585 return false;
1586 }
1587 edge->fCubic[1].set(fPts[2]);
1588 edge->fCubic[2].set(fPts[1]);
1589 return false;
1590 }
1591 if (fVerb == SkPath::kQuad_Verb) {
1592 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1593 } else if (fVerb == SkPath::kConic_Verb) {
1594 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1595 startT, endT, &edge->fConic.fWeight);
1596 } else {
1597 SkASSERT(fVerb == SkPath::kCubic_Verb);
1598 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
1599 }
1600 return true;
1601 }
1602
testForCoincidence(const SkOpPtT * priorPtT,const SkOpPtT * ptT,const SkOpSpanBase * prior,const SkOpSpanBase * spanBase,const SkOpSegment * opp) const1603 bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
1604 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
1605 // average t, find mid pt
1606 double midT = (prior->t() + spanBase->t()) / 2;
1607 SkPoint midPt = this->ptAtT(midT);
1608 bool coincident = true;
1609 // if the mid pt is not near either end pt, project perpendicular through opp seg
1610 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1611 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
1612 if (priorPtT->span() == ptT->span()) {
1613 return false;
1614 }
1615 coincident = false;
1616 SkIntersections i;
1617 SkDCurve curvePart;
1618 this->subDivide(prior, spanBase, &curvePart);
1619 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1620 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1621 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1622 SkDCurve oppPart;
1623 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1624 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
1625 // measure distance and see if it's small enough to denote coincidence
1626 for (int index = 0; index < i.used(); ++index) {
1627 if (!between(0, i[0][index], 1)) {
1628 continue;
1629 }
1630 SkDPoint oppPt = i.pt(index);
1631 if (oppPt.approximatelyDEqual(midPt)) {
1632 // the coincidence can occur at almost any angle
1633 coincident = true;
1634 }
1635 }
1636 }
1637 return coincident;
1638 }
1639
undoneSpan()1640 SkOpSpan* SkOpSegment::undoneSpan() {
1641 SkOpSpan* span = &fHead;
1642 SkOpSpanBase* next;
1643 do {
1644 next = span->next();
1645 if (!span->done()) {
1646 return span;
1647 }
1648 } while (!next->final() && (span = next->upCast()));
1649 return nullptr;
1650 }
1651
updateOppWinding(const SkOpSpanBase * start,const SkOpSpanBase * end) const1652 int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1653 const SkOpSpan* lesser = start->starter(end);
1654 int oppWinding = lesser->oppSum();
1655 int oppSpanWinding = SkOpSegment::OppSign(start, end);
1656 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1657 && oppWinding != SK_MaxS32) {
1658 oppWinding -= oppSpanWinding;
1659 }
1660 return oppWinding;
1661 }
1662
updateOppWinding(const SkOpAngle * angle) const1663 int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
1664 const SkOpSpanBase* startSpan = angle->start();
1665 const SkOpSpanBase* endSpan = angle->end();
1666 return updateOppWinding(endSpan, startSpan);
1667 }
1668
updateOppWindingReverse(const SkOpAngle * angle) const1669 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
1670 const SkOpSpanBase* startSpan = angle->start();
1671 const SkOpSpanBase* endSpan = angle->end();
1672 return updateOppWinding(startSpan, endSpan);
1673 }
1674
updateWinding(SkOpSpanBase * start,SkOpSpanBase * end)1675 int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1676 SkOpSpan* lesser = start->starter(end);
1677 int winding = lesser->windSum();
1678 if (winding == SK_MinS32) {
1679 winding = lesser->computeWindSum();
1680 }
1681 if (winding == SK_MinS32) {
1682 return winding;
1683 }
1684 int spanWinding = SkOpSegment::SpanSign(start, end);
1685 if (winding && UseInnerWinding(winding - spanWinding, winding)
1686 && winding != SK_MaxS32) {
1687 winding -= spanWinding;
1688 }
1689 return winding;
1690 }
1691
updateWinding(SkOpAngle * angle)1692 int SkOpSegment::updateWinding(SkOpAngle* angle) {
1693 SkOpSpanBase* startSpan = angle->start();
1694 SkOpSpanBase* endSpan = angle->end();
1695 return updateWinding(endSpan, startSpan);
1696 }
1697
updateWindingReverse(const SkOpAngle * angle)1698 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1699 SkOpSpanBase* startSpan = angle->start();
1700 SkOpSpanBase* endSpan = angle->end();
1701 return updateWinding(startSpan, endSpan);
1702 }
1703
1704 // OPTIMIZATION: does the following also work, and is it any faster?
1705 // return outerWinding * innerWinding > 0
1706 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
UseInnerWinding(int outerWinding,int innerWinding)1707 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1708 SkASSERT(outerWinding != SK_MaxS32);
1709 SkASSERT(innerWinding != SK_MaxS32);
1710 int absOut = SkTAbs(outerWinding);
1711 int absIn = SkTAbs(innerWinding);
1712 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1713 return result;
1714 }
1715
windSum(const SkOpAngle * angle) const1716 int SkOpSegment::windSum(const SkOpAngle* angle) const {
1717 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1718 return minSpan->windSum();
1719 }
1720