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