blob: 62bce964882a7d989a1bdd752c097fe876cd169d [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;
caryclark54359292015-03-26 07:52:43 -0700899 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
900 if (spanStart->windSum() != SK_MinS32) {
caryclarkb36a3cd2016-10-18 07:59:44 -0700901// SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive?
caryclarkdac1d172014-06-17 05:15:38 -0700902 SkASSERT(!last);
903 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000904 }
caryclark54359292015-03-26 07:52:43 -0700905 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000906 }
caryclark65f55312014-11-13 06:58:52 -0800907 if (lastPtr) {
908 *lastPtr = last;
909 }
910 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000911}
912
caryclark54359292015-03-26 07:52:43 -0700913bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
914 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
915 SkOpSpan* spanStart = start->starter(end);
916 int step = start->step(end);
917 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700918 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000919 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700920 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
921 if (spanStart->windSum() != SK_MinS32) {
922 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700923 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700924 this->globalState()->setWindingFailed();
Cary Clark2587f412018-07-24 12:40:10 -0400925 return true; // ... but let it succeed anyway
caryclarkdac1d172014-06-17 05:15:38 -0700926 }
caryclark54359292015-03-26 07:52:43 -0700927 } else {
Cary Clark2587f412018-07-24 12:40:10 -0400928 FAIL_IF(spanStart->windSum() != oppWinding);
caryclark54359292015-03-26 07:52:43 -0700929 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700930 }
931 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700932 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000933 }
caryclark54359292015-03-26 07:52:43 -0700934 if (this->operand() == other->operand()) {
935 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700936 } else {
caryclark54359292015-03-26 07:52:43 -0700937 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700938 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000939 }
caryclark65f55312014-11-13 06:58:52 -0800940 if (lastPtr) {
941 *lastPtr = last;
942 }
943 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000944}
945
Cary Clark2587f412018-07-24 12:40:10 -0400946bool SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle,
947 SkOpSpanBase** result) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000948 SkASSERT(angle->segment() == this);
949 if (UseInnerWinding(maxWinding, sumWinding)) {
950 maxWinding = sumWinding;
951 }
Cary Clark2587f412018-07-24 12:40:10 -0400952 if (!markAndChaseWinding(angle->start(), angle->end(), maxWinding, result)) {
953 return false;
954 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000955#if DEBUG_WINDING
Cary Clarkcadc5062018-08-06 17:24:04 -0400956 SkOpSpanBase* last = *result;
caryclark@google.com570863f2013-09-16 15:55:01 +0000957 if (last) {
caryclark54359292015-03-26 07:52:43 -0700958 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
959 last->segment()->debugID(), last->debugID());
960 if (!last->final()) {
961 SkDebugf(" windSum=");
962 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
963 }
964 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000965 }
966#endif
Cary Clark2587f412018-07-24 12:40:10 -0400967 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000968}
969
Cary Clark2587f412018-07-24 12:40:10 -0400970bool SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
971 int oppSumWinding, const SkOpAngle* angle, SkOpSpanBase** result) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000972 SkASSERT(angle->segment() == this);
973 if (UseInnerWinding(maxWinding, sumWinding)) {
974 maxWinding = sumWinding;
975 }
976 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
977 oppMaxWinding = oppSumWinding;
978 }
caryclark65f55312014-11-13 06:58:52 -0800979 // caller doesn't require that this marks anything
Cary Clark2587f412018-07-24 12:40:10 -0400980 if (!markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, result)) {
981 return false;
982 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000983#if DEBUG_WINDING
Cary Clarkcadc5062018-08-06 17:24:04 -0400984 SkOpSpanBase* last = *result;
caryclark@google.com570863f2013-09-16 15:55:01 +0000985 if (last) {
caryclark54359292015-03-26 07:52:43 -0700986 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
987 last->segment()->debugID(), last->debugID());
988 if (!last->final()) {
989 SkDebugf(" windSum=");
990 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
991 }
992 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000993 }
994#endif
Cary Clark2587f412018-07-24 12:40:10 -0400995 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000996}
997
caryclark54359292015-03-26 07:52:43 -0700998void SkOpSegment::markDone(SkOpSpan* span) {
999 SkASSERT(this == span->segment());
1000 if (span->done()) {
1001 return;
1002 }
1003#if DEBUG_MARK_DONE
1004 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
1005#endif
1006 span->setDone(true);
1007 ++fDoneCount;
1008 debugValidate();
1009}
1010
1011bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
1012 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -07001013 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -07001014 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001015 return false;
1016 }
1017#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -07001018 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -07001019#endif
caryclark54359292015-03-26 07:52:43 -07001020 span->setWindSum(winding);
1021 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001022 return true;
1023}
1024
caryclark54359292015-03-26 07:52:43 -07001025bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
1026 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +00001027 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -07001028 if (span->done()) {
1029 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001030 }
caryclark54359292015-03-26 07:52:43 -07001031#if DEBUG_MARK_DONE
1032 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1033#endif
1034 span->setWindSum(winding);
1035 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001036 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001037 return true;
1038}
1039
caryclark54359292015-03-26 07:52:43 -07001040bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclarkef4f32a2016-08-24 09:24:18 -07001041 const SkPoint& testPt) const {
caryclark55888e42016-07-18 10:01:36 -07001042 SkASSERT(this == base->segment());
1043 if (this == testParent) {
1044 if (precisely_equal(base->fT, testT)) {
1045 return true;
1046 }
caryclark54359292015-03-26 07:52:43 -07001047 }
1048 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1049 return false;
1050 }
caryclark55888e42016-07-18 10:01:36 -07001051 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001052}
1053
1054static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1055 if (last) {
1056 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001057 }
halcanary96fcdcc2015-08-27 07:41:13 -07001058 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001059}
1060
caryclark54359292015-03-26 07:52:43 -07001061SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1062 SkOpSpanBase** last) const {
1063 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001064 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001065 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1066 SkASSERT(endSpan);
1067 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1068 SkOpSpanBase* foundSpan;
1069 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001070 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001071 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001072 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001073 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001074 }
caryclark54359292015-03-26 07:52:43 -07001075 SkOpPtT* otherPtT = endSpan->ptT()->next();
1076 other = otherPtT->segment();
1077 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001078 otherEnd = step > 0
1079 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1080 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001081 } else {
1082 int loopCount = angle->loopCount();
1083 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001084 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001085 }
1086 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001087 if (nullptr == next) {
1088 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001089 }
caryclarkdac1d172014-06-17 05:15:38 -07001090#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001091 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001092 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001093 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001094 }
caryclark54359292015-03-26 07:52:43 -07001095#endif
caryclarkdac1d172014-06-17 05:15:38 -07001096 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001097 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001098 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001099 }
caryclark343382e2016-06-29 08:18:38 -07001100 if (!otherEnd) {
1101 return nullptr;
1102 }
caryclark54359292015-03-26 07:52:43 -07001103 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001104 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001105 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001106 }
caryclark54359292015-03-26 07:52:43 -07001107 SkASSERT(*startPtr);
caryclark65b427c2014-09-18 10:32:57 -07001108// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001109 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1110 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1111 if (foundMin->windValue() != origMin->windValue()
1112 || foundMin->oppValue() != origMin->oppValue()) {
1113 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001114 }
caryclark54359292015-03-26 07:52:43 -07001115 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001116 *stepPtr = foundStep;
1117 if (minPtr) {
1118 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001119 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001120 return other;
1121}
1122
caryclark55888e42016-07-18 10:01:36 -07001123// Please keep this in sync with DebugClearVisited()
1124void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001125 // reset visited flag back to false
1126 do {
1127 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1128 while ((ptT = ptT->next()) != stopPtT) {
1129 SkOpSegment* opp = ptT->segment();
1130 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001131 }
caryclarkbca19f72015-05-13 08:23:48 -07001132 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001133}
1134
caryclark55888e42016-07-18 10:01:36 -07001135// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001136// look for pairs of undetected coincident curves
1137// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001138// Even though pairs of curves correct detect coincident runs, a run may be missed
1139// if the coincidence is a product of multiple intersections. For instance, given
1140// curves A, B, and C:
1141// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1142// the end of C that the intersection is replaced with the end of C.
1143// Even though A-B correctly do not detect an intersection at point 2,
1144// the resulting run from point 1 to point 2 is coincident on A and B.
1145bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001146 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001147 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001148 }
halcanary96fcdcc2015-08-27 07:41:13 -07001149 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001150 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001151 bool result = false;
caryclark54359292015-03-26 07:52:43 -07001152 do {
caryclarkbca19f72015-05-13 08:23:48 -07001153 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001154 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001155 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001156 if (ptT->deleted()) {
1157 continue;
1158 }
caryclark54359292015-03-26 07:52:43 -07001159 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001160 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001161 continue;
reed0dc4dd62015-03-24 13:55:33 -07001162 }
caryclarkbca19f72015-05-13 08:23:48 -07001163 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1164 if (!opp->visited()) {
1165 continue;
1166 }
1167 if (spanBase == &fHead) {
1168 continue;
1169 }
caryclark55888e42016-07-18 10:01:36 -07001170 if (ptT->segment() == this) {
1171 continue;
1172 }
caryclarkbca19f72015-05-13 08:23:48 -07001173 SkOpSpan* span = spanBase->upCastable();
1174 // FIXME?: this assumes that if the opposite segment is coincident then no more
1175 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001176 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001177 continue;
1178 }
caryclarkbca19f72015-05-13 08:23:48 -07001179 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001180 continue;
caryclark55888e42016-07-18 10:01:36 -07001181 }
halcanary96fcdcc2015-08-27 07:41:13 -07001182 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001183 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001184 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001185 SkOpSpan* priorTest = spanBase->prev();
1186 while (!priorOpp && priorTest) {
1187 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001188 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001189 if (priorPtT->deleted()) {
1190 continue;
1191 }
caryclark54359292015-03-26 07:52:43 -07001192 SkOpSegment* segment = priorPtT->span()->segment();
1193 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001194 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001195 priorOpp = opp;
1196 break;
1197 }
1198 }
caryclarkbca19f72015-05-13 08:23:48 -07001199 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001200 }
1201 if (!priorOpp) {
1202 continue;
1203 }
caryclark26ad22a2015-10-16 09:03:38 -07001204 if (priorPtT == ptT) {
1205 continue;
1206 }
caryclark54359292015-03-26 07:52:43 -07001207 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001208 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001209 bool swapped = priorPtT->fT > ptT->fT;
1210 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001211 using std::swap;
1212 swap(priorPtT, ptT);
1213 swap(oppStart, oppEnd);
caryclark54359292015-03-26 07:52:43 -07001214 }
caryclark55888e42016-07-18 10:01:36 -07001215 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1216 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1217 SkOpPtT* rootPtT = ptT->span()->ptT();
1218 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1219 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1220 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001221 goto swapBack;
1222 }
caryclark55888e42016-07-18 10:01:36 -07001223 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001224 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001225#if DEBUG_COINCIDENCE_VERBOSE
1226 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1227 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1228 rootOppEnd->debugID());
1229#endif
1230 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1231 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001232 }
caryclark55888e42016-07-18 10:01:36 -07001233#if DEBUG_COINCIDENCE
1234 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1235#endif
1236 result = true;
caryclark54359292015-03-26 07:52:43 -07001237 }
1238 swapBack:
1239 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001240 using std::swap;
1241 swap(priorPtT, ptT);
caryclark54359292015-03-26 07:52:43 -07001242 }
reed0dc4dd62015-03-24 13:55:33 -07001243 }
halcanary96fcdcc2015-08-27 07:41:13 -07001244 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001245 ClearVisited(&fHead);
1246 return result;
reed0dc4dd62015-03-24 13:55:33 -07001247}
1248
caryclark55888e42016-07-18 10:01:36 -07001249// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001250// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001251bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001252 debugValidate();
1253 SkOpSpanBase* test = &fHead;
1254 do {
1255 int addCount = test->spanAddsCount();
Cary Clark7eb01e02016-12-08 14:36:32 -05001256// FAIL_IF(addCount < 1);
1257 if (addCount <= 1) {
caryclark08bc8482015-04-24 09:08:57 -07001258 continue;
1259 }
1260 SkOpPtT* startPtT = test->ptT();
1261 SkOpPtT* testPtT = startPtT;
1262 do { // iterate through all spans associated with start
1263 SkOpSpanBase* oppSpan = testPtT->span();
1264 if (oppSpan->spanAddsCount() == addCount) {
1265 continue;
1266 }
1267 if (oppSpan->deleted()) {
1268 continue;
1269 }
1270 SkOpSegment* oppSegment = oppSpan->segment();
1271 if (oppSegment == this) {
1272 continue;
1273 }
1274 // find range of spans to consider merging
1275 SkOpSpanBase* oppPrev = oppSpan;
1276 SkOpSpanBase* oppFirst = oppSpan;
1277 while ((oppPrev = oppPrev->prev())) {
1278 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1279 break;
1280 }
1281 if (oppPrev->spanAddsCount() == addCount) {
1282 continue;
1283 }
1284 if (oppPrev->deleted()) {
1285 continue;
1286 }
1287 oppFirst = oppPrev;
1288 }
1289 SkOpSpanBase* oppNext = oppSpan;
1290 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001291 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001292 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1293 break;
1294 }
1295 if (oppNext->spanAddsCount() == addCount) {
1296 continue;
1297 }
1298 if (oppNext->deleted()) {
1299 continue;
1300 }
1301 oppLast = oppNext;
1302 }
1303 if (oppFirst == oppLast) {
1304 continue;
1305 }
1306 SkOpSpanBase* oppTest = oppFirst;
1307 do {
1308 if (oppTest == oppSpan) {
1309 continue;
1310 }
1311 // check to see if the candidate meets specific criteria:
1312 // it contains spans of segments in test's loop but not including 'this'
1313 SkOpPtT* oppStartPtT = oppTest->ptT();
1314 SkOpPtT* oppPtT = oppStartPtT;
1315 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1316 SkOpSegment* oppPtTSegment = oppPtT->segment();
1317 if (oppPtTSegment == this) {
1318 goto tryNextSpan;
1319 }
1320 SkOpPtT* matchPtT = startPtT;
1321 do {
1322 if (matchPtT->segment() == oppPtTSegment) {
1323 goto foundMatch;
1324 }
1325 } while ((matchPtT = matchPtT->next()) != startPtT);
1326 goto tryNextSpan;
1327 foundMatch: // merge oppTest and oppSpan
1328 oppSegment->debugValidate();
caryclark30b9fdd2016-08-31 14:36:29 -07001329 oppTest->mergeMatches(oppSpan);
1330 oppTest->addOpp(oppSpan);
caryclark08bc8482015-04-24 09:08:57 -07001331 oppSegment->debugValidate();
1332 goto checkNextSpan;
1333 }
caryclark55888e42016-07-18 10:01:36 -07001334 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001335 ;
1336 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1337 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001338checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001339 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001340 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001341 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001342 return true;
caryclark08bc8482015-04-24 09:08:57 -07001343}
1344
caryclark55888e42016-07-18 10:01:36 -07001345// adjacent spans may have points close by
Cary Clark28da2832017-03-21 10:30:50 -04001346bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan,
1347 bool* found) const {
caryclark55888e42016-07-18 10:01:36 -07001348 const SkOpPtT* refHead = refSpan->ptT();
1349 const SkOpPtT* checkHead = checkSpan->ptT();
1350// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
caryclark30b9fdd2016-08-31 14:36:29 -07001351 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
caryclark55888e42016-07-18 10:01:36 -07001352#if DEBUG_COINCIDENCE
1353 // verify that no combination of points are close
1354 const SkOpPtT* dBugRef = refHead;
1355 do {
1356 const SkOpPtT* dBugCheck = checkHead;
1357 do {
caryclark30b9fdd2016-08-31 14:36:29 -07001358 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
caryclark55888e42016-07-18 10:01:36 -07001359 dBugCheck = dBugCheck->next();
1360 } while (dBugCheck != checkHead);
1361 dBugRef = dBugRef->next();
1362 } while (dBugRef != refHead);
1363#endif
Cary Clark28da2832017-03-21 10:30:50 -04001364 *found = false;
1365 return true;
caryclark55888e42016-07-18 10:01:36 -07001366 }
1367 // check only unique points
1368 SkScalar distSqBest = SK_ScalarMax;
1369 const SkOpPtT* refBest = nullptr;
1370 const SkOpPtT* checkBest = nullptr;
1371 const SkOpPtT* ref = refHead;
1372 do {
1373 if (ref->deleted()) {
1374 continue;
1375 }
1376 while (ref->ptAlreadySeen(refHead)) {
1377 ref = ref->next();
1378 if (ref == refHead) {
1379 goto doneCheckingDistance;
1380 }
1381 }
1382 const SkOpPtT* check = checkHead;
1383 const SkOpSegment* refSeg = ref->segment();
Cary Clark28da2832017-03-21 10:30:50 -04001384 int escapeHatch = 100000; // defend against infinite loops
caryclark55888e42016-07-18 10:01:36 -07001385 do {
1386 if (check->deleted()) {
1387 continue;
1388 }
1389 while (check->ptAlreadySeen(checkHead)) {
1390 check = check->next();
1391 if (check == checkHead) {
1392 goto nextRef;
1393 }
1394 }
Cary Clarkdf429f32017-11-08 11:44:31 -05001395 SkScalar distSq = SkPointPriv::DistanceToSqd(ref->fPt, check->fPt);
caryclark55888e42016-07-18 10:01:36 -07001396 if (distSqBest > distSq && (refSeg != check->segment()
1397 || !refSeg->ptsDisjoint(*ref, *check))) {
1398 distSqBest = distSq;
1399 refBest = ref;
1400 checkBest = check;
1401 }
Cary Clark28da2832017-03-21 10:30:50 -04001402 if (--escapeHatch <= 0) {
1403 return false;
1404 }
caryclark55888e42016-07-18 10:01:36 -07001405 } while ((check = check->next()) != checkHead);
Cary Clark28da2832017-03-21 10:30:50 -04001406 nextRef:
caryclark55888e42016-07-18 10:01:36 -07001407 ;
1408 } while ((ref = ref->next()) != refHead);
1409doneCheckingDistance:
Cary Clark28da2832017-03-21 10:30:50 -04001410 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001411 checkBest->fPt);
Cary Clark28da2832017-03-21 10:30:50 -04001412 return true;
caryclark55888e42016-07-18 10:01:36 -07001413}
1414
1415// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001416// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
Cary Clark28da2832017-03-21 10:30:50 -04001417bool SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001418 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001419 // release undeleted spans pointing to this seg that are linked to the primary span
1420 SkOpSpanBase* spanBase = &fHead;
Cary Clark43938b82017-10-18 08:47:32 -04001421 int escapeHatch = 9999; // the largest count for a regular test is 50; for a fuzzer, 500
caryclark54359292015-03-26 07:52:43 -07001422 do {
caryclark55888e42016-07-18 10:01:36 -07001423 SkOpPtT* ptT = spanBase->ptT();
1424 const SkOpPtT* headPtT = ptT;
1425 while ((ptT = ptT->next()) != headPtT) {
Cary Clark43938b82017-10-18 08:47:32 -04001426 if (!--escapeHatch) {
1427 return false;
1428 }
caryclark55888e42016-07-18 10:01:36 -07001429 SkOpSpanBase* test = ptT->span();
1430 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1431 && test->ptT() == ptT) {
1432 if (test->final()) {
1433 if (spanBase == &fHead) {
1434 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001435 return true;
caryclark55888e42016-07-18 10:01:36 -07001436 }
1437 spanBase->upCast()->release(ptT);
1438 } else if (test->prev()) {
1439 test->upCast()->release(headPtT);
1440 }
1441 break;
caryclark54359292015-03-26 07:52:43 -07001442 }
reed0dc4dd62015-03-24 13:55:33 -07001443 }
caryclark55888e42016-07-18 10:01:36 -07001444 spanBase = spanBase->upCast()->next();
1445 } while (!spanBase->final());
caryclark55888e42016-07-18 10:01:36 -07001446 // This loop looks for adjacent spans which are near by
1447 spanBase = &fHead;
1448 do { // iterate through all spans associated with start
1449 SkOpSpanBase* test = spanBase->upCast()->next();
Cary Clark28da2832017-03-21 10:30:50 -04001450 bool found;
1451 if (!this->spansNearby(spanBase, test, &found)) {
1452 return false;
1453 }
1454 if (found) {
caryclark55888e42016-07-18 10:01:36 -07001455 if (test->final()) {
1456 if (spanBase->prev()) {
1457 test->merge(spanBase->upCast());
1458 } else {
1459 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001460 return true;
caryclark55888e42016-07-18 10:01:36 -07001461 }
1462 } else {
1463 spanBase->merge(test->upCast());
1464 }
1465 }
1466 spanBase = test;
1467 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001468 debugValidate();
Cary Clark28da2832017-03-21 10:30:50 -04001469 return true;
reed0dc4dd62015-03-24 13:55:33 -07001470}
1471
caryclark54359292015-03-26 07:52:43 -07001472bool SkOpSegment::operand() const {
1473 return fContour->operand();
1474}
1475
1476bool SkOpSegment::oppXor() const {
1477 return fContour->oppXor();
1478}
1479
1480bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1481 if (fVerb == SkPath::kLine_Verb) {
1482 return false;
1483 }
1484 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1485 // hits in two places with very different t values.
1486 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1487 // 'controls contained by ends' could avoid this check for common curves
1488 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1489 // on the other hand, the below check is relatively inexpensive
1490 double midT = (t1 + t2) / 2;
1491 SkPoint midPt = this->ptAtT(midT);
Cary Clarkdf429f32017-11-08 11:44:31 -05001492 double seDistSq = SkTMax(SkPointPriv::DistanceToSqd(pt1, pt2) * 2, FLT_EPSILON * 2);
1493 return SkPointPriv::DistanceToSqd(midPt, pt1) > seDistSq ||
1494 SkPointPriv::DistanceToSqd(midPt, pt2) > seDistSq;
caryclark54359292015-03-26 07:52:43 -07001495}
1496
1497void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1498 int* maxWinding, int* sumWinding) {
1499 int deltaSum = SpanSign(start, end);
1500 *maxWinding = *sumMiWinding;
1501 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001502 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001503}
1504
1505void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1506 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1507 int* oppSumWinding) {
1508 int deltaSum = SpanSign(start, end);
1509 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001510 if (operand()) {
1511 *maxWinding = *sumSuWinding;
1512 *sumWinding = *sumSuWinding -= deltaSum;
1513 *oppMaxWinding = *sumMiWinding;
1514 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1515 } else {
1516 *maxWinding = *sumMiWinding;
1517 *sumWinding = *sumMiWinding -= deltaSum;
1518 *oppMaxWinding = *sumSuWinding;
1519 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1520 }
bungeman60e0fee2015-08-26 05:15:46 -07001521 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1522 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001523}
1524
caryclarkb36a3cd2016-10-18 07:59:44 -07001525bool SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001526 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001527 do {
caryclark54359292015-03-26 07:52:43 -07001528 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001529 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001530 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001531 continue;
1532 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001533#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001534 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001535#endif
caryclark54359292015-03-26 07:52:43 -07001536 SkOpAngle* baseAngle = fromAngle;
1537 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001538#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001539 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1540 span->debugID());
1541 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001542#endif
caryclarkb36a3cd2016-10-18 07:59:44 -07001543 FAIL_IF(!fromAngle->insert(toAngle));
caryclark54359292015-03-26 07:52:43 -07001544 } else if (!fromAngle) {
1545 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001546 }
caryclark54359292015-03-26 07:52:43 -07001547 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001548 do {
caryclark54359292015-03-26 07:52:43 -07001549 SkOpSpanBase* oSpan = ptT->span();
1550 if (oSpan == span) {
1551 continue;
1552 }
1553 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001554 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001555#if DEBUG_ANGLE
1556 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001557 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1558 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001559 wroteAfterHeader = true;
1560 }
1561#endif
caryclark54359292015-03-26 07:52:43 -07001562 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001563 baseAngle->insert(oAngle);
1564 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001565 }
caryclark54359292015-03-26 07:52:43 -07001566 if (!oSpan->final()) {
1567 oAngle = oSpan->upCast()->toAngle();
1568 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001569#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001570 if (!wroteAfterHeader) {
1571 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1572 span->t(), span->debugID());
1573 wroteAfterHeader = true;
1574 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001575#endif
caryclark54359292015-03-26 07:52:43 -07001576 if (!oAngle->loopContains(baseAngle)) {
1577 baseAngle->insert(oAngle);
1578 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001579 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001580 }
caryclark54359292015-03-26 07:52:43 -07001581 } while ((ptT = ptT->next()) != stopPtT);
1582 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001583 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001584 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001585 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001586 }
halcanary96fcdcc2015-08-27 07:41:13 -07001587 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001588 }
1589#if DEBUG_SORT
1590 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1591#endif
caryclark54359292015-03-26 07:52:43 -07001592 } while (!span->final() && (span = span->upCast()->next()));
caryclarkb36a3cd2016-10-18 07:59:44 -07001593 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +00001594}
1595
caryclark54359292015-03-26 07:52:43 -07001596bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001597 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001598 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001599 const SkOpPtT& startPtT = *start->ptT();
1600 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001601 SkDEBUGCODE(edge->fVerb = fVerb);
1602 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001603 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001604 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001605 if (fVerb == SkPath::kLine_Verb) {
1606 return false;
1607 }
caryclark54359292015-03-26 07:52:43 -07001608 double startT = startPtT.fT;
1609 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001610 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1611 // don't compute midpoints if we already have them
1612 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001613 edge->fLine[1].set(fPts[1]);
1614 return false;
1615 }
1616 if (fVerb == SkPath::kConic_Verb) {
1617 edge->fConic[1].set(fPts[1]);
1618 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001619 return false;
1620 }
1621 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001622 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001623 edge->fCubic[1].set(fPts[1]);
1624 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001625 return false;
1626 }
caryclark1049f122015-04-20 08:31:59 -07001627 edge->fCubic[1].set(fPts[2]);
1628 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001629 return false;
1630 }
1631 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001632 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1633 } else if (fVerb == SkPath::kConic_Verb) {
1634 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1635 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001636 } else {
1637 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001638 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001639 }
1640 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001641}
1642
caryclark27c8eb82015-07-06 11:38:33 -07001643bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001644 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001645 // average t, find mid pt
1646 double midT = (prior->t() + spanBase->t()) / 2;
1647 SkPoint midPt = this->ptAtT(midT);
1648 bool coincident = true;
1649 // if the mid pt is not near either end pt, project perpendicular through opp seg
1650 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1651 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001652 if (priorPtT->span() == ptT->span()) {
1653 return false;
1654 }
caryclark27c8eb82015-07-06 11:38:33 -07001655 coincident = false;
1656 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001657 SkDCurve curvePart;
1658 this->subDivide(prior, spanBase, &curvePart);
1659 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1660 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1661 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1662 SkDCurve oppPart;
1663 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1664 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001665 // measure distance and see if it's small enough to denote coincidence
1666 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001667 if (!between(0, i[0][index], 1)) {
1668 continue;
1669 }
caryclark27c8eb82015-07-06 11:38:33 -07001670 SkDPoint oppPt = i.pt(index);
caryclark30b9fdd2016-08-31 14:36:29 -07001671 if (oppPt.approximatelyDEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001672 // the coincidence can occur at almost any angle
1673 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001674 }
1675 }
1676 }
1677 return coincident;
1678}
1679
Cary Clarkab2d73b2016-12-16 17:17:25 -05001680SkOpSpan* SkOpSegment::undoneSpan() {
1681 SkOpSpan* span = &fHead;
1682 SkOpSpanBase* next;
caryclark54359292015-03-26 07:52:43 -07001683 do {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001684 next = span->next();
caryclark54359292015-03-26 07:52:43 -07001685 if (!span->done()) {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001686 return span;
reed0dc4dd62015-03-24 13:55:33 -07001687 }
Cary Clarkab2d73b2016-12-16 17:17:25 -05001688 } while (!next->final() && (span = next->upCast()));
1689 return nullptr;
reed0dc4dd62015-03-24 13:55:33 -07001690}
1691
caryclark54359292015-03-26 07:52:43 -07001692int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1693 const SkOpSpan* lesser = start->starter(end);
1694 int oppWinding = lesser->oppSum();
1695 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001696 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1697 && oppWinding != SK_MaxS32) {
1698 oppWinding -= oppSpanWinding;
1699 }
1700 return oppWinding;
1701}
1702
1703int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001704 const SkOpSpanBase* startSpan = angle->start();
1705 const SkOpSpanBase* endSpan = angle->end();
1706 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001707}
1708
1709int SkOpSegment::updateOppWindingReverse(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(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001713}
1714
caryclark624637c2015-05-11 07:21:27 -07001715int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1716 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001717 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001718 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001719 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001720 }
1721 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001722 return winding;
1723 }
caryclark54359292015-03-26 07:52:43 -07001724 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001725 if (winding && UseInnerWinding(winding - spanWinding, winding)
1726 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001727 winding -= spanWinding;
1728 }
1729 return winding;
1730}
1731
caryclark624637c2015-05-11 07:21:27 -07001732int SkOpSegment::updateWinding(SkOpAngle* angle) {
1733 SkOpSpanBase* startSpan = angle->start();
1734 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001735 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001736}
1737
caryclark624637c2015-05-11 07:21:27 -07001738int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1739 SkOpSpanBase* startSpan = angle->start();
1740 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001741 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001742}
1743
1744// OPTIMIZATION: does the following also work, and is it any faster?
1745// return outerWinding * innerWinding > 0
1746// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1747bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1748 SkASSERT(outerWinding != SK_MaxS32);
1749 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001750 int absOut = SkTAbs(outerWinding);
1751 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001752 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1753 return result;
1754}
1755
caryclark@google.com07393ca2013-04-08 11:47:37 +00001756int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001757 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1758 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001759}