blob: 66fa6ee5ff7f6d6a7f433be3439a94c3404848bd [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Mike Kleinc0bd9f92019-04-23 12:05:21 -05007#include "src/core/SkPointPriv.h"
8#include "src/pathops/SkOpCoincidence.h"
9#include "src/pathops/SkOpContour.h"
10#include "src/pathops/SkOpSegment.h"
11#include "src/pathops/SkPathWriter.h"
caryclark54359292015-03-26 07:52:43 -070012
Ben Wagnerf08d1d02018-06-18 15:11:00 -040013#include <utility>
14
caryclark54359292015-03-26 07:52:43 -070015/*
16After computing raw intersections, post process all segments to:
17- find small collections of points that can be collapsed to a single point
18- find missing intersections to resolve differences caused by different algorithms
19
20Consider segments containing tiny or small intervals. Consider coincident segments
21because coincidence finds intersections through distance measurement that non-coincident
22intersection tests cannot.
23 */
caryclark@google.com07393ca2013-04-08 11:47:37 +000024
25#define F (false) // discard the edge
26#define T (true) // keep the edge
27
28static const bool gUnaryActiveEdge[2][2] = {
29// from=0 from=1
30// to=0,1 to=0,1
31 {F, T}, {T, F},
32};
33
caryclark54359292015-03-26 07:52:43 -070034static const bool gActiveEdge[kXOR_SkPathOp + 1][2][2][2][2] = {
caryclark@google.com07393ca2013-04-08 11:47:37 +000035// miFrom=0 miFrom=1
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000036// miTo=0 miTo=1 miTo=0 miTo=1
37// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
caryclark@google.com07393ca2013-04-08 11:47:37 +000038// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
39 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
40 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
41 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
42 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su
43};
44
45#undef F
46#undef T
47
caryclark54359292015-03-26 07:52:43 -070048SkOpAngle* SkOpSegment::activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -070049 SkOpSpanBase** endPtr, bool* done) {
50 if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done)) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000051 return result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000052 }
caryclarkbca19f72015-05-13 08:23:48 -070053 if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done)) {
caryclark54359292015-03-26 07:52:43 -070054 return result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000055 }
halcanary96fcdcc2015-08-27 07:41:13 -070056 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +000057}
58
caryclark54359292015-03-26 07:52:43 -070059SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -070060 SkOpSpanBase** endPtr, bool* done) {
caryclark54359292015-03-26 07:52:43 -070061 SkOpSpan* upSpan = start->upCastable();
62 if (upSpan) {
63 if (upSpan->windValue() || upSpan->oppValue()) {
64 SkOpSpanBase* next = upSpan->next();
65 if (!*endPtr) {
66 *startPtr = start;
67 *endPtr = next;
caryclark@google.com07393ca2013-04-08 11:47:37 +000068 }
caryclark54359292015-03-26 07:52:43 -070069 if (!upSpan->done()) {
70 if (upSpan->windSum() != SK_MinS32) {
71 return spanToAngle(start, next);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000072 }
73 *done = false;
74 }
75 } else {
caryclark54359292015-03-26 07:52:43 -070076 SkASSERT(upSpan->done());
caryclark@google.com07393ca2013-04-08 11:47:37 +000077 }
78 }
caryclark54359292015-03-26 07:52:43 -070079 SkOpSpan* downSpan = start->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +000080 // edge leading into junction
caryclark54359292015-03-26 07:52:43 -070081 if (downSpan) {
82 if (downSpan->windValue() || downSpan->oppValue()) {
83 if (!*endPtr) {
84 *startPtr = start;
85 *endPtr = downSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +000086 }
caryclark54359292015-03-26 07:52:43 -070087 if (!downSpan->done()) {
88 if (downSpan->windSum() != SK_MinS32) {
89 return spanToAngle(start, downSpan);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000090 }
91 *done = false;
92 }
93 } else {
caryclark54359292015-03-26 07:52:43 -070094 SkASSERT(downSpan->done());
caryclark@google.com07393ca2013-04-08 11:47:37 +000095 }
96 }
halcanary96fcdcc2015-08-27 07:41:13 -070097 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000098}
99
caryclark54359292015-03-26 07:52:43 -0700100SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -0700101 SkOpSpanBase** endPtr, bool* done) {
caryclark54359292015-03-26 07:52:43 -0700102 SkOpPtT* oPtT = start->ptT()->next();
103 SkOpSegment* other = oPtT->segment();
104 SkOpSpanBase* oSpan = oPtT->span();
caryclarkbca19f72015-05-13 08:23:48 -0700105 return other->activeAngleInner(oSpan, startPtr, endPtr, done);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000106}
107
caryclark54359292015-03-26 07:52:43 -0700108bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xorSuMask,
109 SkPathOp op) {
110 int sumMiWinding = this->updateWinding(end, start);
111 int sumSuWinding = this->updateOppWinding(end, start);
caryclark65f55312014-11-13 06:58:52 -0800112#if DEBUG_LIMIT_WIND_SUM
113 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM);
114 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM);
115#endif
caryclark54359292015-03-26 07:52:43 -0700116 if (this->operand()) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400117 using std::swap;
118 swap(sumMiWinding, sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000119 }
caryclark54359292015-03-26 07:52:43 -0700120 return this->activeOp(xorMiMask, xorSuMask, start, end, op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000121}
122
caryclark54359292015-03-26 07:52:43 -0700123bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end,
124 SkPathOp op, int* sumMiWinding, int* sumSuWinding) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000125 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
caryclark54359292015-03-26 07:52:43 -0700126 this->setUpWindings(start, end, sumMiWinding, sumSuWinding,
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000127 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000128 bool miFrom;
129 bool miTo;
130 bool suFrom;
131 bool suTo;
132 if (operand()) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000133 miFrom = (oppMaxWinding & xorMiMask) != 0;
134 miTo = (oppSumWinding & xorMiMask) != 0;
135 suFrom = (maxWinding & xorSuMask) != 0;
136 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000137 } else {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000138 miFrom = (maxWinding & xorMiMask) != 0;
139 miTo = (sumWinding & xorMiMask) != 0;
140 suFrom = (oppMaxWinding & xorSuMask) != 0;
141 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000142 }
143 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
144#if DEBUG_ACTIVE_OP
caryclarkdac1d172014-06-17 05:15:38 -0700145 SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n",
caryclark54359292015-03-26 07:52:43 -0700146 __FUNCTION__, debugID(), start->t(), end->t(),
caryclark@google.com570863f2013-09-16 15:55:01 +0000147 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000148#endif
149 return result;
150}
151
caryclark54359292015-03-26 07:52:43 -0700152bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
153 int sumWinding = updateWinding(end, start);
154 return activeWinding(start, end, &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000155}
156
caryclark54359292015-03-26 07:52:43 -0700157bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000158 int maxWinding;
caryclark54359292015-03-26 07:52:43 -0700159 setUpWinding(start, end, &maxWinding, sumWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000160 bool from = maxWinding != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000161 bool to = *sumWinding != 0;
162 bool result = gUnaryActiveEdge[from][to];
163 return result;
164}
165
caryclarkef784fb2015-10-30 12:03:06 -0700166bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
167 SkPathWriter* path) const {
Cary Clarkcadc5062018-08-06 17:24:04 -0400168 const SkOpSpan* spanStart = start->starter(end);
169 FAIL_IF(spanStart->alreadyAdded());
170 const_cast<SkOpSpan*>(spanStart)->markAdded();
caryclarkeed356d2016-09-14 07:18:20 -0700171 SkDCurveSweep curvePart;
172 start->segment()->subDivide(start, end, &curvePart.fCurve);
173 curvePart.setCurveHullSweep(fVerb);
174 SkPath::Verb verb = curvePart.isCurve() ? fVerb : SkPath::kLine_Verb;
175 path->deferredMove(start->ptT());
176 switch (verb) {
177 case SkPath::kLine_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700178 FAIL_IF(!path->deferredLine(end->ptT()));
caryclarkeed356d2016-09-14 07:18:20 -0700179 break;
180 case SkPath::kQuad_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700181 path->quadTo(curvePart.fCurve.fQuad[1].asSkPoint(), end->ptT());
caryclarkeed356d2016-09-14 07:18:20 -0700182 break;
183 case SkPath::kConic_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700184 path->conicTo(curvePart.fCurve.fConic[1].asSkPoint(), end->ptT(),
caryclarkeed356d2016-09-14 07:18:20 -0700185 curvePart.fCurve.fConic.fWeight);
186 break;
187 case SkPath::kCubic_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700188 path->cubicTo(curvePart.fCurve.fCubic[1].asSkPoint(),
189 curvePart.fCurve.fCubic[2].asSkPoint(), end->ptT());
caryclarkeed356d2016-09-14 07:18:20 -0700190 break;
191 default:
192 SkASSERT(0);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000193 }
caryclarkef784fb2015-10-30 12:03:06 -0700194 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000195}
196
caryclark55888e42016-07-18 10:01:36 -0700197const SkOpPtT* SkOpSegment::existing(double t, const SkOpSegment* opp) const {
198 const SkOpSpanBase* test = &fHead;
199 const SkOpPtT* testPtT;
200 SkPoint pt = this->ptAtT(t);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000201 do {
caryclark55888e42016-07-18 10:01:36 -0700202 testPtT = test->ptT();
203 if (testPtT->fT == t) {
reed0dc4dd62015-03-24 13:55:33 -0700204 break;
205 }
caryclarkef4f32a2016-08-24 09:24:18 -0700206 if (!this->match(testPtT, this, t, pt)) {
caryclark55888e42016-07-18 10:01:36 -0700207 if (t < testPtT->fT) {
208 return nullptr;
209 }
210 continue;
211 }
212 if (!opp) {
213 return testPtT;
214 }
215 const SkOpPtT* loop = testPtT->next();
216 while (loop != testPtT) {
217 if (loop->segment() == this && loop->fT == t && loop->fPt == pt) {
218 goto foundMatch;
219 }
220 loop = loop->next();
221 }
222 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700223 } while ((test = test->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -0700224foundMatch:
225 return opp && !test->contains(opp) ? nullptr : testPtT;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000226}
227
caryclark55888e42016-07-18 10:01:36 -0700228// break the span so that the coincident part does not change the angle of the remainder
229bool SkOpSegment::addExpanded(double newT, const SkOpSpanBase* test, bool* startOver) {
230 if (this->contains(newT)) {
231 return true;
232 }
caryclark29b25632016-08-25 11:27:17 -0700233 this->globalState()->resetAllocatedOpSpan();
caryclarka35ab3e2016-10-20 08:32:18 -0700234 FAIL_IF(!between(0, newT, 1));
caryclark29b25632016-08-25 11:27:17 -0700235 SkOpPtT* newPtT = this->addT(newT);
236 *startOver |= this->globalState()->allocatedOpSpan();
caryclark55888e42016-07-18 10:01:36 -0700237 if (!newPtT) {
238 return false;
239 }
240 newPtT->fPt = this->ptAtT(newT);
caryclark29b25632016-08-25 11:27:17 -0700241 SkOpPtT* oppPrev = test->ptT()->oppPrev(newPtT);
242 if (oppPrev) {
caryclark8016b262016-09-06 05:59:47 -0700243 // const cast away to change linked list; pt/t values stays unchanged
caryclark29b25632016-08-25 11:27:17 -0700244 SkOpSpanBase* writableTest = const_cast<SkOpSpanBase*>(test);
caryclark30b9fdd2016-08-31 14:36:29 -0700245 writableTest->mergeMatches(newPtT->span());
caryclark29b25632016-08-25 11:27:17 -0700246 writableTest->ptT()->addOpp(newPtT, oppPrev);
caryclark55888e42016-07-18 10:01:36 -0700247 writableTest->checkForCollapsedCoincidence();
248 }
249 return true;
250}
251
252// Please keep this in sync with debugAddT()
Cary Clark73e597d2017-04-18 12:08:58 -0400253SkOpPtT* SkOpSegment::addT(double t, const SkPoint& pt) {
reed0dc4dd62015-03-24 13:55:33 -0700254 debugValidate();
caryclark29b25632016-08-25 11:27:17 -0700255 SkOpSpanBase* spanBase = &fHead;
caryclark54359292015-03-26 07:52:43 -0700256 do {
caryclark29b25632016-08-25 11:27:17 -0700257 SkOpPtT* result = spanBase->ptT();
caryclark27c015d2016-09-23 05:47:20 -0700258 if (t == result->fT || (!zero_or_one(t) && this->match(result, this, t, pt))) {
caryclark29b25632016-08-25 11:27:17 -0700259 spanBase->bumpSpanAdds();
caryclarkef4f32a2016-08-24 09:24:18 -0700260 return result;
reed0dc4dd62015-03-24 13:55:33 -0700261 }
caryclark54359292015-03-26 07:52:43 -0700262 if (t < result->fT) {
263 SkOpSpan* prev = result->span()->prev();
caryclark29b25632016-08-25 11:27:17 -0700264 FAIL_WITH_NULL_IF(!prev);
265 // marks in global state that new op span has been allocated
266 SkOpSpan* span = this->insert(prev);
caryclark54359292015-03-26 07:52:43 -0700267 span->init(this, prev, t, pt);
268 this->debugValidate();
269#if DEBUG_ADD_T
270 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
271 span->segment()->debugID(), span->debugID());
272#endif
caryclark08bc8482015-04-24 09:08:57 -0700273 span->bumpSpanAdds();
caryclark54359292015-03-26 07:52:43 -0700274 return span->ptT();
275 }
caryclark29b25632016-08-25 11:27:17 -0700276 FAIL_WITH_NULL_IF(spanBase == &fTail);
277 } while ((spanBase = spanBase->upCast()->next()));
caryclark54359292015-03-26 07:52:43 -0700278 SkASSERT(0);
caryclark29b25632016-08-25 11:27:17 -0700279 return nullptr; // we never get here, but need this to satisfy compiler
caryclark54359292015-03-26 07:52:43 -0700280}
281
Cary Clark73e597d2017-04-18 12:08:58 -0400282SkOpPtT* SkOpSegment::addT(double t) {
283 return addT(t, this->ptAtT(t));
284}
285
caryclark55888e42016-07-18 10:01:36 -0700286void SkOpSegment::calcAngles() {
caryclark54359292015-03-26 07:52:43 -0700287 bool activePrior = !fHead.isCanceled();
288 if (activePrior && !fHead.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700289 addStartSpan();
reed0dc4dd62015-03-24 13:55:33 -0700290 }
caryclark54359292015-03-26 07:52:43 -0700291 SkOpSpan* prior = &fHead;
292 SkOpSpanBase* spanBase = fHead.next();
293 while (spanBase != &fTail) {
294 if (activePrior) {
Herb Derbyecc364c2017-04-19 15:09:48 -0400295 SkOpAngle* priorAngle = this->globalState()->allocator()->make<SkOpAngle>();
caryclark54359292015-03-26 07:52:43 -0700296 priorAngle->set(spanBase, prior);
297 spanBase->setFromAngle(priorAngle);
reed0dc4dd62015-03-24 13:55:33 -0700298 }
caryclark54359292015-03-26 07:52:43 -0700299 SkOpSpan* span = spanBase->upCast();
300 bool active = !span->isCanceled();
301 SkOpSpanBase* next = span->next();
302 if (active) {
Herb Derbyecc364c2017-04-19 15:09:48 -0400303 SkOpAngle* angle = this->globalState()->allocator()->make<SkOpAngle>();
caryclark54359292015-03-26 07:52:43 -0700304 angle->set(span, next);
305 span->setToAngle(angle);
reed0dc4dd62015-03-24 13:55:33 -0700306 }
reed0dc4dd62015-03-24 13:55:33 -0700307 activePrior = active;
caryclark54359292015-03-26 07:52:43 -0700308 prior = span;
309 spanBase = next;
reed0dc4dd62015-03-24 13:55:33 -0700310 }
caryclark54359292015-03-26 07:52:43 -0700311 if (activePrior && !fTail.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700312 addEndSpan();
reed0dc4dd62015-03-24 13:55:33 -0700313 }
reed0dc4dd62015-03-24 13:55:33 -0700314}
315
caryclark55888e42016-07-18 10:01:36 -0700316// Please keep this in sync with debugClearAll()
317void SkOpSegment::clearAll() {
318 SkOpSpan* span = &fHead;
319 do {
320 this->clearOne(span);
321 } while ((span = span->next()->upCastable()));
322 this->globalState()->coincidence()->release(this);
323}
324
325// Please keep this in sync with debugClearOne()
326void SkOpSegment::clearOne(SkOpSpan* span) {
327 span->setWindValue(0);
328 span->setOppValue(0);
329 this->markDone(span);
330}
331
Cary Clarkba610292018-06-19 09:47:15 -0400332SkOpSpanBase::Collapsed SkOpSegment::collapsed(double s, double e) const {
caryclark30b9fdd2016-08-31 14:36:29 -0700333 const SkOpSpanBase* span = &fHead;
334 do {
Cary Clarkba610292018-06-19 09:47:15 -0400335 SkOpSpanBase::Collapsed result = span->collapsed(s, e);
336 if (SkOpSpanBase::Collapsed::kNo != result) {
337 return result;
caryclark30b9fdd2016-08-31 14:36:29 -0700338 }
339 } while (span->upCastable() && (span = span->upCast()->next()));
Cary Clarkba610292018-06-19 09:47:15 -0400340 return SkOpSpanBase::Collapsed::kNo;
caryclark30b9fdd2016-08-31 14:36:29 -0700341}
342
Cary Clark2587f412018-07-24 12:40:10 -0400343bool SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
caryclark@google.com570863f2013-09-16 15:55:01 +0000344 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700345 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000346 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
347 int sumSuWinding;
348 bool binary = includeType >= SkOpAngle::kBinarySingle;
349 if (binary) {
350 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
351 if (baseSegment->operand()) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400352 using std::swap;
353 swap(sumMiWinding, sumSuWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000354 }
355 }
356 SkOpSegment* nextSegment = nextAngle->segment();
357 int maxWinding, sumWinding;
Cary Clarkb64db382018-07-26 07:40:16 -0400358 SkOpSpanBase* last = nullptr;
caryclark@google.com570863f2013-09-16 15:55:01 +0000359 if (binary) {
360 int oppMaxWinding, oppSumWinding;
361 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
362 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
Cary Clark2587f412018-07-24 12:40:10 -0400363 if (!nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
364 nextAngle, &last)) {
365 return false;
366 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000367 } else {
368 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
369 &maxWinding, &sumWinding);
Cary Clark2587f412018-07-24 12:40:10 -0400370 if (!nextSegment->markAngle(maxWinding, sumWinding, nextAngle, &last)) {
371 return false;
372 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000373 }
374 nextAngle->setLastMarked(last);
Cary Clark2587f412018-07-24 12:40:10 -0400375 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +0000376}
377
Cary Clark2587f412018-07-24 12:40:10 -0400378bool SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
caryclark@google.com570863f2013-09-16 15:55:01 +0000379 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700380 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000381 int sumMiWinding = baseSegment->updateWinding(baseAngle);
382 int sumSuWinding;
383 bool binary = includeType >= SkOpAngle::kBinarySingle;
384 if (binary) {
385 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
386 if (baseSegment->operand()) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400387 using std::swap;
388 swap(sumMiWinding, sumSuWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000389 }
390 }
391 SkOpSegment* nextSegment = nextAngle->segment();
392 int maxWinding, sumWinding;
Cary Clarkb64db382018-07-26 07:40:16 -0400393 SkOpSpanBase* last = nullptr;
caryclark@google.com570863f2013-09-16 15:55:01 +0000394 if (binary) {
395 int oppMaxWinding, oppSumWinding;
396 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
397 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
Cary Clark2587f412018-07-24 12:40:10 -0400398 if (!nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
399 nextAngle, &last)) {
400 return false;
401 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000402 } else {
403 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
404 &maxWinding, &sumWinding);
Cary Clark2587f412018-07-24 12:40:10 -0400405 if (!nextSegment->markAngle(maxWinding, sumWinding, nextAngle, &last)) {
406 return false;
407 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000408 }
409 nextAngle->setLastMarked(last);
Cary Clark2587f412018-07-24 12:40:10 -0400410 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +0000411}
412
caryclark54359292015-03-26 07:52:43 -0700413// at this point, the span is already ordered, or unorderable
414int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
415 SkOpAngle::IncludeType includeType) {
416 SkASSERT(includeType != SkOpAngle::kUnaryXor);
417 SkOpAngle* firstAngle = this->spanToAngle(end, start);
halcanary96fcdcc2015-08-27 07:41:13 -0700418 if (nullptr == firstAngle || nullptr == firstAngle->next()) {
caryclark54359292015-03-26 07:52:43 -0700419 return SK_NaN32;
420 }
421 // if all angles have a computed winding,
422 // or if no adjacent angles are orderable,
423 // or if adjacent orderable angles have no computed winding,
424 // there's nothing to do
425 // if two orderable angles are adjacent, and both are next to orderable angles,
426 // and one has winding computed, transfer to the other
halcanary96fcdcc2015-08-27 07:41:13 -0700427 SkOpAngle* baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700428 bool tryReverse = false;
429 // look for counterclockwise transfers
430 SkOpAngle* angle = firstAngle->previous();
431 SkOpAngle* next = angle->next();
432 firstAngle = next;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000433 do {
caryclark54359292015-03-26 07:52:43 -0700434 SkOpAngle* prior = angle;
435 angle = next;
436 next = angle->next();
437 SkASSERT(prior->next() == angle);
438 SkASSERT(angle->next() == next);
439 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700440 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700441 continue;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000442 }
caryclark54359292015-03-26 07:52:43 -0700443 int testWinding = angle->starter()->windSum();
444 if (SK_MinS32 != testWinding) {
445 baseAngle = angle;
446 tryReverse = true;
447 continue;
reed0dc4dd62015-03-24 13:55:33 -0700448 }
caryclark54359292015-03-26 07:52:43 -0700449 if (baseAngle) {
450 ComputeOneSum(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700451 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
caryclark54359292015-03-26 07:52:43 -0700452 }
453 } while (next != firstAngle);
454 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
455 firstAngle = baseAngle;
456 tryReverse = true;
457 }
458 if (tryReverse) {
halcanary96fcdcc2015-08-27 07:41:13 -0700459 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700460 SkOpAngle* prior = firstAngle;
461 do {
462 angle = prior;
463 prior = angle->previous();
464 SkASSERT(prior->next() == angle);
465 next = angle->next();
466 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700467 baseAngle = nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700468 continue;
469 }
caryclark54359292015-03-26 07:52:43 -0700470 int testWinding = angle->starter()->windSum();
471 if (SK_MinS32 != testWinding) {
472 baseAngle = angle;
473 continue;
reed0dc4dd62015-03-24 13:55:33 -0700474 }
caryclark54359292015-03-26 07:52:43 -0700475 if (baseAngle) {
476 ComputeOneSumReverse(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700477 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700478 }
caryclark54359292015-03-26 07:52:43 -0700479 } while (prior != firstAngle);
reed0dc4dd62015-03-24 13:55:33 -0700480 }
caryclark54359292015-03-26 07:52:43 -0700481 return start->starter(end)->windSum();
reed0dc4dd62015-03-24 13:55:33 -0700482}
483
caryclark55888e42016-07-18 10:01:36 -0700484bool SkOpSegment::contains(double newT) const {
485 const SkOpSpanBase* spanBase = &fHead;
486 do {
487 if (spanBase->ptT()->contains(this, newT)) {
488 return true;
489 }
490 if (spanBase == &fTail) {
491 break;
492 }
493 spanBase = spanBase->upCast()->next();
494 } while (true);
495 return false;
496}
497
mtklein18300a32016-03-16 13:53:35 -0700498void SkOpSegment::release(const SkOpSpan* span) {
caryclark54359292015-03-26 07:52:43 -0700499 if (span->done()) {
caryclark08bc8482015-04-24 09:08:57 -0700500 --fDoneCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000501 }
caryclark08bc8482015-04-24 09:08:57 -0700502 --fCount;
caryclark15976282016-07-21 05:48:43 -0700503 SkOPASSERT(fCount >= fDoneCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000504}
505
Cary Clarke47ae292016-10-05 08:51:39 -0400506#if DEBUG_ANGLE
507// called only by debugCheckNearCoincidence
caryclark26ad22a2015-10-16 09:03:38 -0700508double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
caryclark54359292015-03-26 07:52:43 -0700509 SkDPoint testPt = this->dPtAtT(t);
510 SkDLine testPerp = {{ testPt, testPt }};
511 SkDVector slope = this->dSlopeAtT(t);
512 testPerp[1].fX += slope.fY;
513 testPerp[1].fY -= slope.fX;
514 SkIntersections i;
caryclark26ad22a2015-10-16 09:03:38 -0700515 const SkOpSegment* oppSegment = oppAngle->segment();
caryclark1049f122015-04-20 08:31:59 -0700516 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
caryclark54359292015-03-26 07:52:43 -0700517 double closestDistSq = SK_ScalarInfinity;
518 for (int index = 0; index < i.used(); ++index) {
519 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000520 continue;
521 }
caryclark54359292015-03-26 07:52:43 -0700522 double testDistSq = testPt.distanceSquared(i.pt(index));
523 if (closestDistSq > testDistSq) {
524 closestDistSq = testDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000525 }
526 }
caryclark54359292015-03-26 07:52:43 -0700527 return closestDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000528}
Cary Clarke47ae292016-10-05 08:51:39 -0400529#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000530
caryclark@google.com07393ca2013-04-08 11:47:37 +0000531/*
532 The M and S variable name parts stand for the operators.
533 Mi stands for Minuend (see wiki subtraction, analogous to difference)
534 Su stands for Subtrahend
535 The Opp variable name part designates that the value is for the Opposite operator.
536 Opposite values result from combining coincident spans.
537 */
caryclark54359292015-03-26 07:52:43 -0700538SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
Cary Clark1857ddb2018-07-11 11:01:43 -0400539 SkOpSpanBase** nextEnd, bool* unsortable, bool* simple,
540 SkPathOp op, int xorMiMask, int xorSuMask) {
caryclark54359292015-03-26 07:52:43 -0700541 SkOpSpanBase* start = *nextStart;
542 SkOpSpanBase* end = *nextEnd;
543 SkASSERT(start != end);
544 int step = start->step(end);
545 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
Cary Clark1857ddb2018-07-11 11:01:43 -0400546 if ((*simple = other)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000547 // mark the smaller of startIndex, endIndex done, and all adjacent
548 // spans with the same T value (but not 'other' spans)
549#if DEBUG_WINDING
550 SkDebugf("%s simple\n", __FUNCTION__);
551#endif
caryclark54359292015-03-26 07:52:43 -0700552 SkOpSpan* startSpan = start->starter(end);
553 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700554 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000555 }
caryclark54359292015-03-26 07:52:43 -0700556 markDone(startSpan);
557 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000558 return other;
559 }
caryclark54359292015-03-26 07:52:43 -0700560 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
561 SkASSERT(endNear == end); // is this ever not end?
562 SkASSERT(endNear);
563 SkASSERT(start != endNear);
564 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000565 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700566 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
caryclark@google.com570863f2013-09-16 15:55:01 +0000567 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000568 if (!sortable) {
569 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700570 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700571 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000572 }
caryclark54359292015-03-26 07:52:43 -0700573 SkOpAngle* angle = this->spanToAngle(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000574 if (angle->unorderable()) {
575 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700576 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700577 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000578 }
579#if DEBUG_SORT
580 SkDebugf("%s\n", __FUNCTION__);
581 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000582#endif
caryclark54359292015-03-26 07:52:43 -0700583 int sumMiWinding = updateWinding(end, start);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000584 if (sumMiWinding == SK_MinS32) {
585 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700586 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700587 return nullptr;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000588 }
caryclark54359292015-03-26 07:52:43 -0700589 int sumSuWinding = updateOppWinding(end, start);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000590 if (operand()) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400591 using std::swap;
592 swap(sumMiWinding, sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000593 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000594 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700595 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000596 bool foundDone = false;
597 // iterate through the angle, and compute everyone's winding
598 SkOpSegment* nextSegment;
599 int activeCount = 0;
600 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000601 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000602 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000603 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000604 if (activeAngle) {
605 ++activeCount;
606 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000607 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +0000608 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000609 }
610 }
611 if (nextSegment->done()) {
612 continue;
613 }
reed0dc4dd62015-03-24 13:55:33 -0700614 if (!activeAngle) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400615 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end(), nullptr);
reed0dc4dd62015-03-24 13:55:33 -0700616 }
caryclark54359292015-03-26 07:52:43 -0700617 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000618 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000619 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000620 *chase->append() = last;
621#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700622 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
623 last->segment()->debugID(), last->debugID());
624 if (!last->final()) {
625 SkDebugf(" windSum=%d", last->upCast()->windSum());
626 }
627 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000628#endif
629 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000630 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700631 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000632 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700633 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000634 }
635 *nextStart = foundAngle->start();
636 *nextEnd = foundAngle->end();
637 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000638#if DEBUG_WINDING
639 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
640 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
641 #endif
642 return nextSegment;
643}
644
caryclark54359292015-03-26 07:52:43 -0700645SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
646 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
647 SkOpSpanBase* start = *nextStart;
648 SkOpSpanBase* end = *nextEnd;
649 SkASSERT(start != end);
650 int step = start->step(end);
651 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
652 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000653 // mark the smaller of startIndex, endIndex done, and all adjacent
654 // spans with the same T value (but not 'other' spans)
655#if DEBUG_WINDING
656 SkDebugf("%s simple\n", __FUNCTION__);
657#endif
caryclark54359292015-03-26 07:52:43 -0700658 SkOpSpan* startSpan = start->starter(end);
659 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700660 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000661 }
caryclark54359292015-03-26 07:52:43 -0700662 markDone(startSpan);
663 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000664 return other;
665 }
caryclark54359292015-03-26 07:52:43 -0700666 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
667 SkASSERT(endNear == end); // is this ever not end?
668 SkASSERT(endNear);
669 SkASSERT(start != endNear);
670 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000671 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700672 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000673 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000674 if (!sortable) {
675 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700676 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700677 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000678 }
caryclark54359292015-03-26 07:52:43 -0700679 SkOpAngle* angle = this->spanToAngle(end, start);
680 if (angle->unorderable()) {
681 *unsortable = true;
682 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700683 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700684 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000685#if DEBUG_SORT
686 SkDebugf("%s\n", __FUNCTION__);
687 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000688#endif
caryclark54359292015-03-26 07:52:43 -0700689 int sumWinding = updateWinding(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000690 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700691 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000692 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700693 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000694 SkOpSegment* nextSegment;
695 int activeCount = 0;
696 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000697 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000698 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000699 &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000700 if (activeAngle) {
701 ++activeCount;
702 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000703 foundAngle = nextAngle;
704 foundDone = nextSegment->done(nextAngle);
705 }
706 }
707 if (nextSegment->done()) {
708 continue;
709 }
reed0dc4dd62015-03-24 13:55:33 -0700710 if (!activeAngle) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400711 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end(), nullptr);
reed0dc4dd62015-03-24 13:55:33 -0700712 }
caryclark54359292015-03-26 07:52:43 -0700713 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000714 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000715 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000716 *chase->append() = last;
717#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700718 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
719 last->segment()->debugID(), last->debugID());
720 if (!last->final()) {
721 SkDebugf(" windSum=%d", last->upCast()->windSum());
722 }
723 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000724#endif
725 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000726 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700727 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000728 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700729 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000730 }
731 *nextStart = foundAngle->start();
732 *nextEnd = foundAngle->end();
733 nextSegment = foundAngle->segment();
734#if DEBUG_WINDING
735 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
736 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
737 #endif
738 return nextSegment;
739}
740
caryclark54359292015-03-26 07:52:43 -0700741SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
742 bool* unsortable) {
743 SkOpSpanBase* start = *nextStart;
744 SkOpSpanBase* end = *nextEnd;
745 SkASSERT(start != end);
746 int step = start->step(end);
747 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
748 if (other) {
749 // mark the smaller of startIndex, endIndex done, and all adjacent
750 // spans with the same T value (but not 'other' spans)
caryclark@google.com07393ca2013-04-08 11:47:37 +0000751#if DEBUG_WINDING
752 SkDebugf("%s simple\n", __FUNCTION__);
753#endif
caryclark54359292015-03-26 07:52:43 -0700754 SkOpSpan* startSpan = start->starter(end);
755 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700756 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000757 }
caryclark54359292015-03-26 07:52:43 -0700758 markDone(startSpan);
759 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000760 return other;
761 }
caryclark54359292015-03-26 07:52:43 -0700762 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
763 : (*nextStart)->prev());
764 SkASSERT(endNear == end); // is this ever not end?
765 SkASSERT(endNear);
766 SkASSERT(start != endNear);
767 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
768 SkOpAngle* angle = this->spanToAngle(end, start);
caryclark27c8eb82015-07-06 11:38:33 -0700769 if (!angle || angle->unorderable()) {
caryclark54359292015-03-26 07:52:43 -0700770 *unsortable = true;
771 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700772 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700773 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000774#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000775 SkDebugf("%s\n", __FUNCTION__);
776 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000777#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000778 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700779 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000780 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700781 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000782 SkOpSegment* nextSegment;
783 int activeCount = 0;
784 do {
Cary Clark56071432018-06-19 08:33:52 -0400785 if (!nextAngle) {
786 return nullptr;
787 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000788 nextSegment = nextAngle->segment();
789 ++activeCount;
790 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000791 foundAngle = nextAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000792 if (!(foundDone = nextSegment->done(nextAngle))) {
793 break;
794 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000795 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000796 nextAngle = nextAngle->next();
797 } while (nextAngle != angle);
caryclark54359292015-03-26 07:52:43 -0700798 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000799 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700800 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000801 }
802 *nextStart = foundAngle->start();
803 *nextEnd = foundAngle->end();
804 nextSegment = foundAngle->segment();
805#if DEBUG_WINDING
806 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
807 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
808 #endif
809 return nextSegment;
810}
811
caryclark54359292015-03-26 07:52:43 -0700812SkOpGlobalState* SkOpSegment::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700813 return contour()->globalState();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000814}
815
caryclark1049f122015-04-20 08:31:59 -0700816void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
caryclark54359292015-03-26 07:52:43 -0700817 fContour = contour;
halcanary96fcdcc2015-08-27 07:41:13 -0700818 fNext = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000819 fPts = pts;
caryclark1049f122015-04-20 08:31:59 -0700820 fWeight = weight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000821 fVerb = verb;
caryclark54359292015-03-26 07:52:43 -0700822 fCount = 0;
823 fDoneCount = 0;
824 fVisited = false;
825 SkOpSpan* zeroSpan = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700826 zeroSpan->init(this, nullptr, 0, fPts[0]);
caryclark54359292015-03-26 07:52:43 -0700827 SkOpSpanBase* oneSpan = &fTail;
828 zeroSpan->setNext(oneSpan);
829 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
caryclark1049f122015-04-20 08:31:59 -0700830 SkDEBUGCODE(fID = globalState()->nextSegmentID());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000831}
832
caryclark54359292015-03-26 07:52:43 -0700833bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
834 SkDPoint cPt = this->dPtAtT(t);
caryclark1049f122015-04-20 08:31:59 -0700835 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
caryclark54359292015-03-26 07:52:43 -0700836 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
837 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -0700838 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
caryclark54359292015-03-26 07:52:43 -0700839 int used = i.used();
840 for (int index = 0; index < used; ++index) {
841 if (cPt.roughlyEqual(i.pt(index))) {
reed0dc4dd62015-03-24 13:55:33 -0700842 return true;
843 }
caryclark54359292015-03-26 07:52:43 -0700844 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000845 return false;
846}
847
caryclark54359292015-03-26 07:52:43 -0700848bool SkOpSegment::isXor() const {
849 return fContour->isXor();
850}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000851
caryclark5b5ddd72015-05-18 05:12:56 -0700852void SkOpSegment::markAllDone() {
853 SkOpSpan* span = this->head();
854 do {
855 this->markDone(span);
856 } while ((span = span->next()->upCastable()));
857}
858
Cary Clarkc050a1a2018-06-25 08:45:40 -0400859 bool SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end, SkOpSpanBase** found) {
caryclark54359292015-03-26 07:52:43 -0700860 int step = start->step(end);
861 SkOpSpan* minSpan = start->starter(end);
862 markDone(minSpan);
halcanary96fcdcc2015-08-27 07:41:13 -0700863 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000864 SkOpSegment* other = this;
Cary Clark918fb1f2016-11-15 13:22:25 -0500865 SkOpSpan* priorDone = nullptr;
866 SkOpSpan* lastDone = nullptr;
Cary Clarkc050a1a2018-06-25 08:45:40 -0400867 int safetyNet = 100000;
caryclark54359292015-03-26 07:52:43 -0700868 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400869 if (!--safetyNet) {
870 return false;
871 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000872 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -0700873 SkASSERT(!last);
874 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000875 }
Cary Clark918fb1f2016-11-15 13:22:25 -0500876 if (lastDone == minSpan || priorDone == minSpan) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400877 if (found) {
878 *found = nullptr;
879 }
880 return true;
Cary Clark918fb1f2016-11-15 13:22:25 -0500881 }
caryclark54359292015-03-26 07:52:43 -0700882 other->markDone(minSpan);
Cary Clark918fb1f2016-11-15 13:22:25 -0500883 priorDone = lastDone;
884 lastDone = minSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000885 }
Cary Clarkc050a1a2018-06-25 08:45:40 -0400886 if (found) {
887 *found = last;
888 }
889 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000890}
891
caryclark54359292015-03-26 07:52:43 -0700892bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
893 SkOpSpanBase** lastPtr) {
894 SkOpSpan* spanStart = start->starter(end);
895 int step = start->step(end);
896 bool success = markWinding(spanStart, winding);
halcanary96fcdcc2015-08-27 07:41:13 -0700897 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000898 SkOpSegment* other = this;
Cary Clark5de52332018-08-30 12:58:23 -0400899 int safetyNet = 100000;
caryclark54359292015-03-26 07:52:43 -0700900 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
Cary Clark5de52332018-08-30 12:58:23 -0400901 if (!--safetyNet) {
902 return false;
903 }
caryclark54359292015-03-26 07:52:43 -0700904 if (spanStart->windSum() != SK_MinS32) {
caryclarkb36a3cd2016-10-18 07:59:44 -0700905// SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive?
caryclarkdac1d172014-06-17 05:15:38 -0700906 SkASSERT(!last);
907 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000908 }
caryclark54359292015-03-26 07:52:43 -0700909 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000910 }
caryclark65f55312014-11-13 06:58:52 -0800911 if (lastPtr) {
912 *lastPtr = last;
913 }
914 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000915}
916
caryclark54359292015-03-26 07:52:43 -0700917bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
918 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
919 SkOpSpan* spanStart = start->starter(end);
920 int step = start->step(end);
921 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700922 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000923 SkOpSegment* other = this;
Cary Clark4929a4a2018-10-17 14:12:41 -0400924 int safetyNet = 100000;
caryclark54359292015-03-26 07:52:43 -0700925 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
Cary Clark4929a4a2018-10-17 14:12:41 -0400926 if (!--safetyNet) {
927 return false;
928 }
caryclark54359292015-03-26 07:52:43 -0700929 if (spanStart->windSum() != SK_MinS32) {
930 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700931 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700932 this->globalState()->setWindingFailed();
Cary Clark2587f412018-07-24 12:40:10 -0400933 return true; // ... but let it succeed anyway
caryclarkdac1d172014-06-17 05:15:38 -0700934 }
caryclark54359292015-03-26 07:52:43 -0700935 } else {
Cary Clark2587f412018-07-24 12:40:10 -0400936 FAIL_IF(spanStart->windSum() != oppWinding);
Cary Clark1e00aeb2018-11-13 16:39:44 -0500937 FAIL_IF(spanStart->oppSum() != winding);
caryclarkdac1d172014-06-17 05:15:38 -0700938 }
939 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700940 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000941 }
caryclark54359292015-03-26 07:52:43 -0700942 if (this->operand() == other->operand()) {
943 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700944 } else {
caryclark54359292015-03-26 07:52:43 -0700945 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700946 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000947 }
caryclark65f55312014-11-13 06:58:52 -0800948 if (lastPtr) {
949 *lastPtr = last;
950 }
951 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000952}
953
Cary Clark2587f412018-07-24 12:40:10 -0400954bool SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle,
955 SkOpSpanBase** result) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000956 SkASSERT(angle->segment() == this);
957 if (UseInnerWinding(maxWinding, sumWinding)) {
958 maxWinding = sumWinding;
959 }
Cary Clark2587f412018-07-24 12:40:10 -0400960 if (!markAndChaseWinding(angle->start(), angle->end(), maxWinding, result)) {
961 return false;
962 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000963#if DEBUG_WINDING
Cary Clarkcadc5062018-08-06 17:24:04 -0400964 SkOpSpanBase* last = *result;
caryclark@google.com570863f2013-09-16 15:55:01 +0000965 if (last) {
caryclark54359292015-03-26 07:52:43 -0700966 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
967 last->segment()->debugID(), last->debugID());
968 if (!last->final()) {
969 SkDebugf(" windSum=");
970 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
971 }
972 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000973 }
974#endif
Cary Clark2587f412018-07-24 12:40:10 -0400975 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000976}
977
Cary Clark2587f412018-07-24 12:40:10 -0400978bool SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
979 int oppSumWinding, const SkOpAngle* angle, SkOpSpanBase** result) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000980 SkASSERT(angle->segment() == this);
981 if (UseInnerWinding(maxWinding, sumWinding)) {
982 maxWinding = sumWinding;
983 }
984 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
985 oppMaxWinding = oppSumWinding;
986 }
caryclark65f55312014-11-13 06:58:52 -0800987 // caller doesn't require that this marks anything
Cary Clark2587f412018-07-24 12:40:10 -0400988 if (!markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, result)) {
989 return false;
990 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000991#if DEBUG_WINDING
Cary Clark8762fb62018-10-16 16:06:24 -0400992 if (result) {
993 SkOpSpanBase* last = *result;
994 if (last) {
995 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
996 last->segment()->debugID(), last->debugID());
997 if (!last->final()) {
998 SkDebugf(" windSum=");
999 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
1000 }
1001 SkDebugf(" \n");
caryclark54359292015-03-26 07:52:43 -07001002 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001003 }
1004#endif
Cary Clark2587f412018-07-24 12:40:10 -04001005 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001006}
1007
caryclark54359292015-03-26 07:52:43 -07001008void SkOpSegment::markDone(SkOpSpan* span) {
1009 SkASSERT(this == span->segment());
1010 if (span->done()) {
1011 return;
1012 }
1013#if DEBUG_MARK_DONE
1014 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
1015#endif
1016 span->setDone(true);
1017 ++fDoneCount;
1018 debugValidate();
1019}
1020
1021bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
1022 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -07001023 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -07001024 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001025 return false;
1026 }
1027#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -07001028 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -07001029#endif
caryclark54359292015-03-26 07:52:43 -07001030 span->setWindSum(winding);
1031 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001032 return true;
1033}
1034
caryclark54359292015-03-26 07:52:43 -07001035bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
1036 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +00001037 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -07001038 if (span->done()) {
1039 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001040 }
caryclark54359292015-03-26 07:52:43 -07001041#if DEBUG_MARK_DONE
1042 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1043#endif
1044 span->setWindSum(winding);
1045 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001046 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001047 return true;
1048}
1049
caryclark54359292015-03-26 07:52:43 -07001050bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclarkef4f32a2016-08-24 09:24:18 -07001051 const SkPoint& testPt) const {
caryclark55888e42016-07-18 10:01:36 -07001052 SkASSERT(this == base->segment());
1053 if (this == testParent) {
1054 if (precisely_equal(base->fT, testT)) {
1055 return true;
1056 }
caryclark54359292015-03-26 07:52:43 -07001057 }
1058 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1059 return false;
1060 }
caryclark55888e42016-07-18 10:01:36 -07001061 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001062}
1063
1064static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1065 if (last) {
1066 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001067 }
halcanary96fcdcc2015-08-27 07:41:13 -07001068 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001069}
1070
caryclark54359292015-03-26 07:52:43 -07001071SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1072 SkOpSpanBase** last) const {
1073 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001074 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001075 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1076 SkASSERT(endSpan);
1077 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1078 SkOpSpanBase* foundSpan;
1079 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001080 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001081 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001082 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001083 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001084 }
caryclark54359292015-03-26 07:52:43 -07001085 SkOpPtT* otherPtT = endSpan->ptT()->next();
1086 other = otherPtT->segment();
1087 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001088 otherEnd = step > 0
1089 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1090 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001091 } else {
1092 int loopCount = angle->loopCount();
1093 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001094 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001095 }
1096 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001097 if (nullptr == next) {
1098 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001099 }
caryclarkdac1d172014-06-17 05:15:38 -07001100#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001101 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001102 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001103 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001104 }
caryclark54359292015-03-26 07:52:43 -07001105#endif
caryclarkdac1d172014-06-17 05:15:38 -07001106 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001107 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001108 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001109 }
caryclark343382e2016-06-29 08:18:38 -07001110 if (!otherEnd) {
1111 return nullptr;
1112 }
caryclark54359292015-03-26 07:52:43 -07001113 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001114 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001115 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001116 }
caryclark54359292015-03-26 07:52:43 -07001117 SkASSERT(*startPtr);
caryclark65b427c2014-09-18 10:32:57 -07001118// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001119 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1120 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1121 if (foundMin->windValue() != origMin->windValue()
1122 || foundMin->oppValue() != origMin->oppValue()) {
1123 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001124 }
caryclark54359292015-03-26 07:52:43 -07001125 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001126 *stepPtr = foundStep;
1127 if (minPtr) {
1128 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001129 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001130 return other;
1131}
1132
caryclark55888e42016-07-18 10:01:36 -07001133// Please keep this in sync with DebugClearVisited()
1134void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001135 // reset visited flag back to false
1136 do {
1137 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1138 while ((ptT = ptT->next()) != stopPtT) {
1139 SkOpSegment* opp = ptT->segment();
1140 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001141 }
caryclarkbca19f72015-05-13 08:23:48 -07001142 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001143}
1144
caryclark55888e42016-07-18 10:01:36 -07001145// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001146// look for pairs of undetected coincident curves
1147// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001148// Even though pairs of curves correct detect coincident runs, a run may be missed
1149// if the coincidence is a product of multiple intersections. For instance, given
1150// curves A, B, and C:
1151// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1152// the end of C that the intersection is replaced with the end of C.
1153// Even though A-B correctly do not detect an intersection at point 2,
1154// the resulting run from point 1 to point 2 is coincident on A and B.
1155bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001156 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001157 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001158 }
halcanary96fcdcc2015-08-27 07:41:13 -07001159 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001160 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001161 bool result = false;
Cary Clark62b30042018-10-23 10:05:06 -04001162 int safetyNet = 100000;
caryclark54359292015-03-26 07:52:43 -07001163 do {
caryclarkbca19f72015-05-13 08:23:48 -07001164 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001165 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001166 while ((ptT = ptT->next()) != spanStopPtT) {
Cary Clark62b30042018-10-23 10:05:06 -04001167 if (!--safetyNet) {
1168 return false;
1169 }
caryclark182b4992015-05-14 05:45:54 -07001170 if (ptT->deleted()) {
1171 continue;
1172 }
caryclark54359292015-03-26 07:52:43 -07001173 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001174 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001175 continue;
reed0dc4dd62015-03-24 13:55:33 -07001176 }
caryclarkbca19f72015-05-13 08:23:48 -07001177 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1178 if (!opp->visited()) {
1179 continue;
1180 }
1181 if (spanBase == &fHead) {
1182 continue;
1183 }
caryclark55888e42016-07-18 10:01:36 -07001184 if (ptT->segment() == this) {
1185 continue;
1186 }
caryclarkbca19f72015-05-13 08:23:48 -07001187 SkOpSpan* span = spanBase->upCastable();
1188 // FIXME?: this assumes that if the opposite segment is coincident then no more
1189 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001190 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001191 continue;
1192 }
caryclarkbca19f72015-05-13 08:23:48 -07001193 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001194 continue;
caryclark55888e42016-07-18 10:01:36 -07001195 }
halcanary96fcdcc2015-08-27 07:41:13 -07001196 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001197 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001198 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001199 SkOpSpan* priorTest = spanBase->prev();
1200 while (!priorOpp && priorTest) {
1201 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001202 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001203 if (priorPtT->deleted()) {
1204 continue;
1205 }
caryclark54359292015-03-26 07:52:43 -07001206 SkOpSegment* segment = priorPtT->span()->segment();
1207 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001208 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001209 priorOpp = opp;
1210 break;
1211 }
1212 }
caryclarkbca19f72015-05-13 08:23:48 -07001213 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001214 }
1215 if (!priorOpp) {
1216 continue;
1217 }
caryclark26ad22a2015-10-16 09:03:38 -07001218 if (priorPtT == ptT) {
1219 continue;
1220 }
caryclark54359292015-03-26 07:52:43 -07001221 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001222 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001223 bool swapped = priorPtT->fT > ptT->fT;
1224 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001225 using std::swap;
1226 swap(priorPtT, ptT);
1227 swap(oppStart, oppEnd);
caryclark54359292015-03-26 07:52:43 -07001228 }
caryclark55888e42016-07-18 10:01:36 -07001229 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1230 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1231 SkOpPtT* rootPtT = ptT->span()->ptT();
1232 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1233 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1234 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001235 goto swapBack;
1236 }
caryclark55888e42016-07-18 10:01:36 -07001237 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001238 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001239#if DEBUG_COINCIDENCE_VERBOSE
1240 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1241 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1242 rootOppEnd->debugID());
1243#endif
1244 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1245 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001246 }
caryclark55888e42016-07-18 10:01:36 -07001247#if DEBUG_COINCIDENCE
1248 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1249#endif
1250 result = true;
caryclark54359292015-03-26 07:52:43 -07001251 }
1252 swapBack:
1253 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001254 using std::swap;
1255 swap(priorPtT, ptT);
caryclark54359292015-03-26 07:52:43 -07001256 }
reed0dc4dd62015-03-24 13:55:33 -07001257 }
halcanary96fcdcc2015-08-27 07:41:13 -07001258 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001259 ClearVisited(&fHead);
1260 return result;
reed0dc4dd62015-03-24 13:55:33 -07001261}
1262
caryclark55888e42016-07-18 10:01:36 -07001263// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001264// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001265bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001266 debugValidate();
1267 SkOpSpanBase* test = &fHead;
1268 do {
1269 int addCount = test->spanAddsCount();
Cary Clark7eb01e02016-12-08 14:36:32 -05001270// FAIL_IF(addCount < 1);
1271 if (addCount <= 1) {
caryclark08bc8482015-04-24 09:08:57 -07001272 continue;
1273 }
1274 SkOpPtT* startPtT = test->ptT();
1275 SkOpPtT* testPtT = startPtT;
Cary Clark9a061a52018-11-26 07:55:25 -05001276 int safetyHatch = 1000000;
caryclark08bc8482015-04-24 09:08:57 -07001277 do { // iterate through all spans associated with start
Cary Clark9a061a52018-11-26 07:55:25 -05001278 if (!--safetyHatch) {
1279 return false;
1280 }
caryclark08bc8482015-04-24 09:08:57 -07001281 SkOpSpanBase* oppSpan = testPtT->span();
1282 if (oppSpan->spanAddsCount() == addCount) {
1283 continue;
1284 }
1285 if (oppSpan->deleted()) {
1286 continue;
1287 }
1288 SkOpSegment* oppSegment = oppSpan->segment();
1289 if (oppSegment == this) {
1290 continue;
1291 }
1292 // find range of spans to consider merging
1293 SkOpSpanBase* oppPrev = oppSpan;
1294 SkOpSpanBase* oppFirst = oppSpan;
1295 while ((oppPrev = oppPrev->prev())) {
1296 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1297 break;
1298 }
1299 if (oppPrev->spanAddsCount() == addCount) {
1300 continue;
1301 }
1302 if (oppPrev->deleted()) {
1303 continue;
1304 }
1305 oppFirst = oppPrev;
1306 }
1307 SkOpSpanBase* oppNext = oppSpan;
1308 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001309 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001310 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1311 break;
1312 }
1313 if (oppNext->spanAddsCount() == addCount) {
1314 continue;
1315 }
1316 if (oppNext->deleted()) {
1317 continue;
1318 }
1319 oppLast = oppNext;
1320 }
1321 if (oppFirst == oppLast) {
1322 continue;
1323 }
1324 SkOpSpanBase* oppTest = oppFirst;
1325 do {
1326 if (oppTest == oppSpan) {
1327 continue;
1328 }
1329 // check to see if the candidate meets specific criteria:
1330 // it contains spans of segments in test's loop but not including 'this'
1331 SkOpPtT* oppStartPtT = oppTest->ptT();
1332 SkOpPtT* oppPtT = oppStartPtT;
1333 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1334 SkOpSegment* oppPtTSegment = oppPtT->segment();
1335 if (oppPtTSegment == this) {
1336 goto tryNextSpan;
1337 }
1338 SkOpPtT* matchPtT = startPtT;
1339 do {
1340 if (matchPtT->segment() == oppPtTSegment) {
1341 goto foundMatch;
1342 }
1343 } while ((matchPtT = matchPtT->next()) != startPtT);
1344 goto tryNextSpan;
1345 foundMatch: // merge oppTest and oppSpan
1346 oppSegment->debugValidate();
caryclark30b9fdd2016-08-31 14:36:29 -07001347 oppTest->mergeMatches(oppSpan);
1348 oppTest->addOpp(oppSpan);
caryclark08bc8482015-04-24 09:08:57 -07001349 oppSegment->debugValidate();
1350 goto checkNextSpan;
1351 }
caryclark55888e42016-07-18 10:01:36 -07001352 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001353 ;
1354 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1355 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001356checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001357 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001358 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001359 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001360 return true;
caryclark08bc8482015-04-24 09:08:57 -07001361}
1362
caryclark55888e42016-07-18 10:01:36 -07001363// adjacent spans may have points close by
Cary Clark28da2832017-03-21 10:30:50 -04001364bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan,
1365 bool* found) const {
caryclark55888e42016-07-18 10:01:36 -07001366 const SkOpPtT* refHead = refSpan->ptT();
1367 const SkOpPtT* checkHead = checkSpan->ptT();
1368// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
caryclark30b9fdd2016-08-31 14:36:29 -07001369 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
caryclark55888e42016-07-18 10:01:36 -07001370#if DEBUG_COINCIDENCE
1371 // verify that no combination of points are close
1372 const SkOpPtT* dBugRef = refHead;
1373 do {
1374 const SkOpPtT* dBugCheck = checkHead;
1375 do {
caryclark30b9fdd2016-08-31 14:36:29 -07001376 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
caryclark55888e42016-07-18 10:01:36 -07001377 dBugCheck = dBugCheck->next();
1378 } while (dBugCheck != checkHead);
1379 dBugRef = dBugRef->next();
1380 } while (dBugRef != refHead);
1381#endif
Cary Clark28da2832017-03-21 10:30:50 -04001382 *found = false;
1383 return true;
caryclark55888e42016-07-18 10:01:36 -07001384 }
1385 // check only unique points
1386 SkScalar distSqBest = SK_ScalarMax;
1387 const SkOpPtT* refBest = nullptr;
1388 const SkOpPtT* checkBest = nullptr;
1389 const SkOpPtT* ref = refHead;
1390 do {
1391 if (ref->deleted()) {
1392 continue;
1393 }
1394 while (ref->ptAlreadySeen(refHead)) {
1395 ref = ref->next();
1396 if (ref == refHead) {
1397 goto doneCheckingDistance;
1398 }
1399 }
1400 const SkOpPtT* check = checkHead;
1401 const SkOpSegment* refSeg = ref->segment();
Cary Clark28da2832017-03-21 10:30:50 -04001402 int escapeHatch = 100000; // defend against infinite loops
caryclark55888e42016-07-18 10:01:36 -07001403 do {
1404 if (check->deleted()) {
1405 continue;
1406 }
1407 while (check->ptAlreadySeen(checkHead)) {
1408 check = check->next();
1409 if (check == checkHead) {
1410 goto nextRef;
1411 }
1412 }
Cary Clarkdf429f32017-11-08 11:44:31 -05001413 SkScalar distSq = SkPointPriv::DistanceToSqd(ref->fPt, check->fPt);
caryclark55888e42016-07-18 10:01:36 -07001414 if (distSqBest > distSq && (refSeg != check->segment()
1415 || !refSeg->ptsDisjoint(*ref, *check))) {
1416 distSqBest = distSq;
1417 refBest = ref;
1418 checkBest = check;
1419 }
Cary Clark28da2832017-03-21 10:30:50 -04001420 if (--escapeHatch <= 0) {
1421 return false;
1422 }
caryclark55888e42016-07-18 10:01:36 -07001423 } while ((check = check->next()) != checkHead);
Cary Clark28da2832017-03-21 10:30:50 -04001424 nextRef:
caryclark55888e42016-07-18 10:01:36 -07001425 ;
1426 } while ((ref = ref->next()) != refHead);
1427doneCheckingDistance:
Cary Clark28da2832017-03-21 10:30:50 -04001428 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001429 checkBest->fPt);
Cary Clark28da2832017-03-21 10:30:50 -04001430 return true;
caryclark55888e42016-07-18 10:01:36 -07001431}
1432
1433// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001434// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
Cary Clark28da2832017-03-21 10:30:50 -04001435bool SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001436 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001437 // release undeleted spans pointing to this seg that are linked to the primary span
1438 SkOpSpanBase* spanBase = &fHead;
Cary Clark43938b82017-10-18 08:47:32 -04001439 int escapeHatch = 9999; // the largest count for a regular test is 50; for a fuzzer, 500
caryclark54359292015-03-26 07:52:43 -07001440 do {
caryclark55888e42016-07-18 10:01:36 -07001441 SkOpPtT* ptT = spanBase->ptT();
1442 const SkOpPtT* headPtT = ptT;
1443 while ((ptT = ptT->next()) != headPtT) {
Cary Clark43938b82017-10-18 08:47:32 -04001444 if (!--escapeHatch) {
1445 return false;
1446 }
caryclark55888e42016-07-18 10:01:36 -07001447 SkOpSpanBase* test = ptT->span();
1448 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1449 && test->ptT() == ptT) {
1450 if (test->final()) {
1451 if (spanBase == &fHead) {
1452 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001453 return true;
caryclark55888e42016-07-18 10:01:36 -07001454 }
1455 spanBase->upCast()->release(ptT);
1456 } else if (test->prev()) {
1457 test->upCast()->release(headPtT);
1458 }
1459 break;
caryclark54359292015-03-26 07:52:43 -07001460 }
reed0dc4dd62015-03-24 13:55:33 -07001461 }
caryclark55888e42016-07-18 10:01:36 -07001462 spanBase = spanBase->upCast()->next();
1463 } while (!spanBase->final());
caryclark55888e42016-07-18 10:01:36 -07001464 // This loop looks for adjacent spans which are near by
1465 spanBase = &fHead;
1466 do { // iterate through all spans associated with start
1467 SkOpSpanBase* test = spanBase->upCast()->next();
Cary Clark28da2832017-03-21 10:30:50 -04001468 bool found;
1469 if (!this->spansNearby(spanBase, test, &found)) {
1470 return false;
1471 }
1472 if (found) {
caryclark55888e42016-07-18 10:01:36 -07001473 if (test->final()) {
1474 if (spanBase->prev()) {
1475 test->merge(spanBase->upCast());
1476 } else {
1477 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001478 return true;
caryclark55888e42016-07-18 10:01:36 -07001479 }
1480 } else {
1481 spanBase->merge(test->upCast());
1482 }
1483 }
1484 spanBase = test;
1485 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001486 debugValidate();
Cary Clark28da2832017-03-21 10:30:50 -04001487 return true;
reed0dc4dd62015-03-24 13:55:33 -07001488}
1489
caryclark54359292015-03-26 07:52:43 -07001490bool SkOpSegment::operand() const {
1491 return fContour->operand();
1492}
1493
1494bool SkOpSegment::oppXor() const {
1495 return fContour->oppXor();
1496}
1497
1498bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1499 if (fVerb == SkPath::kLine_Verb) {
1500 return false;
1501 }
1502 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1503 // hits in two places with very different t values.
1504 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1505 // 'controls contained by ends' could avoid this check for common curves
1506 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1507 // on the other hand, the below check is relatively inexpensive
1508 double midT = (t1 + t2) / 2;
1509 SkPoint midPt = this->ptAtT(midT);
Cary Clarkdf429f32017-11-08 11:44:31 -05001510 double seDistSq = SkTMax(SkPointPriv::DistanceToSqd(pt1, pt2) * 2, FLT_EPSILON * 2);
1511 return SkPointPriv::DistanceToSqd(midPt, pt1) > seDistSq ||
1512 SkPointPriv::DistanceToSqd(midPt, pt2) > seDistSq;
caryclark54359292015-03-26 07:52:43 -07001513}
1514
1515void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1516 int* maxWinding, int* sumWinding) {
1517 int deltaSum = SpanSign(start, end);
1518 *maxWinding = *sumMiWinding;
1519 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001520 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001521}
1522
1523void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1524 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1525 int* oppSumWinding) {
1526 int deltaSum = SpanSign(start, end);
1527 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001528 if (operand()) {
1529 *maxWinding = *sumSuWinding;
1530 *sumWinding = *sumSuWinding -= deltaSum;
1531 *oppMaxWinding = *sumMiWinding;
1532 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1533 } else {
1534 *maxWinding = *sumMiWinding;
1535 *sumWinding = *sumMiWinding -= deltaSum;
1536 *oppMaxWinding = *sumSuWinding;
1537 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1538 }
bungeman60e0fee2015-08-26 05:15:46 -07001539 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1540 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001541}
1542
caryclarkb36a3cd2016-10-18 07:59:44 -07001543bool SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001544 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001545 do {
caryclark54359292015-03-26 07:52:43 -07001546 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001547 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001548 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001549 continue;
1550 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001551#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001552 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001553#endif
caryclark54359292015-03-26 07:52:43 -07001554 SkOpAngle* baseAngle = fromAngle;
1555 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001556#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001557 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1558 span->debugID());
1559 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001560#endif
caryclarkb36a3cd2016-10-18 07:59:44 -07001561 FAIL_IF(!fromAngle->insert(toAngle));
caryclark54359292015-03-26 07:52:43 -07001562 } else if (!fromAngle) {
1563 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001564 }
caryclark54359292015-03-26 07:52:43 -07001565 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
Cary Clark5369e142018-11-19 14:57:20 -05001566 int safetyNet = 1000000;
reed0dc4dd62015-03-24 13:55:33 -07001567 do {
Cary Clark5369e142018-11-19 14:57:20 -05001568 if (!--safetyNet) {
1569 return false;
1570 }
caryclark54359292015-03-26 07:52:43 -07001571 SkOpSpanBase* oSpan = ptT->span();
1572 if (oSpan == span) {
1573 continue;
1574 }
1575 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001576 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001577#if DEBUG_ANGLE
1578 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001579 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1580 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001581 wroteAfterHeader = true;
1582 }
1583#endif
caryclark54359292015-03-26 07:52:43 -07001584 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001585 baseAngle->insert(oAngle);
1586 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001587 }
caryclark54359292015-03-26 07:52:43 -07001588 if (!oSpan->final()) {
1589 oAngle = oSpan->upCast()->toAngle();
1590 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001591#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001592 if (!wroteAfterHeader) {
1593 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1594 span->t(), span->debugID());
1595 wroteAfterHeader = true;
1596 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001597#endif
caryclark54359292015-03-26 07:52:43 -07001598 if (!oAngle->loopContains(baseAngle)) {
1599 baseAngle->insert(oAngle);
1600 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001601 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001602 }
caryclark54359292015-03-26 07:52:43 -07001603 } while ((ptT = ptT->next()) != stopPtT);
1604 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001605 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001606 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001607 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001608 }
halcanary96fcdcc2015-08-27 07:41:13 -07001609 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001610 }
1611#if DEBUG_SORT
1612 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1613#endif
caryclark54359292015-03-26 07:52:43 -07001614 } while (!span->final() && (span = span->upCast()->next()));
caryclarkb36a3cd2016-10-18 07:59:44 -07001615 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +00001616}
1617
caryclark54359292015-03-26 07:52:43 -07001618bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001619 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001620 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001621 const SkOpPtT& startPtT = *start->ptT();
1622 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001623 SkDEBUGCODE(edge->fVerb = fVerb);
1624 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001625 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001626 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001627 if (fVerb == SkPath::kLine_Verb) {
1628 return false;
1629 }
caryclark54359292015-03-26 07:52:43 -07001630 double startT = startPtT.fT;
1631 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001632 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1633 // don't compute midpoints if we already have them
1634 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001635 edge->fLine[1].set(fPts[1]);
1636 return false;
1637 }
1638 if (fVerb == SkPath::kConic_Verb) {
1639 edge->fConic[1].set(fPts[1]);
1640 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001641 return false;
1642 }
1643 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001644 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001645 edge->fCubic[1].set(fPts[1]);
1646 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001647 return false;
1648 }
caryclark1049f122015-04-20 08:31:59 -07001649 edge->fCubic[1].set(fPts[2]);
1650 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001651 return false;
1652 }
1653 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001654 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1655 } else if (fVerb == SkPath::kConic_Verb) {
1656 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1657 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001658 } else {
1659 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001660 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001661 }
1662 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001663}
1664
caryclark27c8eb82015-07-06 11:38:33 -07001665bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001666 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001667 // average t, find mid pt
1668 double midT = (prior->t() + spanBase->t()) / 2;
1669 SkPoint midPt = this->ptAtT(midT);
1670 bool coincident = true;
1671 // if the mid pt is not near either end pt, project perpendicular through opp seg
1672 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1673 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001674 if (priorPtT->span() == ptT->span()) {
1675 return false;
1676 }
caryclark27c8eb82015-07-06 11:38:33 -07001677 coincident = false;
1678 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001679 SkDCurve curvePart;
1680 this->subDivide(prior, spanBase, &curvePart);
1681 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1682 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1683 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1684 SkDCurve oppPart;
1685 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1686 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001687 // measure distance and see if it's small enough to denote coincidence
1688 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001689 if (!between(0, i[0][index], 1)) {
1690 continue;
1691 }
caryclark27c8eb82015-07-06 11:38:33 -07001692 SkDPoint oppPt = i.pt(index);
caryclark30b9fdd2016-08-31 14:36:29 -07001693 if (oppPt.approximatelyDEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001694 // the coincidence can occur at almost any angle
1695 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001696 }
1697 }
1698 }
1699 return coincident;
1700}
1701
Cary Clarkab2d73b2016-12-16 17:17:25 -05001702SkOpSpan* SkOpSegment::undoneSpan() {
1703 SkOpSpan* span = &fHead;
1704 SkOpSpanBase* next;
caryclark54359292015-03-26 07:52:43 -07001705 do {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001706 next = span->next();
caryclark54359292015-03-26 07:52:43 -07001707 if (!span->done()) {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001708 return span;
reed0dc4dd62015-03-24 13:55:33 -07001709 }
Cary Clarkab2d73b2016-12-16 17:17:25 -05001710 } while (!next->final() && (span = next->upCast()));
1711 return nullptr;
reed0dc4dd62015-03-24 13:55:33 -07001712}
1713
caryclark54359292015-03-26 07:52:43 -07001714int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1715 const SkOpSpan* lesser = start->starter(end);
1716 int oppWinding = lesser->oppSum();
1717 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001718 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1719 && oppWinding != SK_MaxS32) {
1720 oppWinding -= oppSpanWinding;
1721 }
1722 return oppWinding;
1723}
1724
1725int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001726 const SkOpSpanBase* startSpan = angle->start();
1727 const SkOpSpanBase* endSpan = angle->end();
1728 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001729}
1730
1731int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001732 const SkOpSpanBase* startSpan = angle->start();
1733 const SkOpSpanBase* endSpan = angle->end();
1734 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001735}
1736
caryclark624637c2015-05-11 07:21:27 -07001737int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1738 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001739 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001740 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001741 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001742 }
1743 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001744 return winding;
1745 }
caryclark54359292015-03-26 07:52:43 -07001746 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001747 if (winding && UseInnerWinding(winding - spanWinding, winding)
1748 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001749 winding -= spanWinding;
1750 }
1751 return winding;
1752}
1753
caryclark624637c2015-05-11 07:21:27 -07001754int SkOpSegment::updateWinding(SkOpAngle* angle) {
1755 SkOpSpanBase* startSpan = angle->start();
1756 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001757 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001758}
1759
caryclark624637c2015-05-11 07:21:27 -07001760int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1761 SkOpSpanBase* startSpan = angle->start();
1762 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001763 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001764}
1765
1766// OPTIMIZATION: does the following also work, and is it any faster?
1767// return outerWinding * innerWinding > 0
1768// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1769bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1770 SkASSERT(outerWinding != SK_MaxS32);
1771 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001772 int absOut = SkTAbs(outerWinding);
1773 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001774 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1775 return result;
1776}
1777
caryclark@google.com07393ca2013-04-08 11:47:37 +00001778int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001779 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1780 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001781}