blob: 14863e0b52e5cd3b0c5166455d0973c6f46c5b9b [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 {
caryclark025b11e2016-08-25 05:21:14 -0700168 FAIL_IF(start->starter(end)->alreadyAdded());
caryclarkeed356d2016-09-14 07:18:20 -0700169 SkDCurveSweep curvePart;
170 start->segment()->subDivide(start, end, &curvePart.fCurve);
171 curvePart.setCurveHullSweep(fVerb);
172 SkPath::Verb verb = curvePart.isCurve() ? fVerb : SkPath::kLine_Verb;
173 path->deferredMove(start->ptT());
174 switch (verb) {
175 case SkPath::kLine_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700176 FAIL_IF(!path->deferredLine(end->ptT()));
caryclarkeed356d2016-09-14 07:18:20 -0700177 break;
178 case SkPath::kQuad_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700179 path->quadTo(curvePart.fCurve.fQuad[1].asSkPoint(), end->ptT());
caryclarkeed356d2016-09-14 07:18:20 -0700180 break;
181 case SkPath::kConic_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700182 path->conicTo(curvePart.fCurve.fConic[1].asSkPoint(), end->ptT(),
caryclarkeed356d2016-09-14 07:18:20 -0700183 curvePart.fCurve.fConic.fWeight);
184 break;
185 case SkPath::kCubic_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700186 path->cubicTo(curvePart.fCurve.fCubic[1].asSkPoint(),
187 curvePart.fCurve.fCubic[2].asSkPoint(), end->ptT());
caryclarkeed356d2016-09-14 07:18:20 -0700188 break;
189 default:
190 SkASSERT(0);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000191 }
caryclarkef784fb2015-10-30 12:03:06 -0700192 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000193}
194
caryclark55888e42016-07-18 10:01:36 -0700195const SkOpPtT* SkOpSegment::existing(double t, const SkOpSegment* opp) const {
196 const SkOpSpanBase* test = &fHead;
197 const SkOpPtT* testPtT;
198 SkPoint pt = this->ptAtT(t);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000199 do {
caryclark55888e42016-07-18 10:01:36 -0700200 testPtT = test->ptT();
201 if (testPtT->fT == t) {
reed0dc4dd62015-03-24 13:55:33 -0700202 break;
203 }
caryclarkef4f32a2016-08-24 09:24:18 -0700204 if (!this->match(testPtT, this, t, pt)) {
caryclark55888e42016-07-18 10:01:36 -0700205 if (t < testPtT->fT) {
206 return nullptr;
207 }
208 continue;
209 }
210 if (!opp) {
211 return testPtT;
212 }
213 const SkOpPtT* loop = testPtT->next();
214 while (loop != testPtT) {
215 if (loop->segment() == this && loop->fT == t && loop->fPt == pt) {
216 goto foundMatch;
217 }
218 loop = loop->next();
219 }
220 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700221 } while ((test = test->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -0700222foundMatch:
223 return opp && !test->contains(opp) ? nullptr : testPtT;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000224}
225
caryclark55888e42016-07-18 10:01:36 -0700226// break the span so that the coincident part does not change the angle of the remainder
227bool SkOpSegment::addExpanded(double newT, const SkOpSpanBase* test, bool* startOver) {
228 if (this->contains(newT)) {
229 return true;
230 }
caryclark29b25632016-08-25 11:27:17 -0700231 this->globalState()->resetAllocatedOpSpan();
caryclarka35ab3e2016-10-20 08:32:18 -0700232 FAIL_IF(!between(0, newT, 1));
caryclark29b25632016-08-25 11:27:17 -0700233 SkOpPtT* newPtT = this->addT(newT);
234 *startOver |= this->globalState()->allocatedOpSpan();
caryclark55888e42016-07-18 10:01:36 -0700235 if (!newPtT) {
236 return false;
237 }
238 newPtT->fPt = this->ptAtT(newT);
caryclark29b25632016-08-25 11:27:17 -0700239 SkOpPtT* oppPrev = test->ptT()->oppPrev(newPtT);
240 if (oppPrev) {
caryclark8016b262016-09-06 05:59:47 -0700241 // const cast away to change linked list; pt/t values stays unchanged
caryclark29b25632016-08-25 11:27:17 -0700242 SkOpSpanBase* writableTest = const_cast<SkOpSpanBase*>(test);
caryclark30b9fdd2016-08-31 14:36:29 -0700243 writableTest->mergeMatches(newPtT->span());
caryclark29b25632016-08-25 11:27:17 -0700244 writableTest->ptT()->addOpp(newPtT, oppPrev);
caryclark55888e42016-07-18 10:01:36 -0700245 writableTest->checkForCollapsedCoincidence();
246 }
247 return true;
248}
249
250// Please keep this in sync with debugAddT()
Cary Clark73e597d2017-04-18 12:08:58 -0400251SkOpPtT* SkOpSegment::addT(double t, const SkPoint& pt) {
reed0dc4dd62015-03-24 13:55:33 -0700252 debugValidate();
caryclark29b25632016-08-25 11:27:17 -0700253 SkOpSpanBase* spanBase = &fHead;
caryclark54359292015-03-26 07:52:43 -0700254 do {
caryclark29b25632016-08-25 11:27:17 -0700255 SkOpPtT* result = spanBase->ptT();
caryclark27c015d2016-09-23 05:47:20 -0700256 if (t == result->fT || (!zero_or_one(t) && this->match(result, this, t, pt))) {
caryclark29b25632016-08-25 11:27:17 -0700257 spanBase->bumpSpanAdds();
caryclarkef4f32a2016-08-24 09:24:18 -0700258 return result;
reed0dc4dd62015-03-24 13:55:33 -0700259 }
caryclark54359292015-03-26 07:52:43 -0700260 if (t < result->fT) {
261 SkOpSpan* prev = result->span()->prev();
caryclark29b25632016-08-25 11:27:17 -0700262 FAIL_WITH_NULL_IF(!prev);
263 // marks in global state that new op span has been allocated
264 SkOpSpan* span = this->insert(prev);
caryclark54359292015-03-26 07:52:43 -0700265 span->init(this, prev, t, pt);
266 this->debugValidate();
267#if DEBUG_ADD_T
268 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
269 span->segment()->debugID(), span->debugID());
270#endif
caryclark08bc8482015-04-24 09:08:57 -0700271 span->bumpSpanAdds();
caryclark54359292015-03-26 07:52:43 -0700272 return span->ptT();
273 }
caryclark29b25632016-08-25 11:27:17 -0700274 FAIL_WITH_NULL_IF(spanBase == &fTail);
275 } while ((spanBase = spanBase->upCast()->next()));
caryclark54359292015-03-26 07:52:43 -0700276 SkASSERT(0);
caryclark29b25632016-08-25 11:27:17 -0700277 return nullptr; // we never get here, but need this to satisfy compiler
caryclark54359292015-03-26 07:52:43 -0700278}
279
Cary Clark73e597d2017-04-18 12:08:58 -0400280SkOpPtT* SkOpSegment::addT(double t) {
281 return addT(t, this->ptAtT(t));
282}
283
caryclark55888e42016-07-18 10:01:36 -0700284void SkOpSegment::calcAngles() {
caryclark54359292015-03-26 07:52:43 -0700285 bool activePrior = !fHead.isCanceled();
286 if (activePrior && !fHead.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700287 addStartSpan();
reed0dc4dd62015-03-24 13:55:33 -0700288 }
caryclark54359292015-03-26 07:52:43 -0700289 SkOpSpan* prior = &fHead;
290 SkOpSpanBase* spanBase = fHead.next();
291 while (spanBase != &fTail) {
292 if (activePrior) {
Herb Derbyecc364c2017-04-19 15:09:48 -0400293 SkOpAngle* priorAngle = this->globalState()->allocator()->make<SkOpAngle>();
caryclark54359292015-03-26 07:52:43 -0700294 priorAngle->set(spanBase, prior);
295 spanBase->setFromAngle(priorAngle);
reed0dc4dd62015-03-24 13:55:33 -0700296 }
caryclark54359292015-03-26 07:52:43 -0700297 SkOpSpan* span = spanBase->upCast();
298 bool active = !span->isCanceled();
299 SkOpSpanBase* next = span->next();
300 if (active) {
Herb Derbyecc364c2017-04-19 15:09:48 -0400301 SkOpAngle* angle = this->globalState()->allocator()->make<SkOpAngle>();
caryclark54359292015-03-26 07:52:43 -0700302 angle->set(span, next);
303 span->setToAngle(angle);
reed0dc4dd62015-03-24 13:55:33 -0700304 }
reed0dc4dd62015-03-24 13:55:33 -0700305 activePrior = active;
caryclark54359292015-03-26 07:52:43 -0700306 prior = span;
307 spanBase = next;
reed0dc4dd62015-03-24 13:55:33 -0700308 }
caryclark54359292015-03-26 07:52:43 -0700309 if (activePrior && !fTail.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700310 addEndSpan();
reed0dc4dd62015-03-24 13:55:33 -0700311 }
reed0dc4dd62015-03-24 13:55:33 -0700312}
313
caryclark55888e42016-07-18 10:01:36 -0700314// Please keep this in sync with debugClearAll()
315void SkOpSegment::clearAll() {
316 SkOpSpan* span = &fHead;
317 do {
318 this->clearOne(span);
319 } while ((span = span->next()->upCastable()));
320 this->globalState()->coincidence()->release(this);
321}
322
323// Please keep this in sync with debugClearOne()
324void SkOpSegment::clearOne(SkOpSpan* span) {
325 span->setWindValue(0);
326 span->setOppValue(0);
327 this->markDone(span);
328}
329
Cary Clarkba610292018-06-19 09:47:15 -0400330SkOpSpanBase::Collapsed SkOpSegment::collapsed(double s, double e) const {
caryclark30b9fdd2016-08-31 14:36:29 -0700331 const SkOpSpanBase* span = &fHead;
332 do {
Cary Clarkba610292018-06-19 09:47:15 -0400333 SkOpSpanBase::Collapsed result = span->collapsed(s, e);
334 if (SkOpSpanBase::Collapsed::kNo != result) {
335 return result;
caryclark30b9fdd2016-08-31 14:36:29 -0700336 }
337 } while (span->upCastable() && (span = span->upCast()->next()));
Cary Clarkba610292018-06-19 09:47:15 -0400338 return SkOpSpanBase::Collapsed::kNo;
caryclark30b9fdd2016-08-31 14:36:29 -0700339}
340
Cary Clark2587f412018-07-24 12:40:10 -0400341bool SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
caryclark@google.com570863f2013-09-16 15:55:01 +0000342 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700343 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000344 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
345 int sumSuWinding;
346 bool binary = includeType >= SkOpAngle::kBinarySingle;
347 if (binary) {
348 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
349 if (baseSegment->operand()) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400350 using std::swap;
351 swap(sumMiWinding, sumSuWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000352 }
353 }
354 SkOpSegment* nextSegment = nextAngle->segment();
355 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700356 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000357 if (binary) {
358 int oppMaxWinding, oppSumWinding;
359 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
360 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
Cary Clark2587f412018-07-24 12:40:10 -0400361 if (!nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
362 nextAngle, &last)) {
363 return false;
364 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000365 } else {
366 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
367 &maxWinding, &sumWinding);
Cary Clark2587f412018-07-24 12:40:10 -0400368 if (!nextSegment->markAngle(maxWinding, sumWinding, nextAngle, &last)) {
369 return false;
370 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000371 }
372 nextAngle->setLastMarked(last);
Cary Clark2587f412018-07-24 12:40:10 -0400373 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +0000374}
375
Cary Clark2587f412018-07-24 12:40:10 -0400376bool SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
caryclark@google.com570863f2013-09-16 15:55:01 +0000377 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700378 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000379 int sumMiWinding = baseSegment->updateWinding(baseAngle);
380 int sumSuWinding;
381 bool binary = includeType >= SkOpAngle::kBinarySingle;
382 if (binary) {
383 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
384 if (baseSegment->operand()) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400385 using std::swap;
386 swap(sumMiWinding, sumSuWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000387 }
388 }
389 SkOpSegment* nextSegment = nextAngle->segment();
390 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700391 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000392 if (binary) {
393 int oppMaxWinding, oppSumWinding;
394 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
395 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
Cary Clark2587f412018-07-24 12:40:10 -0400396 if (!nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
397 nextAngle, &last)) {
398 return false;
399 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000400 } else {
401 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
402 &maxWinding, &sumWinding);
Cary Clark2587f412018-07-24 12:40:10 -0400403 if (!nextSegment->markAngle(maxWinding, sumWinding, nextAngle, &last)) {
404 return false;
405 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000406 }
407 nextAngle->setLastMarked(last);
Cary Clark2587f412018-07-24 12:40:10 -0400408 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +0000409}
410
caryclark54359292015-03-26 07:52:43 -0700411// at this point, the span is already ordered, or unorderable
412int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
413 SkOpAngle::IncludeType includeType) {
414 SkASSERT(includeType != SkOpAngle::kUnaryXor);
415 SkOpAngle* firstAngle = this->spanToAngle(end, start);
halcanary96fcdcc2015-08-27 07:41:13 -0700416 if (nullptr == firstAngle || nullptr == firstAngle->next()) {
caryclark54359292015-03-26 07:52:43 -0700417 return SK_NaN32;
418 }
419 // if all angles have a computed winding,
420 // or if no adjacent angles are orderable,
421 // or if adjacent orderable angles have no computed winding,
422 // there's nothing to do
423 // if two orderable angles are adjacent, and both are next to orderable angles,
424 // and one has winding computed, transfer to the other
halcanary96fcdcc2015-08-27 07:41:13 -0700425 SkOpAngle* baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700426 bool tryReverse = false;
427 // look for counterclockwise transfers
428 SkOpAngle* angle = firstAngle->previous();
429 SkOpAngle* next = angle->next();
430 firstAngle = next;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000431 do {
caryclark54359292015-03-26 07:52:43 -0700432 SkOpAngle* prior = angle;
433 angle = next;
434 next = angle->next();
435 SkASSERT(prior->next() == angle);
436 SkASSERT(angle->next() == next);
437 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700438 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700439 continue;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000440 }
caryclark54359292015-03-26 07:52:43 -0700441 int testWinding = angle->starter()->windSum();
442 if (SK_MinS32 != testWinding) {
443 baseAngle = angle;
444 tryReverse = true;
445 continue;
reed0dc4dd62015-03-24 13:55:33 -0700446 }
caryclark54359292015-03-26 07:52:43 -0700447 if (baseAngle) {
448 ComputeOneSum(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700449 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
caryclark54359292015-03-26 07:52:43 -0700450 }
451 } while (next != firstAngle);
452 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
453 firstAngle = baseAngle;
454 tryReverse = true;
455 }
456 if (tryReverse) {
halcanary96fcdcc2015-08-27 07:41:13 -0700457 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700458 SkOpAngle* prior = firstAngle;
459 do {
460 angle = prior;
461 prior = angle->previous();
462 SkASSERT(prior->next() == angle);
463 next = angle->next();
464 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700465 baseAngle = nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700466 continue;
467 }
caryclark54359292015-03-26 07:52:43 -0700468 int testWinding = angle->starter()->windSum();
469 if (SK_MinS32 != testWinding) {
470 baseAngle = angle;
471 continue;
reed0dc4dd62015-03-24 13:55:33 -0700472 }
caryclark54359292015-03-26 07:52:43 -0700473 if (baseAngle) {
474 ComputeOneSumReverse(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700475 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700476 }
caryclark54359292015-03-26 07:52:43 -0700477 } while (prior != firstAngle);
reed0dc4dd62015-03-24 13:55:33 -0700478 }
caryclark54359292015-03-26 07:52:43 -0700479 return start->starter(end)->windSum();
reed0dc4dd62015-03-24 13:55:33 -0700480}
481
caryclark55888e42016-07-18 10:01:36 -0700482bool SkOpSegment::contains(double newT) const {
483 const SkOpSpanBase* spanBase = &fHead;
484 do {
485 if (spanBase->ptT()->contains(this, newT)) {
486 return true;
487 }
488 if (spanBase == &fTail) {
489 break;
490 }
491 spanBase = spanBase->upCast()->next();
492 } while (true);
493 return false;
494}
495
mtklein18300a32016-03-16 13:53:35 -0700496void SkOpSegment::release(const SkOpSpan* span) {
caryclark54359292015-03-26 07:52:43 -0700497 if (span->done()) {
caryclark08bc8482015-04-24 09:08:57 -0700498 --fDoneCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000499 }
caryclark08bc8482015-04-24 09:08:57 -0700500 --fCount;
caryclark15976282016-07-21 05:48:43 -0700501 SkOPASSERT(fCount >= fDoneCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000502}
503
Cary Clarke47ae292016-10-05 08:51:39 -0400504#if DEBUG_ANGLE
505// called only by debugCheckNearCoincidence
caryclark26ad22a2015-10-16 09:03:38 -0700506double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
caryclark54359292015-03-26 07:52:43 -0700507 SkDPoint testPt = this->dPtAtT(t);
508 SkDLine testPerp = {{ testPt, testPt }};
509 SkDVector slope = this->dSlopeAtT(t);
510 testPerp[1].fX += slope.fY;
511 testPerp[1].fY -= slope.fX;
512 SkIntersections i;
caryclark26ad22a2015-10-16 09:03:38 -0700513 const SkOpSegment* oppSegment = oppAngle->segment();
caryclark1049f122015-04-20 08:31:59 -0700514 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
caryclark54359292015-03-26 07:52:43 -0700515 double closestDistSq = SK_ScalarInfinity;
516 for (int index = 0; index < i.used(); ++index) {
517 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000518 continue;
519 }
caryclark54359292015-03-26 07:52:43 -0700520 double testDistSq = testPt.distanceSquared(i.pt(index));
521 if (closestDistSq > testDistSq) {
522 closestDistSq = testDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000523 }
524 }
caryclark54359292015-03-26 07:52:43 -0700525 return closestDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000526}
Cary Clarke47ae292016-10-05 08:51:39 -0400527#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000528
caryclark@google.com07393ca2013-04-08 11:47:37 +0000529/*
530 The M and S variable name parts stand for the operators.
531 Mi stands for Minuend (see wiki subtraction, analogous to difference)
532 Su stands for Subtrahend
533 The Opp variable name part designates that the value is for the Opposite operator.
534 Opposite values result from combining coincident spans.
535 */
caryclark54359292015-03-26 07:52:43 -0700536SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
Cary Clark1857ddb2018-07-11 11:01:43 -0400537 SkOpSpanBase** nextEnd, bool* unsortable, bool* simple,
538 SkPathOp op, int xorMiMask, int xorSuMask) {
caryclark54359292015-03-26 07:52:43 -0700539 SkOpSpanBase* start = *nextStart;
540 SkOpSpanBase* end = *nextEnd;
541 SkASSERT(start != end);
542 int step = start->step(end);
543 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
Cary Clark1857ddb2018-07-11 11:01:43 -0400544 if ((*simple = other)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000545 // mark the smaller of startIndex, endIndex done, and all adjacent
546 // spans with the same T value (but not 'other' spans)
547#if DEBUG_WINDING
548 SkDebugf("%s simple\n", __FUNCTION__);
549#endif
caryclark54359292015-03-26 07:52:43 -0700550 SkOpSpan* startSpan = start->starter(end);
551 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700552 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000553 }
caryclark54359292015-03-26 07:52:43 -0700554 markDone(startSpan);
555 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000556 return other;
557 }
caryclark54359292015-03-26 07:52:43 -0700558 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
559 SkASSERT(endNear == end); // is this ever not end?
560 SkASSERT(endNear);
561 SkASSERT(start != endNear);
562 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000563 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700564 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
caryclark@google.com570863f2013-09-16 15:55:01 +0000565 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000566 if (!sortable) {
567 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700568 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700569 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000570 }
caryclark54359292015-03-26 07:52:43 -0700571 SkOpAngle* angle = this->spanToAngle(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000572 if (angle->unorderable()) {
573 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700574 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700575 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000576 }
577#if DEBUG_SORT
578 SkDebugf("%s\n", __FUNCTION__);
579 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000580#endif
caryclark54359292015-03-26 07:52:43 -0700581 int sumMiWinding = updateWinding(end, start);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000582 if (sumMiWinding == SK_MinS32) {
583 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700584 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700585 return nullptr;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000586 }
caryclark54359292015-03-26 07:52:43 -0700587 int sumSuWinding = updateOppWinding(end, start);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000588 if (operand()) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400589 using std::swap;
590 swap(sumMiWinding, sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000591 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000592 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700593 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000594 bool foundDone = false;
595 // iterate through the angle, and compute everyone's winding
596 SkOpSegment* nextSegment;
597 int activeCount = 0;
598 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000599 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000600 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000601 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000602 if (activeAngle) {
603 ++activeCount;
604 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000605 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +0000606 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000607 }
608 }
609 if (nextSegment->done()) {
610 continue;
611 }
reed0dc4dd62015-03-24 13:55:33 -0700612 if (!activeAngle) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400613 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end(), nullptr);
reed0dc4dd62015-03-24 13:55:33 -0700614 }
caryclark54359292015-03-26 07:52:43 -0700615 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000616 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000617 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000618 *chase->append() = last;
619#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700620 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
621 last->segment()->debugID(), last->debugID());
622 if (!last->final()) {
623 SkDebugf(" windSum=%d", last->upCast()->windSum());
624 }
625 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000626#endif
627 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000628 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700629 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000630 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700631 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000632 }
633 *nextStart = foundAngle->start();
634 *nextEnd = foundAngle->end();
635 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000636#if DEBUG_WINDING
637 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
638 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
639 #endif
640 return nextSegment;
641}
642
caryclark54359292015-03-26 07:52:43 -0700643SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
644 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
645 SkOpSpanBase* start = *nextStart;
646 SkOpSpanBase* end = *nextEnd;
647 SkASSERT(start != end);
648 int step = start->step(end);
649 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
650 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000651 // mark the smaller of startIndex, endIndex done, and all adjacent
652 // spans with the same T value (but not 'other' spans)
653#if DEBUG_WINDING
654 SkDebugf("%s simple\n", __FUNCTION__);
655#endif
caryclark54359292015-03-26 07:52:43 -0700656 SkOpSpan* startSpan = start->starter(end);
657 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700658 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000659 }
caryclark54359292015-03-26 07:52:43 -0700660 markDone(startSpan);
661 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000662 return other;
663 }
caryclark54359292015-03-26 07:52:43 -0700664 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
665 SkASSERT(endNear == end); // is this ever not end?
666 SkASSERT(endNear);
667 SkASSERT(start != endNear);
668 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000669 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700670 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000671 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000672 if (!sortable) {
673 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700674 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700675 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000676 }
caryclark54359292015-03-26 07:52:43 -0700677 SkOpAngle* angle = this->spanToAngle(end, start);
678 if (angle->unorderable()) {
679 *unsortable = true;
680 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700681 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700682 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000683#if DEBUG_SORT
684 SkDebugf("%s\n", __FUNCTION__);
685 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000686#endif
caryclark54359292015-03-26 07:52:43 -0700687 int sumWinding = updateWinding(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000688 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700689 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000690 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700691 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000692 SkOpSegment* nextSegment;
693 int activeCount = 0;
694 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000695 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000696 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000697 &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000698 if (activeAngle) {
699 ++activeCount;
700 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000701 foundAngle = nextAngle;
702 foundDone = nextSegment->done(nextAngle);
703 }
704 }
705 if (nextSegment->done()) {
706 continue;
707 }
reed0dc4dd62015-03-24 13:55:33 -0700708 if (!activeAngle) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400709 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end(), nullptr);
reed0dc4dd62015-03-24 13:55:33 -0700710 }
caryclark54359292015-03-26 07:52:43 -0700711 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000712 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000713 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000714 *chase->append() = last;
715#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700716 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
717 last->segment()->debugID(), last->debugID());
718 if (!last->final()) {
719 SkDebugf(" windSum=%d", last->upCast()->windSum());
720 }
721 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000722#endif
723 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000724 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700725 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000726 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700727 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000728 }
729 *nextStart = foundAngle->start();
730 *nextEnd = foundAngle->end();
731 nextSegment = foundAngle->segment();
732#if DEBUG_WINDING
733 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
734 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
735 #endif
736 return nextSegment;
737}
738
caryclark54359292015-03-26 07:52:43 -0700739SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
740 bool* unsortable) {
741 SkOpSpanBase* start = *nextStart;
742 SkOpSpanBase* end = *nextEnd;
743 SkASSERT(start != end);
744 int step = start->step(end);
745 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
746 if (other) {
747 // mark the smaller of startIndex, endIndex done, and all adjacent
748 // spans with the same T value (but not 'other' spans)
caryclark@google.com07393ca2013-04-08 11:47:37 +0000749#if DEBUG_WINDING
750 SkDebugf("%s simple\n", __FUNCTION__);
751#endif
caryclark54359292015-03-26 07:52:43 -0700752 SkOpSpan* startSpan = start->starter(end);
753 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700754 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000755 }
caryclark54359292015-03-26 07:52:43 -0700756 markDone(startSpan);
757 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000758 return other;
759 }
caryclark54359292015-03-26 07:52:43 -0700760 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
761 : (*nextStart)->prev());
762 SkASSERT(endNear == end); // is this ever not end?
763 SkASSERT(endNear);
764 SkASSERT(start != endNear);
765 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
766 SkOpAngle* angle = this->spanToAngle(end, start);
caryclark27c8eb82015-07-06 11:38:33 -0700767 if (!angle || angle->unorderable()) {
caryclark54359292015-03-26 07:52:43 -0700768 *unsortable = true;
769 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700770 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700771 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000772#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000773 SkDebugf("%s\n", __FUNCTION__);
774 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000775#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000776 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700777 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000778 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700779 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000780 SkOpSegment* nextSegment;
781 int activeCount = 0;
782 do {
Cary Clark56071432018-06-19 08:33:52 -0400783 if (!nextAngle) {
784 return nullptr;
785 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000786 nextSegment = nextAngle->segment();
787 ++activeCount;
788 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000789 foundAngle = nextAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000790 if (!(foundDone = nextSegment->done(nextAngle))) {
791 break;
792 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000793 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000794 nextAngle = nextAngle->next();
795 } while (nextAngle != angle);
caryclark54359292015-03-26 07:52:43 -0700796 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000797 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700798 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000799 }
800 *nextStart = foundAngle->start();
801 *nextEnd = foundAngle->end();
802 nextSegment = foundAngle->segment();
803#if DEBUG_WINDING
804 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
805 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
806 #endif
807 return nextSegment;
808}
809
caryclark54359292015-03-26 07:52:43 -0700810SkOpGlobalState* SkOpSegment::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700811 return contour()->globalState();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000812}
813
caryclark1049f122015-04-20 08:31:59 -0700814void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
caryclark54359292015-03-26 07:52:43 -0700815 fContour = contour;
halcanary96fcdcc2015-08-27 07:41:13 -0700816 fNext = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000817 fPts = pts;
caryclark1049f122015-04-20 08:31:59 -0700818 fWeight = weight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000819 fVerb = verb;
caryclark54359292015-03-26 07:52:43 -0700820 fCount = 0;
821 fDoneCount = 0;
822 fVisited = false;
823 SkOpSpan* zeroSpan = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700824 zeroSpan->init(this, nullptr, 0, fPts[0]);
caryclark54359292015-03-26 07:52:43 -0700825 SkOpSpanBase* oneSpan = &fTail;
826 zeroSpan->setNext(oneSpan);
827 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
caryclark1049f122015-04-20 08:31:59 -0700828 SkDEBUGCODE(fID = globalState()->nextSegmentID());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000829}
830
caryclark54359292015-03-26 07:52:43 -0700831bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
832 SkDPoint cPt = this->dPtAtT(t);
caryclark1049f122015-04-20 08:31:59 -0700833 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
caryclark54359292015-03-26 07:52:43 -0700834 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
835 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -0700836 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
caryclark54359292015-03-26 07:52:43 -0700837 int used = i.used();
838 for (int index = 0; index < used; ++index) {
839 if (cPt.roughlyEqual(i.pt(index))) {
reed0dc4dd62015-03-24 13:55:33 -0700840 return true;
841 }
caryclark54359292015-03-26 07:52:43 -0700842 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000843 return false;
844}
845
caryclark54359292015-03-26 07:52:43 -0700846bool SkOpSegment::isXor() const {
847 return fContour->isXor();
848}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000849
caryclark5b5ddd72015-05-18 05:12:56 -0700850void SkOpSegment::markAllDone() {
851 SkOpSpan* span = this->head();
852 do {
853 this->markDone(span);
854 } while ((span = span->next()->upCastable()));
855}
856
Cary Clarkc050a1a2018-06-25 08:45:40 -0400857 bool SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end, SkOpSpanBase** found) {
caryclark54359292015-03-26 07:52:43 -0700858 int step = start->step(end);
859 SkOpSpan* minSpan = start->starter(end);
860 markDone(minSpan);
halcanary96fcdcc2015-08-27 07:41:13 -0700861 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000862 SkOpSegment* other = this;
Cary Clark918fb1f2016-11-15 13:22:25 -0500863 SkOpSpan* priorDone = nullptr;
864 SkOpSpan* lastDone = nullptr;
Cary Clarkc050a1a2018-06-25 08:45:40 -0400865 int safetyNet = 100000;
caryclark54359292015-03-26 07:52:43 -0700866 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400867 if (!--safetyNet) {
868 return false;
869 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000870 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -0700871 SkASSERT(!last);
872 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000873 }
Cary Clark918fb1f2016-11-15 13:22:25 -0500874 if (lastDone == minSpan || priorDone == minSpan) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400875 if (found) {
876 *found = nullptr;
877 }
878 return true;
Cary Clark918fb1f2016-11-15 13:22:25 -0500879 }
caryclark54359292015-03-26 07:52:43 -0700880 other->markDone(minSpan);
Cary Clark918fb1f2016-11-15 13:22:25 -0500881 priorDone = lastDone;
882 lastDone = minSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000883 }
Cary Clarkc050a1a2018-06-25 08:45:40 -0400884 if (found) {
885 *found = last;
886 }
887 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000888}
889
caryclark54359292015-03-26 07:52:43 -0700890bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
891 SkOpSpanBase** lastPtr) {
892 SkOpSpan* spanStart = start->starter(end);
893 int step = start->step(end);
894 bool success = markWinding(spanStart, winding);
halcanary96fcdcc2015-08-27 07:41:13 -0700895 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000896 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700897 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
898 if (spanStart->windSum() != SK_MinS32) {
caryclarkb36a3cd2016-10-18 07:59:44 -0700899// SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive?
caryclarkdac1d172014-06-17 05:15:38 -0700900 SkASSERT(!last);
901 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000902 }
caryclark54359292015-03-26 07:52:43 -0700903 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000904 }
caryclark65f55312014-11-13 06:58:52 -0800905 if (lastPtr) {
906 *lastPtr = last;
907 }
908 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000909}
910
caryclark54359292015-03-26 07:52:43 -0700911bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
912 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
913 SkOpSpan* spanStart = start->starter(end);
914 int step = start->step(end);
915 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700916 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000917 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700918 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
919 if (spanStart->windSum() != SK_MinS32) {
920 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700921 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700922 this->globalState()->setWindingFailed();
Cary Clark2587f412018-07-24 12:40:10 -0400923 return true; // ... but let it succeed anyway
caryclarkdac1d172014-06-17 05:15:38 -0700924 }
caryclark54359292015-03-26 07:52:43 -0700925 } else {
Cary Clark2587f412018-07-24 12:40:10 -0400926 FAIL_IF(spanStart->windSum() != oppWinding);
caryclark54359292015-03-26 07:52:43 -0700927 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700928 }
929 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700930 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000931 }
caryclark54359292015-03-26 07:52:43 -0700932 if (this->operand() == other->operand()) {
933 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700934 } else {
caryclark54359292015-03-26 07:52:43 -0700935 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700936 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000937 }
caryclark65f55312014-11-13 06:58:52 -0800938 if (lastPtr) {
939 *lastPtr = last;
940 }
941 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000942}
943
Cary Clark2587f412018-07-24 12:40:10 -0400944bool SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle,
945 SkOpSpanBase** result) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000946 SkASSERT(angle->segment() == this);
947 if (UseInnerWinding(maxWinding, sumWinding)) {
948 maxWinding = sumWinding;
949 }
Cary Clark2587f412018-07-24 12:40:10 -0400950 if (!markAndChaseWinding(angle->start(), angle->end(), maxWinding, result)) {
951 return false;
952 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000953#if DEBUG_WINDING
954 if (last) {
caryclark54359292015-03-26 07:52:43 -0700955 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
956 last->segment()->debugID(), last->debugID());
957 if (!last->final()) {
958 SkDebugf(" windSum=");
959 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
960 }
961 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000962 }
963#endif
Cary Clark2587f412018-07-24 12:40:10 -0400964 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000965}
966
Cary Clark2587f412018-07-24 12:40:10 -0400967bool SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
968 int oppSumWinding, const SkOpAngle* angle, SkOpSpanBase** result) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000969 SkASSERT(angle->segment() == this);
970 if (UseInnerWinding(maxWinding, sumWinding)) {
971 maxWinding = sumWinding;
972 }
973 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
974 oppMaxWinding = oppSumWinding;
975 }
caryclark65f55312014-11-13 06:58:52 -0800976 // caller doesn't require that this marks anything
Cary Clark2587f412018-07-24 12:40:10 -0400977 if (!markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, result)) {
978 return false;
979 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000980#if DEBUG_WINDING
981 if (last) {
caryclark54359292015-03-26 07:52:43 -0700982 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
983 last->segment()->debugID(), last->debugID());
984 if (!last->final()) {
985 SkDebugf(" windSum=");
986 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
987 }
988 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000989 }
990#endif
Cary Clark2587f412018-07-24 12:40:10 -0400991 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000992}
993
caryclark54359292015-03-26 07:52:43 -0700994void SkOpSegment::markDone(SkOpSpan* span) {
995 SkASSERT(this == span->segment());
996 if (span->done()) {
997 return;
998 }
999#if DEBUG_MARK_DONE
1000 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
1001#endif
1002 span->setDone(true);
1003 ++fDoneCount;
1004 debugValidate();
1005}
1006
1007bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
1008 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -07001009 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -07001010 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001011 return false;
1012 }
1013#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -07001014 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -07001015#endif
caryclark54359292015-03-26 07:52:43 -07001016 span->setWindSum(winding);
1017 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001018 return true;
1019}
1020
caryclark54359292015-03-26 07:52:43 -07001021bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
1022 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +00001023 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -07001024 if (span->done()) {
1025 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001026 }
caryclark54359292015-03-26 07:52:43 -07001027#if DEBUG_MARK_DONE
1028 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1029#endif
1030 span->setWindSum(winding);
1031 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001032 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001033 return true;
1034}
1035
caryclark54359292015-03-26 07:52:43 -07001036bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclarkef4f32a2016-08-24 09:24:18 -07001037 const SkPoint& testPt) const {
caryclark55888e42016-07-18 10:01:36 -07001038 SkASSERT(this == base->segment());
1039 if (this == testParent) {
1040 if (precisely_equal(base->fT, testT)) {
1041 return true;
1042 }
caryclark54359292015-03-26 07:52:43 -07001043 }
1044 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1045 return false;
1046 }
caryclark55888e42016-07-18 10:01:36 -07001047 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001048}
1049
1050static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1051 if (last) {
1052 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001053 }
halcanary96fcdcc2015-08-27 07:41:13 -07001054 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001055}
1056
caryclark54359292015-03-26 07:52:43 -07001057SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1058 SkOpSpanBase** last) const {
1059 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001060 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001061 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1062 SkASSERT(endSpan);
1063 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1064 SkOpSpanBase* foundSpan;
1065 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001066 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001067 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001068 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001069 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001070 }
caryclark54359292015-03-26 07:52:43 -07001071 SkOpPtT* otherPtT = endSpan->ptT()->next();
1072 other = otherPtT->segment();
1073 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001074 otherEnd = step > 0
1075 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1076 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001077 } else {
1078 int loopCount = angle->loopCount();
1079 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001080 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001081 }
1082 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001083 if (nullptr == next) {
1084 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001085 }
caryclarkdac1d172014-06-17 05:15:38 -07001086#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001087 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001088 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001089 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001090 }
caryclark54359292015-03-26 07:52:43 -07001091#endif
caryclarkdac1d172014-06-17 05:15:38 -07001092 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001093 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001094 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001095 }
caryclark343382e2016-06-29 08:18:38 -07001096 if (!otherEnd) {
1097 return nullptr;
1098 }
caryclark54359292015-03-26 07:52:43 -07001099 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001100 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001101 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001102 }
caryclark54359292015-03-26 07:52:43 -07001103 SkASSERT(*startPtr);
caryclark65b427c2014-09-18 10:32:57 -07001104// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001105 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1106 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1107 if (foundMin->windValue() != origMin->windValue()
1108 || foundMin->oppValue() != origMin->oppValue()) {
1109 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001110 }
caryclark54359292015-03-26 07:52:43 -07001111 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001112 *stepPtr = foundStep;
1113 if (minPtr) {
1114 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001115 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001116 return other;
1117}
1118
caryclark55888e42016-07-18 10:01:36 -07001119// Please keep this in sync with DebugClearVisited()
1120void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001121 // reset visited flag back to false
1122 do {
1123 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1124 while ((ptT = ptT->next()) != stopPtT) {
1125 SkOpSegment* opp = ptT->segment();
1126 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001127 }
caryclarkbca19f72015-05-13 08:23:48 -07001128 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001129}
1130
caryclark55888e42016-07-18 10:01:36 -07001131// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001132// look for pairs of undetected coincident curves
1133// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001134// Even though pairs of curves correct detect coincident runs, a run may be missed
1135// if the coincidence is a product of multiple intersections. For instance, given
1136// curves A, B, and C:
1137// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1138// the end of C that the intersection is replaced with the end of C.
1139// Even though A-B correctly do not detect an intersection at point 2,
1140// the resulting run from point 1 to point 2 is coincident on A and B.
1141bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001142 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001143 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001144 }
halcanary96fcdcc2015-08-27 07:41:13 -07001145 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001146 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001147 bool result = false;
caryclark54359292015-03-26 07:52:43 -07001148 do {
caryclarkbca19f72015-05-13 08:23:48 -07001149 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001150 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001151 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001152 if (ptT->deleted()) {
1153 continue;
1154 }
caryclark54359292015-03-26 07:52:43 -07001155 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001156 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001157 continue;
reed0dc4dd62015-03-24 13:55:33 -07001158 }
caryclarkbca19f72015-05-13 08:23:48 -07001159 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1160 if (!opp->visited()) {
1161 continue;
1162 }
1163 if (spanBase == &fHead) {
1164 continue;
1165 }
caryclark55888e42016-07-18 10:01:36 -07001166 if (ptT->segment() == this) {
1167 continue;
1168 }
caryclarkbca19f72015-05-13 08:23:48 -07001169 SkOpSpan* span = spanBase->upCastable();
1170 // FIXME?: this assumes that if the opposite segment is coincident then no more
1171 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001172 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001173 continue;
1174 }
caryclarkbca19f72015-05-13 08:23:48 -07001175 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001176 continue;
caryclark55888e42016-07-18 10:01:36 -07001177 }
halcanary96fcdcc2015-08-27 07:41:13 -07001178 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001179 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001180 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001181 SkOpSpan* priorTest = spanBase->prev();
1182 while (!priorOpp && priorTest) {
1183 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001184 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001185 if (priorPtT->deleted()) {
1186 continue;
1187 }
caryclark54359292015-03-26 07:52:43 -07001188 SkOpSegment* segment = priorPtT->span()->segment();
1189 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001190 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001191 priorOpp = opp;
1192 break;
1193 }
1194 }
caryclarkbca19f72015-05-13 08:23:48 -07001195 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001196 }
1197 if (!priorOpp) {
1198 continue;
1199 }
caryclark26ad22a2015-10-16 09:03:38 -07001200 if (priorPtT == ptT) {
1201 continue;
1202 }
caryclark54359292015-03-26 07:52:43 -07001203 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001204 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001205 bool swapped = priorPtT->fT > ptT->fT;
1206 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001207 using std::swap;
1208 swap(priorPtT, ptT);
1209 swap(oppStart, oppEnd);
caryclark54359292015-03-26 07:52:43 -07001210 }
caryclark55888e42016-07-18 10:01:36 -07001211 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1212 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1213 SkOpPtT* rootPtT = ptT->span()->ptT();
1214 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1215 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1216 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001217 goto swapBack;
1218 }
caryclark55888e42016-07-18 10:01:36 -07001219 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001220 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001221#if DEBUG_COINCIDENCE_VERBOSE
1222 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1223 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1224 rootOppEnd->debugID());
1225#endif
1226 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1227 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001228 }
caryclark55888e42016-07-18 10:01:36 -07001229#if DEBUG_COINCIDENCE
1230 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1231#endif
1232 result = true;
caryclark54359292015-03-26 07:52:43 -07001233 }
1234 swapBack:
1235 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001236 using std::swap;
1237 swap(priorPtT, ptT);
caryclark54359292015-03-26 07:52:43 -07001238 }
reed0dc4dd62015-03-24 13:55:33 -07001239 }
halcanary96fcdcc2015-08-27 07:41:13 -07001240 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001241 ClearVisited(&fHead);
1242 return result;
reed0dc4dd62015-03-24 13:55:33 -07001243}
1244
caryclark55888e42016-07-18 10:01:36 -07001245// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001246// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001247bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001248 debugValidate();
1249 SkOpSpanBase* test = &fHead;
1250 do {
1251 int addCount = test->spanAddsCount();
Cary Clark7eb01e02016-12-08 14:36:32 -05001252// FAIL_IF(addCount < 1);
1253 if (addCount <= 1) {
caryclark08bc8482015-04-24 09:08:57 -07001254 continue;
1255 }
1256 SkOpPtT* startPtT = test->ptT();
1257 SkOpPtT* testPtT = startPtT;
1258 do { // iterate through all spans associated with start
1259 SkOpSpanBase* oppSpan = testPtT->span();
1260 if (oppSpan->spanAddsCount() == addCount) {
1261 continue;
1262 }
1263 if (oppSpan->deleted()) {
1264 continue;
1265 }
1266 SkOpSegment* oppSegment = oppSpan->segment();
1267 if (oppSegment == this) {
1268 continue;
1269 }
1270 // find range of spans to consider merging
1271 SkOpSpanBase* oppPrev = oppSpan;
1272 SkOpSpanBase* oppFirst = oppSpan;
1273 while ((oppPrev = oppPrev->prev())) {
1274 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1275 break;
1276 }
1277 if (oppPrev->spanAddsCount() == addCount) {
1278 continue;
1279 }
1280 if (oppPrev->deleted()) {
1281 continue;
1282 }
1283 oppFirst = oppPrev;
1284 }
1285 SkOpSpanBase* oppNext = oppSpan;
1286 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001287 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001288 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1289 break;
1290 }
1291 if (oppNext->spanAddsCount() == addCount) {
1292 continue;
1293 }
1294 if (oppNext->deleted()) {
1295 continue;
1296 }
1297 oppLast = oppNext;
1298 }
1299 if (oppFirst == oppLast) {
1300 continue;
1301 }
1302 SkOpSpanBase* oppTest = oppFirst;
1303 do {
1304 if (oppTest == oppSpan) {
1305 continue;
1306 }
1307 // check to see if the candidate meets specific criteria:
1308 // it contains spans of segments in test's loop but not including 'this'
1309 SkOpPtT* oppStartPtT = oppTest->ptT();
1310 SkOpPtT* oppPtT = oppStartPtT;
1311 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1312 SkOpSegment* oppPtTSegment = oppPtT->segment();
1313 if (oppPtTSegment == this) {
1314 goto tryNextSpan;
1315 }
1316 SkOpPtT* matchPtT = startPtT;
1317 do {
1318 if (matchPtT->segment() == oppPtTSegment) {
1319 goto foundMatch;
1320 }
1321 } while ((matchPtT = matchPtT->next()) != startPtT);
1322 goto tryNextSpan;
1323 foundMatch: // merge oppTest and oppSpan
1324 oppSegment->debugValidate();
caryclark30b9fdd2016-08-31 14:36:29 -07001325 oppTest->mergeMatches(oppSpan);
1326 oppTest->addOpp(oppSpan);
caryclark08bc8482015-04-24 09:08:57 -07001327 oppSegment->debugValidate();
1328 goto checkNextSpan;
1329 }
caryclark55888e42016-07-18 10:01:36 -07001330 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001331 ;
1332 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1333 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001334checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001335 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001336 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001337 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001338 return true;
caryclark08bc8482015-04-24 09:08:57 -07001339}
1340
caryclark55888e42016-07-18 10:01:36 -07001341// adjacent spans may have points close by
Cary Clark28da2832017-03-21 10:30:50 -04001342bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan,
1343 bool* found) const {
caryclark55888e42016-07-18 10:01:36 -07001344 const SkOpPtT* refHead = refSpan->ptT();
1345 const SkOpPtT* checkHead = checkSpan->ptT();
1346// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
caryclark30b9fdd2016-08-31 14:36:29 -07001347 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
caryclark55888e42016-07-18 10:01:36 -07001348#if DEBUG_COINCIDENCE
1349 // verify that no combination of points are close
1350 const SkOpPtT* dBugRef = refHead;
1351 do {
1352 const SkOpPtT* dBugCheck = checkHead;
1353 do {
caryclark30b9fdd2016-08-31 14:36:29 -07001354 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
caryclark55888e42016-07-18 10:01:36 -07001355 dBugCheck = dBugCheck->next();
1356 } while (dBugCheck != checkHead);
1357 dBugRef = dBugRef->next();
1358 } while (dBugRef != refHead);
1359#endif
Cary Clark28da2832017-03-21 10:30:50 -04001360 *found = false;
1361 return true;
caryclark55888e42016-07-18 10:01:36 -07001362 }
1363 // check only unique points
1364 SkScalar distSqBest = SK_ScalarMax;
1365 const SkOpPtT* refBest = nullptr;
1366 const SkOpPtT* checkBest = nullptr;
1367 const SkOpPtT* ref = refHead;
1368 do {
1369 if (ref->deleted()) {
1370 continue;
1371 }
1372 while (ref->ptAlreadySeen(refHead)) {
1373 ref = ref->next();
1374 if (ref == refHead) {
1375 goto doneCheckingDistance;
1376 }
1377 }
1378 const SkOpPtT* check = checkHead;
1379 const SkOpSegment* refSeg = ref->segment();
Cary Clark28da2832017-03-21 10:30:50 -04001380 int escapeHatch = 100000; // defend against infinite loops
caryclark55888e42016-07-18 10:01:36 -07001381 do {
1382 if (check->deleted()) {
1383 continue;
1384 }
1385 while (check->ptAlreadySeen(checkHead)) {
1386 check = check->next();
1387 if (check == checkHead) {
1388 goto nextRef;
1389 }
1390 }
Cary Clarkdf429f32017-11-08 11:44:31 -05001391 SkScalar distSq = SkPointPriv::DistanceToSqd(ref->fPt, check->fPt);
caryclark55888e42016-07-18 10:01:36 -07001392 if (distSqBest > distSq && (refSeg != check->segment()
1393 || !refSeg->ptsDisjoint(*ref, *check))) {
1394 distSqBest = distSq;
1395 refBest = ref;
1396 checkBest = check;
1397 }
Cary Clark28da2832017-03-21 10:30:50 -04001398 if (--escapeHatch <= 0) {
1399 return false;
1400 }
caryclark55888e42016-07-18 10:01:36 -07001401 } while ((check = check->next()) != checkHead);
Cary Clark28da2832017-03-21 10:30:50 -04001402 nextRef:
caryclark55888e42016-07-18 10:01:36 -07001403 ;
1404 } while ((ref = ref->next()) != refHead);
1405doneCheckingDistance:
Cary Clark28da2832017-03-21 10:30:50 -04001406 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001407 checkBest->fPt);
Cary Clark28da2832017-03-21 10:30:50 -04001408 return true;
caryclark55888e42016-07-18 10:01:36 -07001409}
1410
1411// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001412// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
Cary Clark28da2832017-03-21 10:30:50 -04001413bool SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001414 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001415 // release undeleted spans pointing to this seg that are linked to the primary span
1416 SkOpSpanBase* spanBase = &fHead;
Cary Clark43938b82017-10-18 08:47:32 -04001417 int escapeHatch = 9999; // the largest count for a regular test is 50; for a fuzzer, 500
caryclark54359292015-03-26 07:52:43 -07001418 do {
caryclark55888e42016-07-18 10:01:36 -07001419 SkOpPtT* ptT = spanBase->ptT();
1420 const SkOpPtT* headPtT = ptT;
1421 while ((ptT = ptT->next()) != headPtT) {
Cary Clark43938b82017-10-18 08:47:32 -04001422 if (!--escapeHatch) {
1423 return false;
1424 }
caryclark55888e42016-07-18 10:01:36 -07001425 SkOpSpanBase* test = ptT->span();
1426 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1427 && test->ptT() == ptT) {
1428 if (test->final()) {
1429 if (spanBase == &fHead) {
1430 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001431 return true;
caryclark55888e42016-07-18 10:01:36 -07001432 }
1433 spanBase->upCast()->release(ptT);
1434 } else if (test->prev()) {
1435 test->upCast()->release(headPtT);
1436 }
1437 break;
caryclark54359292015-03-26 07:52:43 -07001438 }
reed0dc4dd62015-03-24 13:55:33 -07001439 }
caryclark55888e42016-07-18 10:01:36 -07001440 spanBase = spanBase->upCast()->next();
1441 } while (!spanBase->final());
caryclark55888e42016-07-18 10:01:36 -07001442 // This loop looks for adjacent spans which are near by
1443 spanBase = &fHead;
1444 do { // iterate through all spans associated with start
1445 SkOpSpanBase* test = spanBase->upCast()->next();
Cary Clark28da2832017-03-21 10:30:50 -04001446 bool found;
1447 if (!this->spansNearby(spanBase, test, &found)) {
1448 return false;
1449 }
1450 if (found) {
caryclark55888e42016-07-18 10:01:36 -07001451 if (test->final()) {
1452 if (spanBase->prev()) {
1453 test->merge(spanBase->upCast());
1454 } else {
1455 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001456 return true;
caryclark55888e42016-07-18 10:01:36 -07001457 }
1458 } else {
1459 spanBase->merge(test->upCast());
1460 }
1461 }
1462 spanBase = test;
1463 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001464 debugValidate();
Cary Clark28da2832017-03-21 10:30:50 -04001465 return true;
reed0dc4dd62015-03-24 13:55:33 -07001466}
1467
caryclark54359292015-03-26 07:52:43 -07001468bool SkOpSegment::operand() const {
1469 return fContour->operand();
1470}
1471
1472bool SkOpSegment::oppXor() const {
1473 return fContour->oppXor();
1474}
1475
1476bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1477 if (fVerb == SkPath::kLine_Verb) {
1478 return false;
1479 }
1480 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1481 // hits in two places with very different t values.
1482 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1483 // 'controls contained by ends' could avoid this check for common curves
1484 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1485 // on the other hand, the below check is relatively inexpensive
1486 double midT = (t1 + t2) / 2;
1487 SkPoint midPt = this->ptAtT(midT);
Cary Clarkdf429f32017-11-08 11:44:31 -05001488 double seDistSq = SkTMax(SkPointPriv::DistanceToSqd(pt1, pt2) * 2, FLT_EPSILON * 2);
1489 return SkPointPriv::DistanceToSqd(midPt, pt1) > seDistSq ||
1490 SkPointPriv::DistanceToSqd(midPt, pt2) > seDistSq;
caryclark54359292015-03-26 07:52:43 -07001491}
1492
1493void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1494 int* maxWinding, int* sumWinding) {
1495 int deltaSum = SpanSign(start, end);
1496 *maxWinding = *sumMiWinding;
1497 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001498 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001499}
1500
1501void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1502 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1503 int* oppSumWinding) {
1504 int deltaSum = SpanSign(start, end);
1505 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001506 if (operand()) {
1507 *maxWinding = *sumSuWinding;
1508 *sumWinding = *sumSuWinding -= deltaSum;
1509 *oppMaxWinding = *sumMiWinding;
1510 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1511 } else {
1512 *maxWinding = *sumMiWinding;
1513 *sumWinding = *sumMiWinding -= deltaSum;
1514 *oppMaxWinding = *sumSuWinding;
1515 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1516 }
bungeman60e0fee2015-08-26 05:15:46 -07001517 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1518 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001519}
1520
caryclarkb36a3cd2016-10-18 07:59:44 -07001521bool SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001522 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001523 do {
caryclark54359292015-03-26 07:52:43 -07001524 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001525 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001526 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001527 continue;
1528 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001529#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001530 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001531#endif
caryclark54359292015-03-26 07:52:43 -07001532 SkOpAngle* baseAngle = fromAngle;
1533 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001534#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001535 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1536 span->debugID());
1537 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001538#endif
caryclarkb36a3cd2016-10-18 07:59:44 -07001539 FAIL_IF(!fromAngle->insert(toAngle));
caryclark54359292015-03-26 07:52:43 -07001540 } else if (!fromAngle) {
1541 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001542 }
caryclark54359292015-03-26 07:52:43 -07001543 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001544 do {
caryclark54359292015-03-26 07:52:43 -07001545 SkOpSpanBase* oSpan = ptT->span();
1546 if (oSpan == span) {
1547 continue;
1548 }
1549 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001550 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001551#if DEBUG_ANGLE
1552 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001553 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1554 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001555 wroteAfterHeader = true;
1556 }
1557#endif
caryclark54359292015-03-26 07:52:43 -07001558 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001559 baseAngle->insert(oAngle);
1560 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001561 }
caryclark54359292015-03-26 07:52:43 -07001562 if (!oSpan->final()) {
1563 oAngle = oSpan->upCast()->toAngle();
1564 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001565#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001566 if (!wroteAfterHeader) {
1567 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1568 span->t(), span->debugID());
1569 wroteAfterHeader = true;
1570 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001571#endif
caryclark54359292015-03-26 07:52:43 -07001572 if (!oAngle->loopContains(baseAngle)) {
1573 baseAngle->insert(oAngle);
1574 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001575 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001576 }
caryclark54359292015-03-26 07:52:43 -07001577 } while ((ptT = ptT->next()) != stopPtT);
1578 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001579 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001580 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001581 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001582 }
halcanary96fcdcc2015-08-27 07:41:13 -07001583 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001584 }
1585#if DEBUG_SORT
1586 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1587#endif
caryclark54359292015-03-26 07:52:43 -07001588 } while (!span->final() && (span = span->upCast()->next()));
caryclarkb36a3cd2016-10-18 07:59:44 -07001589 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +00001590}
1591
caryclark54359292015-03-26 07:52:43 -07001592bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001593 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001594 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001595 const SkOpPtT& startPtT = *start->ptT();
1596 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001597 SkDEBUGCODE(edge->fVerb = fVerb);
1598 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001599 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001600 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001601 if (fVerb == SkPath::kLine_Verb) {
1602 return false;
1603 }
caryclark54359292015-03-26 07:52:43 -07001604 double startT = startPtT.fT;
1605 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001606 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1607 // don't compute midpoints if we already have them
1608 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001609 edge->fLine[1].set(fPts[1]);
1610 return false;
1611 }
1612 if (fVerb == SkPath::kConic_Verb) {
1613 edge->fConic[1].set(fPts[1]);
1614 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001615 return false;
1616 }
1617 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001618 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001619 edge->fCubic[1].set(fPts[1]);
1620 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001621 return false;
1622 }
caryclark1049f122015-04-20 08:31:59 -07001623 edge->fCubic[1].set(fPts[2]);
1624 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001625 return false;
1626 }
1627 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001628 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1629 } else if (fVerb == SkPath::kConic_Verb) {
1630 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1631 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001632 } else {
1633 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001634 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001635 }
1636 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001637}
1638
caryclark27c8eb82015-07-06 11:38:33 -07001639bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001640 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001641 // average t, find mid pt
1642 double midT = (prior->t() + spanBase->t()) / 2;
1643 SkPoint midPt = this->ptAtT(midT);
1644 bool coincident = true;
1645 // if the mid pt is not near either end pt, project perpendicular through opp seg
1646 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1647 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001648 if (priorPtT->span() == ptT->span()) {
1649 return false;
1650 }
caryclark27c8eb82015-07-06 11:38:33 -07001651 coincident = false;
1652 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001653 SkDCurve curvePart;
1654 this->subDivide(prior, spanBase, &curvePart);
1655 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1656 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1657 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1658 SkDCurve oppPart;
1659 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1660 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001661 // measure distance and see if it's small enough to denote coincidence
1662 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001663 if (!between(0, i[0][index], 1)) {
1664 continue;
1665 }
caryclark27c8eb82015-07-06 11:38:33 -07001666 SkDPoint oppPt = i.pt(index);
caryclark30b9fdd2016-08-31 14:36:29 -07001667 if (oppPt.approximatelyDEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001668 // the coincidence can occur at almost any angle
1669 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001670 }
1671 }
1672 }
1673 return coincident;
1674}
1675
Cary Clarkab2d73b2016-12-16 17:17:25 -05001676SkOpSpan* SkOpSegment::undoneSpan() {
1677 SkOpSpan* span = &fHead;
1678 SkOpSpanBase* next;
caryclark54359292015-03-26 07:52:43 -07001679 do {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001680 next = span->next();
caryclark54359292015-03-26 07:52:43 -07001681 if (!span->done()) {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001682 return span;
reed0dc4dd62015-03-24 13:55:33 -07001683 }
Cary Clarkab2d73b2016-12-16 17:17:25 -05001684 } while (!next->final() && (span = next->upCast()));
1685 return nullptr;
reed0dc4dd62015-03-24 13:55:33 -07001686}
1687
caryclark54359292015-03-26 07:52:43 -07001688int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1689 const SkOpSpan* lesser = start->starter(end);
1690 int oppWinding = lesser->oppSum();
1691 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001692 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1693 && oppWinding != SK_MaxS32) {
1694 oppWinding -= oppSpanWinding;
1695 }
1696 return oppWinding;
1697}
1698
1699int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001700 const SkOpSpanBase* startSpan = angle->start();
1701 const SkOpSpanBase* endSpan = angle->end();
1702 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001703}
1704
1705int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001706 const SkOpSpanBase* startSpan = angle->start();
1707 const SkOpSpanBase* endSpan = angle->end();
1708 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001709}
1710
caryclark624637c2015-05-11 07:21:27 -07001711int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1712 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001713 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001714 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001715 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001716 }
1717 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001718 return winding;
1719 }
caryclark54359292015-03-26 07:52:43 -07001720 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001721 if (winding && UseInnerWinding(winding - spanWinding, winding)
1722 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001723 winding -= spanWinding;
1724 }
1725 return winding;
1726}
1727
caryclark624637c2015-05-11 07:21:27 -07001728int SkOpSegment::updateWinding(SkOpAngle* angle) {
1729 SkOpSpanBase* startSpan = angle->start();
1730 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001731 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001732}
1733
caryclark624637c2015-05-11 07:21:27 -07001734int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1735 SkOpSpanBase* startSpan = angle->start();
1736 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001737 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001738}
1739
1740// OPTIMIZATION: does the following also work, and is it any faster?
1741// return outerWinding * innerWinding > 0
1742// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1743bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1744 SkASSERT(outerWinding != SK_MaxS32);
1745 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001746 int absOut = SkTAbs(outerWinding);
1747 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001748 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1749 return result;
1750}
1751
caryclark@google.com07393ca2013-04-08 11:47:37 +00001752int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001753 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1754 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001755}