blob: 89a39b450adc754a0861dc68af283773c242b5fb [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 */
caryclark54359292015-03-26 07:52:43 -07007#include "SkOpCoincidence.h"
caryclarkdac1d172014-06-17 05:15:38 -07008#include "SkOpContour.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +00009#include "SkOpSegment.h"
10#include "SkPathWriter.h"
Cary Clarkdf429f32017-11-08 11:44:31 -050011#include "SkPointPriv.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);
caryclark54359292015-03-26 07:52:43 -0700937 SkASSERT(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;
caryclark54359292015-03-26 07:52:43 -07001162 do {
caryclarkbca19f72015-05-13 08:23:48 -07001163 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001164 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001165 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001166 if (ptT->deleted()) {
1167 continue;
1168 }
caryclark54359292015-03-26 07:52:43 -07001169 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001170 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001171 continue;
reed0dc4dd62015-03-24 13:55:33 -07001172 }
caryclarkbca19f72015-05-13 08:23:48 -07001173 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1174 if (!opp->visited()) {
1175 continue;
1176 }
1177 if (spanBase == &fHead) {
1178 continue;
1179 }
caryclark55888e42016-07-18 10:01:36 -07001180 if (ptT->segment() == this) {
1181 continue;
1182 }
caryclarkbca19f72015-05-13 08:23:48 -07001183 SkOpSpan* span = spanBase->upCastable();
1184 // FIXME?: this assumes that if the opposite segment is coincident then no more
1185 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001186 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001187 continue;
1188 }
caryclarkbca19f72015-05-13 08:23:48 -07001189 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001190 continue;
caryclark55888e42016-07-18 10:01:36 -07001191 }
halcanary96fcdcc2015-08-27 07:41:13 -07001192 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001193 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001194 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001195 SkOpSpan* priorTest = spanBase->prev();
1196 while (!priorOpp && priorTest) {
1197 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001198 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001199 if (priorPtT->deleted()) {
1200 continue;
1201 }
caryclark54359292015-03-26 07:52:43 -07001202 SkOpSegment* segment = priorPtT->span()->segment();
1203 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001204 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001205 priorOpp = opp;
1206 break;
1207 }
1208 }
caryclarkbca19f72015-05-13 08:23:48 -07001209 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001210 }
1211 if (!priorOpp) {
1212 continue;
1213 }
caryclark26ad22a2015-10-16 09:03:38 -07001214 if (priorPtT == ptT) {
1215 continue;
1216 }
caryclark54359292015-03-26 07:52:43 -07001217 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001218 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001219 bool swapped = priorPtT->fT > ptT->fT;
1220 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001221 using std::swap;
1222 swap(priorPtT, ptT);
1223 swap(oppStart, oppEnd);
caryclark54359292015-03-26 07:52:43 -07001224 }
caryclark55888e42016-07-18 10:01:36 -07001225 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1226 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1227 SkOpPtT* rootPtT = ptT->span()->ptT();
1228 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1229 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1230 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001231 goto swapBack;
1232 }
caryclark55888e42016-07-18 10:01:36 -07001233 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001234 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001235#if DEBUG_COINCIDENCE_VERBOSE
1236 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1237 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1238 rootOppEnd->debugID());
1239#endif
1240 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1241 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001242 }
caryclark55888e42016-07-18 10:01:36 -07001243#if DEBUG_COINCIDENCE
1244 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1245#endif
1246 result = true;
caryclark54359292015-03-26 07:52:43 -07001247 }
1248 swapBack:
1249 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001250 using std::swap;
1251 swap(priorPtT, ptT);
caryclark54359292015-03-26 07:52:43 -07001252 }
reed0dc4dd62015-03-24 13:55:33 -07001253 }
halcanary96fcdcc2015-08-27 07:41:13 -07001254 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001255 ClearVisited(&fHead);
1256 return result;
reed0dc4dd62015-03-24 13:55:33 -07001257}
1258
caryclark55888e42016-07-18 10:01:36 -07001259// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001260// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001261bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001262 debugValidate();
1263 SkOpSpanBase* test = &fHead;
1264 do {
1265 int addCount = test->spanAddsCount();
Cary Clark7eb01e02016-12-08 14:36:32 -05001266// FAIL_IF(addCount < 1);
1267 if (addCount <= 1) {
caryclark08bc8482015-04-24 09:08:57 -07001268 continue;
1269 }
1270 SkOpPtT* startPtT = test->ptT();
1271 SkOpPtT* testPtT = startPtT;
1272 do { // iterate through all spans associated with start
1273 SkOpSpanBase* oppSpan = testPtT->span();
1274 if (oppSpan->spanAddsCount() == addCount) {
1275 continue;
1276 }
1277 if (oppSpan->deleted()) {
1278 continue;
1279 }
1280 SkOpSegment* oppSegment = oppSpan->segment();
1281 if (oppSegment == this) {
1282 continue;
1283 }
1284 // find range of spans to consider merging
1285 SkOpSpanBase* oppPrev = oppSpan;
1286 SkOpSpanBase* oppFirst = oppSpan;
1287 while ((oppPrev = oppPrev->prev())) {
1288 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1289 break;
1290 }
1291 if (oppPrev->spanAddsCount() == addCount) {
1292 continue;
1293 }
1294 if (oppPrev->deleted()) {
1295 continue;
1296 }
1297 oppFirst = oppPrev;
1298 }
1299 SkOpSpanBase* oppNext = oppSpan;
1300 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001301 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001302 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1303 break;
1304 }
1305 if (oppNext->spanAddsCount() == addCount) {
1306 continue;
1307 }
1308 if (oppNext->deleted()) {
1309 continue;
1310 }
1311 oppLast = oppNext;
1312 }
1313 if (oppFirst == oppLast) {
1314 continue;
1315 }
1316 SkOpSpanBase* oppTest = oppFirst;
1317 do {
1318 if (oppTest == oppSpan) {
1319 continue;
1320 }
1321 // check to see if the candidate meets specific criteria:
1322 // it contains spans of segments in test's loop but not including 'this'
1323 SkOpPtT* oppStartPtT = oppTest->ptT();
1324 SkOpPtT* oppPtT = oppStartPtT;
1325 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1326 SkOpSegment* oppPtTSegment = oppPtT->segment();
1327 if (oppPtTSegment == this) {
1328 goto tryNextSpan;
1329 }
1330 SkOpPtT* matchPtT = startPtT;
1331 do {
1332 if (matchPtT->segment() == oppPtTSegment) {
1333 goto foundMatch;
1334 }
1335 } while ((matchPtT = matchPtT->next()) != startPtT);
1336 goto tryNextSpan;
1337 foundMatch: // merge oppTest and oppSpan
1338 oppSegment->debugValidate();
caryclark30b9fdd2016-08-31 14:36:29 -07001339 oppTest->mergeMatches(oppSpan);
1340 oppTest->addOpp(oppSpan);
caryclark08bc8482015-04-24 09:08:57 -07001341 oppSegment->debugValidate();
1342 goto checkNextSpan;
1343 }
caryclark55888e42016-07-18 10:01:36 -07001344 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001345 ;
1346 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1347 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001348checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001349 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001350 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001351 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001352 return true;
caryclark08bc8482015-04-24 09:08:57 -07001353}
1354
caryclark55888e42016-07-18 10:01:36 -07001355// adjacent spans may have points close by
Cary Clark28da2832017-03-21 10:30:50 -04001356bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan,
1357 bool* found) const {
caryclark55888e42016-07-18 10:01:36 -07001358 const SkOpPtT* refHead = refSpan->ptT();
1359 const SkOpPtT* checkHead = checkSpan->ptT();
1360// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
caryclark30b9fdd2016-08-31 14:36:29 -07001361 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
caryclark55888e42016-07-18 10:01:36 -07001362#if DEBUG_COINCIDENCE
1363 // verify that no combination of points are close
1364 const SkOpPtT* dBugRef = refHead;
1365 do {
1366 const SkOpPtT* dBugCheck = checkHead;
1367 do {
caryclark30b9fdd2016-08-31 14:36:29 -07001368 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
caryclark55888e42016-07-18 10:01:36 -07001369 dBugCheck = dBugCheck->next();
1370 } while (dBugCheck != checkHead);
1371 dBugRef = dBugRef->next();
1372 } while (dBugRef != refHead);
1373#endif
Cary Clark28da2832017-03-21 10:30:50 -04001374 *found = false;
1375 return true;
caryclark55888e42016-07-18 10:01:36 -07001376 }
1377 // check only unique points
1378 SkScalar distSqBest = SK_ScalarMax;
1379 const SkOpPtT* refBest = nullptr;
1380 const SkOpPtT* checkBest = nullptr;
1381 const SkOpPtT* ref = refHead;
1382 do {
1383 if (ref->deleted()) {
1384 continue;
1385 }
1386 while (ref->ptAlreadySeen(refHead)) {
1387 ref = ref->next();
1388 if (ref == refHead) {
1389 goto doneCheckingDistance;
1390 }
1391 }
1392 const SkOpPtT* check = checkHead;
1393 const SkOpSegment* refSeg = ref->segment();
Cary Clark28da2832017-03-21 10:30:50 -04001394 int escapeHatch = 100000; // defend against infinite loops
caryclark55888e42016-07-18 10:01:36 -07001395 do {
1396 if (check->deleted()) {
1397 continue;
1398 }
1399 while (check->ptAlreadySeen(checkHead)) {
1400 check = check->next();
1401 if (check == checkHead) {
1402 goto nextRef;
1403 }
1404 }
Cary Clarkdf429f32017-11-08 11:44:31 -05001405 SkScalar distSq = SkPointPriv::DistanceToSqd(ref->fPt, check->fPt);
caryclark55888e42016-07-18 10:01:36 -07001406 if (distSqBest > distSq && (refSeg != check->segment()
1407 || !refSeg->ptsDisjoint(*ref, *check))) {
1408 distSqBest = distSq;
1409 refBest = ref;
1410 checkBest = check;
1411 }
Cary Clark28da2832017-03-21 10:30:50 -04001412 if (--escapeHatch <= 0) {
1413 return false;
1414 }
caryclark55888e42016-07-18 10:01:36 -07001415 } while ((check = check->next()) != checkHead);
Cary Clark28da2832017-03-21 10:30:50 -04001416 nextRef:
caryclark55888e42016-07-18 10:01:36 -07001417 ;
1418 } while ((ref = ref->next()) != refHead);
1419doneCheckingDistance:
Cary Clark28da2832017-03-21 10:30:50 -04001420 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001421 checkBest->fPt);
Cary Clark28da2832017-03-21 10:30:50 -04001422 return true;
caryclark55888e42016-07-18 10:01:36 -07001423}
1424
1425// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001426// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
Cary Clark28da2832017-03-21 10:30:50 -04001427bool SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001428 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001429 // release undeleted spans pointing to this seg that are linked to the primary span
1430 SkOpSpanBase* spanBase = &fHead;
Cary Clark43938b82017-10-18 08:47:32 -04001431 int escapeHatch = 9999; // the largest count for a regular test is 50; for a fuzzer, 500
caryclark54359292015-03-26 07:52:43 -07001432 do {
caryclark55888e42016-07-18 10:01:36 -07001433 SkOpPtT* ptT = spanBase->ptT();
1434 const SkOpPtT* headPtT = ptT;
1435 while ((ptT = ptT->next()) != headPtT) {
Cary Clark43938b82017-10-18 08:47:32 -04001436 if (!--escapeHatch) {
1437 return false;
1438 }
caryclark55888e42016-07-18 10:01:36 -07001439 SkOpSpanBase* test = ptT->span();
1440 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1441 && test->ptT() == ptT) {
1442 if (test->final()) {
1443 if (spanBase == &fHead) {
1444 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001445 return true;
caryclark55888e42016-07-18 10:01:36 -07001446 }
1447 spanBase->upCast()->release(ptT);
1448 } else if (test->prev()) {
1449 test->upCast()->release(headPtT);
1450 }
1451 break;
caryclark54359292015-03-26 07:52:43 -07001452 }
reed0dc4dd62015-03-24 13:55:33 -07001453 }
caryclark55888e42016-07-18 10:01:36 -07001454 spanBase = spanBase->upCast()->next();
1455 } while (!spanBase->final());
caryclark55888e42016-07-18 10:01:36 -07001456 // This loop looks for adjacent spans which are near by
1457 spanBase = &fHead;
1458 do { // iterate through all spans associated with start
1459 SkOpSpanBase* test = spanBase->upCast()->next();
Cary Clark28da2832017-03-21 10:30:50 -04001460 bool found;
1461 if (!this->spansNearby(spanBase, test, &found)) {
1462 return false;
1463 }
1464 if (found) {
caryclark55888e42016-07-18 10:01:36 -07001465 if (test->final()) {
1466 if (spanBase->prev()) {
1467 test->merge(spanBase->upCast());
1468 } else {
1469 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001470 return true;
caryclark55888e42016-07-18 10:01:36 -07001471 }
1472 } else {
1473 spanBase->merge(test->upCast());
1474 }
1475 }
1476 spanBase = test;
1477 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001478 debugValidate();
Cary Clark28da2832017-03-21 10:30:50 -04001479 return true;
reed0dc4dd62015-03-24 13:55:33 -07001480}
1481
caryclark54359292015-03-26 07:52:43 -07001482bool SkOpSegment::operand() const {
1483 return fContour->operand();
1484}
1485
1486bool SkOpSegment::oppXor() const {
1487 return fContour->oppXor();
1488}
1489
1490bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1491 if (fVerb == SkPath::kLine_Verb) {
1492 return false;
1493 }
1494 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1495 // hits in two places with very different t values.
1496 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1497 // 'controls contained by ends' could avoid this check for common curves
1498 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1499 // on the other hand, the below check is relatively inexpensive
1500 double midT = (t1 + t2) / 2;
1501 SkPoint midPt = this->ptAtT(midT);
Cary Clarkdf429f32017-11-08 11:44:31 -05001502 double seDistSq = SkTMax(SkPointPriv::DistanceToSqd(pt1, pt2) * 2, FLT_EPSILON * 2);
1503 return SkPointPriv::DistanceToSqd(midPt, pt1) > seDistSq ||
1504 SkPointPriv::DistanceToSqd(midPt, pt2) > seDistSq;
caryclark54359292015-03-26 07:52:43 -07001505}
1506
1507void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1508 int* maxWinding, int* sumWinding) {
1509 int deltaSum = SpanSign(start, end);
1510 *maxWinding = *sumMiWinding;
1511 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001512 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001513}
1514
1515void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1516 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1517 int* oppSumWinding) {
1518 int deltaSum = SpanSign(start, end);
1519 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001520 if (operand()) {
1521 *maxWinding = *sumSuWinding;
1522 *sumWinding = *sumSuWinding -= deltaSum;
1523 *oppMaxWinding = *sumMiWinding;
1524 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1525 } else {
1526 *maxWinding = *sumMiWinding;
1527 *sumWinding = *sumMiWinding -= deltaSum;
1528 *oppMaxWinding = *sumSuWinding;
1529 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1530 }
bungeman60e0fee2015-08-26 05:15:46 -07001531 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1532 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001533}
1534
caryclarkb36a3cd2016-10-18 07:59:44 -07001535bool SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001536 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001537 do {
caryclark54359292015-03-26 07:52:43 -07001538 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001539 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001540 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001541 continue;
1542 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001543#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001544 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001545#endif
caryclark54359292015-03-26 07:52:43 -07001546 SkOpAngle* baseAngle = fromAngle;
1547 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001548#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001549 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1550 span->debugID());
1551 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001552#endif
caryclarkb36a3cd2016-10-18 07:59:44 -07001553 FAIL_IF(!fromAngle->insert(toAngle));
caryclark54359292015-03-26 07:52:43 -07001554 } else if (!fromAngle) {
1555 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001556 }
caryclark54359292015-03-26 07:52:43 -07001557 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001558 do {
caryclark54359292015-03-26 07:52:43 -07001559 SkOpSpanBase* oSpan = ptT->span();
1560 if (oSpan == span) {
1561 continue;
1562 }
1563 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001564 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001565#if DEBUG_ANGLE
1566 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001567 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1568 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001569 wroteAfterHeader = true;
1570 }
1571#endif
caryclark54359292015-03-26 07:52:43 -07001572 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001573 baseAngle->insert(oAngle);
1574 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001575 }
caryclark54359292015-03-26 07:52:43 -07001576 if (!oSpan->final()) {
1577 oAngle = oSpan->upCast()->toAngle();
1578 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001579#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001580 if (!wroteAfterHeader) {
1581 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1582 span->t(), span->debugID());
1583 wroteAfterHeader = true;
1584 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001585#endif
caryclark54359292015-03-26 07:52:43 -07001586 if (!oAngle->loopContains(baseAngle)) {
1587 baseAngle->insert(oAngle);
1588 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001589 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001590 }
caryclark54359292015-03-26 07:52:43 -07001591 } while ((ptT = ptT->next()) != stopPtT);
1592 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001593 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001594 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001595 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001596 }
halcanary96fcdcc2015-08-27 07:41:13 -07001597 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001598 }
1599#if DEBUG_SORT
1600 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1601#endif
caryclark54359292015-03-26 07:52:43 -07001602 } while (!span->final() && (span = span->upCast()->next()));
caryclarkb36a3cd2016-10-18 07:59:44 -07001603 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +00001604}
1605
caryclark54359292015-03-26 07:52:43 -07001606bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001607 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001608 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001609 const SkOpPtT& startPtT = *start->ptT();
1610 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001611 SkDEBUGCODE(edge->fVerb = fVerb);
1612 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001613 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001614 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001615 if (fVerb == SkPath::kLine_Verb) {
1616 return false;
1617 }
caryclark54359292015-03-26 07:52:43 -07001618 double startT = startPtT.fT;
1619 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001620 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1621 // don't compute midpoints if we already have them
1622 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001623 edge->fLine[1].set(fPts[1]);
1624 return false;
1625 }
1626 if (fVerb == SkPath::kConic_Verb) {
1627 edge->fConic[1].set(fPts[1]);
1628 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001629 return false;
1630 }
1631 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001632 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001633 edge->fCubic[1].set(fPts[1]);
1634 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001635 return false;
1636 }
caryclark1049f122015-04-20 08:31:59 -07001637 edge->fCubic[1].set(fPts[2]);
1638 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001639 return false;
1640 }
1641 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001642 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1643 } else if (fVerb == SkPath::kConic_Verb) {
1644 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1645 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001646 } else {
1647 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001648 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001649 }
1650 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001651}
1652
caryclark27c8eb82015-07-06 11:38:33 -07001653bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001654 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001655 // average t, find mid pt
1656 double midT = (prior->t() + spanBase->t()) / 2;
1657 SkPoint midPt = this->ptAtT(midT);
1658 bool coincident = true;
1659 // if the mid pt is not near either end pt, project perpendicular through opp seg
1660 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1661 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001662 if (priorPtT->span() == ptT->span()) {
1663 return false;
1664 }
caryclark27c8eb82015-07-06 11:38:33 -07001665 coincident = false;
1666 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001667 SkDCurve curvePart;
1668 this->subDivide(prior, spanBase, &curvePart);
1669 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1670 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1671 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1672 SkDCurve oppPart;
1673 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1674 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001675 // measure distance and see if it's small enough to denote coincidence
1676 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001677 if (!between(0, i[0][index], 1)) {
1678 continue;
1679 }
caryclark27c8eb82015-07-06 11:38:33 -07001680 SkDPoint oppPt = i.pt(index);
caryclark30b9fdd2016-08-31 14:36:29 -07001681 if (oppPt.approximatelyDEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001682 // the coincidence can occur at almost any angle
1683 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001684 }
1685 }
1686 }
1687 return coincident;
1688}
1689
Cary Clarkab2d73b2016-12-16 17:17:25 -05001690SkOpSpan* SkOpSegment::undoneSpan() {
1691 SkOpSpan* span = &fHead;
1692 SkOpSpanBase* next;
caryclark54359292015-03-26 07:52:43 -07001693 do {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001694 next = span->next();
caryclark54359292015-03-26 07:52:43 -07001695 if (!span->done()) {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001696 return span;
reed0dc4dd62015-03-24 13:55:33 -07001697 }
Cary Clarkab2d73b2016-12-16 17:17:25 -05001698 } while (!next->final() && (span = next->upCast()));
1699 return nullptr;
reed0dc4dd62015-03-24 13:55:33 -07001700}
1701
caryclark54359292015-03-26 07:52:43 -07001702int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1703 const SkOpSpan* lesser = start->starter(end);
1704 int oppWinding = lesser->oppSum();
1705 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001706 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1707 && oppWinding != SK_MaxS32) {
1708 oppWinding -= oppSpanWinding;
1709 }
1710 return oppWinding;
1711}
1712
1713int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001714 const SkOpSpanBase* startSpan = angle->start();
1715 const SkOpSpanBase* endSpan = angle->end();
1716 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001717}
1718
1719int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001720 const SkOpSpanBase* startSpan = angle->start();
1721 const SkOpSpanBase* endSpan = angle->end();
1722 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001723}
1724
caryclark624637c2015-05-11 07:21:27 -07001725int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1726 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001727 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001728 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001729 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001730 }
1731 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001732 return winding;
1733 }
caryclark54359292015-03-26 07:52:43 -07001734 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001735 if (winding && UseInnerWinding(winding - spanWinding, winding)
1736 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001737 winding -= spanWinding;
1738 }
1739 return winding;
1740}
1741
caryclark624637c2015-05-11 07:21:27 -07001742int SkOpSegment::updateWinding(SkOpAngle* angle) {
1743 SkOpSpanBase* startSpan = angle->start();
1744 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001745 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001746}
1747
caryclark624637c2015-05-11 07:21:27 -07001748int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1749 SkOpSpanBase* startSpan = angle->start();
1750 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001751 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001752}
1753
1754// OPTIMIZATION: does the following also work, and is it any faster?
1755// return outerWinding * innerWinding > 0
1756// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1757bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1758 SkASSERT(outerWinding != SK_MaxS32);
1759 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001760 int absOut = SkTAbs(outerWinding);
1761 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001762 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1763 return result;
1764}
1765
caryclark@google.com07393ca2013-04-08 11:47:37 +00001766int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001767 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1768 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001769}