blob: ff83f4fd4d2cbfbf1bb14fea334838a3150ac845 [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 Clarkb2c7d842018-10-16 18:16:59 +0000988 SkOpSpanBase* last = *result;
989 if (last) {
990 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
991 last->segment()->debugID(), last->debugID());
992 if (!last->final()) {
993 SkDebugf(" windSum=");
994 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
caryclark54359292015-03-26 07:52:43 -0700995 }
Cary Clarkb2c7d842018-10-16 18:16:59 +0000996 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000997 }
998#endif
Cary Clark2587f412018-07-24 12:40:10 -0400999 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001000}
1001
caryclark54359292015-03-26 07:52:43 -07001002void SkOpSegment::markDone(SkOpSpan* span) {
1003 SkASSERT(this == span->segment());
1004 if (span->done()) {
1005 return;
1006 }
1007#if DEBUG_MARK_DONE
1008 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
1009#endif
1010 span->setDone(true);
1011 ++fDoneCount;
1012 debugValidate();
1013}
1014
1015bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
1016 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -07001017 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -07001018 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001019 return false;
1020 }
1021#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -07001022 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -07001023#endif
caryclark54359292015-03-26 07:52:43 -07001024 span->setWindSum(winding);
1025 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001026 return true;
1027}
1028
caryclark54359292015-03-26 07:52:43 -07001029bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
1030 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +00001031 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -07001032 if (span->done()) {
1033 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001034 }
caryclark54359292015-03-26 07:52:43 -07001035#if DEBUG_MARK_DONE
1036 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1037#endif
1038 span->setWindSum(winding);
1039 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001040 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001041 return true;
1042}
1043
caryclark54359292015-03-26 07:52:43 -07001044bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclarkef4f32a2016-08-24 09:24:18 -07001045 const SkPoint& testPt) const {
caryclark55888e42016-07-18 10:01:36 -07001046 SkASSERT(this == base->segment());
1047 if (this == testParent) {
1048 if (precisely_equal(base->fT, testT)) {
1049 return true;
1050 }
caryclark54359292015-03-26 07:52:43 -07001051 }
1052 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1053 return false;
1054 }
caryclark55888e42016-07-18 10:01:36 -07001055 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001056}
1057
1058static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1059 if (last) {
1060 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001061 }
halcanary96fcdcc2015-08-27 07:41:13 -07001062 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001063}
1064
caryclark54359292015-03-26 07:52:43 -07001065SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1066 SkOpSpanBase** last) const {
1067 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001068 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001069 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1070 SkASSERT(endSpan);
1071 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1072 SkOpSpanBase* foundSpan;
1073 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001074 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001075 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001076 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001077 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001078 }
caryclark54359292015-03-26 07:52:43 -07001079 SkOpPtT* otherPtT = endSpan->ptT()->next();
1080 other = otherPtT->segment();
1081 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001082 otherEnd = step > 0
1083 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1084 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001085 } else {
1086 int loopCount = angle->loopCount();
1087 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001088 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001089 }
1090 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001091 if (nullptr == next) {
1092 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001093 }
caryclarkdac1d172014-06-17 05:15:38 -07001094#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001095 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001096 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001097 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001098 }
caryclark54359292015-03-26 07:52:43 -07001099#endif
caryclarkdac1d172014-06-17 05:15:38 -07001100 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001101 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001102 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001103 }
caryclark343382e2016-06-29 08:18:38 -07001104 if (!otherEnd) {
1105 return nullptr;
1106 }
caryclark54359292015-03-26 07:52:43 -07001107 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001108 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001109 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001110 }
caryclark54359292015-03-26 07:52:43 -07001111 SkASSERT(*startPtr);
caryclark65b427c2014-09-18 10:32:57 -07001112// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001113 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1114 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1115 if (foundMin->windValue() != origMin->windValue()
1116 || foundMin->oppValue() != origMin->oppValue()) {
1117 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001118 }
caryclark54359292015-03-26 07:52:43 -07001119 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001120 *stepPtr = foundStep;
1121 if (minPtr) {
1122 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001123 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001124 return other;
1125}
1126
caryclark55888e42016-07-18 10:01:36 -07001127// Please keep this in sync with DebugClearVisited()
1128void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001129 // reset visited flag back to false
1130 do {
1131 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1132 while ((ptT = ptT->next()) != stopPtT) {
1133 SkOpSegment* opp = ptT->segment();
1134 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001135 }
caryclarkbca19f72015-05-13 08:23:48 -07001136 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001137}
1138
caryclark55888e42016-07-18 10:01:36 -07001139// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001140// look for pairs of undetected coincident curves
1141// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001142// Even though pairs of curves correct detect coincident runs, a run may be missed
1143// if the coincidence is a product of multiple intersections. For instance, given
1144// curves A, B, and C:
1145// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1146// the end of C that the intersection is replaced with the end of C.
1147// Even though A-B correctly do not detect an intersection at point 2,
1148// the resulting run from point 1 to point 2 is coincident on A and B.
1149bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001150 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001151 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001152 }
halcanary96fcdcc2015-08-27 07:41:13 -07001153 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001154 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001155 bool result = false;
caryclark54359292015-03-26 07:52:43 -07001156 do {
caryclarkbca19f72015-05-13 08:23:48 -07001157 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001158 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001159 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001160 if (ptT->deleted()) {
1161 continue;
1162 }
caryclark54359292015-03-26 07:52:43 -07001163 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001164 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001165 continue;
reed0dc4dd62015-03-24 13:55:33 -07001166 }
caryclarkbca19f72015-05-13 08:23:48 -07001167 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1168 if (!opp->visited()) {
1169 continue;
1170 }
1171 if (spanBase == &fHead) {
1172 continue;
1173 }
caryclark55888e42016-07-18 10:01:36 -07001174 if (ptT->segment() == this) {
1175 continue;
1176 }
caryclarkbca19f72015-05-13 08:23:48 -07001177 SkOpSpan* span = spanBase->upCastable();
1178 // FIXME?: this assumes that if the opposite segment is coincident then no more
1179 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001180 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001181 continue;
1182 }
caryclarkbca19f72015-05-13 08:23:48 -07001183 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001184 continue;
caryclark55888e42016-07-18 10:01:36 -07001185 }
halcanary96fcdcc2015-08-27 07:41:13 -07001186 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001187 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001188 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001189 SkOpSpan* priorTest = spanBase->prev();
1190 while (!priorOpp && priorTest) {
1191 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001192 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001193 if (priorPtT->deleted()) {
1194 continue;
1195 }
caryclark54359292015-03-26 07:52:43 -07001196 SkOpSegment* segment = priorPtT->span()->segment();
1197 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001198 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001199 priorOpp = opp;
1200 break;
1201 }
1202 }
caryclarkbca19f72015-05-13 08:23:48 -07001203 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001204 }
1205 if (!priorOpp) {
1206 continue;
1207 }
caryclark26ad22a2015-10-16 09:03:38 -07001208 if (priorPtT == ptT) {
1209 continue;
1210 }
caryclark54359292015-03-26 07:52:43 -07001211 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001212 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001213 bool swapped = priorPtT->fT > ptT->fT;
1214 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001215 using std::swap;
1216 swap(priorPtT, ptT);
1217 swap(oppStart, oppEnd);
caryclark54359292015-03-26 07:52:43 -07001218 }
caryclark55888e42016-07-18 10:01:36 -07001219 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1220 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1221 SkOpPtT* rootPtT = ptT->span()->ptT();
1222 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1223 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1224 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001225 goto swapBack;
1226 }
caryclark55888e42016-07-18 10:01:36 -07001227 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001228 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001229#if DEBUG_COINCIDENCE_VERBOSE
1230 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1231 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1232 rootOppEnd->debugID());
1233#endif
1234 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1235 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001236 }
caryclark55888e42016-07-18 10:01:36 -07001237#if DEBUG_COINCIDENCE
1238 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1239#endif
1240 result = true;
caryclark54359292015-03-26 07:52:43 -07001241 }
1242 swapBack:
1243 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001244 using std::swap;
1245 swap(priorPtT, ptT);
caryclark54359292015-03-26 07:52:43 -07001246 }
reed0dc4dd62015-03-24 13:55:33 -07001247 }
halcanary96fcdcc2015-08-27 07:41:13 -07001248 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001249 ClearVisited(&fHead);
1250 return result;
reed0dc4dd62015-03-24 13:55:33 -07001251}
1252
caryclark55888e42016-07-18 10:01:36 -07001253// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001254// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001255bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001256 debugValidate();
1257 SkOpSpanBase* test = &fHead;
1258 do {
1259 int addCount = test->spanAddsCount();
Cary Clark7eb01e02016-12-08 14:36:32 -05001260// FAIL_IF(addCount < 1);
1261 if (addCount <= 1) {
caryclark08bc8482015-04-24 09:08:57 -07001262 continue;
1263 }
1264 SkOpPtT* startPtT = test->ptT();
1265 SkOpPtT* testPtT = startPtT;
1266 do { // iterate through all spans associated with start
1267 SkOpSpanBase* oppSpan = testPtT->span();
1268 if (oppSpan->spanAddsCount() == addCount) {
1269 continue;
1270 }
1271 if (oppSpan->deleted()) {
1272 continue;
1273 }
1274 SkOpSegment* oppSegment = oppSpan->segment();
1275 if (oppSegment == this) {
1276 continue;
1277 }
1278 // find range of spans to consider merging
1279 SkOpSpanBase* oppPrev = oppSpan;
1280 SkOpSpanBase* oppFirst = oppSpan;
1281 while ((oppPrev = oppPrev->prev())) {
1282 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1283 break;
1284 }
1285 if (oppPrev->spanAddsCount() == addCount) {
1286 continue;
1287 }
1288 if (oppPrev->deleted()) {
1289 continue;
1290 }
1291 oppFirst = oppPrev;
1292 }
1293 SkOpSpanBase* oppNext = oppSpan;
1294 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001295 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001296 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1297 break;
1298 }
1299 if (oppNext->spanAddsCount() == addCount) {
1300 continue;
1301 }
1302 if (oppNext->deleted()) {
1303 continue;
1304 }
1305 oppLast = oppNext;
1306 }
1307 if (oppFirst == oppLast) {
1308 continue;
1309 }
1310 SkOpSpanBase* oppTest = oppFirst;
1311 do {
1312 if (oppTest == oppSpan) {
1313 continue;
1314 }
1315 // check to see if the candidate meets specific criteria:
1316 // it contains spans of segments in test's loop but not including 'this'
1317 SkOpPtT* oppStartPtT = oppTest->ptT();
1318 SkOpPtT* oppPtT = oppStartPtT;
1319 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1320 SkOpSegment* oppPtTSegment = oppPtT->segment();
1321 if (oppPtTSegment == this) {
1322 goto tryNextSpan;
1323 }
1324 SkOpPtT* matchPtT = startPtT;
1325 do {
1326 if (matchPtT->segment() == oppPtTSegment) {
1327 goto foundMatch;
1328 }
1329 } while ((matchPtT = matchPtT->next()) != startPtT);
1330 goto tryNextSpan;
1331 foundMatch: // merge oppTest and oppSpan
1332 oppSegment->debugValidate();
caryclark30b9fdd2016-08-31 14:36:29 -07001333 oppTest->mergeMatches(oppSpan);
1334 oppTest->addOpp(oppSpan);
caryclark08bc8482015-04-24 09:08:57 -07001335 oppSegment->debugValidate();
1336 goto checkNextSpan;
1337 }
caryclark55888e42016-07-18 10:01:36 -07001338 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001339 ;
1340 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1341 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001342checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001343 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001344 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001345 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001346 return true;
caryclark08bc8482015-04-24 09:08:57 -07001347}
1348
caryclark55888e42016-07-18 10:01:36 -07001349// adjacent spans may have points close by
Cary Clark28da2832017-03-21 10:30:50 -04001350bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan,
1351 bool* found) const {
caryclark55888e42016-07-18 10:01:36 -07001352 const SkOpPtT* refHead = refSpan->ptT();
1353 const SkOpPtT* checkHead = checkSpan->ptT();
1354// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
caryclark30b9fdd2016-08-31 14:36:29 -07001355 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
caryclark55888e42016-07-18 10:01:36 -07001356#if DEBUG_COINCIDENCE
1357 // verify that no combination of points are close
1358 const SkOpPtT* dBugRef = refHead;
1359 do {
1360 const SkOpPtT* dBugCheck = checkHead;
1361 do {
caryclark30b9fdd2016-08-31 14:36:29 -07001362 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
caryclark55888e42016-07-18 10:01:36 -07001363 dBugCheck = dBugCheck->next();
1364 } while (dBugCheck != checkHead);
1365 dBugRef = dBugRef->next();
1366 } while (dBugRef != refHead);
1367#endif
Cary Clark28da2832017-03-21 10:30:50 -04001368 *found = false;
1369 return true;
caryclark55888e42016-07-18 10:01:36 -07001370 }
1371 // check only unique points
1372 SkScalar distSqBest = SK_ScalarMax;
1373 const SkOpPtT* refBest = nullptr;
1374 const SkOpPtT* checkBest = nullptr;
1375 const SkOpPtT* ref = refHead;
1376 do {
1377 if (ref->deleted()) {
1378 continue;
1379 }
1380 while (ref->ptAlreadySeen(refHead)) {
1381 ref = ref->next();
1382 if (ref == refHead) {
1383 goto doneCheckingDistance;
1384 }
1385 }
1386 const SkOpPtT* check = checkHead;
1387 const SkOpSegment* refSeg = ref->segment();
Cary Clark28da2832017-03-21 10:30:50 -04001388 int escapeHatch = 100000; // defend against infinite loops
caryclark55888e42016-07-18 10:01:36 -07001389 do {
1390 if (check->deleted()) {
1391 continue;
1392 }
1393 while (check->ptAlreadySeen(checkHead)) {
1394 check = check->next();
1395 if (check == checkHead) {
1396 goto nextRef;
1397 }
1398 }
Cary Clarkdf429f32017-11-08 11:44:31 -05001399 SkScalar distSq = SkPointPriv::DistanceToSqd(ref->fPt, check->fPt);
caryclark55888e42016-07-18 10:01:36 -07001400 if (distSqBest > distSq && (refSeg != check->segment()
1401 || !refSeg->ptsDisjoint(*ref, *check))) {
1402 distSqBest = distSq;
1403 refBest = ref;
1404 checkBest = check;
1405 }
Cary Clark28da2832017-03-21 10:30:50 -04001406 if (--escapeHatch <= 0) {
1407 return false;
1408 }
caryclark55888e42016-07-18 10:01:36 -07001409 } while ((check = check->next()) != checkHead);
Cary Clark28da2832017-03-21 10:30:50 -04001410 nextRef:
caryclark55888e42016-07-18 10:01:36 -07001411 ;
1412 } while ((ref = ref->next()) != refHead);
1413doneCheckingDistance:
Cary Clark28da2832017-03-21 10:30:50 -04001414 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001415 checkBest->fPt);
Cary Clark28da2832017-03-21 10:30:50 -04001416 return true;
caryclark55888e42016-07-18 10:01:36 -07001417}
1418
1419// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001420// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
Cary Clark28da2832017-03-21 10:30:50 -04001421bool SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001422 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001423 // release undeleted spans pointing to this seg that are linked to the primary span
1424 SkOpSpanBase* spanBase = &fHead;
Cary Clark43938b82017-10-18 08:47:32 -04001425 int escapeHatch = 9999; // the largest count for a regular test is 50; for a fuzzer, 500
caryclark54359292015-03-26 07:52:43 -07001426 do {
caryclark55888e42016-07-18 10:01:36 -07001427 SkOpPtT* ptT = spanBase->ptT();
1428 const SkOpPtT* headPtT = ptT;
1429 while ((ptT = ptT->next()) != headPtT) {
Cary Clark43938b82017-10-18 08:47:32 -04001430 if (!--escapeHatch) {
1431 return false;
1432 }
caryclark55888e42016-07-18 10:01:36 -07001433 SkOpSpanBase* test = ptT->span();
1434 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1435 && test->ptT() == ptT) {
1436 if (test->final()) {
1437 if (spanBase == &fHead) {
1438 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001439 return true;
caryclark55888e42016-07-18 10:01:36 -07001440 }
1441 spanBase->upCast()->release(ptT);
1442 } else if (test->prev()) {
1443 test->upCast()->release(headPtT);
1444 }
1445 break;
caryclark54359292015-03-26 07:52:43 -07001446 }
reed0dc4dd62015-03-24 13:55:33 -07001447 }
caryclark55888e42016-07-18 10:01:36 -07001448 spanBase = spanBase->upCast()->next();
1449 } while (!spanBase->final());
caryclark55888e42016-07-18 10:01:36 -07001450 // This loop looks for adjacent spans which are near by
1451 spanBase = &fHead;
1452 do { // iterate through all spans associated with start
1453 SkOpSpanBase* test = spanBase->upCast()->next();
Cary Clark28da2832017-03-21 10:30:50 -04001454 bool found;
1455 if (!this->spansNearby(spanBase, test, &found)) {
1456 return false;
1457 }
1458 if (found) {
caryclark55888e42016-07-18 10:01:36 -07001459 if (test->final()) {
1460 if (spanBase->prev()) {
1461 test->merge(spanBase->upCast());
1462 } else {
1463 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001464 return true;
caryclark55888e42016-07-18 10:01:36 -07001465 }
1466 } else {
1467 spanBase->merge(test->upCast());
1468 }
1469 }
1470 spanBase = test;
1471 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001472 debugValidate();
Cary Clark28da2832017-03-21 10:30:50 -04001473 return true;
reed0dc4dd62015-03-24 13:55:33 -07001474}
1475
caryclark54359292015-03-26 07:52:43 -07001476bool SkOpSegment::operand() const {
1477 return fContour->operand();
1478}
1479
1480bool SkOpSegment::oppXor() const {
1481 return fContour->oppXor();
1482}
1483
1484bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1485 if (fVerb == SkPath::kLine_Verb) {
1486 return false;
1487 }
1488 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1489 // hits in two places with very different t values.
1490 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1491 // 'controls contained by ends' could avoid this check for common curves
1492 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1493 // on the other hand, the below check is relatively inexpensive
1494 double midT = (t1 + t2) / 2;
1495 SkPoint midPt = this->ptAtT(midT);
Cary Clarkdf429f32017-11-08 11:44:31 -05001496 double seDistSq = SkTMax(SkPointPriv::DistanceToSqd(pt1, pt2) * 2, FLT_EPSILON * 2);
1497 return SkPointPriv::DistanceToSqd(midPt, pt1) > seDistSq ||
1498 SkPointPriv::DistanceToSqd(midPt, pt2) > seDistSq;
caryclark54359292015-03-26 07:52:43 -07001499}
1500
1501void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1502 int* maxWinding, int* sumWinding) {
1503 int deltaSum = SpanSign(start, end);
1504 *maxWinding = *sumMiWinding;
1505 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001506 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001507}
1508
1509void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1510 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1511 int* oppSumWinding) {
1512 int deltaSum = SpanSign(start, end);
1513 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001514 if (operand()) {
1515 *maxWinding = *sumSuWinding;
1516 *sumWinding = *sumSuWinding -= deltaSum;
1517 *oppMaxWinding = *sumMiWinding;
1518 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1519 } else {
1520 *maxWinding = *sumMiWinding;
1521 *sumWinding = *sumMiWinding -= deltaSum;
1522 *oppMaxWinding = *sumSuWinding;
1523 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1524 }
bungeman60e0fee2015-08-26 05:15:46 -07001525 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1526 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001527}
1528
caryclarkb36a3cd2016-10-18 07:59:44 -07001529bool SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001530 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001531 do {
caryclark54359292015-03-26 07:52:43 -07001532 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001533 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001534 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001535 continue;
1536 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001537#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001538 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001539#endif
caryclark54359292015-03-26 07:52:43 -07001540 SkOpAngle* baseAngle = fromAngle;
1541 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001542#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001543 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1544 span->debugID());
1545 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001546#endif
caryclarkb36a3cd2016-10-18 07:59:44 -07001547 FAIL_IF(!fromAngle->insert(toAngle));
caryclark54359292015-03-26 07:52:43 -07001548 } else if (!fromAngle) {
1549 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001550 }
caryclark54359292015-03-26 07:52:43 -07001551 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001552 do {
caryclark54359292015-03-26 07:52:43 -07001553 SkOpSpanBase* oSpan = ptT->span();
1554 if (oSpan == span) {
1555 continue;
1556 }
1557 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001558 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001559#if DEBUG_ANGLE
1560 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001561 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1562 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001563 wroteAfterHeader = true;
1564 }
1565#endif
caryclark54359292015-03-26 07:52:43 -07001566 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001567 baseAngle->insert(oAngle);
1568 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001569 }
caryclark54359292015-03-26 07:52:43 -07001570 if (!oSpan->final()) {
1571 oAngle = oSpan->upCast()->toAngle();
1572 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001573#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001574 if (!wroteAfterHeader) {
1575 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1576 span->t(), span->debugID());
1577 wroteAfterHeader = true;
1578 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001579#endif
caryclark54359292015-03-26 07:52:43 -07001580 if (!oAngle->loopContains(baseAngle)) {
1581 baseAngle->insert(oAngle);
1582 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001583 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001584 }
caryclark54359292015-03-26 07:52:43 -07001585 } while ((ptT = ptT->next()) != stopPtT);
1586 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001587 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001588 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001589 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001590 }
halcanary96fcdcc2015-08-27 07:41:13 -07001591 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001592 }
1593#if DEBUG_SORT
1594 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1595#endif
caryclark54359292015-03-26 07:52:43 -07001596 } while (!span->final() && (span = span->upCast()->next()));
caryclarkb36a3cd2016-10-18 07:59:44 -07001597 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +00001598}
1599
caryclark54359292015-03-26 07:52:43 -07001600bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001601 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001602 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001603 const SkOpPtT& startPtT = *start->ptT();
1604 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001605 SkDEBUGCODE(edge->fVerb = fVerb);
1606 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001607 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001608 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001609 if (fVerb == SkPath::kLine_Verb) {
1610 return false;
1611 }
caryclark54359292015-03-26 07:52:43 -07001612 double startT = startPtT.fT;
1613 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001614 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1615 // don't compute midpoints if we already have them
1616 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001617 edge->fLine[1].set(fPts[1]);
1618 return false;
1619 }
1620 if (fVerb == SkPath::kConic_Verb) {
1621 edge->fConic[1].set(fPts[1]);
1622 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001623 return false;
1624 }
1625 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001626 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001627 edge->fCubic[1].set(fPts[1]);
1628 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001629 return false;
1630 }
caryclark1049f122015-04-20 08:31:59 -07001631 edge->fCubic[1].set(fPts[2]);
1632 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001633 return false;
1634 }
1635 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001636 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1637 } else if (fVerb == SkPath::kConic_Verb) {
1638 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1639 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001640 } else {
1641 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001642 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001643 }
1644 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001645}
1646
caryclark27c8eb82015-07-06 11:38:33 -07001647bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001648 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001649 // average t, find mid pt
1650 double midT = (prior->t() + spanBase->t()) / 2;
1651 SkPoint midPt = this->ptAtT(midT);
1652 bool coincident = true;
1653 // if the mid pt is not near either end pt, project perpendicular through opp seg
1654 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1655 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001656 if (priorPtT->span() == ptT->span()) {
1657 return false;
1658 }
caryclark27c8eb82015-07-06 11:38:33 -07001659 coincident = false;
1660 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001661 SkDCurve curvePart;
1662 this->subDivide(prior, spanBase, &curvePart);
1663 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1664 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1665 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1666 SkDCurve oppPart;
1667 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1668 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001669 // measure distance and see if it's small enough to denote coincidence
1670 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001671 if (!between(0, i[0][index], 1)) {
1672 continue;
1673 }
caryclark27c8eb82015-07-06 11:38:33 -07001674 SkDPoint oppPt = i.pt(index);
caryclark30b9fdd2016-08-31 14:36:29 -07001675 if (oppPt.approximatelyDEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001676 // the coincidence can occur at almost any angle
1677 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001678 }
1679 }
1680 }
1681 return coincident;
1682}
1683
Cary Clarkab2d73b2016-12-16 17:17:25 -05001684SkOpSpan* SkOpSegment::undoneSpan() {
1685 SkOpSpan* span = &fHead;
1686 SkOpSpanBase* next;
caryclark54359292015-03-26 07:52:43 -07001687 do {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001688 next = span->next();
caryclark54359292015-03-26 07:52:43 -07001689 if (!span->done()) {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001690 return span;
reed0dc4dd62015-03-24 13:55:33 -07001691 }
Cary Clarkab2d73b2016-12-16 17:17:25 -05001692 } while (!next->final() && (span = next->upCast()));
1693 return nullptr;
reed0dc4dd62015-03-24 13:55:33 -07001694}
1695
caryclark54359292015-03-26 07:52:43 -07001696int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1697 const SkOpSpan* lesser = start->starter(end);
1698 int oppWinding = lesser->oppSum();
1699 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001700 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1701 && oppWinding != SK_MaxS32) {
1702 oppWinding -= oppSpanWinding;
1703 }
1704 return oppWinding;
1705}
1706
1707int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001708 const SkOpSpanBase* startSpan = angle->start();
1709 const SkOpSpanBase* endSpan = angle->end();
1710 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001711}
1712
1713int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001714 const SkOpSpanBase* startSpan = angle->start();
1715 const SkOpSpanBase* endSpan = angle->end();
1716 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001717}
1718
caryclark624637c2015-05-11 07:21:27 -07001719int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1720 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001721 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001722 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001723 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001724 }
1725 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001726 return winding;
1727 }
caryclark54359292015-03-26 07:52:43 -07001728 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001729 if (winding && UseInnerWinding(winding - spanWinding, winding)
1730 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001731 winding -= spanWinding;
1732 }
1733 return winding;
1734}
1735
caryclark624637c2015-05-11 07:21:27 -07001736int SkOpSegment::updateWinding(SkOpAngle* angle) {
1737 SkOpSpanBase* startSpan = angle->start();
1738 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001739 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001740}
1741
caryclark624637c2015-05-11 07:21:27 -07001742int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1743 SkOpSpanBase* startSpan = angle->start();
1744 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001745 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001746}
1747
1748// OPTIMIZATION: does the following also work, and is it any faster?
1749// return outerWinding * innerWinding > 0
1750// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1751bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1752 SkASSERT(outerWinding != SK_MaxS32);
1753 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001754 int absOut = SkTAbs(outerWinding);
1755 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001756 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1757 return result;
1758}
1759
caryclark@google.com07393ca2013-04-08 11:47:37 +00001760int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001761 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1762 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001763}