blob: e35f6d0fd162f5e5a056eb4f3caf064a412b6014 [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;
caryclark54359292015-03-26 07:52:43 -0700924 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
925 if (spanStart->windSum() != SK_MinS32) {
926 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700927 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700928 this->globalState()->setWindingFailed();
Cary Clark2587f412018-07-24 12:40:10 -0400929 return true; // ... but let it succeed anyway
caryclarkdac1d172014-06-17 05:15:38 -0700930 }
caryclark54359292015-03-26 07:52:43 -0700931 } else {
Cary Clark2587f412018-07-24 12:40:10 -0400932 FAIL_IF(spanStart->windSum() != oppWinding);
caryclark54359292015-03-26 07:52:43 -0700933 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700934 }
935 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700936 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000937 }
caryclark54359292015-03-26 07:52:43 -0700938 if (this->operand() == other->operand()) {
939 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700940 } else {
caryclark54359292015-03-26 07:52:43 -0700941 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700942 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000943 }
caryclark65f55312014-11-13 06:58:52 -0800944 if (lastPtr) {
945 *lastPtr = last;
946 }
947 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000948}
949
Cary Clark2587f412018-07-24 12:40:10 -0400950bool SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle,
951 SkOpSpanBase** result) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000952 SkASSERT(angle->segment() == this);
953 if (UseInnerWinding(maxWinding, sumWinding)) {
954 maxWinding = sumWinding;
955 }
Cary Clark2587f412018-07-24 12:40:10 -0400956 if (!markAndChaseWinding(angle->start(), angle->end(), maxWinding, result)) {
957 return false;
958 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000959#if DEBUG_WINDING
Cary Clarkcadc5062018-08-06 17:24:04 -0400960 SkOpSpanBase* last = *result;
caryclark@google.com570863f2013-09-16 15:55:01 +0000961 if (last) {
caryclark54359292015-03-26 07:52:43 -0700962 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
963 last->segment()->debugID(), last->debugID());
964 if (!last->final()) {
965 SkDebugf(" windSum=");
966 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
967 }
968 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000969 }
970#endif
Cary Clark2587f412018-07-24 12:40:10 -0400971 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000972}
973
Cary Clark2587f412018-07-24 12:40:10 -0400974bool SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
975 int oppSumWinding, const SkOpAngle* angle, SkOpSpanBase** result) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000976 SkASSERT(angle->segment() == this);
977 if (UseInnerWinding(maxWinding, sumWinding)) {
978 maxWinding = sumWinding;
979 }
980 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
981 oppMaxWinding = oppSumWinding;
982 }
caryclark65f55312014-11-13 06:58:52 -0800983 // caller doesn't require that this marks anything
Cary Clark2587f412018-07-24 12:40:10 -0400984 if (!markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, result)) {
985 return false;
986 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000987#if DEBUG_WINDING
Cary Clark8762fb62018-10-16 16:06:24 -0400988 if (result) {
989 SkOpSpanBase* last = *result;
990 if (last) {
991 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
992 last->segment()->debugID(), last->debugID());
993 if (!last->final()) {
994 SkDebugf(" windSum=");
995 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
996 }
997 SkDebugf(" \n");
caryclark54359292015-03-26 07:52:43 -0700998 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000999 }
1000#endif
Cary Clark2587f412018-07-24 12:40:10 -04001001 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001002}
1003
caryclark54359292015-03-26 07:52:43 -07001004void SkOpSegment::markDone(SkOpSpan* span) {
1005 SkASSERT(this == span->segment());
1006 if (span->done()) {
1007 return;
1008 }
1009#if DEBUG_MARK_DONE
1010 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
1011#endif
1012 span->setDone(true);
1013 ++fDoneCount;
1014 debugValidate();
1015}
1016
1017bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
1018 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -07001019 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -07001020 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001021 return false;
1022 }
1023#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -07001024 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -07001025#endif
caryclark54359292015-03-26 07:52:43 -07001026 span->setWindSum(winding);
1027 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001028 return true;
1029}
1030
caryclark54359292015-03-26 07:52:43 -07001031bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
1032 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +00001033 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -07001034 if (span->done()) {
1035 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001036 }
caryclark54359292015-03-26 07:52:43 -07001037#if DEBUG_MARK_DONE
1038 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1039#endif
1040 span->setWindSum(winding);
1041 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001042 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001043 return true;
1044}
1045
caryclark54359292015-03-26 07:52:43 -07001046bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclarkef4f32a2016-08-24 09:24:18 -07001047 const SkPoint& testPt) const {
caryclark55888e42016-07-18 10:01:36 -07001048 SkASSERT(this == base->segment());
1049 if (this == testParent) {
1050 if (precisely_equal(base->fT, testT)) {
1051 return true;
1052 }
caryclark54359292015-03-26 07:52:43 -07001053 }
1054 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1055 return false;
1056 }
caryclark55888e42016-07-18 10:01:36 -07001057 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001058}
1059
1060static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1061 if (last) {
1062 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001063 }
halcanary96fcdcc2015-08-27 07:41:13 -07001064 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001065}
1066
caryclark54359292015-03-26 07:52:43 -07001067SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1068 SkOpSpanBase** last) const {
1069 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001070 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001071 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1072 SkASSERT(endSpan);
1073 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1074 SkOpSpanBase* foundSpan;
1075 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001076 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001077 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001078 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001079 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001080 }
caryclark54359292015-03-26 07:52:43 -07001081 SkOpPtT* otherPtT = endSpan->ptT()->next();
1082 other = otherPtT->segment();
1083 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001084 otherEnd = step > 0
1085 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1086 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001087 } else {
1088 int loopCount = angle->loopCount();
1089 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001090 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001091 }
1092 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001093 if (nullptr == next) {
1094 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001095 }
caryclarkdac1d172014-06-17 05:15:38 -07001096#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001097 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001098 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001099 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001100 }
caryclark54359292015-03-26 07:52:43 -07001101#endif
caryclarkdac1d172014-06-17 05:15:38 -07001102 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001103 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001104 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001105 }
caryclark343382e2016-06-29 08:18:38 -07001106 if (!otherEnd) {
1107 return nullptr;
1108 }
caryclark54359292015-03-26 07:52:43 -07001109 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001110 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001111 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001112 }
caryclark54359292015-03-26 07:52:43 -07001113 SkASSERT(*startPtr);
caryclark65b427c2014-09-18 10:32:57 -07001114// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001115 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1116 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1117 if (foundMin->windValue() != origMin->windValue()
1118 || foundMin->oppValue() != origMin->oppValue()) {
1119 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001120 }
caryclark54359292015-03-26 07:52:43 -07001121 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001122 *stepPtr = foundStep;
1123 if (minPtr) {
1124 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001125 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001126 return other;
1127}
1128
caryclark55888e42016-07-18 10:01:36 -07001129// Please keep this in sync with DebugClearVisited()
1130void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001131 // reset visited flag back to false
1132 do {
1133 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1134 while ((ptT = ptT->next()) != stopPtT) {
1135 SkOpSegment* opp = ptT->segment();
1136 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001137 }
caryclarkbca19f72015-05-13 08:23:48 -07001138 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001139}
1140
caryclark55888e42016-07-18 10:01:36 -07001141// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001142// look for pairs of undetected coincident curves
1143// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001144// Even though pairs of curves correct detect coincident runs, a run may be missed
1145// if the coincidence is a product of multiple intersections. For instance, given
1146// curves A, B, and C:
1147// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1148// the end of C that the intersection is replaced with the end of C.
1149// Even though A-B correctly do not detect an intersection at point 2,
1150// the resulting run from point 1 to point 2 is coincident on A and B.
1151bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001152 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001153 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001154 }
halcanary96fcdcc2015-08-27 07:41:13 -07001155 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001156 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001157 bool result = false;
caryclark54359292015-03-26 07:52:43 -07001158 do {
caryclarkbca19f72015-05-13 08:23:48 -07001159 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001160 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001161 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001162 if (ptT->deleted()) {
1163 continue;
1164 }
caryclark54359292015-03-26 07:52:43 -07001165 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001166 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001167 continue;
reed0dc4dd62015-03-24 13:55:33 -07001168 }
caryclarkbca19f72015-05-13 08:23:48 -07001169 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1170 if (!opp->visited()) {
1171 continue;
1172 }
1173 if (spanBase == &fHead) {
1174 continue;
1175 }
caryclark55888e42016-07-18 10:01:36 -07001176 if (ptT->segment() == this) {
1177 continue;
1178 }
caryclarkbca19f72015-05-13 08:23:48 -07001179 SkOpSpan* span = spanBase->upCastable();
1180 // FIXME?: this assumes that if the opposite segment is coincident then no more
1181 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001182 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001183 continue;
1184 }
caryclarkbca19f72015-05-13 08:23:48 -07001185 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001186 continue;
caryclark55888e42016-07-18 10:01:36 -07001187 }
halcanary96fcdcc2015-08-27 07:41:13 -07001188 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001189 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001190 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001191 SkOpSpan* priorTest = spanBase->prev();
1192 while (!priorOpp && priorTest) {
1193 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001194 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001195 if (priorPtT->deleted()) {
1196 continue;
1197 }
caryclark54359292015-03-26 07:52:43 -07001198 SkOpSegment* segment = priorPtT->span()->segment();
1199 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001200 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001201 priorOpp = opp;
1202 break;
1203 }
1204 }
caryclarkbca19f72015-05-13 08:23:48 -07001205 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001206 }
1207 if (!priorOpp) {
1208 continue;
1209 }
caryclark26ad22a2015-10-16 09:03:38 -07001210 if (priorPtT == ptT) {
1211 continue;
1212 }
caryclark54359292015-03-26 07:52:43 -07001213 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001214 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001215 bool swapped = priorPtT->fT > ptT->fT;
1216 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001217 using std::swap;
1218 swap(priorPtT, ptT);
1219 swap(oppStart, oppEnd);
caryclark54359292015-03-26 07:52:43 -07001220 }
caryclark55888e42016-07-18 10:01:36 -07001221 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1222 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1223 SkOpPtT* rootPtT = ptT->span()->ptT();
1224 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1225 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1226 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001227 goto swapBack;
1228 }
caryclark55888e42016-07-18 10:01:36 -07001229 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001230 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001231#if DEBUG_COINCIDENCE_VERBOSE
1232 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1233 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1234 rootOppEnd->debugID());
1235#endif
1236 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1237 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001238 }
caryclark55888e42016-07-18 10:01:36 -07001239#if DEBUG_COINCIDENCE
1240 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1241#endif
1242 result = true;
caryclark54359292015-03-26 07:52:43 -07001243 }
1244 swapBack:
1245 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001246 using std::swap;
1247 swap(priorPtT, ptT);
caryclark54359292015-03-26 07:52:43 -07001248 }
reed0dc4dd62015-03-24 13:55:33 -07001249 }
halcanary96fcdcc2015-08-27 07:41:13 -07001250 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001251 ClearVisited(&fHead);
1252 return result;
reed0dc4dd62015-03-24 13:55:33 -07001253}
1254
caryclark55888e42016-07-18 10:01:36 -07001255// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001256// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001257bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001258 debugValidate();
1259 SkOpSpanBase* test = &fHead;
1260 do {
1261 int addCount = test->spanAddsCount();
Cary Clark7eb01e02016-12-08 14:36:32 -05001262// FAIL_IF(addCount < 1);
1263 if (addCount <= 1) {
caryclark08bc8482015-04-24 09:08:57 -07001264 continue;
1265 }
1266 SkOpPtT* startPtT = test->ptT();
1267 SkOpPtT* testPtT = startPtT;
1268 do { // iterate through all spans associated with start
1269 SkOpSpanBase* oppSpan = testPtT->span();
1270 if (oppSpan->spanAddsCount() == addCount) {
1271 continue;
1272 }
1273 if (oppSpan->deleted()) {
1274 continue;
1275 }
1276 SkOpSegment* oppSegment = oppSpan->segment();
1277 if (oppSegment == this) {
1278 continue;
1279 }
1280 // find range of spans to consider merging
1281 SkOpSpanBase* oppPrev = oppSpan;
1282 SkOpSpanBase* oppFirst = oppSpan;
1283 while ((oppPrev = oppPrev->prev())) {
1284 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1285 break;
1286 }
1287 if (oppPrev->spanAddsCount() == addCount) {
1288 continue;
1289 }
1290 if (oppPrev->deleted()) {
1291 continue;
1292 }
1293 oppFirst = oppPrev;
1294 }
1295 SkOpSpanBase* oppNext = oppSpan;
1296 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001297 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001298 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1299 break;
1300 }
1301 if (oppNext->spanAddsCount() == addCount) {
1302 continue;
1303 }
1304 if (oppNext->deleted()) {
1305 continue;
1306 }
1307 oppLast = oppNext;
1308 }
1309 if (oppFirst == oppLast) {
1310 continue;
1311 }
1312 SkOpSpanBase* oppTest = oppFirst;
1313 do {
1314 if (oppTest == oppSpan) {
1315 continue;
1316 }
1317 // check to see if the candidate meets specific criteria:
1318 // it contains spans of segments in test's loop but not including 'this'
1319 SkOpPtT* oppStartPtT = oppTest->ptT();
1320 SkOpPtT* oppPtT = oppStartPtT;
1321 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1322 SkOpSegment* oppPtTSegment = oppPtT->segment();
1323 if (oppPtTSegment == this) {
1324 goto tryNextSpan;
1325 }
1326 SkOpPtT* matchPtT = startPtT;
1327 do {
1328 if (matchPtT->segment() == oppPtTSegment) {
1329 goto foundMatch;
1330 }
1331 } while ((matchPtT = matchPtT->next()) != startPtT);
1332 goto tryNextSpan;
1333 foundMatch: // merge oppTest and oppSpan
1334 oppSegment->debugValidate();
caryclark30b9fdd2016-08-31 14:36:29 -07001335 oppTest->mergeMatches(oppSpan);
1336 oppTest->addOpp(oppSpan);
caryclark08bc8482015-04-24 09:08:57 -07001337 oppSegment->debugValidate();
1338 goto checkNextSpan;
1339 }
caryclark55888e42016-07-18 10:01:36 -07001340 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001341 ;
1342 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1343 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001344checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001345 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001346 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001347 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001348 return true;
caryclark08bc8482015-04-24 09:08:57 -07001349}
1350
caryclark55888e42016-07-18 10:01:36 -07001351// adjacent spans may have points close by
Cary Clark28da2832017-03-21 10:30:50 -04001352bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan,
1353 bool* found) const {
caryclark55888e42016-07-18 10:01:36 -07001354 const SkOpPtT* refHead = refSpan->ptT();
1355 const SkOpPtT* checkHead = checkSpan->ptT();
1356// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
caryclark30b9fdd2016-08-31 14:36:29 -07001357 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
caryclark55888e42016-07-18 10:01:36 -07001358#if DEBUG_COINCIDENCE
1359 // verify that no combination of points are close
1360 const SkOpPtT* dBugRef = refHead;
1361 do {
1362 const SkOpPtT* dBugCheck = checkHead;
1363 do {
caryclark30b9fdd2016-08-31 14:36:29 -07001364 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
caryclark55888e42016-07-18 10:01:36 -07001365 dBugCheck = dBugCheck->next();
1366 } while (dBugCheck != checkHead);
1367 dBugRef = dBugRef->next();
1368 } while (dBugRef != refHead);
1369#endif
Cary Clark28da2832017-03-21 10:30:50 -04001370 *found = false;
1371 return true;
caryclark55888e42016-07-18 10:01:36 -07001372 }
1373 // check only unique points
1374 SkScalar distSqBest = SK_ScalarMax;
1375 const SkOpPtT* refBest = nullptr;
1376 const SkOpPtT* checkBest = nullptr;
1377 const SkOpPtT* ref = refHead;
1378 do {
1379 if (ref->deleted()) {
1380 continue;
1381 }
1382 while (ref->ptAlreadySeen(refHead)) {
1383 ref = ref->next();
1384 if (ref == refHead) {
1385 goto doneCheckingDistance;
1386 }
1387 }
1388 const SkOpPtT* check = checkHead;
1389 const SkOpSegment* refSeg = ref->segment();
Cary Clark28da2832017-03-21 10:30:50 -04001390 int escapeHatch = 100000; // defend against infinite loops
caryclark55888e42016-07-18 10:01:36 -07001391 do {
1392 if (check->deleted()) {
1393 continue;
1394 }
1395 while (check->ptAlreadySeen(checkHead)) {
1396 check = check->next();
1397 if (check == checkHead) {
1398 goto nextRef;
1399 }
1400 }
Cary Clarkdf429f32017-11-08 11:44:31 -05001401 SkScalar distSq = SkPointPriv::DistanceToSqd(ref->fPt, check->fPt);
caryclark55888e42016-07-18 10:01:36 -07001402 if (distSqBest > distSq && (refSeg != check->segment()
1403 || !refSeg->ptsDisjoint(*ref, *check))) {
1404 distSqBest = distSq;
1405 refBest = ref;
1406 checkBest = check;
1407 }
Cary Clark28da2832017-03-21 10:30:50 -04001408 if (--escapeHatch <= 0) {
1409 return false;
1410 }
caryclark55888e42016-07-18 10:01:36 -07001411 } while ((check = check->next()) != checkHead);
Cary Clark28da2832017-03-21 10:30:50 -04001412 nextRef:
caryclark55888e42016-07-18 10:01:36 -07001413 ;
1414 } while ((ref = ref->next()) != refHead);
1415doneCheckingDistance:
Cary Clark28da2832017-03-21 10:30:50 -04001416 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001417 checkBest->fPt);
Cary Clark28da2832017-03-21 10:30:50 -04001418 return true;
caryclark55888e42016-07-18 10:01:36 -07001419}
1420
1421// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001422// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
Cary Clark28da2832017-03-21 10:30:50 -04001423bool SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001424 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001425 // release undeleted spans pointing to this seg that are linked to the primary span
1426 SkOpSpanBase* spanBase = &fHead;
Cary Clark43938b82017-10-18 08:47:32 -04001427 int escapeHatch = 9999; // the largest count for a regular test is 50; for a fuzzer, 500
caryclark54359292015-03-26 07:52:43 -07001428 do {
caryclark55888e42016-07-18 10:01:36 -07001429 SkOpPtT* ptT = spanBase->ptT();
1430 const SkOpPtT* headPtT = ptT;
1431 while ((ptT = ptT->next()) != headPtT) {
Cary Clark43938b82017-10-18 08:47:32 -04001432 if (!--escapeHatch) {
1433 return false;
1434 }
caryclark55888e42016-07-18 10:01:36 -07001435 SkOpSpanBase* test = ptT->span();
1436 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1437 && test->ptT() == ptT) {
1438 if (test->final()) {
1439 if (spanBase == &fHead) {
1440 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001441 return true;
caryclark55888e42016-07-18 10:01:36 -07001442 }
1443 spanBase->upCast()->release(ptT);
1444 } else if (test->prev()) {
1445 test->upCast()->release(headPtT);
1446 }
1447 break;
caryclark54359292015-03-26 07:52:43 -07001448 }
reed0dc4dd62015-03-24 13:55:33 -07001449 }
caryclark55888e42016-07-18 10:01:36 -07001450 spanBase = spanBase->upCast()->next();
1451 } while (!spanBase->final());
caryclark55888e42016-07-18 10:01:36 -07001452 // This loop looks for adjacent spans which are near by
1453 spanBase = &fHead;
1454 do { // iterate through all spans associated with start
1455 SkOpSpanBase* test = spanBase->upCast()->next();
Cary Clark28da2832017-03-21 10:30:50 -04001456 bool found;
1457 if (!this->spansNearby(spanBase, test, &found)) {
1458 return false;
1459 }
1460 if (found) {
caryclark55888e42016-07-18 10:01:36 -07001461 if (test->final()) {
1462 if (spanBase->prev()) {
1463 test->merge(spanBase->upCast());
1464 } else {
1465 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001466 return true;
caryclark55888e42016-07-18 10:01:36 -07001467 }
1468 } else {
1469 spanBase->merge(test->upCast());
1470 }
1471 }
1472 spanBase = test;
1473 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001474 debugValidate();
Cary Clark28da2832017-03-21 10:30:50 -04001475 return true;
reed0dc4dd62015-03-24 13:55:33 -07001476}
1477
caryclark54359292015-03-26 07:52:43 -07001478bool SkOpSegment::operand() const {
1479 return fContour->operand();
1480}
1481
1482bool SkOpSegment::oppXor() const {
1483 return fContour->oppXor();
1484}
1485
1486bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1487 if (fVerb == SkPath::kLine_Verb) {
1488 return false;
1489 }
1490 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1491 // hits in two places with very different t values.
1492 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1493 // 'controls contained by ends' could avoid this check for common curves
1494 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1495 // on the other hand, the below check is relatively inexpensive
1496 double midT = (t1 + t2) / 2;
1497 SkPoint midPt = this->ptAtT(midT);
Cary Clarkdf429f32017-11-08 11:44:31 -05001498 double seDistSq = SkTMax(SkPointPriv::DistanceToSqd(pt1, pt2) * 2, FLT_EPSILON * 2);
1499 return SkPointPriv::DistanceToSqd(midPt, pt1) > seDistSq ||
1500 SkPointPriv::DistanceToSqd(midPt, pt2) > seDistSq;
caryclark54359292015-03-26 07:52:43 -07001501}
1502
1503void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1504 int* maxWinding, int* sumWinding) {
1505 int deltaSum = SpanSign(start, end);
1506 *maxWinding = *sumMiWinding;
1507 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001508 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001509}
1510
1511void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1512 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1513 int* oppSumWinding) {
1514 int deltaSum = SpanSign(start, end);
1515 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001516 if (operand()) {
1517 *maxWinding = *sumSuWinding;
1518 *sumWinding = *sumSuWinding -= deltaSum;
1519 *oppMaxWinding = *sumMiWinding;
1520 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1521 } else {
1522 *maxWinding = *sumMiWinding;
1523 *sumWinding = *sumMiWinding -= deltaSum;
1524 *oppMaxWinding = *sumSuWinding;
1525 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1526 }
bungeman60e0fee2015-08-26 05:15:46 -07001527 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1528 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001529}
1530
caryclarkb36a3cd2016-10-18 07:59:44 -07001531bool SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001532 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001533 do {
caryclark54359292015-03-26 07:52:43 -07001534 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001535 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001536 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001537 continue;
1538 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001539#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001540 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001541#endif
caryclark54359292015-03-26 07:52:43 -07001542 SkOpAngle* baseAngle = fromAngle;
1543 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001544#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001545 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1546 span->debugID());
1547 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001548#endif
caryclarkb36a3cd2016-10-18 07:59:44 -07001549 FAIL_IF(!fromAngle->insert(toAngle));
caryclark54359292015-03-26 07:52:43 -07001550 } else if (!fromAngle) {
1551 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001552 }
caryclark54359292015-03-26 07:52:43 -07001553 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001554 do {
caryclark54359292015-03-26 07:52:43 -07001555 SkOpSpanBase* oSpan = ptT->span();
1556 if (oSpan == span) {
1557 continue;
1558 }
1559 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001560 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001561#if DEBUG_ANGLE
1562 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001563 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1564 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001565 wroteAfterHeader = true;
1566 }
1567#endif
caryclark54359292015-03-26 07:52:43 -07001568 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001569 baseAngle->insert(oAngle);
1570 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001571 }
caryclark54359292015-03-26 07:52:43 -07001572 if (!oSpan->final()) {
1573 oAngle = oSpan->upCast()->toAngle();
1574 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001575#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001576 if (!wroteAfterHeader) {
1577 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1578 span->t(), span->debugID());
1579 wroteAfterHeader = true;
1580 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001581#endif
caryclark54359292015-03-26 07:52:43 -07001582 if (!oAngle->loopContains(baseAngle)) {
1583 baseAngle->insert(oAngle);
1584 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001585 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001586 }
caryclark54359292015-03-26 07:52:43 -07001587 } while ((ptT = ptT->next()) != stopPtT);
1588 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001589 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001590 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001591 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001592 }
halcanary96fcdcc2015-08-27 07:41:13 -07001593 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001594 }
1595#if DEBUG_SORT
1596 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1597#endif
caryclark54359292015-03-26 07:52:43 -07001598 } while (!span->final() && (span = span->upCast()->next()));
caryclarkb36a3cd2016-10-18 07:59:44 -07001599 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +00001600}
1601
caryclark54359292015-03-26 07:52:43 -07001602bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001603 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001604 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001605 const SkOpPtT& startPtT = *start->ptT();
1606 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001607 SkDEBUGCODE(edge->fVerb = fVerb);
1608 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001609 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001610 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001611 if (fVerb == SkPath::kLine_Verb) {
1612 return false;
1613 }
caryclark54359292015-03-26 07:52:43 -07001614 double startT = startPtT.fT;
1615 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001616 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1617 // don't compute midpoints if we already have them
1618 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001619 edge->fLine[1].set(fPts[1]);
1620 return false;
1621 }
1622 if (fVerb == SkPath::kConic_Verb) {
1623 edge->fConic[1].set(fPts[1]);
1624 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001625 return false;
1626 }
1627 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001628 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001629 edge->fCubic[1].set(fPts[1]);
1630 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001631 return false;
1632 }
caryclark1049f122015-04-20 08:31:59 -07001633 edge->fCubic[1].set(fPts[2]);
1634 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001635 return false;
1636 }
1637 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001638 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1639 } else if (fVerb == SkPath::kConic_Verb) {
1640 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1641 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001642 } else {
1643 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001644 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001645 }
1646 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001647}
1648
caryclark27c8eb82015-07-06 11:38:33 -07001649bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001650 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001651 // average t, find mid pt
1652 double midT = (prior->t() + spanBase->t()) / 2;
1653 SkPoint midPt = this->ptAtT(midT);
1654 bool coincident = true;
1655 // if the mid pt is not near either end pt, project perpendicular through opp seg
1656 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1657 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001658 if (priorPtT->span() == ptT->span()) {
1659 return false;
1660 }
caryclark27c8eb82015-07-06 11:38:33 -07001661 coincident = false;
1662 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001663 SkDCurve curvePart;
1664 this->subDivide(prior, spanBase, &curvePart);
1665 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1666 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1667 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1668 SkDCurve oppPart;
1669 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1670 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001671 // measure distance and see if it's small enough to denote coincidence
1672 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001673 if (!between(0, i[0][index], 1)) {
1674 continue;
1675 }
caryclark27c8eb82015-07-06 11:38:33 -07001676 SkDPoint oppPt = i.pt(index);
caryclark30b9fdd2016-08-31 14:36:29 -07001677 if (oppPt.approximatelyDEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001678 // the coincidence can occur at almost any angle
1679 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001680 }
1681 }
1682 }
1683 return coincident;
1684}
1685
Cary Clarkab2d73b2016-12-16 17:17:25 -05001686SkOpSpan* SkOpSegment::undoneSpan() {
1687 SkOpSpan* span = &fHead;
1688 SkOpSpanBase* next;
caryclark54359292015-03-26 07:52:43 -07001689 do {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001690 next = span->next();
caryclark54359292015-03-26 07:52:43 -07001691 if (!span->done()) {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001692 return span;
reed0dc4dd62015-03-24 13:55:33 -07001693 }
Cary Clarkab2d73b2016-12-16 17:17:25 -05001694 } while (!next->final() && (span = next->upCast()));
1695 return nullptr;
reed0dc4dd62015-03-24 13:55:33 -07001696}
1697
caryclark54359292015-03-26 07:52:43 -07001698int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1699 const SkOpSpan* lesser = start->starter(end);
1700 int oppWinding = lesser->oppSum();
1701 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001702 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1703 && oppWinding != SK_MaxS32) {
1704 oppWinding -= oppSpanWinding;
1705 }
1706 return oppWinding;
1707}
1708
1709int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001710 const SkOpSpanBase* startSpan = angle->start();
1711 const SkOpSpanBase* endSpan = angle->end();
1712 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001713}
1714
1715int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001716 const SkOpSpanBase* startSpan = angle->start();
1717 const SkOpSpanBase* endSpan = angle->end();
1718 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001719}
1720
caryclark624637c2015-05-11 07:21:27 -07001721int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1722 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001723 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001724 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001725 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001726 }
1727 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001728 return winding;
1729 }
caryclark54359292015-03-26 07:52:43 -07001730 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001731 if (winding && UseInnerWinding(winding - spanWinding, winding)
1732 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001733 winding -= spanWinding;
1734 }
1735 return winding;
1736}
1737
caryclark624637c2015-05-11 07:21:27 -07001738int SkOpSegment::updateWinding(SkOpAngle* angle) {
1739 SkOpSpanBase* startSpan = angle->start();
1740 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001741 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001742}
1743
caryclark624637c2015-05-11 07:21:27 -07001744int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1745 SkOpSpanBase* startSpan = angle->start();
1746 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001747 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001748}
1749
1750// OPTIMIZATION: does the following also work, and is it any faster?
1751// return outerWinding * innerWinding > 0
1752// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1753bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1754 SkASSERT(outerWinding != SK_MaxS32);
1755 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001756 int absOut = SkTAbs(outerWinding);
1757 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001758 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1759 return result;
1760}
1761
caryclark@google.com07393ca2013-04-08 11:47:37 +00001762int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001763 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1764 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001765}