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