blob: bfbf9dc687875f3debf78265c5d1e034c07bad19 [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) {
caryclark54359292015-03-26 07:52:43 -0700602 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
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) {
caryclark54359292015-03-26 07:52:43 -0700698 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
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
caryclark54359292015-03-26 07:52:43 -0700846SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) {
847 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;
caryclark54359292015-03-26 07:52:43 -0700854 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000855 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -0700856 SkASSERT(!last);
857 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000858 }
Cary Clark918fb1f2016-11-15 13:22:25 -0500859 if (lastDone == minSpan || priorDone == minSpan) {
860 return nullptr;
861 }
caryclark54359292015-03-26 07:52:43 -0700862 other->markDone(minSpan);
Cary Clark918fb1f2016-11-15 13:22:25 -0500863 priorDone = lastDone;
864 lastDone = minSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000865 }
866 return last;
867}
868
caryclark54359292015-03-26 07:52:43 -0700869bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
870 SkOpSpanBase** lastPtr) {
871 SkOpSpan* spanStart = start->starter(end);
872 int step = start->step(end);
873 bool success = markWinding(spanStart, winding);
halcanary96fcdcc2015-08-27 07:41:13 -0700874 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000875 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700876 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
877 if (spanStart->windSum() != SK_MinS32) {
caryclarkb36a3cd2016-10-18 07:59:44 -0700878// SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive?
caryclarkdac1d172014-06-17 05:15:38 -0700879 SkASSERT(!last);
880 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000881 }
caryclark54359292015-03-26 07:52:43 -0700882 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000883 }
caryclark65f55312014-11-13 06:58:52 -0800884 if (lastPtr) {
885 *lastPtr = last;
886 }
887 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000888}
889
caryclark54359292015-03-26 07:52:43 -0700890bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
891 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
892 SkOpSpan* spanStart = start->starter(end);
893 int step = start->step(end);
894 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700895 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000896 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700897 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
898 if (spanStart->windSum() != SK_MinS32) {
899 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700900 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700901 this->globalState()->setWindingFailed();
902 return false;
caryclarkdac1d172014-06-17 05:15:38 -0700903 }
caryclark54359292015-03-26 07:52:43 -0700904 } else {
905 SkASSERT(spanStart->windSum() == oppWinding);
906 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700907 }
908 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700909 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000910 }
caryclark54359292015-03-26 07:52:43 -0700911 if (this->operand() == other->operand()) {
912 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700913 } else {
caryclark54359292015-03-26 07:52:43 -0700914 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700915 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000916 }
caryclark65f55312014-11-13 06:58:52 -0800917 if (lastPtr) {
918 *lastPtr = last;
919 }
920 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000921}
922
caryclark54359292015-03-26 07:52:43 -0700923SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000924 SkASSERT(angle->segment() == this);
925 if (UseInnerWinding(maxWinding, sumWinding)) {
926 maxWinding = sumWinding;
927 }
caryclark54359292015-03-26 07:52:43 -0700928 SkOpSpanBase* last;
929 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000930#if DEBUG_WINDING
931 if (last) {
caryclark54359292015-03-26 07:52:43 -0700932 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
933 last->segment()->debugID(), last->debugID());
934 if (!last->final()) {
935 SkDebugf(" windSum=");
936 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
937 }
938 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000939 }
940#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000941 return last;
942}
943
caryclark54359292015-03-26 07:52:43 -0700944SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
945 int oppSumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000946 SkASSERT(angle->segment() == this);
947 if (UseInnerWinding(maxWinding, sumWinding)) {
948 maxWinding = sumWinding;
949 }
950 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
951 oppMaxWinding = oppSumWinding;
952 }
halcanary96fcdcc2015-08-27 07:41:13 -0700953 SkOpSpanBase* last = nullptr;
caryclark65f55312014-11-13 06:58:52 -0800954 // caller doesn't require that this marks anything
caryclark54359292015-03-26 07:52:43 -0700955 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000956#if DEBUG_WINDING
957 if (last) {
caryclark54359292015-03-26 07:52:43 -0700958 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
959 last->segment()->debugID(), last->debugID());
960 if (!last->final()) {
961 SkDebugf(" windSum=");
962 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
963 }
964 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000965 }
966#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000967 return last;
968}
969
caryclark54359292015-03-26 07:52:43 -0700970void SkOpSegment::markDone(SkOpSpan* span) {
971 SkASSERT(this == span->segment());
972 if (span->done()) {
973 return;
974 }
975#if DEBUG_MARK_DONE
976 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
977#endif
978 span->setDone(true);
979 ++fDoneCount;
980 debugValidate();
981}
982
983bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
984 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -0700985 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -0700986 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -0700987 return false;
988 }
989#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -0700990 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -0700991#endif
caryclark54359292015-03-26 07:52:43 -0700992 span->setWindSum(winding);
993 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -0700994 return true;
995}
996
caryclark54359292015-03-26 07:52:43 -0700997bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
998 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000999 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -07001000 if (span->done()) {
1001 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001002 }
caryclark54359292015-03-26 07:52:43 -07001003#if DEBUG_MARK_DONE
1004 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1005#endif
1006 span->setWindSum(winding);
1007 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001008 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001009 return true;
1010}
1011
caryclark54359292015-03-26 07:52:43 -07001012bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclarkef4f32a2016-08-24 09:24:18 -07001013 const SkPoint& testPt) const {
caryclark55888e42016-07-18 10:01:36 -07001014 SkASSERT(this == base->segment());
1015 if (this == testParent) {
1016 if (precisely_equal(base->fT, testT)) {
1017 return true;
1018 }
caryclark54359292015-03-26 07:52:43 -07001019 }
1020 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1021 return false;
1022 }
caryclark55888e42016-07-18 10:01:36 -07001023 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001024}
1025
1026static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1027 if (last) {
1028 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001029 }
halcanary96fcdcc2015-08-27 07:41:13 -07001030 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001031}
1032
caryclark54359292015-03-26 07:52:43 -07001033SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1034 SkOpSpanBase** last) const {
1035 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001036 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001037 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1038 SkASSERT(endSpan);
1039 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1040 SkOpSpanBase* foundSpan;
1041 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001042 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001043 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001044 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001045 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001046 }
caryclark54359292015-03-26 07:52:43 -07001047 SkOpPtT* otherPtT = endSpan->ptT()->next();
1048 other = otherPtT->segment();
1049 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001050 otherEnd = step > 0
1051 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1052 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001053 } else {
1054 int loopCount = angle->loopCount();
1055 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001056 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001057 }
1058 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001059 if (nullptr == next) {
1060 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001061 }
caryclarkdac1d172014-06-17 05:15:38 -07001062#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001063 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001064 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001065 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001066 }
caryclark54359292015-03-26 07:52:43 -07001067#endif
caryclarkdac1d172014-06-17 05:15:38 -07001068 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001069 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001070 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001071 }
caryclark343382e2016-06-29 08:18:38 -07001072 if (!otherEnd) {
1073 return nullptr;
1074 }
caryclark54359292015-03-26 07:52:43 -07001075 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001076 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001077 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001078 }
caryclark54359292015-03-26 07:52:43 -07001079 SkASSERT(*startPtr);
caryclark65b427c2014-09-18 10:32:57 -07001080// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001081 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1082 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1083 if (foundMin->windValue() != origMin->windValue()
1084 || foundMin->oppValue() != origMin->oppValue()) {
1085 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001086 }
caryclark54359292015-03-26 07:52:43 -07001087 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001088 *stepPtr = foundStep;
1089 if (minPtr) {
1090 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001091 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001092 return other;
1093}
1094
caryclark55888e42016-07-18 10:01:36 -07001095// Please keep this in sync with DebugClearVisited()
1096void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001097 // reset visited flag back to false
1098 do {
1099 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1100 while ((ptT = ptT->next()) != stopPtT) {
1101 SkOpSegment* opp = ptT->segment();
1102 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001103 }
caryclarkbca19f72015-05-13 08:23:48 -07001104 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001105}
1106
caryclark55888e42016-07-18 10:01:36 -07001107// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001108// look for pairs of undetected coincident curves
1109// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001110// Even though pairs of curves correct detect coincident runs, a run may be missed
1111// if the coincidence is a product of multiple intersections. For instance, given
1112// curves A, B, and C:
1113// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1114// the end of C that the intersection is replaced with the end of C.
1115// Even though A-B correctly do not detect an intersection at point 2,
1116// the resulting run from point 1 to point 2 is coincident on A and B.
1117bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001118 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001119 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001120 }
halcanary96fcdcc2015-08-27 07:41:13 -07001121 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001122 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001123 bool result = false;
caryclark54359292015-03-26 07:52:43 -07001124 do {
caryclarkbca19f72015-05-13 08:23:48 -07001125 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001126 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001127 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001128 if (ptT->deleted()) {
1129 continue;
1130 }
caryclark54359292015-03-26 07:52:43 -07001131 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001132 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001133 continue;
reed0dc4dd62015-03-24 13:55:33 -07001134 }
caryclarkbca19f72015-05-13 08:23:48 -07001135 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1136 if (!opp->visited()) {
1137 continue;
1138 }
1139 if (spanBase == &fHead) {
1140 continue;
1141 }
caryclark55888e42016-07-18 10:01:36 -07001142 if (ptT->segment() == this) {
1143 continue;
1144 }
caryclarkbca19f72015-05-13 08:23:48 -07001145 SkOpSpan* span = spanBase->upCastable();
1146 // FIXME?: this assumes that if the opposite segment is coincident then no more
1147 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001148 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001149 continue;
1150 }
caryclarkbca19f72015-05-13 08:23:48 -07001151 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001152 continue;
caryclark55888e42016-07-18 10:01:36 -07001153 }
halcanary96fcdcc2015-08-27 07:41:13 -07001154 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001155 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001156 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001157 SkOpSpan* priorTest = spanBase->prev();
1158 while (!priorOpp && priorTest) {
1159 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001160 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001161 if (priorPtT->deleted()) {
1162 continue;
1163 }
caryclark54359292015-03-26 07:52:43 -07001164 SkOpSegment* segment = priorPtT->span()->segment();
1165 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001166 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001167 priorOpp = opp;
1168 break;
1169 }
1170 }
caryclarkbca19f72015-05-13 08:23:48 -07001171 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001172 }
1173 if (!priorOpp) {
1174 continue;
1175 }
caryclark26ad22a2015-10-16 09:03:38 -07001176 if (priorPtT == ptT) {
1177 continue;
1178 }
caryclark54359292015-03-26 07:52:43 -07001179 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001180 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001181 bool swapped = priorPtT->fT > ptT->fT;
1182 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001183 using std::swap;
1184 swap(priorPtT, ptT);
1185 swap(oppStart, oppEnd);
caryclark54359292015-03-26 07:52:43 -07001186 }
caryclark55888e42016-07-18 10:01:36 -07001187 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1188 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1189 SkOpPtT* rootPtT = ptT->span()->ptT();
1190 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1191 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1192 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001193 goto swapBack;
1194 }
caryclark55888e42016-07-18 10:01:36 -07001195 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001196 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001197#if DEBUG_COINCIDENCE_VERBOSE
1198 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1199 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1200 rootOppEnd->debugID());
1201#endif
1202 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1203 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001204 }
caryclark55888e42016-07-18 10:01:36 -07001205#if DEBUG_COINCIDENCE
1206 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1207#endif
1208 result = true;
caryclark54359292015-03-26 07:52:43 -07001209 }
1210 swapBack:
1211 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001212 using std::swap;
1213 swap(priorPtT, ptT);
caryclark54359292015-03-26 07:52:43 -07001214 }
reed0dc4dd62015-03-24 13:55:33 -07001215 }
halcanary96fcdcc2015-08-27 07:41:13 -07001216 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001217 ClearVisited(&fHead);
1218 return result;
reed0dc4dd62015-03-24 13:55:33 -07001219}
1220
caryclark55888e42016-07-18 10:01:36 -07001221// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001222// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001223bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001224 debugValidate();
1225 SkOpSpanBase* test = &fHead;
1226 do {
1227 int addCount = test->spanAddsCount();
Cary Clark7eb01e02016-12-08 14:36:32 -05001228// FAIL_IF(addCount < 1);
1229 if (addCount <= 1) {
caryclark08bc8482015-04-24 09:08:57 -07001230 continue;
1231 }
1232 SkOpPtT* startPtT = test->ptT();
1233 SkOpPtT* testPtT = startPtT;
1234 do { // iterate through all spans associated with start
1235 SkOpSpanBase* oppSpan = testPtT->span();
1236 if (oppSpan->spanAddsCount() == addCount) {
1237 continue;
1238 }
1239 if (oppSpan->deleted()) {
1240 continue;
1241 }
1242 SkOpSegment* oppSegment = oppSpan->segment();
1243 if (oppSegment == this) {
1244 continue;
1245 }
1246 // find range of spans to consider merging
1247 SkOpSpanBase* oppPrev = oppSpan;
1248 SkOpSpanBase* oppFirst = oppSpan;
1249 while ((oppPrev = oppPrev->prev())) {
1250 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1251 break;
1252 }
1253 if (oppPrev->spanAddsCount() == addCount) {
1254 continue;
1255 }
1256 if (oppPrev->deleted()) {
1257 continue;
1258 }
1259 oppFirst = oppPrev;
1260 }
1261 SkOpSpanBase* oppNext = oppSpan;
1262 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001263 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001264 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1265 break;
1266 }
1267 if (oppNext->spanAddsCount() == addCount) {
1268 continue;
1269 }
1270 if (oppNext->deleted()) {
1271 continue;
1272 }
1273 oppLast = oppNext;
1274 }
1275 if (oppFirst == oppLast) {
1276 continue;
1277 }
1278 SkOpSpanBase* oppTest = oppFirst;
1279 do {
1280 if (oppTest == oppSpan) {
1281 continue;
1282 }
1283 // check to see if the candidate meets specific criteria:
1284 // it contains spans of segments in test's loop but not including 'this'
1285 SkOpPtT* oppStartPtT = oppTest->ptT();
1286 SkOpPtT* oppPtT = oppStartPtT;
1287 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1288 SkOpSegment* oppPtTSegment = oppPtT->segment();
1289 if (oppPtTSegment == this) {
1290 goto tryNextSpan;
1291 }
1292 SkOpPtT* matchPtT = startPtT;
1293 do {
1294 if (matchPtT->segment() == oppPtTSegment) {
1295 goto foundMatch;
1296 }
1297 } while ((matchPtT = matchPtT->next()) != startPtT);
1298 goto tryNextSpan;
1299 foundMatch: // merge oppTest and oppSpan
1300 oppSegment->debugValidate();
caryclark30b9fdd2016-08-31 14:36:29 -07001301 oppTest->mergeMatches(oppSpan);
1302 oppTest->addOpp(oppSpan);
caryclark08bc8482015-04-24 09:08:57 -07001303 oppSegment->debugValidate();
1304 goto checkNextSpan;
1305 }
caryclark55888e42016-07-18 10:01:36 -07001306 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001307 ;
1308 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1309 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001310checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001311 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001312 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001313 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001314 return true;
caryclark08bc8482015-04-24 09:08:57 -07001315}
1316
caryclark55888e42016-07-18 10:01:36 -07001317// adjacent spans may have points close by
Cary Clark28da2832017-03-21 10:30:50 -04001318bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan,
1319 bool* found) const {
caryclark55888e42016-07-18 10:01:36 -07001320 const SkOpPtT* refHead = refSpan->ptT();
1321 const SkOpPtT* checkHead = checkSpan->ptT();
1322// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
caryclark30b9fdd2016-08-31 14:36:29 -07001323 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
caryclark55888e42016-07-18 10:01:36 -07001324#if DEBUG_COINCIDENCE
1325 // verify that no combination of points are close
1326 const SkOpPtT* dBugRef = refHead;
1327 do {
1328 const SkOpPtT* dBugCheck = checkHead;
1329 do {
caryclark30b9fdd2016-08-31 14:36:29 -07001330 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
caryclark55888e42016-07-18 10:01:36 -07001331 dBugCheck = dBugCheck->next();
1332 } while (dBugCheck != checkHead);
1333 dBugRef = dBugRef->next();
1334 } while (dBugRef != refHead);
1335#endif
Cary Clark28da2832017-03-21 10:30:50 -04001336 *found = false;
1337 return true;
caryclark55888e42016-07-18 10:01:36 -07001338 }
1339 // check only unique points
1340 SkScalar distSqBest = SK_ScalarMax;
1341 const SkOpPtT* refBest = nullptr;
1342 const SkOpPtT* checkBest = nullptr;
1343 const SkOpPtT* ref = refHead;
1344 do {
1345 if (ref->deleted()) {
1346 continue;
1347 }
1348 while (ref->ptAlreadySeen(refHead)) {
1349 ref = ref->next();
1350 if (ref == refHead) {
1351 goto doneCheckingDistance;
1352 }
1353 }
1354 const SkOpPtT* check = checkHead;
1355 const SkOpSegment* refSeg = ref->segment();
Cary Clark28da2832017-03-21 10:30:50 -04001356 int escapeHatch = 100000; // defend against infinite loops
caryclark55888e42016-07-18 10:01:36 -07001357 do {
1358 if (check->deleted()) {
1359 continue;
1360 }
1361 while (check->ptAlreadySeen(checkHead)) {
1362 check = check->next();
1363 if (check == checkHead) {
1364 goto nextRef;
1365 }
1366 }
Cary Clarkdf429f32017-11-08 11:44:31 -05001367 SkScalar distSq = SkPointPriv::DistanceToSqd(ref->fPt, check->fPt);
caryclark55888e42016-07-18 10:01:36 -07001368 if (distSqBest > distSq && (refSeg != check->segment()
1369 || !refSeg->ptsDisjoint(*ref, *check))) {
1370 distSqBest = distSq;
1371 refBest = ref;
1372 checkBest = check;
1373 }
Cary Clark28da2832017-03-21 10:30:50 -04001374 if (--escapeHatch <= 0) {
1375 return false;
1376 }
caryclark55888e42016-07-18 10:01:36 -07001377 } while ((check = check->next()) != checkHead);
Cary Clark28da2832017-03-21 10:30:50 -04001378 nextRef:
caryclark55888e42016-07-18 10:01:36 -07001379 ;
1380 } while ((ref = ref->next()) != refHead);
1381doneCheckingDistance:
Cary Clark28da2832017-03-21 10:30:50 -04001382 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001383 checkBest->fPt);
Cary Clark28da2832017-03-21 10:30:50 -04001384 return true;
caryclark55888e42016-07-18 10:01:36 -07001385}
1386
1387// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001388// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
Cary Clark28da2832017-03-21 10:30:50 -04001389bool SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001390 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001391 // release undeleted spans pointing to this seg that are linked to the primary span
1392 SkOpSpanBase* spanBase = &fHead;
Cary Clark43938b82017-10-18 08:47:32 -04001393 int escapeHatch = 9999; // the largest count for a regular test is 50; for a fuzzer, 500
caryclark54359292015-03-26 07:52:43 -07001394 do {
caryclark55888e42016-07-18 10:01:36 -07001395 SkOpPtT* ptT = spanBase->ptT();
1396 const SkOpPtT* headPtT = ptT;
1397 while ((ptT = ptT->next()) != headPtT) {
Cary Clark43938b82017-10-18 08:47:32 -04001398 if (!--escapeHatch) {
1399 return false;
1400 }
caryclark55888e42016-07-18 10:01:36 -07001401 SkOpSpanBase* test = ptT->span();
1402 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1403 && test->ptT() == ptT) {
1404 if (test->final()) {
1405 if (spanBase == &fHead) {
1406 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001407 return true;
caryclark55888e42016-07-18 10:01:36 -07001408 }
1409 spanBase->upCast()->release(ptT);
1410 } else if (test->prev()) {
1411 test->upCast()->release(headPtT);
1412 }
1413 break;
caryclark54359292015-03-26 07:52:43 -07001414 }
reed0dc4dd62015-03-24 13:55:33 -07001415 }
caryclark55888e42016-07-18 10:01:36 -07001416 spanBase = spanBase->upCast()->next();
1417 } while (!spanBase->final());
caryclark55888e42016-07-18 10:01:36 -07001418 // This loop looks for adjacent spans which are near by
1419 spanBase = &fHead;
1420 do { // iterate through all spans associated with start
1421 SkOpSpanBase* test = spanBase->upCast()->next();
Cary Clark28da2832017-03-21 10:30:50 -04001422 bool found;
1423 if (!this->spansNearby(spanBase, test, &found)) {
1424 return false;
1425 }
1426 if (found) {
caryclark55888e42016-07-18 10:01:36 -07001427 if (test->final()) {
1428 if (spanBase->prev()) {
1429 test->merge(spanBase->upCast());
1430 } else {
1431 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001432 return true;
caryclark55888e42016-07-18 10:01:36 -07001433 }
1434 } else {
1435 spanBase->merge(test->upCast());
1436 }
1437 }
1438 spanBase = test;
1439 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001440 debugValidate();
Cary Clark28da2832017-03-21 10:30:50 -04001441 return true;
reed0dc4dd62015-03-24 13:55:33 -07001442}
1443
caryclark54359292015-03-26 07:52:43 -07001444bool SkOpSegment::operand() const {
1445 return fContour->operand();
1446}
1447
1448bool SkOpSegment::oppXor() const {
1449 return fContour->oppXor();
1450}
1451
1452bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1453 if (fVerb == SkPath::kLine_Verb) {
1454 return false;
1455 }
1456 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1457 // hits in two places with very different t values.
1458 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1459 // 'controls contained by ends' could avoid this check for common curves
1460 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1461 // on the other hand, the below check is relatively inexpensive
1462 double midT = (t1 + t2) / 2;
1463 SkPoint midPt = this->ptAtT(midT);
Cary Clarkdf429f32017-11-08 11:44:31 -05001464 double seDistSq = SkTMax(SkPointPriv::DistanceToSqd(pt1, pt2) * 2, FLT_EPSILON * 2);
1465 return SkPointPriv::DistanceToSqd(midPt, pt1) > seDistSq ||
1466 SkPointPriv::DistanceToSqd(midPt, pt2) > seDistSq;
caryclark54359292015-03-26 07:52:43 -07001467}
1468
1469void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1470 int* maxWinding, int* sumWinding) {
1471 int deltaSum = SpanSign(start, end);
1472 *maxWinding = *sumMiWinding;
1473 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001474 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001475}
1476
1477void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1478 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1479 int* oppSumWinding) {
1480 int deltaSum = SpanSign(start, end);
1481 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001482 if (operand()) {
1483 *maxWinding = *sumSuWinding;
1484 *sumWinding = *sumSuWinding -= deltaSum;
1485 *oppMaxWinding = *sumMiWinding;
1486 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1487 } else {
1488 *maxWinding = *sumMiWinding;
1489 *sumWinding = *sumMiWinding -= deltaSum;
1490 *oppMaxWinding = *sumSuWinding;
1491 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1492 }
bungeman60e0fee2015-08-26 05:15:46 -07001493 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1494 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001495}
1496
caryclarkb36a3cd2016-10-18 07:59:44 -07001497bool SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001498 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001499 do {
caryclark54359292015-03-26 07:52:43 -07001500 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001501 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001502 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001503 continue;
1504 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001505#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001506 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001507#endif
caryclark54359292015-03-26 07:52:43 -07001508 SkOpAngle* baseAngle = fromAngle;
1509 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001510#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001511 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1512 span->debugID());
1513 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001514#endif
caryclarkb36a3cd2016-10-18 07:59:44 -07001515 FAIL_IF(!fromAngle->insert(toAngle));
caryclark54359292015-03-26 07:52:43 -07001516 } else if (!fromAngle) {
1517 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001518 }
caryclark54359292015-03-26 07:52:43 -07001519 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001520 do {
caryclark54359292015-03-26 07:52:43 -07001521 SkOpSpanBase* oSpan = ptT->span();
1522 if (oSpan == span) {
1523 continue;
1524 }
1525 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001526 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001527#if DEBUG_ANGLE
1528 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001529 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1530 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001531 wroteAfterHeader = true;
1532 }
1533#endif
caryclark54359292015-03-26 07:52:43 -07001534 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001535 baseAngle->insert(oAngle);
1536 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001537 }
caryclark54359292015-03-26 07:52:43 -07001538 if (!oSpan->final()) {
1539 oAngle = oSpan->upCast()->toAngle();
1540 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001541#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001542 if (!wroteAfterHeader) {
1543 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1544 span->t(), span->debugID());
1545 wroteAfterHeader = true;
1546 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001547#endif
caryclark54359292015-03-26 07:52:43 -07001548 if (!oAngle->loopContains(baseAngle)) {
1549 baseAngle->insert(oAngle);
1550 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001551 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001552 }
caryclark54359292015-03-26 07:52:43 -07001553 } while ((ptT = ptT->next()) != stopPtT);
1554 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001555 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001556 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001557 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001558 }
halcanary96fcdcc2015-08-27 07:41:13 -07001559 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001560 }
1561#if DEBUG_SORT
1562 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1563#endif
caryclark54359292015-03-26 07:52:43 -07001564 } while (!span->final() && (span = span->upCast()->next()));
caryclarkb36a3cd2016-10-18 07:59:44 -07001565 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +00001566}
1567
caryclark54359292015-03-26 07:52:43 -07001568bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001569 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001570 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001571 const SkOpPtT& startPtT = *start->ptT();
1572 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001573 SkDEBUGCODE(edge->fVerb = fVerb);
1574 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001575 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001576 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001577 if (fVerb == SkPath::kLine_Verb) {
1578 return false;
1579 }
caryclark54359292015-03-26 07:52:43 -07001580 double startT = startPtT.fT;
1581 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001582 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1583 // don't compute midpoints if we already have them
1584 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001585 edge->fLine[1].set(fPts[1]);
1586 return false;
1587 }
1588 if (fVerb == SkPath::kConic_Verb) {
1589 edge->fConic[1].set(fPts[1]);
1590 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001591 return false;
1592 }
1593 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001594 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001595 edge->fCubic[1].set(fPts[1]);
1596 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001597 return false;
1598 }
caryclark1049f122015-04-20 08:31:59 -07001599 edge->fCubic[1].set(fPts[2]);
1600 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001601 return false;
1602 }
1603 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001604 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1605 } else if (fVerb == SkPath::kConic_Verb) {
1606 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1607 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001608 } else {
1609 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001610 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001611 }
1612 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001613}
1614
caryclark27c8eb82015-07-06 11:38:33 -07001615bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001616 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001617 // average t, find mid pt
1618 double midT = (prior->t() + spanBase->t()) / 2;
1619 SkPoint midPt = this->ptAtT(midT);
1620 bool coincident = true;
1621 // if the mid pt is not near either end pt, project perpendicular through opp seg
1622 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1623 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001624 if (priorPtT->span() == ptT->span()) {
1625 return false;
1626 }
caryclark27c8eb82015-07-06 11:38:33 -07001627 coincident = false;
1628 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001629 SkDCurve curvePart;
1630 this->subDivide(prior, spanBase, &curvePart);
1631 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1632 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1633 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1634 SkDCurve oppPart;
1635 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1636 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001637 // measure distance and see if it's small enough to denote coincidence
1638 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001639 if (!between(0, i[0][index], 1)) {
1640 continue;
1641 }
caryclark27c8eb82015-07-06 11:38:33 -07001642 SkDPoint oppPt = i.pt(index);
caryclark30b9fdd2016-08-31 14:36:29 -07001643 if (oppPt.approximatelyDEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001644 // the coincidence can occur at almost any angle
1645 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001646 }
1647 }
1648 }
1649 return coincident;
1650}
1651
Cary Clarkab2d73b2016-12-16 17:17:25 -05001652SkOpSpan* SkOpSegment::undoneSpan() {
1653 SkOpSpan* span = &fHead;
1654 SkOpSpanBase* next;
caryclark54359292015-03-26 07:52:43 -07001655 do {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001656 next = span->next();
caryclark54359292015-03-26 07:52:43 -07001657 if (!span->done()) {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001658 return span;
reed0dc4dd62015-03-24 13:55:33 -07001659 }
Cary Clarkab2d73b2016-12-16 17:17:25 -05001660 } while (!next->final() && (span = next->upCast()));
1661 return nullptr;
reed0dc4dd62015-03-24 13:55:33 -07001662}
1663
caryclark54359292015-03-26 07:52:43 -07001664int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1665 const SkOpSpan* lesser = start->starter(end);
1666 int oppWinding = lesser->oppSum();
1667 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001668 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1669 && oppWinding != SK_MaxS32) {
1670 oppWinding -= oppSpanWinding;
1671 }
1672 return oppWinding;
1673}
1674
1675int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001676 const SkOpSpanBase* startSpan = angle->start();
1677 const SkOpSpanBase* endSpan = angle->end();
1678 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001679}
1680
1681int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001682 const SkOpSpanBase* startSpan = angle->start();
1683 const SkOpSpanBase* endSpan = angle->end();
1684 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001685}
1686
caryclark624637c2015-05-11 07:21:27 -07001687int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1688 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001689 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001690 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001691 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001692 }
1693 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001694 return winding;
1695 }
caryclark54359292015-03-26 07:52:43 -07001696 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001697 if (winding && UseInnerWinding(winding - spanWinding, winding)
1698 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001699 winding -= spanWinding;
1700 }
1701 return winding;
1702}
1703
caryclark624637c2015-05-11 07:21:27 -07001704int SkOpSegment::updateWinding(SkOpAngle* angle) {
1705 SkOpSpanBase* startSpan = angle->start();
1706 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001707 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001708}
1709
caryclark624637c2015-05-11 07:21:27 -07001710int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1711 SkOpSpanBase* startSpan = angle->start();
1712 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001713 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001714}
1715
1716// OPTIMIZATION: does the following also work, and is it any faster?
1717// return outerWinding * innerWinding > 0
1718// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1719bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1720 SkASSERT(outerWinding != SK_MaxS32);
1721 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001722 int absOut = SkTAbs(outerWinding);
1723 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001724 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1725 return result;
1726}
1727
caryclark@google.com07393ca2013-04-08 11:47:37 +00001728int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001729 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1730 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001731}