blob: df70034f93dd0fd00e55b73829b1238069a00005 [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
caryclark30b9fdd2016-08-31 14:36:29 -0700330bool SkOpSegment::collapsed(double s, double e) const {
331 const SkOpSpanBase* span = &fHead;
332 do {
333 if (span->collapsed(s, e)) {
334 return true;
335 }
336 } while (span->upCastable() && (span = span->upCast()->next()));
337 return false;
338}
339
caryclark@google.com570863f2013-09-16 15:55:01 +0000340void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
341 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700342 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000343 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
344 int sumSuWinding;
345 bool binary = includeType >= SkOpAngle::kBinarySingle;
346 if (binary) {
347 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
348 if (baseSegment->operand()) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400349 using std::swap;
350 swap(sumMiWinding, sumSuWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000351 }
352 }
353 SkOpSegment* nextSegment = nextAngle->segment();
354 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700355 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000356 if (binary) {
357 int oppMaxWinding, oppSumWinding;
358 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
359 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
360 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000361 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000362 } else {
363 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
364 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000365 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000366 }
367 nextAngle->setLastMarked(last);
368}
369
caryclark624637c2015-05-11 07:21:27 -0700370void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
caryclark@google.com570863f2013-09-16 15:55:01 +0000371 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700372 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000373 int sumMiWinding = baseSegment->updateWinding(baseAngle);
374 int sumSuWinding;
375 bool binary = includeType >= SkOpAngle::kBinarySingle;
376 if (binary) {
377 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
378 if (baseSegment->operand()) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400379 using std::swap;
380 swap(sumMiWinding, sumSuWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000381 }
382 }
383 SkOpSegment* nextSegment = nextAngle->segment();
384 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700385 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000386 if (binary) {
387 int oppMaxWinding, oppSumWinding;
388 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
389 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
390 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000391 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000392 } else {
393 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
394 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000395 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000396 }
397 nextAngle->setLastMarked(last);
398}
399
caryclark54359292015-03-26 07:52:43 -0700400// at this point, the span is already ordered, or unorderable
401int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
402 SkOpAngle::IncludeType includeType) {
403 SkASSERT(includeType != SkOpAngle::kUnaryXor);
404 SkOpAngle* firstAngle = this->spanToAngle(end, start);
halcanary96fcdcc2015-08-27 07:41:13 -0700405 if (nullptr == firstAngle || nullptr == firstAngle->next()) {
caryclark54359292015-03-26 07:52:43 -0700406 return SK_NaN32;
407 }
408 // if all angles have a computed winding,
409 // or if no adjacent angles are orderable,
410 // or if adjacent orderable angles have no computed winding,
411 // there's nothing to do
412 // if two orderable angles are adjacent, and both are next to orderable angles,
413 // and one has winding computed, transfer to the other
halcanary96fcdcc2015-08-27 07:41:13 -0700414 SkOpAngle* baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700415 bool tryReverse = false;
416 // look for counterclockwise transfers
417 SkOpAngle* angle = firstAngle->previous();
418 SkOpAngle* next = angle->next();
419 firstAngle = next;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000420 do {
caryclark54359292015-03-26 07:52:43 -0700421 SkOpAngle* prior = angle;
422 angle = next;
423 next = angle->next();
424 SkASSERT(prior->next() == angle);
425 SkASSERT(angle->next() == next);
426 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700427 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700428 continue;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000429 }
caryclark54359292015-03-26 07:52:43 -0700430 int testWinding = angle->starter()->windSum();
431 if (SK_MinS32 != testWinding) {
432 baseAngle = angle;
433 tryReverse = true;
434 continue;
reed0dc4dd62015-03-24 13:55:33 -0700435 }
caryclark54359292015-03-26 07:52:43 -0700436 if (baseAngle) {
437 ComputeOneSum(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700438 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
caryclark54359292015-03-26 07:52:43 -0700439 }
440 } while (next != firstAngle);
441 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
442 firstAngle = baseAngle;
443 tryReverse = true;
444 }
445 if (tryReverse) {
halcanary96fcdcc2015-08-27 07:41:13 -0700446 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700447 SkOpAngle* prior = firstAngle;
448 do {
449 angle = prior;
450 prior = angle->previous();
451 SkASSERT(prior->next() == angle);
452 next = angle->next();
453 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700454 baseAngle = nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700455 continue;
456 }
caryclark54359292015-03-26 07:52:43 -0700457 int testWinding = angle->starter()->windSum();
458 if (SK_MinS32 != testWinding) {
459 baseAngle = angle;
460 continue;
reed0dc4dd62015-03-24 13:55:33 -0700461 }
caryclark54359292015-03-26 07:52:43 -0700462 if (baseAngle) {
463 ComputeOneSumReverse(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700464 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700465 }
caryclark54359292015-03-26 07:52:43 -0700466 } while (prior != firstAngle);
reed0dc4dd62015-03-24 13:55:33 -0700467 }
caryclark54359292015-03-26 07:52:43 -0700468 return start->starter(end)->windSum();
reed0dc4dd62015-03-24 13:55:33 -0700469}
470
caryclark55888e42016-07-18 10:01:36 -0700471bool SkOpSegment::contains(double newT) const {
472 const SkOpSpanBase* spanBase = &fHead;
473 do {
474 if (spanBase->ptT()->contains(this, newT)) {
475 return true;
476 }
477 if (spanBase == &fTail) {
478 break;
479 }
480 spanBase = spanBase->upCast()->next();
481 } while (true);
482 return false;
483}
484
mtklein18300a32016-03-16 13:53:35 -0700485void SkOpSegment::release(const SkOpSpan* span) {
caryclark54359292015-03-26 07:52:43 -0700486 if (span->done()) {
caryclark08bc8482015-04-24 09:08:57 -0700487 --fDoneCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000488 }
caryclark08bc8482015-04-24 09:08:57 -0700489 --fCount;
caryclark15976282016-07-21 05:48:43 -0700490 SkOPASSERT(fCount >= fDoneCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000491}
492
Cary Clarke47ae292016-10-05 08:51:39 -0400493#if DEBUG_ANGLE
494// called only by debugCheckNearCoincidence
caryclark26ad22a2015-10-16 09:03:38 -0700495double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
caryclark54359292015-03-26 07:52:43 -0700496 SkDPoint testPt = this->dPtAtT(t);
497 SkDLine testPerp = {{ testPt, testPt }};
498 SkDVector slope = this->dSlopeAtT(t);
499 testPerp[1].fX += slope.fY;
500 testPerp[1].fY -= slope.fX;
501 SkIntersections i;
caryclark26ad22a2015-10-16 09:03:38 -0700502 const SkOpSegment* oppSegment = oppAngle->segment();
caryclark1049f122015-04-20 08:31:59 -0700503 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
caryclark54359292015-03-26 07:52:43 -0700504 double closestDistSq = SK_ScalarInfinity;
505 for (int index = 0; index < i.used(); ++index) {
506 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000507 continue;
508 }
caryclark54359292015-03-26 07:52:43 -0700509 double testDistSq = testPt.distanceSquared(i.pt(index));
510 if (closestDistSq > testDistSq) {
511 closestDistSq = testDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000512 }
513 }
caryclark54359292015-03-26 07:52:43 -0700514 return closestDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000515}
Cary Clarke47ae292016-10-05 08:51:39 -0400516#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000517
caryclark@google.com07393ca2013-04-08 11:47:37 +0000518/*
519 The M and S variable name parts stand for the operators.
520 Mi stands for Minuend (see wiki subtraction, analogous to difference)
521 Su stands for Subtrahend
522 The Opp variable name part designates that the value is for the Opposite operator.
523 Opposite values result from combining coincident spans.
524 */
caryclark54359292015-03-26 07:52:43 -0700525SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
526 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) {
527 SkOpSpanBase* start = *nextStart;
528 SkOpSpanBase* end = *nextEnd;
529 SkASSERT(start != end);
530 int step = start->step(end);
531 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
532 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000533 // mark the smaller of startIndex, endIndex done, and all adjacent
534 // spans with the same T value (but not 'other' spans)
535#if DEBUG_WINDING
536 SkDebugf("%s simple\n", __FUNCTION__);
537#endif
caryclark54359292015-03-26 07:52:43 -0700538 SkOpSpan* startSpan = start->starter(end);
539 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700540 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000541 }
caryclark54359292015-03-26 07:52:43 -0700542 markDone(startSpan);
543 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000544 return other;
545 }
caryclark54359292015-03-26 07:52:43 -0700546 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
547 SkASSERT(endNear == end); // is this ever not end?
548 SkASSERT(endNear);
549 SkASSERT(start != endNear);
550 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000551 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700552 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
caryclark@google.com570863f2013-09-16 15:55:01 +0000553 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000554 if (!sortable) {
555 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700556 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700557 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000558 }
caryclark54359292015-03-26 07:52:43 -0700559 SkOpAngle* angle = this->spanToAngle(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000560 if (angle->unorderable()) {
561 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700562 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700563 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000564 }
565#if DEBUG_SORT
566 SkDebugf("%s\n", __FUNCTION__);
567 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000568#endif
caryclark54359292015-03-26 07:52:43 -0700569 int sumMiWinding = updateWinding(end, start);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000570 if (sumMiWinding == SK_MinS32) {
571 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700572 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700573 return nullptr;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000574 }
caryclark54359292015-03-26 07:52:43 -0700575 int sumSuWinding = updateOppWinding(end, start);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000576 if (operand()) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400577 using std::swap;
578 swap(sumMiWinding, sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000579 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000580 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700581 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000582 bool foundDone = false;
583 // iterate through the angle, and compute everyone's winding
584 SkOpSegment* nextSegment;
585 int activeCount = 0;
586 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000587 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000588 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000589 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000590 if (activeAngle) {
591 ++activeCount;
592 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000593 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +0000594 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000595 }
596 }
597 if (nextSegment->done()) {
598 continue;
599 }
reed0dc4dd62015-03-24 13:55:33 -0700600 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700601 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700602 }
caryclark54359292015-03-26 07:52:43 -0700603 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000604 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000605 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000606 *chase->append() = last;
607#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700608 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
609 last->segment()->debugID(), last->debugID());
610 if (!last->final()) {
611 SkDebugf(" windSum=%d", last->upCast()->windSum());
612 }
613 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000614#endif
615 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000616 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700617 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000618 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700619 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000620 }
621 *nextStart = foundAngle->start();
622 *nextEnd = foundAngle->end();
623 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000624#if DEBUG_WINDING
625 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
626 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
627 #endif
628 return nextSegment;
629}
630
caryclark54359292015-03-26 07:52:43 -0700631SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
632 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
633 SkOpSpanBase* start = *nextStart;
634 SkOpSpanBase* end = *nextEnd;
635 SkASSERT(start != end);
636 int step = start->step(end);
637 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
638 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000639 // mark the smaller of startIndex, endIndex done, and all adjacent
640 // spans with the same T value (but not 'other' spans)
641#if DEBUG_WINDING
642 SkDebugf("%s simple\n", __FUNCTION__);
643#endif
caryclark54359292015-03-26 07:52:43 -0700644 SkOpSpan* startSpan = start->starter(end);
645 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700646 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000647 }
caryclark54359292015-03-26 07:52:43 -0700648 markDone(startSpan);
649 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000650 return other;
651 }
caryclark54359292015-03-26 07:52:43 -0700652 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
653 SkASSERT(endNear == end); // is this ever not end?
654 SkASSERT(endNear);
655 SkASSERT(start != endNear);
656 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000657 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700658 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000659 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000660 if (!sortable) {
661 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700662 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700663 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000664 }
caryclark54359292015-03-26 07:52:43 -0700665 SkOpAngle* angle = this->spanToAngle(end, start);
666 if (angle->unorderable()) {
667 *unsortable = true;
668 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700669 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700670 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000671#if DEBUG_SORT
672 SkDebugf("%s\n", __FUNCTION__);
673 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000674#endif
caryclark54359292015-03-26 07:52:43 -0700675 int sumWinding = updateWinding(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000676 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700677 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000678 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700679 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000680 SkOpSegment* nextSegment;
681 int activeCount = 0;
682 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000683 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000684 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000685 &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000686 if (activeAngle) {
687 ++activeCount;
688 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000689 foundAngle = nextAngle;
690 foundDone = nextSegment->done(nextAngle);
691 }
692 }
693 if (nextSegment->done()) {
694 continue;
695 }
reed0dc4dd62015-03-24 13:55:33 -0700696 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700697 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700698 }
caryclark54359292015-03-26 07:52:43 -0700699 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000700 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000701 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000702 *chase->append() = last;
703#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700704 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
705 last->segment()->debugID(), last->debugID());
706 if (!last->final()) {
707 SkDebugf(" windSum=%d", last->upCast()->windSum());
708 }
709 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000710#endif
711 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000712 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700713 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000714 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700715 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000716 }
717 *nextStart = foundAngle->start();
718 *nextEnd = foundAngle->end();
719 nextSegment = foundAngle->segment();
720#if DEBUG_WINDING
721 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
722 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
723 #endif
724 return nextSegment;
725}
726
caryclark54359292015-03-26 07:52:43 -0700727SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
728 bool* unsortable) {
729 SkOpSpanBase* start = *nextStart;
730 SkOpSpanBase* end = *nextEnd;
731 SkASSERT(start != end);
732 int step = start->step(end);
733 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
734 if (other) {
735 // mark the smaller of startIndex, endIndex done, and all adjacent
736 // spans with the same T value (but not 'other' spans)
caryclark@google.com07393ca2013-04-08 11:47:37 +0000737#if DEBUG_WINDING
738 SkDebugf("%s simple\n", __FUNCTION__);
739#endif
caryclark54359292015-03-26 07:52:43 -0700740 SkOpSpan* startSpan = start->starter(end);
741 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700742 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000743 }
caryclark54359292015-03-26 07:52:43 -0700744 markDone(startSpan);
745 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000746 return other;
747 }
caryclark54359292015-03-26 07:52:43 -0700748 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
749 : (*nextStart)->prev());
750 SkASSERT(endNear == end); // is this ever not end?
751 SkASSERT(endNear);
752 SkASSERT(start != endNear);
753 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
754 SkOpAngle* angle = this->spanToAngle(end, start);
caryclark27c8eb82015-07-06 11:38:33 -0700755 if (!angle || angle->unorderable()) {
caryclark54359292015-03-26 07:52:43 -0700756 *unsortable = true;
757 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700758 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700759 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000760#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000761 SkDebugf("%s\n", __FUNCTION__);
762 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000763#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000764 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700765 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000766 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700767 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000768 SkOpSegment* nextSegment;
769 int activeCount = 0;
770 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000771 nextSegment = nextAngle->segment();
772 ++activeCount;
773 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000774 foundAngle = nextAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000775 if (!(foundDone = nextSegment->done(nextAngle))) {
776 break;
777 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000778 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000779 nextAngle = nextAngle->next();
780 } while (nextAngle != angle);
caryclark54359292015-03-26 07:52:43 -0700781 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000782 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700783 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000784 }
785 *nextStart = foundAngle->start();
786 *nextEnd = foundAngle->end();
787 nextSegment = foundAngle->segment();
788#if DEBUG_WINDING
789 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
790 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
791 #endif
792 return nextSegment;
793}
794
caryclark54359292015-03-26 07:52:43 -0700795SkOpGlobalState* SkOpSegment::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700796 return contour()->globalState();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000797}
798
caryclark1049f122015-04-20 08:31:59 -0700799void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
caryclark54359292015-03-26 07:52:43 -0700800 fContour = contour;
halcanary96fcdcc2015-08-27 07:41:13 -0700801 fNext = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000802 fPts = pts;
caryclark1049f122015-04-20 08:31:59 -0700803 fWeight = weight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000804 fVerb = verb;
caryclark54359292015-03-26 07:52:43 -0700805 fCount = 0;
806 fDoneCount = 0;
807 fVisited = false;
808 SkOpSpan* zeroSpan = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700809 zeroSpan->init(this, nullptr, 0, fPts[0]);
caryclark54359292015-03-26 07:52:43 -0700810 SkOpSpanBase* oneSpan = &fTail;
811 zeroSpan->setNext(oneSpan);
812 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
caryclark1049f122015-04-20 08:31:59 -0700813 SkDEBUGCODE(fID = globalState()->nextSegmentID());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000814}
815
caryclark54359292015-03-26 07:52:43 -0700816bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
817 SkDPoint cPt = this->dPtAtT(t);
caryclark1049f122015-04-20 08:31:59 -0700818 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
caryclark54359292015-03-26 07:52:43 -0700819 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
820 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -0700821 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
caryclark54359292015-03-26 07:52:43 -0700822 int used = i.used();
823 for (int index = 0; index < used; ++index) {
824 if (cPt.roughlyEqual(i.pt(index))) {
reed0dc4dd62015-03-24 13:55:33 -0700825 return true;
826 }
caryclark54359292015-03-26 07:52:43 -0700827 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000828 return false;
829}
830
caryclark54359292015-03-26 07:52:43 -0700831bool SkOpSegment::isXor() const {
832 return fContour->isXor();
833}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000834
caryclark5b5ddd72015-05-18 05:12:56 -0700835void SkOpSegment::markAllDone() {
836 SkOpSpan* span = this->head();
837 do {
838 this->markDone(span);
839 } while ((span = span->next()->upCastable()));
840}
841
caryclark54359292015-03-26 07:52:43 -0700842SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) {
843 int step = start->step(end);
844 SkOpSpan* minSpan = start->starter(end);
845 markDone(minSpan);
halcanary96fcdcc2015-08-27 07:41:13 -0700846 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000847 SkOpSegment* other = this;
Cary Clark918fb1f2016-11-15 13:22:25 -0500848 SkOpSpan* priorDone = nullptr;
849 SkOpSpan* lastDone = nullptr;
caryclark54359292015-03-26 07:52:43 -0700850 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000851 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -0700852 SkASSERT(!last);
853 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000854 }
Cary Clark918fb1f2016-11-15 13:22:25 -0500855 if (lastDone == minSpan || priorDone == minSpan) {
856 return nullptr;
857 }
caryclark54359292015-03-26 07:52:43 -0700858 other->markDone(minSpan);
Cary Clark918fb1f2016-11-15 13:22:25 -0500859 priorDone = lastDone;
860 lastDone = minSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000861 }
862 return last;
863}
864
caryclark54359292015-03-26 07:52:43 -0700865bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
866 SkOpSpanBase** lastPtr) {
867 SkOpSpan* spanStart = start->starter(end);
868 int step = start->step(end);
869 bool success = markWinding(spanStart, winding);
halcanary96fcdcc2015-08-27 07:41:13 -0700870 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000871 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700872 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
873 if (spanStart->windSum() != SK_MinS32) {
caryclarkb36a3cd2016-10-18 07:59:44 -0700874// SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive?
caryclarkdac1d172014-06-17 05:15:38 -0700875 SkASSERT(!last);
876 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000877 }
caryclark54359292015-03-26 07:52:43 -0700878 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000879 }
caryclark65f55312014-11-13 06:58:52 -0800880 if (lastPtr) {
881 *lastPtr = last;
882 }
883 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000884}
885
caryclark54359292015-03-26 07:52:43 -0700886bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
887 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
888 SkOpSpan* spanStart = start->starter(end);
889 int step = start->step(end);
890 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700891 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000892 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700893 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
894 if (spanStart->windSum() != SK_MinS32) {
895 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700896 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700897 this->globalState()->setWindingFailed();
898 return false;
caryclarkdac1d172014-06-17 05:15:38 -0700899 }
caryclark54359292015-03-26 07:52:43 -0700900 } else {
901 SkASSERT(spanStart->windSum() == oppWinding);
902 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700903 }
904 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700905 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000906 }
caryclark54359292015-03-26 07:52:43 -0700907 if (this->operand() == other->operand()) {
908 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700909 } else {
caryclark54359292015-03-26 07:52:43 -0700910 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700911 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000912 }
caryclark65f55312014-11-13 06:58:52 -0800913 if (lastPtr) {
914 *lastPtr = last;
915 }
916 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000917}
918
caryclark54359292015-03-26 07:52:43 -0700919SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000920 SkASSERT(angle->segment() == this);
921 if (UseInnerWinding(maxWinding, sumWinding)) {
922 maxWinding = sumWinding;
923 }
caryclark54359292015-03-26 07:52:43 -0700924 SkOpSpanBase* last;
925 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000926#if DEBUG_WINDING
927 if (last) {
caryclark54359292015-03-26 07:52:43 -0700928 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
929 last->segment()->debugID(), last->debugID());
930 if (!last->final()) {
931 SkDebugf(" windSum=");
932 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
933 }
934 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000935 }
936#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000937 return last;
938}
939
caryclark54359292015-03-26 07:52:43 -0700940SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
941 int oppSumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000942 SkASSERT(angle->segment() == this);
943 if (UseInnerWinding(maxWinding, sumWinding)) {
944 maxWinding = sumWinding;
945 }
946 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
947 oppMaxWinding = oppSumWinding;
948 }
halcanary96fcdcc2015-08-27 07:41:13 -0700949 SkOpSpanBase* last = nullptr;
caryclark65f55312014-11-13 06:58:52 -0800950 // caller doesn't require that this marks anything
caryclark54359292015-03-26 07:52:43 -0700951 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000952#if DEBUG_WINDING
953 if (last) {
caryclark54359292015-03-26 07:52:43 -0700954 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
955 last->segment()->debugID(), last->debugID());
956 if (!last->final()) {
957 SkDebugf(" windSum=");
958 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
959 }
960 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000961 }
962#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000963 return last;
964}
965
caryclark54359292015-03-26 07:52:43 -0700966void SkOpSegment::markDone(SkOpSpan* span) {
967 SkASSERT(this == span->segment());
968 if (span->done()) {
969 return;
970 }
971#if DEBUG_MARK_DONE
972 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
973#endif
974 span->setDone(true);
975 ++fDoneCount;
976 debugValidate();
977}
978
979bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
980 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -0700981 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -0700982 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -0700983 return false;
984 }
985#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -0700986 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -0700987#endif
caryclark54359292015-03-26 07:52:43 -0700988 span->setWindSum(winding);
989 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -0700990 return true;
991}
992
caryclark54359292015-03-26 07:52:43 -0700993bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
994 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000995 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -0700996 if (span->done()) {
997 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000998 }
caryclark54359292015-03-26 07:52:43 -0700999#if DEBUG_MARK_DONE
1000 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1001#endif
1002 span->setWindSum(winding);
1003 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001004 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001005 return true;
1006}
1007
caryclark54359292015-03-26 07:52:43 -07001008bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclarkef4f32a2016-08-24 09:24:18 -07001009 const SkPoint& testPt) const {
caryclark55888e42016-07-18 10:01:36 -07001010 SkASSERT(this == base->segment());
1011 if (this == testParent) {
1012 if (precisely_equal(base->fT, testT)) {
1013 return true;
1014 }
caryclark54359292015-03-26 07:52:43 -07001015 }
1016 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1017 return false;
1018 }
caryclark55888e42016-07-18 10:01:36 -07001019 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001020}
1021
1022static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1023 if (last) {
1024 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001025 }
halcanary96fcdcc2015-08-27 07:41:13 -07001026 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001027}
1028
caryclark54359292015-03-26 07:52:43 -07001029SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1030 SkOpSpanBase** last) const {
1031 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001032 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001033 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1034 SkASSERT(endSpan);
1035 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1036 SkOpSpanBase* foundSpan;
1037 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001038 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001039 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001040 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001041 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001042 }
caryclark54359292015-03-26 07:52:43 -07001043 SkOpPtT* otherPtT = endSpan->ptT()->next();
1044 other = otherPtT->segment();
1045 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001046 otherEnd = step > 0
1047 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1048 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001049 } else {
1050 int loopCount = angle->loopCount();
1051 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001052 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001053 }
1054 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001055 if (nullptr == next) {
1056 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001057 }
caryclarkdac1d172014-06-17 05:15:38 -07001058#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001059 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001060 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001061 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001062 }
caryclark54359292015-03-26 07:52:43 -07001063#endif
caryclarkdac1d172014-06-17 05:15:38 -07001064 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001065 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001066 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001067 }
caryclark343382e2016-06-29 08:18:38 -07001068 if (!otherEnd) {
1069 return nullptr;
1070 }
caryclark54359292015-03-26 07:52:43 -07001071 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001072 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001073 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001074 }
caryclark54359292015-03-26 07:52:43 -07001075 SkASSERT(*startPtr);
caryclark65b427c2014-09-18 10:32:57 -07001076// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001077 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1078 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1079 if (foundMin->windValue() != origMin->windValue()
1080 || foundMin->oppValue() != origMin->oppValue()) {
1081 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001082 }
caryclark54359292015-03-26 07:52:43 -07001083 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001084 *stepPtr = foundStep;
1085 if (minPtr) {
1086 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001087 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001088 return other;
1089}
1090
caryclark55888e42016-07-18 10:01:36 -07001091// Please keep this in sync with DebugClearVisited()
1092void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001093 // reset visited flag back to false
1094 do {
1095 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1096 while ((ptT = ptT->next()) != stopPtT) {
1097 SkOpSegment* opp = ptT->segment();
1098 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001099 }
caryclarkbca19f72015-05-13 08:23:48 -07001100 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001101}
1102
caryclark55888e42016-07-18 10:01:36 -07001103// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001104// look for pairs of undetected coincident curves
1105// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001106// Even though pairs of curves correct detect coincident runs, a run may be missed
1107// if the coincidence is a product of multiple intersections. For instance, given
1108// curves A, B, and C:
1109// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1110// the end of C that the intersection is replaced with the end of C.
1111// Even though A-B correctly do not detect an intersection at point 2,
1112// the resulting run from point 1 to point 2 is coincident on A and B.
1113bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001114 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001115 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001116 }
halcanary96fcdcc2015-08-27 07:41:13 -07001117 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001118 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001119 bool result = false;
caryclark54359292015-03-26 07:52:43 -07001120 do {
caryclarkbca19f72015-05-13 08:23:48 -07001121 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001122 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001123 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001124 if (ptT->deleted()) {
1125 continue;
1126 }
caryclark54359292015-03-26 07:52:43 -07001127 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001128 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001129 continue;
reed0dc4dd62015-03-24 13:55:33 -07001130 }
caryclarkbca19f72015-05-13 08:23:48 -07001131 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1132 if (!opp->visited()) {
1133 continue;
1134 }
1135 if (spanBase == &fHead) {
1136 continue;
1137 }
caryclark55888e42016-07-18 10:01:36 -07001138 if (ptT->segment() == this) {
1139 continue;
1140 }
caryclarkbca19f72015-05-13 08:23:48 -07001141 SkOpSpan* span = spanBase->upCastable();
1142 // FIXME?: this assumes that if the opposite segment is coincident then no more
1143 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001144 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001145 continue;
1146 }
caryclarkbca19f72015-05-13 08:23:48 -07001147 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001148 continue;
caryclark55888e42016-07-18 10:01:36 -07001149 }
halcanary96fcdcc2015-08-27 07:41:13 -07001150 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001151 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001152 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001153 SkOpSpan* priorTest = spanBase->prev();
1154 while (!priorOpp && priorTest) {
1155 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001156 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001157 if (priorPtT->deleted()) {
1158 continue;
1159 }
caryclark54359292015-03-26 07:52:43 -07001160 SkOpSegment* segment = priorPtT->span()->segment();
1161 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001162 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001163 priorOpp = opp;
1164 break;
1165 }
1166 }
caryclarkbca19f72015-05-13 08:23:48 -07001167 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001168 }
1169 if (!priorOpp) {
1170 continue;
1171 }
caryclark26ad22a2015-10-16 09:03:38 -07001172 if (priorPtT == ptT) {
1173 continue;
1174 }
caryclark54359292015-03-26 07:52:43 -07001175 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001176 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001177 bool swapped = priorPtT->fT > ptT->fT;
1178 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001179 using std::swap;
1180 swap(priorPtT, ptT);
1181 swap(oppStart, oppEnd);
caryclark54359292015-03-26 07:52:43 -07001182 }
caryclark55888e42016-07-18 10:01:36 -07001183 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1184 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1185 SkOpPtT* rootPtT = ptT->span()->ptT();
1186 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1187 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1188 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001189 goto swapBack;
1190 }
caryclark55888e42016-07-18 10:01:36 -07001191 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001192 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001193#if DEBUG_COINCIDENCE_VERBOSE
1194 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1195 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1196 rootOppEnd->debugID());
1197#endif
1198 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1199 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001200 }
caryclark55888e42016-07-18 10:01:36 -07001201#if DEBUG_COINCIDENCE
1202 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1203#endif
1204 result = true;
caryclark54359292015-03-26 07:52:43 -07001205 }
1206 swapBack:
1207 if (swapped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001208 using std::swap;
1209 swap(priorPtT, ptT);
caryclark54359292015-03-26 07:52:43 -07001210 }
reed0dc4dd62015-03-24 13:55:33 -07001211 }
halcanary96fcdcc2015-08-27 07:41:13 -07001212 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001213 ClearVisited(&fHead);
1214 return result;
reed0dc4dd62015-03-24 13:55:33 -07001215}
1216
caryclark55888e42016-07-18 10:01:36 -07001217// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001218// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001219bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001220 debugValidate();
1221 SkOpSpanBase* test = &fHead;
1222 do {
1223 int addCount = test->spanAddsCount();
Cary Clark7eb01e02016-12-08 14:36:32 -05001224// FAIL_IF(addCount < 1);
1225 if (addCount <= 1) {
caryclark08bc8482015-04-24 09:08:57 -07001226 continue;
1227 }
1228 SkOpPtT* startPtT = test->ptT();
1229 SkOpPtT* testPtT = startPtT;
1230 do { // iterate through all spans associated with start
1231 SkOpSpanBase* oppSpan = testPtT->span();
1232 if (oppSpan->spanAddsCount() == addCount) {
1233 continue;
1234 }
1235 if (oppSpan->deleted()) {
1236 continue;
1237 }
1238 SkOpSegment* oppSegment = oppSpan->segment();
1239 if (oppSegment == this) {
1240 continue;
1241 }
1242 // find range of spans to consider merging
1243 SkOpSpanBase* oppPrev = oppSpan;
1244 SkOpSpanBase* oppFirst = oppSpan;
1245 while ((oppPrev = oppPrev->prev())) {
1246 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1247 break;
1248 }
1249 if (oppPrev->spanAddsCount() == addCount) {
1250 continue;
1251 }
1252 if (oppPrev->deleted()) {
1253 continue;
1254 }
1255 oppFirst = oppPrev;
1256 }
1257 SkOpSpanBase* oppNext = oppSpan;
1258 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001259 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001260 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1261 break;
1262 }
1263 if (oppNext->spanAddsCount() == addCount) {
1264 continue;
1265 }
1266 if (oppNext->deleted()) {
1267 continue;
1268 }
1269 oppLast = oppNext;
1270 }
1271 if (oppFirst == oppLast) {
1272 continue;
1273 }
1274 SkOpSpanBase* oppTest = oppFirst;
1275 do {
1276 if (oppTest == oppSpan) {
1277 continue;
1278 }
1279 // check to see if the candidate meets specific criteria:
1280 // it contains spans of segments in test's loop but not including 'this'
1281 SkOpPtT* oppStartPtT = oppTest->ptT();
1282 SkOpPtT* oppPtT = oppStartPtT;
1283 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1284 SkOpSegment* oppPtTSegment = oppPtT->segment();
1285 if (oppPtTSegment == this) {
1286 goto tryNextSpan;
1287 }
1288 SkOpPtT* matchPtT = startPtT;
1289 do {
1290 if (matchPtT->segment() == oppPtTSegment) {
1291 goto foundMatch;
1292 }
1293 } while ((matchPtT = matchPtT->next()) != startPtT);
1294 goto tryNextSpan;
1295 foundMatch: // merge oppTest and oppSpan
1296 oppSegment->debugValidate();
caryclark30b9fdd2016-08-31 14:36:29 -07001297 oppTest->mergeMatches(oppSpan);
1298 oppTest->addOpp(oppSpan);
caryclark08bc8482015-04-24 09:08:57 -07001299 oppSegment->debugValidate();
1300 goto checkNextSpan;
1301 }
caryclark55888e42016-07-18 10:01:36 -07001302 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001303 ;
1304 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1305 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001306checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001307 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001308 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001309 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001310 return true;
caryclark08bc8482015-04-24 09:08:57 -07001311}
1312
caryclark55888e42016-07-18 10:01:36 -07001313// adjacent spans may have points close by
Cary Clark28da2832017-03-21 10:30:50 -04001314bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan,
1315 bool* found) const {
caryclark55888e42016-07-18 10:01:36 -07001316 const SkOpPtT* refHead = refSpan->ptT();
1317 const SkOpPtT* checkHead = checkSpan->ptT();
1318// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
caryclark30b9fdd2016-08-31 14:36:29 -07001319 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
caryclark55888e42016-07-18 10:01:36 -07001320#if DEBUG_COINCIDENCE
1321 // verify that no combination of points are close
1322 const SkOpPtT* dBugRef = refHead;
1323 do {
1324 const SkOpPtT* dBugCheck = checkHead;
1325 do {
caryclark30b9fdd2016-08-31 14:36:29 -07001326 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
caryclark55888e42016-07-18 10:01:36 -07001327 dBugCheck = dBugCheck->next();
1328 } while (dBugCheck != checkHead);
1329 dBugRef = dBugRef->next();
1330 } while (dBugRef != refHead);
1331#endif
Cary Clark28da2832017-03-21 10:30:50 -04001332 *found = false;
1333 return true;
caryclark55888e42016-07-18 10:01:36 -07001334 }
1335 // check only unique points
1336 SkScalar distSqBest = SK_ScalarMax;
1337 const SkOpPtT* refBest = nullptr;
1338 const SkOpPtT* checkBest = nullptr;
1339 const SkOpPtT* ref = refHead;
1340 do {
1341 if (ref->deleted()) {
1342 continue;
1343 }
1344 while (ref->ptAlreadySeen(refHead)) {
1345 ref = ref->next();
1346 if (ref == refHead) {
1347 goto doneCheckingDistance;
1348 }
1349 }
1350 const SkOpPtT* check = checkHead;
1351 const SkOpSegment* refSeg = ref->segment();
Cary Clark28da2832017-03-21 10:30:50 -04001352 int escapeHatch = 100000; // defend against infinite loops
caryclark55888e42016-07-18 10:01:36 -07001353 do {
1354 if (check->deleted()) {
1355 continue;
1356 }
1357 while (check->ptAlreadySeen(checkHead)) {
1358 check = check->next();
1359 if (check == checkHead) {
1360 goto nextRef;
1361 }
1362 }
Cary Clarkdf429f32017-11-08 11:44:31 -05001363 SkScalar distSq = SkPointPriv::DistanceToSqd(ref->fPt, check->fPt);
caryclark55888e42016-07-18 10:01:36 -07001364 if (distSqBest > distSq && (refSeg != check->segment()
1365 || !refSeg->ptsDisjoint(*ref, *check))) {
1366 distSqBest = distSq;
1367 refBest = ref;
1368 checkBest = check;
1369 }
Cary Clark28da2832017-03-21 10:30:50 -04001370 if (--escapeHatch <= 0) {
1371 return false;
1372 }
caryclark55888e42016-07-18 10:01:36 -07001373 } while ((check = check->next()) != checkHead);
Cary Clark28da2832017-03-21 10:30:50 -04001374 nextRef:
caryclark55888e42016-07-18 10:01:36 -07001375 ;
1376 } while ((ref = ref->next()) != refHead);
1377doneCheckingDistance:
Cary Clark28da2832017-03-21 10:30:50 -04001378 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001379 checkBest->fPt);
Cary Clark28da2832017-03-21 10:30:50 -04001380 return true;
caryclark55888e42016-07-18 10:01:36 -07001381}
1382
1383// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001384// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
Cary Clark28da2832017-03-21 10:30:50 -04001385bool SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001386 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001387 // release undeleted spans pointing to this seg that are linked to the primary span
1388 SkOpSpanBase* spanBase = &fHead;
Cary Clark43938b82017-10-18 08:47:32 -04001389 int escapeHatch = 9999; // the largest count for a regular test is 50; for a fuzzer, 500
caryclark54359292015-03-26 07:52:43 -07001390 do {
caryclark55888e42016-07-18 10:01:36 -07001391 SkOpPtT* ptT = spanBase->ptT();
1392 const SkOpPtT* headPtT = ptT;
1393 while ((ptT = ptT->next()) != headPtT) {
Cary Clark43938b82017-10-18 08:47:32 -04001394 if (!--escapeHatch) {
1395 return false;
1396 }
caryclark55888e42016-07-18 10:01:36 -07001397 SkOpSpanBase* test = ptT->span();
1398 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1399 && test->ptT() == ptT) {
1400 if (test->final()) {
1401 if (spanBase == &fHead) {
1402 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001403 return true;
caryclark55888e42016-07-18 10:01:36 -07001404 }
1405 spanBase->upCast()->release(ptT);
1406 } else if (test->prev()) {
1407 test->upCast()->release(headPtT);
1408 }
1409 break;
caryclark54359292015-03-26 07:52:43 -07001410 }
reed0dc4dd62015-03-24 13:55:33 -07001411 }
caryclark55888e42016-07-18 10:01:36 -07001412 spanBase = spanBase->upCast()->next();
1413 } while (!spanBase->final());
caryclark55888e42016-07-18 10:01:36 -07001414 // This loop looks for adjacent spans which are near by
1415 spanBase = &fHead;
1416 do { // iterate through all spans associated with start
1417 SkOpSpanBase* test = spanBase->upCast()->next();
Cary Clark28da2832017-03-21 10:30:50 -04001418 bool found;
1419 if (!this->spansNearby(spanBase, test, &found)) {
1420 return false;
1421 }
1422 if (found) {
caryclark55888e42016-07-18 10:01:36 -07001423 if (test->final()) {
1424 if (spanBase->prev()) {
1425 test->merge(spanBase->upCast());
1426 } else {
1427 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001428 return true;
caryclark55888e42016-07-18 10:01:36 -07001429 }
1430 } else {
1431 spanBase->merge(test->upCast());
1432 }
1433 }
1434 spanBase = test;
1435 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001436 debugValidate();
Cary Clark28da2832017-03-21 10:30:50 -04001437 return true;
reed0dc4dd62015-03-24 13:55:33 -07001438}
1439
caryclark54359292015-03-26 07:52:43 -07001440bool SkOpSegment::operand() const {
1441 return fContour->operand();
1442}
1443
1444bool SkOpSegment::oppXor() const {
1445 return fContour->oppXor();
1446}
1447
1448bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1449 if (fVerb == SkPath::kLine_Verb) {
1450 return false;
1451 }
1452 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1453 // hits in two places with very different t values.
1454 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1455 // 'controls contained by ends' could avoid this check for common curves
1456 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1457 // on the other hand, the below check is relatively inexpensive
1458 double midT = (t1 + t2) / 2;
1459 SkPoint midPt = this->ptAtT(midT);
Cary Clarkdf429f32017-11-08 11:44:31 -05001460 double seDistSq = SkTMax(SkPointPriv::DistanceToSqd(pt1, pt2) * 2, FLT_EPSILON * 2);
1461 return SkPointPriv::DistanceToSqd(midPt, pt1) > seDistSq ||
1462 SkPointPriv::DistanceToSqd(midPt, pt2) > seDistSq;
caryclark54359292015-03-26 07:52:43 -07001463}
1464
1465void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1466 int* maxWinding, int* sumWinding) {
1467 int deltaSum = SpanSign(start, end);
1468 *maxWinding = *sumMiWinding;
1469 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001470 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001471}
1472
1473void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1474 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1475 int* oppSumWinding) {
1476 int deltaSum = SpanSign(start, end);
1477 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001478 if (operand()) {
1479 *maxWinding = *sumSuWinding;
1480 *sumWinding = *sumSuWinding -= deltaSum;
1481 *oppMaxWinding = *sumMiWinding;
1482 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1483 } else {
1484 *maxWinding = *sumMiWinding;
1485 *sumWinding = *sumMiWinding -= deltaSum;
1486 *oppMaxWinding = *sumSuWinding;
1487 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1488 }
bungeman60e0fee2015-08-26 05:15:46 -07001489 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1490 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001491}
1492
caryclarkb36a3cd2016-10-18 07:59:44 -07001493bool SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001494 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001495 do {
caryclark54359292015-03-26 07:52:43 -07001496 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001497 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001498 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001499 continue;
1500 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001501#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001502 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001503#endif
caryclark54359292015-03-26 07:52:43 -07001504 SkOpAngle* baseAngle = fromAngle;
1505 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001506#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001507 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1508 span->debugID());
1509 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001510#endif
caryclarkb36a3cd2016-10-18 07:59:44 -07001511 FAIL_IF(!fromAngle->insert(toAngle));
caryclark54359292015-03-26 07:52:43 -07001512 } else if (!fromAngle) {
1513 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001514 }
caryclark54359292015-03-26 07:52:43 -07001515 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001516 do {
caryclark54359292015-03-26 07:52:43 -07001517 SkOpSpanBase* oSpan = ptT->span();
1518 if (oSpan == span) {
1519 continue;
1520 }
1521 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001522 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001523#if DEBUG_ANGLE
1524 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001525 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1526 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001527 wroteAfterHeader = true;
1528 }
1529#endif
caryclark54359292015-03-26 07:52:43 -07001530 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001531 baseAngle->insert(oAngle);
1532 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001533 }
caryclark54359292015-03-26 07:52:43 -07001534 if (!oSpan->final()) {
1535 oAngle = oSpan->upCast()->toAngle();
1536 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001537#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001538 if (!wroteAfterHeader) {
1539 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1540 span->t(), span->debugID());
1541 wroteAfterHeader = true;
1542 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001543#endif
caryclark54359292015-03-26 07:52:43 -07001544 if (!oAngle->loopContains(baseAngle)) {
1545 baseAngle->insert(oAngle);
1546 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001547 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001548 }
caryclark54359292015-03-26 07:52:43 -07001549 } while ((ptT = ptT->next()) != stopPtT);
1550 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001551 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001552 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001553 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001554 }
halcanary96fcdcc2015-08-27 07:41:13 -07001555 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001556 }
1557#if DEBUG_SORT
1558 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1559#endif
caryclark54359292015-03-26 07:52:43 -07001560 } while (!span->final() && (span = span->upCast()->next()));
caryclarkb36a3cd2016-10-18 07:59:44 -07001561 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +00001562}
1563
caryclark54359292015-03-26 07:52:43 -07001564bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001565 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001566 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001567 const SkOpPtT& startPtT = *start->ptT();
1568 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001569 SkDEBUGCODE(edge->fVerb = fVerb);
1570 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001571 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001572 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001573 if (fVerb == SkPath::kLine_Verb) {
1574 return false;
1575 }
caryclark54359292015-03-26 07:52:43 -07001576 double startT = startPtT.fT;
1577 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001578 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1579 // don't compute midpoints if we already have them
1580 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001581 edge->fLine[1].set(fPts[1]);
1582 return false;
1583 }
1584 if (fVerb == SkPath::kConic_Verb) {
1585 edge->fConic[1].set(fPts[1]);
1586 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001587 return false;
1588 }
1589 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001590 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001591 edge->fCubic[1].set(fPts[1]);
1592 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001593 return false;
1594 }
caryclark1049f122015-04-20 08:31:59 -07001595 edge->fCubic[1].set(fPts[2]);
1596 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001597 return false;
1598 }
1599 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001600 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1601 } else if (fVerb == SkPath::kConic_Verb) {
1602 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1603 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001604 } else {
1605 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001606 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001607 }
1608 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001609}
1610
caryclark27c8eb82015-07-06 11:38:33 -07001611bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001612 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001613 // average t, find mid pt
1614 double midT = (prior->t() + spanBase->t()) / 2;
1615 SkPoint midPt = this->ptAtT(midT);
1616 bool coincident = true;
1617 // if the mid pt is not near either end pt, project perpendicular through opp seg
1618 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1619 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001620 if (priorPtT->span() == ptT->span()) {
1621 return false;
1622 }
caryclark27c8eb82015-07-06 11:38:33 -07001623 coincident = false;
1624 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001625 SkDCurve curvePart;
1626 this->subDivide(prior, spanBase, &curvePart);
1627 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1628 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1629 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1630 SkDCurve oppPart;
1631 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1632 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001633 // measure distance and see if it's small enough to denote coincidence
1634 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001635 if (!between(0, i[0][index], 1)) {
1636 continue;
1637 }
caryclark27c8eb82015-07-06 11:38:33 -07001638 SkDPoint oppPt = i.pt(index);
caryclark30b9fdd2016-08-31 14:36:29 -07001639 if (oppPt.approximatelyDEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001640 // the coincidence can occur at almost any angle
1641 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001642 }
1643 }
1644 }
1645 return coincident;
1646}
1647
Cary Clarkab2d73b2016-12-16 17:17:25 -05001648SkOpSpan* SkOpSegment::undoneSpan() {
1649 SkOpSpan* span = &fHead;
1650 SkOpSpanBase* next;
caryclark54359292015-03-26 07:52:43 -07001651 do {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001652 next = span->next();
caryclark54359292015-03-26 07:52:43 -07001653 if (!span->done()) {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001654 return span;
reed0dc4dd62015-03-24 13:55:33 -07001655 }
Cary Clarkab2d73b2016-12-16 17:17:25 -05001656 } while (!next->final() && (span = next->upCast()));
1657 return nullptr;
reed0dc4dd62015-03-24 13:55:33 -07001658}
1659
caryclark54359292015-03-26 07:52:43 -07001660int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1661 const SkOpSpan* lesser = start->starter(end);
1662 int oppWinding = lesser->oppSum();
1663 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001664 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1665 && oppWinding != SK_MaxS32) {
1666 oppWinding -= oppSpanWinding;
1667 }
1668 return oppWinding;
1669}
1670
1671int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001672 const SkOpSpanBase* startSpan = angle->start();
1673 const SkOpSpanBase* endSpan = angle->end();
1674 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001675}
1676
1677int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001678 const SkOpSpanBase* startSpan = angle->start();
1679 const SkOpSpanBase* endSpan = angle->end();
1680 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001681}
1682
caryclark624637c2015-05-11 07:21:27 -07001683int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1684 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001685 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001686 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001687 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001688 }
1689 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001690 return winding;
1691 }
caryclark54359292015-03-26 07:52:43 -07001692 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001693 if (winding && UseInnerWinding(winding - spanWinding, winding)
1694 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001695 winding -= spanWinding;
1696 }
1697 return winding;
1698}
1699
caryclark624637c2015-05-11 07:21:27 -07001700int SkOpSegment::updateWinding(SkOpAngle* angle) {
1701 SkOpSpanBase* startSpan = angle->start();
1702 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001703 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001704}
1705
caryclark624637c2015-05-11 07:21:27 -07001706int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1707 SkOpSpanBase* startSpan = angle->start();
1708 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001709 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001710}
1711
1712// OPTIMIZATION: does the following also work, and is it any faster?
1713// return outerWinding * innerWinding > 0
1714// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1715bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1716 SkASSERT(outerWinding != SK_MaxS32);
1717 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001718 int absOut = SkTAbs(outerWinding);
1719 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001720 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1721 return result;
1722}
1723
caryclark@google.com07393ca2013-04-08 11:47:37 +00001724int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001725 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1726 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001727}