blob: 3bd925c0c36a738da02f8e13febd1f003a87d12f [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
caryclark@google.com570863f2013-09-16 15:55:01 +0000341void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
342 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);
361 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000362 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000363 } else {
364 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
365 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000366 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000367 }
368 nextAngle->setLastMarked(last);
369}
370
caryclark624637c2015-05-11 07:21:27 -0700371void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
caryclark@google.com570863f2013-09-16 15:55:01 +0000372 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700373 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000374 int sumMiWinding = baseSegment->updateWinding(baseAngle);
375 int sumSuWinding;
376 bool binary = includeType >= SkOpAngle::kBinarySingle;
377 if (binary) {
378 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
379 if (baseSegment->operand()) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400380 using std::swap;
381 swap(sumMiWinding, sumSuWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000382 }
383 }
384 SkOpSegment* nextSegment = nextAngle->segment();
385 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700386 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000387 if (binary) {
388 int oppMaxWinding, oppSumWinding;
389 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
390 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
391 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000392 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000393 } else {
394 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
395 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000396 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000397 }
398 nextAngle->setLastMarked(last);
399}
400
caryclark54359292015-03-26 07:52:43 -0700401// at this point, the span is already ordered, or unorderable
402int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
403 SkOpAngle::IncludeType includeType) {
404 SkASSERT(includeType != SkOpAngle::kUnaryXor);
405 SkOpAngle* firstAngle = this->spanToAngle(end, start);
halcanary96fcdcc2015-08-27 07:41:13 -0700406 if (nullptr == firstAngle || nullptr == firstAngle->next()) {
caryclark54359292015-03-26 07:52:43 -0700407 return SK_NaN32;
408 }
409 // if all angles have a computed winding,
410 // or if no adjacent angles are orderable,
411 // or if adjacent orderable angles have no computed winding,
412 // there's nothing to do
413 // if two orderable angles are adjacent, and both are next to orderable angles,
414 // and one has winding computed, transfer to the other
halcanary96fcdcc2015-08-27 07:41:13 -0700415 SkOpAngle* baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700416 bool tryReverse = false;
417 // look for counterclockwise transfers
418 SkOpAngle* angle = firstAngle->previous();
419 SkOpAngle* next = angle->next();
420 firstAngle = next;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000421 do {
caryclark54359292015-03-26 07:52:43 -0700422 SkOpAngle* prior = angle;
423 angle = next;
424 next = angle->next();
425 SkASSERT(prior->next() == angle);
426 SkASSERT(angle->next() == next);
427 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700428 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700429 continue;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000430 }
caryclark54359292015-03-26 07:52:43 -0700431 int testWinding = angle->starter()->windSum();
432 if (SK_MinS32 != testWinding) {
433 baseAngle = angle;
434 tryReverse = true;
435 continue;
reed0dc4dd62015-03-24 13:55:33 -0700436 }
caryclark54359292015-03-26 07:52:43 -0700437 if (baseAngle) {
438 ComputeOneSum(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700439 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
caryclark54359292015-03-26 07:52:43 -0700440 }
441 } while (next != firstAngle);
442 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
443 firstAngle = baseAngle;
444 tryReverse = true;
445 }
446 if (tryReverse) {
halcanary96fcdcc2015-08-27 07:41:13 -0700447 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700448 SkOpAngle* prior = firstAngle;
449 do {
450 angle = prior;
451 prior = angle->previous();
452 SkASSERT(prior->next() == angle);
453 next = angle->next();
454 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700455 baseAngle = nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700456 continue;
457 }
caryclark54359292015-03-26 07:52:43 -0700458 int testWinding = angle->starter()->windSum();
459 if (SK_MinS32 != testWinding) {
460 baseAngle = angle;
461 continue;
reed0dc4dd62015-03-24 13:55:33 -0700462 }
caryclark54359292015-03-26 07:52:43 -0700463 if (baseAngle) {
464 ComputeOneSumReverse(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700465 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700466 }
caryclark54359292015-03-26 07:52:43 -0700467 } while (prior != firstAngle);
reed0dc4dd62015-03-24 13:55:33 -0700468 }
caryclark54359292015-03-26 07:52:43 -0700469 return start->starter(end)->windSum();
reed0dc4dd62015-03-24 13:55:33 -0700470}
471
caryclark55888e42016-07-18 10:01:36 -0700472bool SkOpSegment::contains(double newT) const {
473 const SkOpSpanBase* spanBase = &fHead;
474 do {
475 if (spanBase->ptT()->contains(this, newT)) {
476 return true;
477 }
478 if (spanBase == &fTail) {
479 break;
480 }
481 spanBase = spanBase->upCast()->next();
482 } while (true);
483 return false;
484}
485
mtklein18300a32016-03-16 13:53:35 -0700486void SkOpSegment::release(const SkOpSpan* span) {
caryclark54359292015-03-26 07:52:43 -0700487 if (span->done()) {
caryclark08bc8482015-04-24 09:08:57 -0700488 --fDoneCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000489 }
caryclark08bc8482015-04-24 09:08:57 -0700490 --fCount;
caryclark15976282016-07-21 05:48:43 -0700491 SkOPASSERT(fCount >= fDoneCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000492}
493
Cary Clarke47ae292016-10-05 08:51:39 -0400494#if DEBUG_ANGLE
495// called only by debugCheckNearCoincidence
caryclark26ad22a2015-10-16 09:03:38 -0700496double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
caryclark54359292015-03-26 07:52:43 -0700497 SkDPoint testPt = this->dPtAtT(t);
498 SkDLine testPerp = {{ testPt, testPt }};
499 SkDVector slope = this->dSlopeAtT(t);
500 testPerp[1].fX += slope.fY;
501 testPerp[1].fY -= slope.fX;
502 SkIntersections i;
caryclark26ad22a2015-10-16 09:03:38 -0700503 const SkOpSegment* oppSegment = oppAngle->segment();
caryclark1049f122015-04-20 08:31:59 -0700504 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
caryclark54359292015-03-26 07:52:43 -0700505 double closestDistSq = SK_ScalarInfinity;
506 for (int index = 0; index < i.used(); ++index) {
507 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000508 continue;
509 }
caryclark54359292015-03-26 07:52:43 -0700510 double testDistSq = testPt.distanceSquared(i.pt(index));
511 if (closestDistSq > testDistSq) {
512 closestDistSq = testDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000513 }
514 }
caryclark54359292015-03-26 07:52:43 -0700515 return closestDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000516}
Cary Clarke47ae292016-10-05 08:51:39 -0400517#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000518
caryclark@google.com07393ca2013-04-08 11:47:37 +0000519/*
520 The M and S variable name parts stand for the operators.
521 Mi stands for Minuend (see wiki subtraction, analogous to difference)
522 Su stands for Subtrahend
523 The Opp variable name part designates that the value is for the Opposite operator.
524 Opposite values result from combining coincident spans.
525 */
caryclark54359292015-03-26 07:52:43 -0700526SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
527 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) {
528 SkOpSpanBase* start = *nextStart;
529 SkOpSpanBase* end = *nextEnd;
530 SkASSERT(start != end);
531 int step = start->step(end);
532 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
533 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000534 // mark the smaller of startIndex, endIndex done, and all adjacent
535 // spans with the same T value (but not 'other' spans)
536#if DEBUG_WINDING
537 SkDebugf("%s simple\n", __FUNCTION__);
538#endif
caryclark54359292015-03-26 07:52:43 -0700539 SkOpSpan* startSpan = start->starter(end);
540 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700541 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000542 }
caryclark54359292015-03-26 07:52:43 -0700543 markDone(startSpan);
544 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000545 return other;
546 }
caryclark54359292015-03-26 07:52:43 -0700547 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
548 SkASSERT(endNear == end); // is this ever not end?
549 SkASSERT(endNear);
550 SkASSERT(start != endNear);
551 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000552 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700553 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
caryclark@google.com570863f2013-09-16 15:55:01 +0000554 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000555 if (!sortable) {
556 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700557 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700558 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000559 }
caryclark54359292015-03-26 07:52:43 -0700560 SkOpAngle* angle = this->spanToAngle(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000561 if (angle->unorderable()) {
562 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700563 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700564 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000565 }
566#if DEBUG_SORT
567 SkDebugf("%s\n", __FUNCTION__);
568 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000569#endif
caryclark54359292015-03-26 07:52:43 -0700570 int sumMiWinding = updateWinding(end, start);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000571 if (sumMiWinding == SK_MinS32) {
572 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700573 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700574 return nullptr;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000575 }
caryclark54359292015-03-26 07:52:43 -0700576 int sumSuWinding = updateOppWinding(end, start);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000577 if (operand()) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400578 using std::swap;
579 swap(sumMiWinding, sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000580 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000581 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700582 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000583 bool foundDone = false;
584 // iterate through the angle, and compute everyone's winding
585 SkOpSegment* nextSegment;
586 int activeCount = 0;
587 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000588 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000589 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000590 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000591 if (activeAngle) {
592 ++activeCount;
593 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000594 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +0000595 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000596 }
597 }
598 if (nextSegment->done()) {
599 continue;
600 }
reed0dc4dd62015-03-24 13:55:33 -0700601 if (!activeAngle) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400602 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end(), nullptr);
reed0dc4dd62015-03-24 13:55:33 -0700603 }
caryclark54359292015-03-26 07:52:43 -0700604 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000605 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000606 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000607 *chase->append() = last;
608#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700609 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
610 last->segment()->debugID(), last->debugID());
611 if (!last->final()) {
612 SkDebugf(" windSum=%d", last->upCast()->windSum());
613 }
614 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000615#endif
616 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000617 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700618 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000619 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700620 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000621 }
622 *nextStart = foundAngle->start();
623 *nextEnd = foundAngle->end();
624 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000625#if DEBUG_WINDING
626 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
627 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
628 #endif
629 return nextSegment;
630}
631
caryclark54359292015-03-26 07:52:43 -0700632SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
633 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
634 SkOpSpanBase* start = *nextStart;
635 SkOpSpanBase* end = *nextEnd;
636 SkASSERT(start != end);
637 int step = start->step(end);
638 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
639 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000640 // mark the smaller of startIndex, endIndex done, and all adjacent
641 // spans with the same T value (but not 'other' spans)
642#if DEBUG_WINDING
643 SkDebugf("%s simple\n", __FUNCTION__);
644#endif
caryclark54359292015-03-26 07:52:43 -0700645 SkOpSpan* startSpan = start->starter(end);
646 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700647 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000648 }
caryclark54359292015-03-26 07:52:43 -0700649 markDone(startSpan);
650 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000651 return other;
652 }
caryclark54359292015-03-26 07:52:43 -0700653 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
654 SkASSERT(endNear == end); // is this ever not end?
655 SkASSERT(endNear);
656 SkASSERT(start != endNear);
657 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000658 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700659 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000660 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000661 if (!sortable) {
662 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700663 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700664 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000665 }
caryclark54359292015-03-26 07:52:43 -0700666 SkOpAngle* angle = this->spanToAngle(end, start);
667 if (angle->unorderable()) {
668 *unsortable = true;
669 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700670 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700671 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000672#if DEBUG_SORT
673 SkDebugf("%s\n", __FUNCTION__);
674 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000675#endif
caryclark54359292015-03-26 07:52:43 -0700676 int sumWinding = updateWinding(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000677 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700678 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000679 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700680 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000681 SkOpSegment* nextSegment;
682 int activeCount = 0;
683 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000684 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000685 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000686 &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000687 if (activeAngle) {
688 ++activeCount;
689 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000690 foundAngle = nextAngle;
691 foundDone = nextSegment->done(nextAngle);
692 }
693 }
694 if (nextSegment->done()) {
695 continue;
696 }
reed0dc4dd62015-03-24 13:55:33 -0700697 if (!activeAngle) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400698 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end(), nullptr);
reed0dc4dd62015-03-24 13:55:33 -0700699 }
caryclark54359292015-03-26 07:52:43 -0700700 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000701 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000702 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000703 *chase->append() = last;
704#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700705 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
706 last->segment()->debugID(), last->debugID());
707 if (!last->final()) {
708 SkDebugf(" windSum=%d", last->upCast()->windSum());
709 }
710 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000711#endif
712 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000713 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700714 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000715 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700716 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000717 }
718 *nextStart = foundAngle->start();
719 *nextEnd = foundAngle->end();
720 nextSegment = foundAngle->segment();
721#if DEBUG_WINDING
722 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
723 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
724 #endif
725 return nextSegment;
726}
727
caryclark54359292015-03-26 07:52:43 -0700728SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
729 bool* unsortable) {
730 SkOpSpanBase* start = *nextStart;
731 SkOpSpanBase* end = *nextEnd;
732 SkASSERT(start != end);
733 int step = start->step(end);
734 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
735 if (other) {
736 // mark the smaller of startIndex, endIndex done, and all adjacent
737 // spans with the same T value (but not 'other' spans)
caryclark@google.com07393ca2013-04-08 11:47:37 +0000738#if DEBUG_WINDING
739 SkDebugf("%s simple\n", __FUNCTION__);
740#endif
caryclark54359292015-03-26 07:52:43 -0700741 SkOpSpan* startSpan = start->starter(end);
742 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700743 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000744 }
caryclark54359292015-03-26 07:52:43 -0700745 markDone(startSpan);
746 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000747 return other;
748 }
caryclark54359292015-03-26 07:52:43 -0700749 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
750 : (*nextStart)->prev());
751 SkASSERT(endNear == end); // is this ever not end?
752 SkASSERT(endNear);
753 SkASSERT(start != endNear);
754 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
755 SkOpAngle* angle = this->spanToAngle(end, start);
caryclark27c8eb82015-07-06 11:38:33 -0700756 if (!angle || angle->unorderable()) {
caryclark54359292015-03-26 07:52:43 -0700757 *unsortable = true;
758 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700759 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700760 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000761#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000762 SkDebugf("%s\n", __FUNCTION__);
763 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000764#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000765 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700766 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000767 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700768 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000769 SkOpSegment* nextSegment;
770 int activeCount = 0;
771 do {
Cary Clark56071432018-06-19 08:33:52 -0400772 if (!nextAngle) {
773 return nullptr;
774 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000775 nextSegment = nextAngle->segment();
776 ++activeCount;
777 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000778 foundAngle = nextAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000779 if (!(foundDone = nextSegment->done(nextAngle))) {
780 break;
781 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000782 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000783 nextAngle = nextAngle->next();
784 } while (nextAngle != angle);
caryclark54359292015-03-26 07:52:43 -0700785 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000786 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700787 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000788 }
789 *nextStart = foundAngle->start();
790 *nextEnd = foundAngle->end();
791 nextSegment = foundAngle->segment();
792#if DEBUG_WINDING
793 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
794 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
795 #endif
796 return nextSegment;
797}
798
caryclark54359292015-03-26 07:52:43 -0700799SkOpGlobalState* SkOpSegment::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700800 return contour()->globalState();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000801}
802
caryclark1049f122015-04-20 08:31:59 -0700803void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
caryclark54359292015-03-26 07:52:43 -0700804 fContour = contour;
halcanary96fcdcc2015-08-27 07:41:13 -0700805 fNext = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000806 fPts = pts;
caryclark1049f122015-04-20 08:31:59 -0700807 fWeight = weight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000808 fVerb = verb;
caryclark54359292015-03-26 07:52:43 -0700809 fCount = 0;
810 fDoneCount = 0;
811 fVisited = false;
812 SkOpSpan* zeroSpan = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700813 zeroSpan->init(this, nullptr, 0, fPts[0]);
caryclark54359292015-03-26 07:52:43 -0700814 SkOpSpanBase* oneSpan = &fTail;
815 zeroSpan->setNext(oneSpan);
816 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
caryclark1049f122015-04-20 08:31:59 -0700817 SkDEBUGCODE(fID = globalState()->nextSegmentID());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000818}
819
caryclark54359292015-03-26 07:52:43 -0700820bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
821 SkDPoint cPt = this->dPtAtT(t);
caryclark1049f122015-04-20 08:31:59 -0700822 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
caryclark54359292015-03-26 07:52:43 -0700823 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
824 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -0700825 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
caryclark54359292015-03-26 07:52:43 -0700826 int used = i.used();
827 for (int index = 0; index < used; ++index) {
828 if (cPt.roughlyEqual(i.pt(index))) {
reed0dc4dd62015-03-24 13:55:33 -0700829 return true;
830 }
caryclark54359292015-03-26 07:52:43 -0700831 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000832 return false;
833}
834
caryclark54359292015-03-26 07:52:43 -0700835bool SkOpSegment::isXor() const {
836 return fContour->isXor();
837}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000838
caryclark5b5ddd72015-05-18 05:12:56 -0700839void SkOpSegment::markAllDone() {
840 SkOpSpan* span = this->head();
841 do {
842 this->markDone(span);
843 } while ((span = span->next()->upCastable()));
844}
845
Cary Clarkc050a1a2018-06-25 08:45:40 -0400846 bool SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end, SkOpSpanBase** found) {
caryclark54359292015-03-26 07:52:43 -0700847 int step = start->step(end);
848 SkOpSpan* minSpan = start->starter(end);
849 markDone(minSpan);
halcanary96fcdcc2015-08-27 07:41:13 -0700850 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000851 SkOpSegment* other = this;
Cary Clark918fb1f2016-11-15 13:22:25 -0500852 SkOpSpan* priorDone = nullptr;
853 SkOpSpan* lastDone = nullptr;
Cary Clarkc050a1a2018-06-25 08:45:40 -0400854 int safetyNet = 100000;
caryclark54359292015-03-26 07:52:43 -0700855 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400856 if (!--safetyNet) {
857 return false;
858 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000859 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -0700860 SkASSERT(!last);
861 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000862 }
Cary Clark918fb1f2016-11-15 13:22:25 -0500863 if (lastDone == minSpan || priorDone == minSpan) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400864 if (found) {
865 *found = nullptr;
866 }
867 return true;
Cary Clark918fb1f2016-11-15 13:22:25 -0500868 }
caryclark54359292015-03-26 07:52:43 -0700869 other->markDone(minSpan);
Cary Clark918fb1f2016-11-15 13:22:25 -0500870 priorDone = lastDone;
871 lastDone = minSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000872 }
Cary Clarkc050a1a2018-06-25 08:45:40 -0400873 if (found) {
874 *found = last;
875 }
876 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000877}
878
caryclark54359292015-03-26 07:52:43 -0700879bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
880 SkOpSpanBase** lastPtr) {
881 SkOpSpan* spanStart = start->starter(end);
882 int step = start->step(end);
883 bool success = markWinding(spanStart, winding);
halcanary96fcdcc2015-08-27 07:41:13 -0700884 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000885 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700886 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
887 if (spanStart->windSum() != SK_MinS32) {
caryclarkb36a3cd2016-10-18 07:59:44 -0700888// SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive?
caryclarkdac1d172014-06-17 05:15:38 -0700889 SkASSERT(!last);
890 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000891 }
caryclark54359292015-03-26 07:52:43 -0700892 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000893 }
caryclark65f55312014-11-13 06:58:52 -0800894 if (lastPtr) {
895 *lastPtr = last;
896 }
897 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000898}
899
caryclark54359292015-03-26 07:52:43 -0700900bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
901 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
902 SkOpSpan* spanStart = start->starter(end);
903 int step = start->step(end);
904 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700905 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000906 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700907 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
908 if (spanStart->windSum() != SK_MinS32) {
909 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700910 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700911 this->globalState()->setWindingFailed();
912 return false;
caryclarkdac1d172014-06-17 05:15:38 -0700913 }
caryclark54359292015-03-26 07:52:43 -0700914 } else {
915 SkASSERT(spanStart->windSum() == oppWinding);
916 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700917 }
918 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700919 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000920 }
caryclark54359292015-03-26 07:52:43 -0700921 if (this->operand() == other->operand()) {
922 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700923 } else {
caryclark54359292015-03-26 07:52:43 -0700924 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700925 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000926 }
caryclark65f55312014-11-13 06:58:52 -0800927 if (lastPtr) {
928 *lastPtr = last;
929 }
930 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000931}
932
caryclark54359292015-03-26 07:52:43 -0700933SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000934 SkASSERT(angle->segment() == this);
935 if (UseInnerWinding(maxWinding, sumWinding)) {
936 maxWinding = sumWinding;
937 }
caryclark54359292015-03-26 07:52:43 -0700938 SkOpSpanBase* last;
939 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000940#if DEBUG_WINDING
941 if (last) {
caryclark54359292015-03-26 07:52:43 -0700942 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
943 last->segment()->debugID(), last->debugID());
944 if (!last->final()) {
945 SkDebugf(" windSum=");
946 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
947 }
948 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000949 }
950#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000951 return last;
952}
953
caryclark54359292015-03-26 07:52:43 -0700954SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
955 int oppSumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000956 SkASSERT(angle->segment() == this);
957 if (UseInnerWinding(maxWinding, sumWinding)) {
958 maxWinding = sumWinding;
959 }
960 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
961 oppMaxWinding = oppSumWinding;
962 }
halcanary96fcdcc2015-08-27 07:41:13 -0700963 SkOpSpanBase* last = nullptr;
caryclark65f55312014-11-13 06:58:52 -0800964 // caller doesn't require that this marks anything
caryclark54359292015-03-26 07:52:43 -0700965 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000966#if DEBUG_WINDING
967 if (last) {
caryclark54359292015-03-26 07:52:43 -0700968 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
969 last->segment()->debugID(), last->debugID());
970 if (!last->final()) {
971 SkDebugf(" windSum=");
972 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
973 }
974 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000975 }
976#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000977 return last;
978}
979
caryclark54359292015-03-26 07:52:43 -0700980void SkOpSegment::markDone(SkOpSpan* span) {
981 SkASSERT(this == span->segment());
982 if (span->done()) {
983 return;
984 }
985#if DEBUG_MARK_DONE
986 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
987#endif
988 span->setDone(true);
989 ++fDoneCount;
990 debugValidate();
991}
992
993bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
994 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -0700995 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -0700996 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -0700997 return false;
998 }
999#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -07001000 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -07001001#endif
caryclark54359292015-03-26 07:52:43 -07001002 span->setWindSum(winding);
1003 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001004 return true;
1005}
1006
caryclark54359292015-03-26 07:52:43 -07001007bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
1008 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +00001009 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -07001010 if (span->done()) {
1011 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001012 }
caryclark54359292015-03-26 07:52:43 -07001013#if DEBUG_MARK_DONE
1014 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1015#endif
1016 span->setWindSum(winding);
1017 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001018 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001019 return true;
1020}
1021
caryclark54359292015-03-26 07:52:43 -07001022bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclarkef4f32a2016-08-24 09:24:18 -07001023 const SkPoint& testPt) const {
caryclark55888e42016-07-18 10:01:36 -07001024 SkASSERT(this == base->segment());
1025 if (this == testParent) {
1026 if (precisely_equal(base->fT, testT)) {
1027 return true;
1028 }
caryclark54359292015-03-26 07:52:43 -07001029 }
1030 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1031 return false;
1032 }
caryclark55888e42016-07-18 10:01:36 -07001033 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001034}
1035
1036static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1037 if (last) {
1038 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001039 }
halcanary96fcdcc2015-08-27 07:41:13 -07001040 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001041}
1042
caryclark54359292015-03-26 07:52:43 -07001043SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1044 SkOpSpanBase** last) const {
1045 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001046 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001047 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1048 SkASSERT(endSpan);
1049 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1050 SkOpSpanBase* foundSpan;
1051 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001052 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001053 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001054 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001055 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001056 }
caryclark54359292015-03-26 07:52:43 -07001057 SkOpPtT* otherPtT = endSpan->ptT()->next();
1058 other = otherPtT->segment();
1059 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001060 otherEnd = step > 0
1061 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1062 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001063 } else {
1064 int loopCount = angle->loopCount();
1065 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001066 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001067 }
1068 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001069 if (nullptr == next) {
1070 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001071 }
caryclarkdac1d172014-06-17 05:15:38 -07001072#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001073 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001074 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001075 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001076 }
caryclark54359292015-03-26 07:52:43 -07001077#endif
caryclarkdac1d172014-06-17 05:15:38 -07001078 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001079 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001080 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001081 }
caryclark343382e2016-06-29 08:18:38 -07001082 if (!otherEnd) {
1083 return nullptr;
1084 }
caryclark54359292015-03-26 07:52:43 -07001085 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001086 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001087 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001088 }
caryclark54359292015-03-26 07:52:43 -07001089 SkASSERT(*startPtr);
caryclark65b427c2014-09-18 10:32:57 -07001090// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001091 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1092 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1093 if (foundMin->windValue() != origMin->windValue()
1094 || foundMin->oppValue() != origMin->oppValue()) {
1095 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001096 }
caryclark54359292015-03-26 07:52:43 -07001097 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001098 *stepPtr = foundStep;
1099 if (minPtr) {
1100 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001101 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001102 return other;
1103}
1104
caryclark55888e42016-07-18 10:01:36 -07001105// Please keep this in sync with DebugClearVisited()
1106void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001107 // reset visited flag back to false
1108 do {
1109 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1110 while ((ptT = ptT->next()) != stopPtT) {
1111 SkOpSegment* opp = ptT->segment();
1112 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001113 }
caryclarkbca19f72015-05-13 08:23:48 -07001114 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001115}
1116
caryclark55888e42016-07-18 10:01:36 -07001117// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001118// look for pairs of undetected coincident curves
1119// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001120// Even though pairs of curves correct detect coincident runs, a run may be missed
1121// if the coincidence is a product of multiple intersections. For instance, given
1122// curves A, B, and C:
1123// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1124// the end of C that the intersection is replaced with the end of C.
1125// Even though A-B correctly do not detect an intersection at point 2,
1126// the resulting run from point 1 to point 2 is coincident on A and B.
1127bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001128 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001129 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001130 }
halcanary96fcdcc2015-08-27 07:41:13 -07001131 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001132 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001133 bool result = false;
caryclark54359292015-03-26 07:52:43 -07001134 do {
caryclarkbca19f72015-05-13 08:23:48 -07001135 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001136 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001137 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001138 if (ptT->deleted()) {
1139 continue;
1140 }
caryclark54359292015-03-26 07:52:43 -07001141 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001142 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001143 continue;
reed0dc4dd62015-03-24 13:55:33 -07001144 }
caryclarkbca19f72015-05-13 08:23:48 -07001145 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1146 if (!opp->visited()) {
1147 continue;
1148 }
1149 if (spanBase == &fHead) {
1150 continue;
1151 }
caryclark55888e42016-07-18 10:01:36 -07001152 if (ptT->segment() == this) {
1153 continue;
1154 }
caryclarkbca19f72015-05-13 08:23:48 -07001155 SkOpSpan* span = spanBase->upCastable();
1156 // FIXME?: this assumes that if the opposite segment is coincident then no more
1157 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001158 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001159 continue;
1160 }
caryclarkbca19f72015-05-13 08:23:48 -07001161 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001162 continue;
caryclark55888e42016-07-18 10:01:36 -07001163 }
halcanary96fcdcc2015-08-27 07:41:13 -07001164 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001165 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001166 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001167 SkOpSpan* priorTest = spanBase->prev();
1168 while (!priorOpp && priorTest) {
1169 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001170 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001171 if (priorPtT->deleted()) {
1172 continue;
1173 }
caryclark54359292015-03-26 07:52:43 -07001174 SkOpSegment* segment = priorPtT->span()->segment();
1175 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001176 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001177 priorOpp = opp;
1178 break;
1179 }
1180 }
caryclarkbca19f72015-05-13 08:23:48 -07001181 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001182 }
1183 if (!priorOpp) {
1184 continue;
1185 }
caryclark26ad22a2015-10-16 09:03:38 -07001186 if (priorPtT == ptT) {
1187 continue;
1188 }
caryclark54359292015-03-26 07:52:43 -07001189 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001190 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001191 bool swapped = priorPtT->fT > ptT->fT;
1192 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001193 using std::swap;
1194 swap(priorPtT, ptT);
1195 swap(oppStart, oppEnd);
caryclark54359292015-03-26 07:52:43 -07001196 }
caryclark55888e42016-07-18 10:01:36 -07001197 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1198 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1199 SkOpPtT* rootPtT = ptT->span()->ptT();
1200 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1201 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1202 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001203 goto swapBack;
1204 }
caryclark55888e42016-07-18 10:01:36 -07001205 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001206 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001207#if DEBUG_COINCIDENCE_VERBOSE
1208 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1209 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1210 rootOppEnd->debugID());
1211#endif
1212 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1213 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001214 }
caryclark55888e42016-07-18 10:01:36 -07001215#if DEBUG_COINCIDENCE
1216 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1217#endif
1218 result = true;
caryclark54359292015-03-26 07:52:43 -07001219 }
1220 swapBack:
1221 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001222 using std::swap;
1223 swap(priorPtT, ptT);
caryclark54359292015-03-26 07:52:43 -07001224 }
reed0dc4dd62015-03-24 13:55:33 -07001225 }
halcanary96fcdcc2015-08-27 07:41:13 -07001226 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001227 ClearVisited(&fHead);
1228 return result;
reed0dc4dd62015-03-24 13:55:33 -07001229}
1230
caryclark55888e42016-07-18 10:01:36 -07001231// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001232// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001233bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001234 debugValidate();
1235 SkOpSpanBase* test = &fHead;
1236 do {
1237 int addCount = test->spanAddsCount();
Cary Clark7eb01e02016-12-08 14:36:32 -05001238// FAIL_IF(addCount < 1);
1239 if (addCount <= 1) {
caryclark08bc8482015-04-24 09:08:57 -07001240 continue;
1241 }
1242 SkOpPtT* startPtT = test->ptT();
1243 SkOpPtT* testPtT = startPtT;
1244 do { // iterate through all spans associated with start
1245 SkOpSpanBase* oppSpan = testPtT->span();
1246 if (oppSpan->spanAddsCount() == addCount) {
1247 continue;
1248 }
1249 if (oppSpan->deleted()) {
1250 continue;
1251 }
1252 SkOpSegment* oppSegment = oppSpan->segment();
1253 if (oppSegment == this) {
1254 continue;
1255 }
1256 // find range of spans to consider merging
1257 SkOpSpanBase* oppPrev = oppSpan;
1258 SkOpSpanBase* oppFirst = oppSpan;
1259 while ((oppPrev = oppPrev->prev())) {
1260 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1261 break;
1262 }
1263 if (oppPrev->spanAddsCount() == addCount) {
1264 continue;
1265 }
1266 if (oppPrev->deleted()) {
1267 continue;
1268 }
1269 oppFirst = oppPrev;
1270 }
1271 SkOpSpanBase* oppNext = oppSpan;
1272 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001273 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001274 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1275 break;
1276 }
1277 if (oppNext->spanAddsCount() == addCount) {
1278 continue;
1279 }
1280 if (oppNext->deleted()) {
1281 continue;
1282 }
1283 oppLast = oppNext;
1284 }
1285 if (oppFirst == oppLast) {
1286 continue;
1287 }
1288 SkOpSpanBase* oppTest = oppFirst;
1289 do {
1290 if (oppTest == oppSpan) {
1291 continue;
1292 }
1293 // check to see if the candidate meets specific criteria:
1294 // it contains spans of segments in test's loop but not including 'this'
1295 SkOpPtT* oppStartPtT = oppTest->ptT();
1296 SkOpPtT* oppPtT = oppStartPtT;
1297 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1298 SkOpSegment* oppPtTSegment = oppPtT->segment();
1299 if (oppPtTSegment == this) {
1300 goto tryNextSpan;
1301 }
1302 SkOpPtT* matchPtT = startPtT;
1303 do {
1304 if (matchPtT->segment() == oppPtTSegment) {
1305 goto foundMatch;
1306 }
1307 } while ((matchPtT = matchPtT->next()) != startPtT);
1308 goto tryNextSpan;
1309 foundMatch: // merge oppTest and oppSpan
1310 oppSegment->debugValidate();
caryclark30b9fdd2016-08-31 14:36:29 -07001311 oppTest->mergeMatches(oppSpan);
1312 oppTest->addOpp(oppSpan);
caryclark08bc8482015-04-24 09:08:57 -07001313 oppSegment->debugValidate();
1314 goto checkNextSpan;
1315 }
caryclark55888e42016-07-18 10:01:36 -07001316 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001317 ;
1318 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1319 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001320checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001321 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001322 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001323 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001324 return true;
caryclark08bc8482015-04-24 09:08:57 -07001325}
1326
caryclark55888e42016-07-18 10:01:36 -07001327// adjacent spans may have points close by
Cary Clark28da2832017-03-21 10:30:50 -04001328bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan,
1329 bool* found) const {
caryclark55888e42016-07-18 10:01:36 -07001330 const SkOpPtT* refHead = refSpan->ptT();
1331 const SkOpPtT* checkHead = checkSpan->ptT();
1332// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
caryclark30b9fdd2016-08-31 14:36:29 -07001333 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
caryclark55888e42016-07-18 10:01:36 -07001334#if DEBUG_COINCIDENCE
1335 // verify that no combination of points are close
1336 const SkOpPtT* dBugRef = refHead;
1337 do {
1338 const SkOpPtT* dBugCheck = checkHead;
1339 do {
caryclark30b9fdd2016-08-31 14:36:29 -07001340 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
caryclark55888e42016-07-18 10:01:36 -07001341 dBugCheck = dBugCheck->next();
1342 } while (dBugCheck != checkHead);
1343 dBugRef = dBugRef->next();
1344 } while (dBugRef != refHead);
1345#endif
Cary Clark28da2832017-03-21 10:30:50 -04001346 *found = false;
1347 return true;
caryclark55888e42016-07-18 10:01:36 -07001348 }
1349 // check only unique points
1350 SkScalar distSqBest = SK_ScalarMax;
1351 const SkOpPtT* refBest = nullptr;
1352 const SkOpPtT* checkBest = nullptr;
1353 const SkOpPtT* ref = refHead;
1354 do {
1355 if (ref->deleted()) {
1356 continue;
1357 }
1358 while (ref->ptAlreadySeen(refHead)) {
1359 ref = ref->next();
1360 if (ref == refHead) {
1361 goto doneCheckingDistance;
1362 }
1363 }
1364 const SkOpPtT* check = checkHead;
1365 const SkOpSegment* refSeg = ref->segment();
Cary Clark28da2832017-03-21 10:30:50 -04001366 int escapeHatch = 100000; // defend against infinite loops
caryclark55888e42016-07-18 10:01:36 -07001367 do {
1368 if (check->deleted()) {
1369 continue;
1370 }
1371 while (check->ptAlreadySeen(checkHead)) {
1372 check = check->next();
1373 if (check == checkHead) {
1374 goto nextRef;
1375 }
1376 }
Cary Clarkdf429f32017-11-08 11:44:31 -05001377 SkScalar distSq = SkPointPriv::DistanceToSqd(ref->fPt, check->fPt);
caryclark55888e42016-07-18 10:01:36 -07001378 if (distSqBest > distSq && (refSeg != check->segment()
1379 || !refSeg->ptsDisjoint(*ref, *check))) {
1380 distSqBest = distSq;
1381 refBest = ref;
1382 checkBest = check;
1383 }
Cary Clark28da2832017-03-21 10:30:50 -04001384 if (--escapeHatch <= 0) {
1385 return false;
1386 }
caryclark55888e42016-07-18 10:01:36 -07001387 } while ((check = check->next()) != checkHead);
Cary Clark28da2832017-03-21 10:30:50 -04001388 nextRef:
caryclark55888e42016-07-18 10:01:36 -07001389 ;
1390 } while ((ref = ref->next()) != refHead);
1391doneCheckingDistance:
Cary Clark28da2832017-03-21 10:30:50 -04001392 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001393 checkBest->fPt);
Cary Clark28da2832017-03-21 10:30:50 -04001394 return true;
caryclark55888e42016-07-18 10:01:36 -07001395}
1396
1397// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001398// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
Cary Clark28da2832017-03-21 10:30:50 -04001399bool SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001400 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001401 // release undeleted spans pointing to this seg that are linked to the primary span
1402 SkOpSpanBase* spanBase = &fHead;
Cary Clark43938b82017-10-18 08:47:32 -04001403 int escapeHatch = 9999; // the largest count for a regular test is 50; for a fuzzer, 500
caryclark54359292015-03-26 07:52:43 -07001404 do {
caryclark55888e42016-07-18 10:01:36 -07001405 SkOpPtT* ptT = spanBase->ptT();
1406 const SkOpPtT* headPtT = ptT;
1407 while ((ptT = ptT->next()) != headPtT) {
Cary Clark43938b82017-10-18 08:47:32 -04001408 if (!--escapeHatch) {
1409 return false;
1410 }
caryclark55888e42016-07-18 10:01:36 -07001411 SkOpSpanBase* test = ptT->span();
1412 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1413 && test->ptT() == ptT) {
1414 if (test->final()) {
1415 if (spanBase == &fHead) {
1416 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001417 return true;
caryclark55888e42016-07-18 10:01:36 -07001418 }
1419 spanBase->upCast()->release(ptT);
1420 } else if (test->prev()) {
1421 test->upCast()->release(headPtT);
1422 }
1423 break;
caryclark54359292015-03-26 07:52:43 -07001424 }
reed0dc4dd62015-03-24 13:55:33 -07001425 }
caryclark55888e42016-07-18 10:01:36 -07001426 spanBase = spanBase->upCast()->next();
1427 } while (!spanBase->final());
caryclark55888e42016-07-18 10:01:36 -07001428 // This loop looks for adjacent spans which are near by
1429 spanBase = &fHead;
1430 do { // iterate through all spans associated with start
1431 SkOpSpanBase* test = spanBase->upCast()->next();
Cary Clark28da2832017-03-21 10:30:50 -04001432 bool found;
1433 if (!this->spansNearby(spanBase, test, &found)) {
1434 return false;
1435 }
1436 if (found) {
caryclark55888e42016-07-18 10:01:36 -07001437 if (test->final()) {
1438 if (spanBase->prev()) {
1439 test->merge(spanBase->upCast());
1440 } else {
1441 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001442 return true;
caryclark55888e42016-07-18 10:01:36 -07001443 }
1444 } else {
1445 spanBase->merge(test->upCast());
1446 }
1447 }
1448 spanBase = test;
1449 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001450 debugValidate();
Cary Clark28da2832017-03-21 10:30:50 -04001451 return true;
reed0dc4dd62015-03-24 13:55:33 -07001452}
1453
caryclark54359292015-03-26 07:52:43 -07001454bool SkOpSegment::operand() const {
1455 return fContour->operand();
1456}
1457
1458bool SkOpSegment::oppXor() const {
1459 return fContour->oppXor();
1460}
1461
1462bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1463 if (fVerb == SkPath::kLine_Verb) {
1464 return false;
1465 }
1466 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1467 // hits in two places with very different t values.
1468 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1469 // 'controls contained by ends' could avoid this check for common curves
1470 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1471 // on the other hand, the below check is relatively inexpensive
1472 double midT = (t1 + t2) / 2;
1473 SkPoint midPt = this->ptAtT(midT);
Cary Clarkdf429f32017-11-08 11:44:31 -05001474 double seDistSq = SkTMax(SkPointPriv::DistanceToSqd(pt1, pt2) * 2, FLT_EPSILON * 2);
1475 return SkPointPriv::DistanceToSqd(midPt, pt1) > seDistSq ||
1476 SkPointPriv::DistanceToSqd(midPt, pt2) > seDistSq;
caryclark54359292015-03-26 07:52:43 -07001477}
1478
1479void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1480 int* maxWinding, int* sumWinding) {
1481 int deltaSum = SpanSign(start, end);
1482 *maxWinding = *sumMiWinding;
1483 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001484 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001485}
1486
1487void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1488 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1489 int* oppSumWinding) {
1490 int deltaSum = SpanSign(start, end);
1491 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001492 if (operand()) {
1493 *maxWinding = *sumSuWinding;
1494 *sumWinding = *sumSuWinding -= deltaSum;
1495 *oppMaxWinding = *sumMiWinding;
1496 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1497 } else {
1498 *maxWinding = *sumMiWinding;
1499 *sumWinding = *sumMiWinding -= deltaSum;
1500 *oppMaxWinding = *sumSuWinding;
1501 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1502 }
bungeman60e0fee2015-08-26 05:15:46 -07001503 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1504 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001505}
1506
caryclarkb36a3cd2016-10-18 07:59:44 -07001507bool SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001508 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001509 do {
caryclark54359292015-03-26 07:52:43 -07001510 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001511 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001512 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001513 continue;
1514 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001515#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001516 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001517#endif
caryclark54359292015-03-26 07:52:43 -07001518 SkOpAngle* baseAngle = fromAngle;
1519 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001520#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001521 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1522 span->debugID());
1523 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001524#endif
caryclarkb36a3cd2016-10-18 07:59:44 -07001525 FAIL_IF(!fromAngle->insert(toAngle));
caryclark54359292015-03-26 07:52:43 -07001526 } else if (!fromAngle) {
1527 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001528 }
caryclark54359292015-03-26 07:52:43 -07001529 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001530 do {
caryclark54359292015-03-26 07:52:43 -07001531 SkOpSpanBase* oSpan = ptT->span();
1532 if (oSpan == span) {
1533 continue;
1534 }
1535 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001536 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001537#if DEBUG_ANGLE
1538 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001539 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1540 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001541 wroteAfterHeader = true;
1542 }
1543#endif
caryclark54359292015-03-26 07:52:43 -07001544 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001545 baseAngle->insert(oAngle);
1546 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001547 }
caryclark54359292015-03-26 07:52:43 -07001548 if (!oSpan->final()) {
1549 oAngle = oSpan->upCast()->toAngle();
1550 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001551#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001552 if (!wroteAfterHeader) {
1553 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1554 span->t(), span->debugID());
1555 wroteAfterHeader = true;
1556 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001557#endif
caryclark54359292015-03-26 07:52:43 -07001558 if (!oAngle->loopContains(baseAngle)) {
1559 baseAngle->insert(oAngle);
1560 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001561 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001562 }
caryclark54359292015-03-26 07:52:43 -07001563 } while ((ptT = ptT->next()) != stopPtT);
1564 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001565 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001566 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001567 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001568 }
halcanary96fcdcc2015-08-27 07:41:13 -07001569 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001570 }
1571#if DEBUG_SORT
1572 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1573#endif
caryclark54359292015-03-26 07:52:43 -07001574 } while (!span->final() && (span = span->upCast()->next()));
caryclarkb36a3cd2016-10-18 07:59:44 -07001575 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +00001576}
1577
caryclark54359292015-03-26 07:52:43 -07001578bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001579 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001580 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001581 const SkOpPtT& startPtT = *start->ptT();
1582 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001583 SkDEBUGCODE(edge->fVerb = fVerb);
1584 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001585 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001586 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001587 if (fVerb == SkPath::kLine_Verb) {
1588 return false;
1589 }
caryclark54359292015-03-26 07:52:43 -07001590 double startT = startPtT.fT;
1591 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001592 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1593 // don't compute midpoints if we already have them
1594 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001595 edge->fLine[1].set(fPts[1]);
1596 return false;
1597 }
1598 if (fVerb == SkPath::kConic_Verb) {
1599 edge->fConic[1].set(fPts[1]);
1600 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001601 return false;
1602 }
1603 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001604 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001605 edge->fCubic[1].set(fPts[1]);
1606 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001607 return false;
1608 }
caryclark1049f122015-04-20 08:31:59 -07001609 edge->fCubic[1].set(fPts[2]);
1610 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001611 return false;
1612 }
1613 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001614 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1615 } else if (fVerb == SkPath::kConic_Verb) {
1616 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1617 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001618 } else {
1619 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001620 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001621 }
1622 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001623}
1624
caryclark27c8eb82015-07-06 11:38:33 -07001625bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001626 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001627 // average t, find mid pt
1628 double midT = (prior->t() + spanBase->t()) / 2;
1629 SkPoint midPt = this->ptAtT(midT);
1630 bool coincident = true;
1631 // if the mid pt is not near either end pt, project perpendicular through opp seg
1632 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1633 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001634 if (priorPtT->span() == ptT->span()) {
1635 return false;
1636 }
caryclark27c8eb82015-07-06 11:38:33 -07001637 coincident = false;
1638 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001639 SkDCurve curvePart;
1640 this->subDivide(prior, spanBase, &curvePart);
1641 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1642 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1643 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1644 SkDCurve oppPart;
1645 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1646 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001647 // measure distance and see if it's small enough to denote coincidence
1648 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001649 if (!between(0, i[0][index], 1)) {
1650 continue;
1651 }
caryclark27c8eb82015-07-06 11:38:33 -07001652 SkDPoint oppPt = i.pt(index);
caryclark30b9fdd2016-08-31 14:36:29 -07001653 if (oppPt.approximatelyDEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001654 // the coincidence can occur at almost any angle
1655 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001656 }
1657 }
1658 }
1659 return coincident;
1660}
1661
Cary Clarkab2d73b2016-12-16 17:17:25 -05001662SkOpSpan* SkOpSegment::undoneSpan() {
1663 SkOpSpan* span = &fHead;
1664 SkOpSpanBase* next;
caryclark54359292015-03-26 07:52:43 -07001665 do {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001666 next = span->next();
caryclark54359292015-03-26 07:52:43 -07001667 if (!span->done()) {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001668 return span;
reed0dc4dd62015-03-24 13:55:33 -07001669 }
Cary Clarkab2d73b2016-12-16 17:17:25 -05001670 } while (!next->final() && (span = next->upCast()));
1671 return nullptr;
reed0dc4dd62015-03-24 13:55:33 -07001672}
1673
caryclark54359292015-03-26 07:52:43 -07001674int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1675 const SkOpSpan* lesser = start->starter(end);
1676 int oppWinding = lesser->oppSum();
1677 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001678 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1679 && oppWinding != SK_MaxS32) {
1680 oppWinding -= oppSpanWinding;
1681 }
1682 return oppWinding;
1683}
1684
1685int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001686 const SkOpSpanBase* startSpan = angle->start();
1687 const SkOpSpanBase* endSpan = angle->end();
1688 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001689}
1690
1691int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001692 const SkOpSpanBase* startSpan = angle->start();
1693 const SkOpSpanBase* endSpan = angle->end();
1694 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001695}
1696
caryclark624637c2015-05-11 07:21:27 -07001697int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1698 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001699 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001700 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001701 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001702 }
1703 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001704 return winding;
1705 }
caryclark54359292015-03-26 07:52:43 -07001706 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001707 if (winding && UseInnerWinding(winding - spanWinding, winding)
1708 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001709 winding -= spanWinding;
1710 }
1711 return winding;
1712}
1713
caryclark624637c2015-05-11 07:21:27 -07001714int SkOpSegment::updateWinding(SkOpAngle* angle) {
1715 SkOpSpanBase* startSpan = angle->start();
1716 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001717 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001718}
1719
caryclark624637c2015-05-11 07:21:27 -07001720int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1721 SkOpSpanBase* startSpan = angle->start();
1722 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001723 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001724}
1725
1726// OPTIMIZATION: does the following also work, and is it any faster?
1727// return outerWinding * innerWinding > 0
1728// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1729bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1730 SkASSERT(outerWinding != SK_MaxS32);
1731 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001732 int absOut = SkTAbs(outerWinding);
1733 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001734 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1735 return result;
1736}
1737
caryclark@google.com07393ca2013-04-08 11:47:37 +00001738int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001739 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1740 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001741}