blob: 720b34f5974e70791be03c34d6f12fcae57bf7ee [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,
Cary Clark1857ddb2018-07-11 11:01:43 -0400527 SkOpSpanBase** nextEnd, bool* unsortable, bool* simple,
528 SkPathOp op, int xorMiMask, int xorSuMask) {
caryclark54359292015-03-26 07:52:43 -0700529 SkOpSpanBase* start = *nextStart;
530 SkOpSpanBase* end = *nextEnd;
531 SkASSERT(start != end);
532 int step = start->step(end);
533 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
Cary Clark1857ddb2018-07-11 11:01:43 -0400534 if ((*simple = other)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000535 // mark the smaller of startIndex, endIndex done, and all adjacent
536 // spans with the same T value (but not 'other' spans)
537#if DEBUG_WINDING
538 SkDebugf("%s simple\n", __FUNCTION__);
539#endif
caryclark54359292015-03-26 07:52:43 -0700540 SkOpSpan* startSpan = start->starter(end);
541 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700542 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000543 }
caryclark54359292015-03-26 07:52:43 -0700544 markDone(startSpan);
545 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000546 return other;
547 }
caryclark54359292015-03-26 07:52:43 -0700548 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
549 SkASSERT(endNear == end); // is this ever not end?
550 SkASSERT(endNear);
551 SkASSERT(start != endNear);
552 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000553 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700554 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
caryclark@google.com570863f2013-09-16 15:55:01 +0000555 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000556 if (!sortable) {
557 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700558 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700559 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000560 }
caryclark54359292015-03-26 07:52:43 -0700561 SkOpAngle* angle = this->spanToAngle(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000562 if (angle->unorderable()) {
563 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700564 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700565 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000566 }
567#if DEBUG_SORT
568 SkDebugf("%s\n", __FUNCTION__);
569 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000570#endif
caryclark54359292015-03-26 07:52:43 -0700571 int sumMiWinding = updateWinding(end, start);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000572 if (sumMiWinding == SK_MinS32) {
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.org8cb1daa2014-04-25 12:59:11 +0000576 }
caryclark54359292015-03-26 07:52:43 -0700577 int sumSuWinding = updateOppWinding(end, start);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000578 if (operand()) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400579 using std::swap;
580 swap(sumMiWinding, sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000581 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000582 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700583 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000584 bool foundDone = false;
585 // iterate through the angle, and compute everyone's winding
586 SkOpSegment* nextSegment;
587 int activeCount = 0;
588 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000589 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000590 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000591 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000592 if (activeAngle) {
593 ++activeCount;
594 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000595 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +0000596 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000597 }
598 }
599 if (nextSegment->done()) {
600 continue;
601 }
reed0dc4dd62015-03-24 13:55:33 -0700602 if (!activeAngle) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400603 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end(), nullptr);
reed0dc4dd62015-03-24 13:55:33 -0700604 }
caryclark54359292015-03-26 07:52:43 -0700605 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000606 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000607 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000608 *chase->append() = last;
609#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700610 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
611 last->segment()->debugID(), last->debugID());
612 if (!last->final()) {
613 SkDebugf(" windSum=%d", last->upCast()->windSum());
614 }
615 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000616#endif
617 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000618 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700619 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000620 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700621 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000622 }
623 *nextStart = foundAngle->start();
624 *nextEnd = foundAngle->end();
625 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000626#if DEBUG_WINDING
627 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
628 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
629 #endif
630 return nextSegment;
631}
632
caryclark54359292015-03-26 07:52:43 -0700633SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
634 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
635 SkOpSpanBase* start = *nextStart;
636 SkOpSpanBase* end = *nextEnd;
637 SkASSERT(start != end);
638 int step = start->step(end);
639 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
640 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000641 // mark the smaller of startIndex, endIndex done, and all adjacent
642 // spans with the same T value (but not 'other' spans)
643#if DEBUG_WINDING
644 SkDebugf("%s simple\n", __FUNCTION__);
645#endif
caryclark54359292015-03-26 07:52:43 -0700646 SkOpSpan* startSpan = start->starter(end);
647 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700648 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000649 }
caryclark54359292015-03-26 07:52:43 -0700650 markDone(startSpan);
651 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000652 return other;
653 }
caryclark54359292015-03-26 07:52:43 -0700654 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
655 SkASSERT(endNear == end); // is this ever not end?
656 SkASSERT(endNear);
657 SkASSERT(start != endNear);
658 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000659 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700660 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000661 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000662 if (!sortable) {
663 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700664 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700665 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000666 }
caryclark54359292015-03-26 07:52:43 -0700667 SkOpAngle* angle = this->spanToAngle(end, start);
668 if (angle->unorderable()) {
669 *unsortable = true;
670 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700671 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700672 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000673#if DEBUG_SORT
674 SkDebugf("%s\n", __FUNCTION__);
675 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000676#endif
caryclark54359292015-03-26 07:52:43 -0700677 int sumWinding = updateWinding(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000678 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700679 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000680 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700681 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000682 SkOpSegment* nextSegment;
683 int activeCount = 0;
684 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000685 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000686 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000687 &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000688 if (activeAngle) {
689 ++activeCount;
690 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000691 foundAngle = nextAngle;
692 foundDone = nextSegment->done(nextAngle);
693 }
694 }
695 if (nextSegment->done()) {
696 continue;
697 }
reed0dc4dd62015-03-24 13:55:33 -0700698 if (!activeAngle) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400699 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end(), nullptr);
reed0dc4dd62015-03-24 13:55:33 -0700700 }
caryclark54359292015-03-26 07:52:43 -0700701 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000702 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000703 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000704 *chase->append() = last;
705#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700706 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
707 last->segment()->debugID(), last->debugID());
708 if (!last->final()) {
709 SkDebugf(" windSum=%d", last->upCast()->windSum());
710 }
711 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000712#endif
713 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000714 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700715 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000716 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700717 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000718 }
719 *nextStart = foundAngle->start();
720 *nextEnd = foundAngle->end();
721 nextSegment = foundAngle->segment();
722#if DEBUG_WINDING
723 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
724 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
725 #endif
726 return nextSegment;
727}
728
caryclark54359292015-03-26 07:52:43 -0700729SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
730 bool* unsortable) {
731 SkOpSpanBase* start = *nextStart;
732 SkOpSpanBase* end = *nextEnd;
733 SkASSERT(start != end);
734 int step = start->step(end);
735 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
736 if (other) {
737 // mark the smaller of startIndex, endIndex done, and all adjacent
738 // spans with the same T value (but not 'other' spans)
caryclark@google.com07393ca2013-04-08 11:47:37 +0000739#if DEBUG_WINDING
740 SkDebugf("%s simple\n", __FUNCTION__);
741#endif
caryclark54359292015-03-26 07:52:43 -0700742 SkOpSpan* startSpan = start->starter(end);
743 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700744 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000745 }
caryclark54359292015-03-26 07:52:43 -0700746 markDone(startSpan);
747 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000748 return other;
749 }
caryclark54359292015-03-26 07:52:43 -0700750 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
751 : (*nextStart)->prev());
752 SkASSERT(endNear == end); // is this ever not end?
753 SkASSERT(endNear);
754 SkASSERT(start != endNear);
755 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
756 SkOpAngle* angle = this->spanToAngle(end, start);
caryclark27c8eb82015-07-06 11:38:33 -0700757 if (!angle || angle->unorderable()) {
caryclark54359292015-03-26 07:52:43 -0700758 *unsortable = true;
759 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700760 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700761 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000762#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000763 SkDebugf("%s\n", __FUNCTION__);
764 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000765#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000766 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700767 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000768 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700769 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000770 SkOpSegment* nextSegment;
771 int activeCount = 0;
772 do {
Cary Clark56071432018-06-19 08:33:52 -0400773 if (!nextAngle) {
774 return nullptr;
775 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000776 nextSegment = nextAngle->segment();
777 ++activeCount;
778 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000779 foundAngle = nextAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000780 if (!(foundDone = nextSegment->done(nextAngle))) {
781 break;
782 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000783 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000784 nextAngle = nextAngle->next();
785 } while (nextAngle != angle);
caryclark54359292015-03-26 07:52:43 -0700786 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000787 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700788 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000789 }
790 *nextStart = foundAngle->start();
791 *nextEnd = foundAngle->end();
792 nextSegment = foundAngle->segment();
793#if DEBUG_WINDING
794 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
795 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
796 #endif
797 return nextSegment;
798}
799
caryclark54359292015-03-26 07:52:43 -0700800SkOpGlobalState* SkOpSegment::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700801 return contour()->globalState();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000802}
803
caryclark1049f122015-04-20 08:31:59 -0700804void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
caryclark54359292015-03-26 07:52:43 -0700805 fContour = contour;
halcanary96fcdcc2015-08-27 07:41:13 -0700806 fNext = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000807 fPts = pts;
caryclark1049f122015-04-20 08:31:59 -0700808 fWeight = weight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000809 fVerb = verb;
caryclark54359292015-03-26 07:52:43 -0700810 fCount = 0;
811 fDoneCount = 0;
812 fVisited = false;
813 SkOpSpan* zeroSpan = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700814 zeroSpan->init(this, nullptr, 0, fPts[0]);
caryclark54359292015-03-26 07:52:43 -0700815 SkOpSpanBase* oneSpan = &fTail;
816 zeroSpan->setNext(oneSpan);
817 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
caryclark1049f122015-04-20 08:31:59 -0700818 SkDEBUGCODE(fID = globalState()->nextSegmentID());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000819}
820
caryclark54359292015-03-26 07:52:43 -0700821bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
822 SkDPoint cPt = this->dPtAtT(t);
caryclark1049f122015-04-20 08:31:59 -0700823 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
caryclark54359292015-03-26 07:52:43 -0700824 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
825 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -0700826 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
caryclark54359292015-03-26 07:52:43 -0700827 int used = i.used();
828 for (int index = 0; index < used; ++index) {
829 if (cPt.roughlyEqual(i.pt(index))) {
reed0dc4dd62015-03-24 13:55:33 -0700830 return true;
831 }
caryclark54359292015-03-26 07:52:43 -0700832 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000833 return false;
834}
835
caryclark54359292015-03-26 07:52:43 -0700836bool SkOpSegment::isXor() const {
837 return fContour->isXor();
838}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000839
caryclark5b5ddd72015-05-18 05:12:56 -0700840void SkOpSegment::markAllDone() {
841 SkOpSpan* span = this->head();
842 do {
843 this->markDone(span);
844 } while ((span = span->next()->upCastable()));
845}
846
Cary Clarkc050a1a2018-06-25 08:45:40 -0400847 bool SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end, SkOpSpanBase** found) {
caryclark54359292015-03-26 07:52:43 -0700848 int step = start->step(end);
849 SkOpSpan* minSpan = start->starter(end);
850 markDone(minSpan);
halcanary96fcdcc2015-08-27 07:41:13 -0700851 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000852 SkOpSegment* other = this;
Cary Clark918fb1f2016-11-15 13:22:25 -0500853 SkOpSpan* priorDone = nullptr;
854 SkOpSpan* lastDone = nullptr;
Cary Clarkc050a1a2018-06-25 08:45:40 -0400855 int safetyNet = 100000;
caryclark54359292015-03-26 07:52:43 -0700856 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400857 if (!--safetyNet) {
858 return false;
859 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000860 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -0700861 SkASSERT(!last);
862 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000863 }
Cary Clark918fb1f2016-11-15 13:22:25 -0500864 if (lastDone == minSpan || priorDone == minSpan) {
Cary Clarkc050a1a2018-06-25 08:45:40 -0400865 if (found) {
866 *found = nullptr;
867 }
868 return true;
Cary Clark918fb1f2016-11-15 13:22:25 -0500869 }
caryclark54359292015-03-26 07:52:43 -0700870 other->markDone(minSpan);
Cary Clark918fb1f2016-11-15 13:22:25 -0500871 priorDone = lastDone;
872 lastDone = minSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000873 }
Cary Clarkc050a1a2018-06-25 08:45:40 -0400874 if (found) {
875 *found = last;
876 }
877 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000878}
879
caryclark54359292015-03-26 07:52:43 -0700880bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
881 SkOpSpanBase** lastPtr) {
882 SkOpSpan* spanStart = start->starter(end);
883 int step = start->step(end);
884 bool success = markWinding(spanStart, winding);
halcanary96fcdcc2015-08-27 07:41:13 -0700885 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000886 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700887 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
888 if (spanStart->windSum() != SK_MinS32) {
caryclarkb36a3cd2016-10-18 07:59:44 -0700889// SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive?
caryclarkdac1d172014-06-17 05:15:38 -0700890 SkASSERT(!last);
891 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000892 }
caryclark54359292015-03-26 07:52:43 -0700893 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000894 }
caryclark65f55312014-11-13 06:58:52 -0800895 if (lastPtr) {
896 *lastPtr = last;
897 }
898 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000899}
900
caryclark54359292015-03-26 07:52:43 -0700901bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
902 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
903 SkOpSpan* spanStart = start->starter(end);
904 int step = start->step(end);
905 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700906 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000907 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700908 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
909 if (spanStart->windSum() != SK_MinS32) {
910 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700911 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700912 this->globalState()->setWindingFailed();
913 return false;
caryclarkdac1d172014-06-17 05:15:38 -0700914 }
caryclark54359292015-03-26 07:52:43 -0700915 } else {
916 SkASSERT(spanStart->windSum() == oppWinding);
917 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700918 }
919 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700920 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000921 }
caryclark54359292015-03-26 07:52:43 -0700922 if (this->operand() == other->operand()) {
923 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700924 } else {
caryclark54359292015-03-26 07:52:43 -0700925 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700926 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000927 }
caryclark65f55312014-11-13 06:58:52 -0800928 if (lastPtr) {
929 *lastPtr = last;
930 }
931 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000932}
933
caryclark54359292015-03-26 07:52:43 -0700934SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000935 SkASSERT(angle->segment() == this);
936 if (UseInnerWinding(maxWinding, sumWinding)) {
937 maxWinding = sumWinding;
938 }
caryclark54359292015-03-26 07:52:43 -0700939 SkOpSpanBase* last;
940 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000941#if DEBUG_WINDING
942 if (last) {
caryclark54359292015-03-26 07:52:43 -0700943 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
944 last->segment()->debugID(), last->debugID());
945 if (!last->final()) {
946 SkDebugf(" windSum=");
947 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
948 }
949 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000950 }
951#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000952 return last;
953}
954
caryclark54359292015-03-26 07:52:43 -0700955SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
956 int oppSumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000957 SkASSERT(angle->segment() == this);
958 if (UseInnerWinding(maxWinding, sumWinding)) {
959 maxWinding = sumWinding;
960 }
961 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
962 oppMaxWinding = oppSumWinding;
963 }
halcanary96fcdcc2015-08-27 07:41:13 -0700964 SkOpSpanBase* last = nullptr;
caryclark65f55312014-11-13 06:58:52 -0800965 // caller doesn't require that this marks anything
caryclark54359292015-03-26 07:52:43 -0700966 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000967#if DEBUG_WINDING
968 if (last) {
caryclark54359292015-03-26 07:52:43 -0700969 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
970 last->segment()->debugID(), last->debugID());
971 if (!last->final()) {
972 SkDebugf(" windSum=");
973 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
974 }
975 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000976 }
977#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000978 return last;
979}
980
caryclark54359292015-03-26 07:52:43 -0700981void SkOpSegment::markDone(SkOpSpan* span) {
982 SkASSERT(this == span->segment());
983 if (span->done()) {
984 return;
985 }
986#if DEBUG_MARK_DONE
987 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
988#endif
989 span->setDone(true);
990 ++fDoneCount;
991 debugValidate();
992}
993
994bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
995 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -0700996 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -0700997 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -0700998 return false;
999 }
1000#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -07001001 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -07001002#endif
caryclark54359292015-03-26 07:52:43 -07001003 span->setWindSum(winding);
1004 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001005 return true;
1006}
1007
caryclark54359292015-03-26 07:52:43 -07001008bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
1009 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +00001010 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -07001011 if (span->done()) {
1012 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001013 }
caryclark54359292015-03-26 07:52:43 -07001014#if DEBUG_MARK_DONE
1015 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1016#endif
1017 span->setWindSum(winding);
1018 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001019 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001020 return true;
1021}
1022
caryclark54359292015-03-26 07:52:43 -07001023bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclarkef4f32a2016-08-24 09:24:18 -07001024 const SkPoint& testPt) const {
caryclark55888e42016-07-18 10:01:36 -07001025 SkASSERT(this == base->segment());
1026 if (this == testParent) {
1027 if (precisely_equal(base->fT, testT)) {
1028 return true;
1029 }
caryclark54359292015-03-26 07:52:43 -07001030 }
1031 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1032 return false;
1033 }
caryclark55888e42016-07-18 10:01:36 -07001034 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001035}
1036
1037static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1038 if (last) {
1039 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001040 }
halcanary96fcdcc2015-08-27 07:41:13 -07001041 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001042}
1043
caryclark54359292015-03-26 07:52:43 -07001044SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1045 SkOpSpanBase** last) const {
1046 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001047 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001048 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1049 SkASSERT(endSpan);
1050 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1051 SkOpSpanBase* foundSpan;
1052 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001053 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001054 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001055 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001056 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001057 }
caryclark54359292015-03-26 07:52:43 -07001058 SkOpPtT* otherPtT = endSpan->ptT()->next();
1059 other = otherPtT->segment();
1060 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001061 otherEnd = step > 0
1062 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1063 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001064 } else {
1065 int loopCount = angle->loopCount();
1066 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001067 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001068 }
1069 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001070 if (nullptr == next) {
1071 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001072 }
caryclarkdac1d172014-06-17 05:15:38 -07001073#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001074 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001075 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001076 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001077 }
caryclark54359292015-03-26 07:52:43 -07001078#endif
caryclarkdac1d172014-06-17 05:15:38 -07001079 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001080 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001081 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001082 }
caryclark343382e2016-06-29 08:18:38 -07001083 if (!otherEnd) {
1084 return nullptr;
1085 }
caryclark54359292015-03-26 07:52:43 -07001086 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001087 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001088 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001089 }
caryclark54359292015-03-26 07:52:43 -07001090 SkASSERT(*startPtr);
caryclark65b427c2014-09-18 10:32:57 -07001091// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001092 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1093 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1094 if (foundMin->windValue() != origMin->windValue()
1095 || foundMin->oppValue() != origMin->oppValue()) {
1096 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001097 }
caryclark54359292015-03-26 07:52:43 -07001098 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001099 *stepPtr = foundStep;
1100 if (minPtr) {
1101 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001102 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001103 return other;
1104}
1105
caryclark55888e42016-07-18 10:01:36 -07001106// Please keep this in sync with DebugClearVisited()
1107void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001108 // reset visited flag back to false
1109 do {
1110 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1111 while ((ptT = ptT->next()) != stopPtT) {
1112 SkOpSegment* opp = ptT->segment();
1113 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001114 }
caryclarkbca19f72015-05-13 08:23:48 -07001115 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001116}
1117
caryclark55888e42016-07-18 10:01:36 -07001118// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001119// look for pairs of undetected coincident curves
1120// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001121// Even though pairs of curves correct detect coincident runs, a run may be missed
1122// if the coincidence is a product of multiple intersections. For instance, given
1123// curves A, B, and C:
1124// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1125// the end of C that the intersection is replaced with the end of C.
1126// Even though A-B correctly do not detect an intersection at point 2,
1127// the resulting run from point 1 to point 2 is coincident on A and B.
1128bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001129 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001130 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001131 }
halcanary96fcdcc2015-08-27 07:41:13 -07001132 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001133 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001134 bool result = false;
caryclark54359292015-03-26 07:52:43 -07001135 do {
caryclarkbca19f72015-05-13 08:23:48 -07001136 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001137 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001138 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001139 if (ptT->deleted()) {
1140 continue;
1141 }
caryclark54359292015-03-26 07:52:43 -07001142 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001143 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001144 continue;
reed0dc4dd62015-03-24 13:55:33 -07001145 }
caryclarkbca19f72015-05-13 08:23:48 -07001146 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1147 if (!opp->visited()) {
1148 continue;
1149 }
1150 if (spanBase == &fHead) {
1151 continue;
1152 }
caryclark55888e42016-07-18 10:01:36 -07001153 if (ptT->segment() == this) {
1154 continue;
1155 }
caryclarkbca19f72015-05-13 08:23:48 -07001156 SkOpSpan* span = spanBase->upCastable();
1157 // FIXME?: this assumes that if the opposite segment is coincident then no more
1158 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001159 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001160 continue;
1161 }
caryclarkbca19f72015-05-13 08:23:48 -07001162 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001163 continue;
caryclark55888e42016-07-18 10:01:36 -07001164 }
halcanary96fcdcc2015-08-27 07:41:13 -07001165 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001166 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001167 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001168 SkOpSpan* priorTest = spanBase->prev();
1169 while (!priorOpp && priorTest) {
1170 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001171 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001172 if (priorPtT->deleted()) {
1173 continue;
1174 }
caryclark54359292015-03-26 07:52:43 -07001175 SkOpSegment* segment = priorPtT->span()->segment();
1176 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001177 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001178 priorOpp = opp;
1179 break;
1180 }
1181 }
caryclarkbca19f72015-05-13 08:23:48 -07001182 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001183 }
1184 if (!priorOpp) {
1185 continue;
1186 }
caryclark26ad22a2015-10-16 09:03:38 -07001187 if (priorPtT == ptT) {
1188 continue;
1189 }
caryclark54359292015-03-26 07:52:43 -07001190 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001191 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001192 bool swapped = priorPtT->fT > ptT->fT;
1193 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001194 using std::swap;
1195 swap(priorPtT, ptT);
1196 swap(oppStart, oppEnd);
caryclark54359292015-03-26 07:52:43 -07001197 }
caryclark55888e42016-07-18 10:01:36 -07001198 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1199 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1200 SkOpPtT* rootPtT = ptT->span()->ptT();
1201 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1202 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1203 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001204 goto swapBack;
1205 }
caryclark55888e42016-07-18 10:01:36 -07001206 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001207 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001208#if DEBUG_COINCIDENCE_VERBOSE
1209 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1210 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1211 rootOppEnd->debugID());
1212#endif
1213 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1214 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001215 }
caryclark55888e42016-07-18 10:01:36 -07001216#if DEBUG_COINCIDENCE
1217 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1218#endif
1219 result = true;
caryclark54359292015-03-26 07:52:43 -07001220 }
1221 swapBack:
1222 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001223 using std::swap;
1224 swap(priorPtT, ptT);
caryclark54359292015-03-26 07:52:43 -07001225 }
reed0dc4dd62015-03-24 13:55:33 -07001226 }
halcanary96fcdcc2015-08-27 07:41:13 -07001227 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001228 ClearVisited(&fHead);
1229 return result;
reed0dc4dd62015-03-24 13:55:33 -07001230}
1231
caryclark55888e42016-07-18 10:01:36 -07001232// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001233// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001234bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001235 debugValidate();
1236 SkOpSpanBase* test = &fHead;
1237 do {
1238 int addCount = test->spanAddsCount();
Cary Clark7eb01e02016-12-08 14:36:32 -05001239// FAIL_IF(addCount < 1);
1240 if (addCount <= 1) {
caryclark08bc8482015-04-24 09:08:57 -07001241 continue;
1242 }
1243 SkOpPtT* startPtT = test->ptT();
1244 SkOpPtT* testPtT = startPtT;
1245 do { // iterate through all spans associated with start
1246 SkOpSpanBase* oppSpan = testPtT->span();
1247 if (oppSpan->spanAddsCount() == addCount) {
1248 continue;
1249 }
1250 if (oppSpan->deleted()) {
1251 continue;
1252 }
1253 SkOpSegment* oppSegment = oppSpan->segment();
1254 if (oppSegment == this) {
1255 continue;
1256 }
1257 // find range of spans to consider merging
1258 SkOpSpanBase* oppPrev = oppSpan;
1259 SkOpSpanBase* oppFirst = oppSpan;
1260 while ((oppPrev = oppPrev->prev())) {
1261 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1262 break;
1263 }
1264 if (oppPrev->spanAddsCount() == addCount) {
1265 continue;
1266 }
1267 if (oppPrev->deleted()) {
1268 continue;
1269 }
1270 oppFirst = oppPrev;
1271 }
1272 SkOpSpanBase* oppNext = oppSpan;
1273 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001274 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001275 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1276 break;
1277 }
1278 if (oppNext->spanAddsCount() == addCount) {
1279 continue;
1280 }
1281 if (oppNext->deleted()) {
1282 continue;
1283 }
1284 oppLast = oppNext;
1285 }
1286 if (oppFirst == oppLast) {
1287 continue;
1288 }
1289 SkOpSpanBase* oppTest = oppFirst;
1290 do {
1291 if (oppTest == oppSpan) {
1292 continue;
1293 }
1294 // check to see if the candidate meets specific criteria:
1295 // it contains spans of segments in test's loop but not including 'this'
1296 SkOpPtT* oppStartPtT = oppTest->ptT();
1297 SkOpPtT* oppPtT = oppStartPtT;
1298 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1299 SkOpSegment* oppPtTSegment = oppPtT->segment();
1300 if (oppPtTSegment == this) {
1301 goto tryNextSpan;
1302 }
1303 SkOpPtT* matchPtT = startPtT;
1304 do {
1305 if (matchPtT->segment() == oppPtTSegment) {
1306 goto foundMatch;
1307 }
1308 } while ((matchPtT = matchPtT->next()) != startPtT);
1309 goto tryNextSpan;
1310 foundMatch: // merge oppTest and oppSpan
1311 oppSegment->debugValidate();
caryclark30b9fdd2016-08-31 14:36:29 -07001312 oppTest->mergeMatches(oppSpan);
1313 oppTest->addOpp(oppSpan);
caryclark08bc8482015-04-24 09:08:57 -07001314 oppSegment->debugValidate();
1315 goto checkNextSpan;
1316 }
caryclark55888e42016-07-18 10:01:36 -07001317 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001318 ;
1319 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1320 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001321checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001322 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001323 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001324 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001325 return true;
caryclark08bc8482015-04-24 09:08:57 -07001326}
1327
caryclark55888e42016-07-18 10:01:36 -07001328// adjacent spans may have points close by
Cary Clark28da2832017-03-21 10:30:50 -04001329bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan,
1330 bool* found) const {
caryclark55888e42016-07-18 10:01:36 -07001331 const SkOpPtT* refHead = refSpan->ptT();
1332 const SkOpPtT* checkHead = checkSpan->ptT();
1333// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
caryclark30b9fdd2016-08-31 14:36:29 -07001334 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
caryclark55888e42016-07-18 10:01:36 -07001335#if DEBUG_COINCIDENCE
1336 // verify that no combination of points are close
1337 const SkOpPtT* dBugRef = refHead;
1338 do {
1339 const SkOpPtT* dBugCheck = checkHead;
1340 do {
caryclark30b9fdd2016-08-31 14:36:29 -07001341 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
caryclark55888e42016-07-18 10:01:36 -07001342 dBugCheck = dBugCheck->next();
1343 } while (dBugCheck != checkHead);
1344 dBugRef = dBugRef->next();
1345 } while (dBugRef != refHead);
1346#endif
Cary Clark28da2832017-03-21 10:30:50 -04001347 *found = false;
1348 return true;
caryclark55888e42016-07-18 10:01:36 -07001349 }
1350 // check only unique points
1351 SkScalar distSqBest = SK_ScalarMax;
1352 const SkOpPtT* refBest = nullptr;
1353 const SkOpPtT* checkBest = nullptr;
1354 const SkOpPtT* ref = refHead;
1355 do {
1356 if (ref->deleted()) {
1357 continue;
1358 }
1359 while (ref->ptAlreadySeen(refHead)) {
1360 ref = ref->next();
1361 if (ref == refHead) {
1362 goto doneCheckingDistance;
1363 }
1364 }
1365 const SkOpPtT* check = checkHead;
1366 const SkOpSegment* refSeg = ref->segment();
Cary Clark28da2832017-03-21 10:30:50 -04001367 int escapeHatch = 100000; // defend against infinite loops
caryclark55888e42016-07-18 10:01:36 -07001368 do {
1369 if (check->deleted()) {
1370 continue;
1371 }
1372 while (check->ptAlreadySeen(checkHead)) {
1373 check = check->next();
1374 if (check == checkHead) {
1375 goto nextRef;
1376 }
1377 }
Cary Clarkdf429f32017-11-08 11:44:31 -05001378 SkScalar distSq = SkPointPriv::DistanceToSqd(ref->fPt, check->fPt);
caryclark55888e42016-07-18 10:01:36 -07001379 if (distSqBest > distSq && (refSeg != check->segment()
1380 || !refSeg->ptsDisjoint(*ref, *check))) {
1381 distSqBest = distSq;
1382 refBest = ref;
1383 checkBest = check;
1384 }
Cary Clark28da2832017-03-21 10:30:50 -04001385 if (--escapeHatch <= 0) {
1386 return false;
1387 }
caryclark55888e42016-07-18 10:01:36 -07001388 } while ((check = check->next()) != checkHead);
Cary Clark28da2832017-03-21 10:30:50 -04001389 nextRef:
caryclark55888e42016-07-18 10:01:36 -07001390 ;
1391 } while ((ref = ref->next()) != refHead);
1392doneCheckingDistance:
Cary Clark28da2832017-03-21 10:30:50 -04001393 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001394 checkBest->fPt);
Cary Clark28da2832017-03-21 10:30:50 -04001395 return true;
caryclark55888e42016-07-18 10:01:36 -07001396}
1397
1398// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001399// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
Cary Clark28da2832017-03-21 10:30:50 -04001400bool SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001401 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001402 // release undeleted spans pointing to this seg that are linked to the primary span
1403 SkOpSpanBase* spanBase = &fHead;
Cary Clark43938b82017-10-18 08:47:32 -04001404 int escapeHatch = 9999; // the largest count for a regular test is 50; for a fuzzer, 500
caryclark54359292015-03-26 07:52:43 -07001405 do {
caryclark55888e42016-07-18 10:01:36 -07001406 SkOpPtT* ptT = spanBase->ptT();
1407 const SkOpPtT* headPtT = ptT;
1408 while ((ptT = ptT->next()) != headPtT) {
Cary Clark43938b82017-10-18 08:47:32 -04001409 if (!--escapeHatch) {
1410 return false;
1411 }
caryclark55888e42016-07-18 10:01:36 -07001412 SkOpSpanBase* test = ptT->span();
1413 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1414 && test->ptT() == ptT) {
1415 if (test->final()) {
1416 if (spanBase == &fHead) {
1417 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001418 return true;
caryclark55888e42016-07-18 10:01:36 -07001419 }
1420 spanBase->upCast()->release(ptT);
1421 } else if (test->prev()) {
1422 test->upCast()->release(headPtT);
1423 }
1424 break;
caryclark54359292015-03-26 07:52:43 -07001425 }
reed0dc4dd62015-03-24 13:55:33 -07001426 }
caryclark55888e42016-07-18 10:01:36 -07001427 spanBase = spanBase->upCast()->next();
1428 } while (!spanBase->final());
caryclark55888e42016-07-18 10:01:36 -07001429 // This loop looks for adjacent spans which are near by
1430 spanBase = &fHead;
1431 do { // iterate through all spans associated with start
1432 SkOpSpanBase* test = spanBase->upCast()->next();
Cary Clark28da2832017-03-21 10:30:50 -04001433 bool found;
1434 if (!this->spansNearby(spanBase, test, &found)) {
1435 return false;
1436 }
1437 if (found) {
caryclark55888e42016-07-18 10:01:36 -07001438 if (test->final()) {
1439 if (spanBase->prev()) {
1440 test->merge(spanBase->upCast());
1441 } else {
1442 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001443 return true;
caryclark55888e42016-07-18 10:01:36 -07001444 }
1445 } else {
1446 spanBase->merge(test->upCast());
1447 }
1448 }
1449 spanBase = test;
1450 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001451 debugValidate();
Cary Clark28da2832017-03-21 10:30:50 -04001452 return true;
reed0dc4dd62015-03-24 13:55:33 -07001453}
1454
caryclark54359292015-03-26 07:52:43 -07001455bool SkOpSegment::operand() const {
1456 return fContour->operand();
1457}
1458
1459bool SkOpSegment::oppXor() const {
1460 return fContour->oppXor();
1461}
1462
1463bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1464 if (fVerb == SkPath::kLine_Verb) {
1465 return false;
1466 }
1467 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1468 // hits in two places with very different t values.
1469 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1470 // 'controls contained by ends' could avoid this check for common curves
1471 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1472 // on the other hand, the below check is relatively inexpensive
1473 double midT = (t1 + t2) / 2;
1474 SkPoint midPt = this->ptAtT(midT);
Cary Clarkdf429f32017-11-08 11:44:31 -05001475 double seDistSq = SkTMax(SkPointPriv::DistanceToSqd(pt1, pt2) * 2, FLT_EPSILON * 2);
1476 return SkPointPriv::DistanceToSqd(midPt, pt1) > seDistSq ||
1477 SkPointPriv::DistanceToSqd(midPt, pt2) > seDistSq;
caryclark54359292015-03-26 07:52:43 -07001478}
1479
1480void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1481 int* maxWinding, int* sumWinding) {
1482 int deltaSum = SpanSign(start, end);
1483 *maxWinding = *sumMiWinding;
1484 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001485 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001486}
1487
1488void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1489 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1490 int* oppSumWinding) {
1491 int deltaSum = SpanSign(start, end);
1492 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001493 if (operand()) {
1494 *maxWinding = *sumSuWinding;
1495 *sumWinding = *sumSuWinding -= deltaSum;
1496 *oppMaxWinding = *sumMiWinding;
1497 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1498 } else {
1499 *maxWinding = *sumMiWinding;
1500 *sumWinding = *sumMiWinding -= deltaSum;
1501 *oppMaxWinding = *sumSuWinding;
1502 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1503 }
bungeman60e0fee2015-08-26 05:15:46 -07001504 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1505 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001506}
1507
caryclarkb36a3cd2016-10-18 07:59:44 -07001508bool SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001509 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001510 do {
caryclark54359292015-03-26 07:52:43 -07001511 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001512 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001513 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001514 continue;
1515 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001516#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001517 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001518#endif
caryclark54359292015-03-26 07:52:43 -07001519 SkOpAngle* baseAngle = fromAngle;
1520 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001521#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001522 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1523 span->debugID());
1524 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001525#endif
caryclarkb36a3cd2016-10-18 07:59:44 -07001526 FAIL_IF(!fromAngle->insert(toAngle));
caryclark54359292015-03-26 07:52:43 -07001527 } else if (!fromAngle) {
1528 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001529 }
caryclark54359292015-03-26 07:52:43 -07001530 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001531 do {
caryclark54359292015-03-26 07:52:43 -07001532 SkOpSpanBase* oSpan = ptT->span();
1533 if (oSpan == span) {
1534 continue;
1535 }
1536 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001537 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001538#if DEBUG_ANGLE
1539 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001540 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1541 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001542 wroteAfterHeader = true;
1543 }
1544#endif
caryclark54359292015-03-26 07:52:43 -07001545 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001546 baseAngle->insert(oAngle);
1547 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001548 }
caryclark54359292015-03-26 07:52:43 -07001549 if (!oSpan->final()) {
1550 oAngle = oSpan->upCast()->toAngle();
1551 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001552#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001553 if (!wroteAfterHeader) {
1554 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1555 span->t(), span->debugID());
1556 wroteAfterHeader = true;
1557 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001558#endif
caryclark54359292015-03-26 07:52:43 -07001559 if (!oAngle->loopContains(baseAngle)) {
1560 baseAngle->insert(oAngle);
1561 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001562 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001563 }
caryclark54359292015-03-26 07:52:43 -07001564 } while ((ptT = ptT->next()) != stopPtT);
1565 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001566 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001567 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001568 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001569 }
halcanary96fcdcc2015-08-27 07:41:13 -07001570 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001571 }
1572#if DEBUG_SORT
1573 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1574#endif
caryclark54359292015-03-26 07:52:43 -07001575 } while (!span->final() && (span = span->upCast()->next()));
caryclarkb36a3cd2016-10-18 07:59:44 -07001576 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +00001577}
1578
caryclark54359292015-03-26 07:52:43 -07001579bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001580 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001581 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001582 const SkOpPtT& startPtT = *start->ptT();
1583 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001584 SkDEBUGCODE(edge->fVerb = fVerb);
1585 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001586 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001587 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001588 if (fVerb == SkPath::kLine_Verb) {
1589 return false;
1590 }
caryclark54359292015-03-26 07:52:43 -07001591 double startT = startPtT.fT;
1592 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001593 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1594 // don't compute midpoints if we already have them
1595 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001596 edge->fLine[1].set(fPts[1]);
1597 return false;
1598 }
1599 if (fVerb == SkPath::kConic_Verb) {
1600 edge->fConic[1].set(fPts[1]);
1601 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001602 return false;
1603 }
1604 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001605 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001606 edge->fCubic[1].set(fPts[1]);
1607 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001608 return false;
1609 }
caryclark1049f122015-04-20 08:31:59 -07001610 edge->fCubic[1].set(fPts[2]);
1611 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001612 return false;
1613 }
1614 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001615 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1616 } else if (fVerb == SkPath::kConic_Verb) {
1617 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1618 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001619 } else {
1620 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001621 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001622 }
1623 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001624}
1625
caryclark27c8eb82015-07-06 11:38:33 -07001626bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001627 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001628 // average t, find mid pt
1629 double midT = (prior->t() + spanBase->t()) / 2;
1630 SkPoint midPt = this->ptAtT(midT);
1631 bool coincident = true;
1632 // if the mid pt is not near either end pt, project perpendicular through opp seg
1633 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1634 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001635 if (priorPtT->span() == ptT->span()) {
1636 return false;
1637 }
caryclark27c8eb82015-07-06 11:38:33 -07001638 coincident = false;
1639 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001640 SkDCurve curvePart;
1641 this->subDivide(prior, spanBase, &curvePart);
1642 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1643 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1644 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1645 SkDCurve oppPart;
1646 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1647 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001648 // measure distance and see if it's small enough to denote coincidence
1649 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001650 if (!between(0, i[0][index], 1)) {
1651 continue;
1652 }
caryclark27c8eb82015-07-06 11:38:33 -07001653 SkDPoint oppPt = i.pt(index);
caryclark30b9fdd2016-08-31 14:36:29 -07001654 if (oppPt.approximatelyDEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001655 // the coincidence can occur at almost any angle
1656 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001657 }
1658 }
1659 }
1660 return coincident;
1661}
1662
Cary Clarkab2d73b2016-12-16 17:17:25 -05001663SkOpSpan* SkOpSegment::undoneSpan() {
1664 SkOpSpan* span = &fHead;
1665 SkOpSpanBase* next;
caryclark54359292015-03-26 07:52:43 -07001666 do {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001667 next = span->next();
caryclark54359292015-03-26 07:52:43 -07001668 if (!span->done()) {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001669 return span;
reed0dc4dd62015-03-24 13:55:33 -07001670 }
Cary Clarkab2d73b2016-12-16 17:17:25 -05001671 } while (!next->final() && (span = next->upCast()));
1672 return nullptr;
reed0dc4dd62015-03-24 13:55:33 -07001673}
1674
caryclark54359292015-03-26 07:52:43 -07001675int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1676 const SkOpSpan* lesser = start->starter(end);
1677 int oppWinding = lesser->oppSum();
1678 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001679 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1680 && oppWinding != SK_MaxS32) {
1681 oppWinding -= oppSpanWinding;
1682 }
1683 return oppWinding;
1684}
1685
1686int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001687 const SkOpSpanBase* startSpan = angle->start();
1688 const SkOpSpanBase* endSpan = angle->end();
1689 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001690}
1691
1692int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001693 const SkOpSpanBase* startSpan = angle->start();
1694 const SkOpSpanBase* endSpan = angle->end();
1695 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001696}
1697
caryclark624637c2015-05-11 07:21:27 -07001698int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1699 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001700 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001701 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001702 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001703 }
1704 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001705 return winding;
1706 }
caryclark54359292015-03-26 07:52:43 -07001707 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001708 if (winding && UseInnerWinding(winding - spanWinding, winding)
1709 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001710 winding -= spanWinding;
1711 }
1712 return winding;
1713}
1714
caryclark624637c2015-05-11 07:21:27 -07001715int SkOpSegment::updateWinding(SkOpAngle* angle) {
1716 SkOpSpanBase* startSpan = angle->start();
1717 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001718 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001719}
1720
caryclark624637c2015-05-11 07:21:27 -07001721int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1722 SkOpSpanBase* startSpan = angle->start();
1723 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001724 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001725}
1726
1727// OPTIMIZATION: does the following also work, and is it any faster?
1728// return outerWinding * innerWinding > 0
1729// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1730bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1731 SkASSERT(outerWinding != SK_MaxS32);
1732 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001733 int absOut = SkTAbs(outerWinding);
1734 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001735 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1736 return result;
1737}
1738
caryclark@google.com07393ca2013-04-08 11:47:37 +00001739int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001740 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1741 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001742}