blob: f266ed949f5e57831d78f786171780656dbf0804 [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"
caryclark54359292015-03-26 07:52:43 -070011
12/*
13After computing raw intersections, post process all segments to:
14- find small collections of points that can be collapsed to a single point
15- find missing intersections to resolve differences caused by different algorithms
16
17Consider segments containing tiny or small intervals. Consider coincident segments
18because coincidence finds intersections through distance measurement that non-coincident
19intersection tests cannot.
20 */
caryclark@google.com07393ca2013-04-08 11:47:37 +000021
22#define F (false) // discard the edge
23#define T (true) // keep the edge
24
25static const bool gUnaryActiveEdge[2][2] = {
26// from=0 from=1
27// to=0,1 to=0,1
28 {F, T}, {T, F},
29};
30
caryclark54359292015-03-26 07:52:43 -070031static const bool gActiveEdge[kXOR_SkPathOp + 1][2][2][2][2] = {
caryclark@google.com07393ca2013-04-08 11:47:37 +000032// miFrom=0 miFrom=1
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000033// miTo=0 miTo=1 miTo=0 miTo=1
34// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
caryclark@google.com07393ca2013-04-08 11:47:37 +000035// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
36 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
37 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
38 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
39 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su
40};
41
42#undef F
43#undef T
44
caryclark54359292015-03-26 07:52:43 -070045SkOpAngle* SkOpSegment::activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -070046 SkOpSpanBase** endPtr, bool* done) {
47 if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done)) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000048 return result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000049 }
caryclarkbca19f72015-05-13 08:23:48 -070050 if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done)) {
caryclark54359292015-03-26 07:52:43 -070051 return result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000052 }
halcanary96fcdcc2015-08-27 07:41:13 -070053 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +000054}
55
caryclark54359292015-03-26 07:52:43 -070056SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -070057 SkOpSpanBase** endPtr, bool* done) {
caryclark54359292015-03-26 07:52:43 -070058 SkOpSpan* upSpan = start->upCastable();
59 if (upSpan) {
60 if (upSpan->windValue() || upSpan->oppValue()) {
61 SkOpSpanBase* next = upSpan->next();
62 if (!*endPtr) {
63 *startPtr = start;
64 *endPtr = next;
caryclark@google.com07393ca2013-04-08 11:47:37 +000065 }
caryclark54359292015-03-26 07:52:43 -070066 if (!upSpan->done()) {
67 if (upSpan->windSum() != SK_MinS32) {
68 return spanToAngle(start, next);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000069 }
70 *done = false;
71 }
72 } else {
caryclark54359292015-03-26 07:52:43 -070073 SkASSERT(upSpan->done());
caryclark@google.com07393ca2013-04-08 11:47:37 +000074 }
75 }
caryclark54359292015-03-26 07:52:43 -070076 SkOpSpan* downSpan = start->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +000077 // edge leading into junction
caryclark54359292015-03-26 07:52:43 -070078 if (downSpan) {
79 if (downSpan->windValue() || downSpan->oppValue()) {
80 if (!*endPtr) {
81 *startPtr = start;
82 *endPtr = downSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +000083 }
caryclark54359292015-03-26 07:52:43 -070084 if (!downSpan->done()) {
85 if (downSpan->windSum() != SK_MinS32) {
86 return spanToAngle(start, downSpan);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000087 }
88 *done = false;
89 }
90 } else {
caryclark54359292015-03-26 07:52:43 -070091 SkASSERT(downSpan->done());
caryclark@google.com07393ca2013-04-08 11:47:37 +000092 }
93 }
halcanary96fcdcc2015-08-27 07:41:13 -070094 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000095}
96
caryclark54359292015-03-26 07:52:43 -070097SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -070098 SkOpSpanBase** endPtr, bool* done) {
caryclark54359292015-03-26 07:52:43 -070099 SkOpPtT* oPtT = start->ptT()->next();
100 SkOpSegment* other = oPtT->segment();
101 SkOpSpanBase* oSpan = oPtT->span();
caryclarkbca19f72015-05-13 08:23:48 -0700102 return other->activeAngleInner(oSpan, startPtr, endPtr, done);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000103}
104
caryclark54359292015-03-26 07:52:43 -0700105bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xorSuMask,
106 SkPathOp op) {
107 int sumMiWinding = this->updateWinding(end, start);
108 int sumSuWinding = this->updateOppWinding(end, start);
caryclark65f55312014-11-13 06:58:52 -0800109#if DEBUG_LIMIT_WIND_SUM
110 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM);
111 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM);
112#endif
caryclark54359292015-03-26 07:52:43 -0700113 if (this->operand()) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000114 SkTSwap<int>(sumMiWinding, sumSuWinding);
115 }
caryclark54359292015-03-26 07:52:43 -0700116 return this->activeOp(xorMiMask, xorSuMask, start, end, op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000117}
118
caryclark54359292015-03-26 07:52:43 -0700119bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end,
120 SkPathOp op, int* sumMiWinding, int* sumSuWinding) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000121 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
caryclark54359292015-03-26 07:52:43 -0700122 this->setUpWindings(start, end, sumMiWinding, sumSuWinding,
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000123 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000124 bool miFrom;
125 bool miTo;
126 bool suFrom;
127 bool suTo;
128 if (operand()) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000129 miFrom = (oppMaxWinding & xorMiMask) != 0;
130 miTo = (oppSumWinding & xorMiMask) != 0;
131 suFrom = (maxWinding & xorSuMask) != 0;
132 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000133 } else {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000134 miFrom = (maxWinding & xorMiMask) != 0;
135 miTo = (sumWinding & xorMiMask) != 0;
136 suFrom = (oppMaxWinding & xorSuMask) != 0;
137 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000138 }
139 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
140#if DEBUG_ACTIVE_OP
caryclarkdac1d172014-06-17 05:15:38 -0700141 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 -0700142 __FUNCTION__, debugID(), start->t(), end->t(),
caryclark@google.com570863f2013-09-16 15:55:01 +0000143 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000144#endif
145 return result;
146}
147
caryclark54359292015-03-26 07:52:43 -0700148bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
149 int sumWinding = updateWinding(end, start);
150 return activeWinding(start, end, &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000151}
152
caryclark54359292015-03-26 07:52:43 -0700153bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000154 int maxWinding;
caryclark54359292015-03-26 07:52:43 -0700155 setUpWinding(start, end, &maxWinding, sumWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000156 bool from = maxWinding != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000157 bool to = *sumWinding != 0;
158 bool result = gUnaryActiveEdge[from][to];
159 return result;
160}
161
caryclarkef784fb2015-10-30 12:03:06 -0700162bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
163 SkPathWriter* path) const {
caryclark025b11e2016-08-25 05:21:14 -0700164 FAIL_IF(start->starter(end)->alreadyAdded());
caryclarkeed356d2016-09-14 07:18:20 -0700165 SkDCurveSweep curvePart;
166 start->segment()->subDivide(start, end, &curvePart.fCurve);
167 curvePart.setCurveHullSweep(fVerb);
168 SkPath::Verb verb = curvePart.isCurve() ? fVerb : SkPath::kLine_Verb;
169 path->deferredMove(start->ptT());
170 switch (verb) {
171 case SkPath::kLine_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700172 FAIL_IF(!path->deferredLine(end->ptT()));
caryclarkeed356d2016-09-14 07:18:20 -0700173 break;
174 case SkPath::kQuad_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700175 path->quadTo(curvePart.fCurve.fQuad[1].asSkPoint(), end->ptT());
caryclarkeed356d2016-09-14 07:18:20 -0700176 break;
177 case SkPath::kConic_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700178 path->conicTo(curvePart.fCurve.fConic[1].asSkPoint(), end->ptT(),
caryclarkeed356d2016-09-14 07:18:20 -0700179 curvePart.fCurve.fConic.fWeight);
180 break;
181 case SkPath::kCubic_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700182 path->cubicTo(curvePart.fCurve.fCubic[1].asSkPoint(),
183 curvePart.fCurve.fCubic[2].asSkPoint(), end->ptT());
caryclarkeed356d2016-09-14 07:18:20 -0700184 break;
185 default:
186 SkASSERT(0);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000187 }
caryclarkef784fb2015-10-30 12:03:06 -0700188 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000189}
190
caryclark55888e42016-07-18 10:01:36 -0700191const SkOpPtT* SkOpSegment::existing(double t, const SkOpSegment* opp) const {
192 const SkOpSpanBase* test = &fHead;
193 const SkOpPtT* testPtT;
194 SkPoint pt = this->ptAtT(t);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000195 do {
caryclark55888e42016-07-18 10:01:36 -0700196 testPtT = test->ptT();
197 if (testPtT->fT == t) {
reed0dc4dd62015-03-24 13:55:33 -0700198 break;
199 }
caryclarkef4f32a2016-08-24 09:24:18 -0700200 if (!this->match(testPtT, this, t, pt)) {
caryclark55888e42016-07-18 10:01:36 -0700201 if (t < testPtT->fT) {
202 return nullptr;
203 }
204 continue;
205 }
206 if (!opp) {
207 return testPtT;
208 }
209 const SkOpPtT* loop = testPtT->next();
210 while (loop != testPtT) {
211 if (loop->segment() == this && loop->fT == t && loop->fPt == pt) {
212 goto foundMatch;
213 }
214 loop = loop->next();
215 }
216 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700217 } while ((test = test->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -0700218foundMatch:
219 return opp && !test->contains(opp) ? nullptr : testPtT;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000220}
221
caryclark55888e42016-07-18 10:01:36 -0700222// break the span so that the coincident part does not change the angle of the remainder
223bool SkOpSegment::addExpanded(double newT, const SkOpSpanBase* test, bool* startOver) {
224 if (this->contains(newT)) {
225 return true;
226 }
caryclark29b25632016-08-25 11:27:17 -0700227 this->globalState()->resetAllocatedOpSpan();
caryclarka35ab3e2016-10-20 08:32:18 -0700228 FAIL_IF(!between(0, newT, 1));
caryclark29b25632016-08-25 11:27:17 -0700229 SkOpPtT* newPtT = this->addT(newT);
230 *startOver |= this->globalState()->allocatedOpSpan();
caryclark55888e42016-07-18 10:01:36 -0700231 if (!newPtT) {
232 return false;
233 }
234 newPtT->fPt = this->ptAtT(newT);
caryclark29b25632016-08-25 11:27:17 -0700235 SkOpPtT* oppPrev = test->ptT()->oppPrev(newPtT);
236 if (oppPrev) {
caryclark8016b262016-09-06 05:59:47 -0700237 // const cast away to change linked list; pt/t values stays unchanged
caryclark29b25632016-08-25 11:27:17 -0700238 SkOpSpanBase* writableTest = const_cast<SkOpSpanBase*>(test);
caryclark30b9fdd2016-08-31 14:36:29 -0700239 writableTest->mergeMatches(newPtT->span());
caryclark29b25632016-08-25 11:27:17 -0700240 writableTest->ptT()->addOpp(newPtT, oppPrev);
caryclark55888e42016-07-18 10:01:36 -0700241 writableTest->checkForCollapsedCoincidence();
242 }
243 return true;
244}
245
246// Please keep this in sync with debugAddT()
Cary Clark73e597d2017-04-18 12:08:58 -0400247SkOpPtT* SkOpSegment::addT(double t, const SkPoint& pt) {
reed0dc4dd62015-03-24 13:55:33 -0700248 debugValidate();
caryclark29b25632016-08-25 11:27:17 -0700249 SkOpSpanBase* spanBase = &fHead;
caryclark54359292015-03-26 07:52:43 -0700250 do {
caryclark29b25632016-08-25 11:27:17 -0700251 SkOpPtT* result = spanBase->ptT();
caryclark27c015d2016-09-23 05:47:20 -0700252 if (t == result->fT || (!zero_or_one(t) && this->match(result, this, t, pt))) {
caryclark29b25632016-08-25 11:27:17 -0700253 spanBase->bumpSpanAdds();
caryclarkef4f32a2016-08-24 09:24:18 -0700254 return result;
reed0dc4dd62015-03-24 13:55:33 -0700255 }
caryclark54359292015-03-26 07:52:43 -0700256 if (t < result->fT) {
257 SkOpSpan* prev = result->span()->prev();
caryclark29b25632016-08-25 11:27:17 -0700258 FAIL_WITH_NULL_IF(!prev);
259 // marks in global state that new op span has been allocated
260 SkOpSpan* span = this->insert(prev);
caryclark54359292015-03-26 07:52:43 -0700261 span->init(this, prev, t, pt);
262 this->debugValidate();
263#if DEBUG_ADD_T
264 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
265 span->segment()->debugID(), span->debugID());
266#endif
caryclark08bc8482015-04-24 09:08:57 -0700267 span->bumpSpanAdds();
caryclark54359292015-03-26 07:52:43 -0700268 return span->ptT();
269 }
caryclark29b25632016-08-25 11:27:17 -0700270 FAIL_WITH_NULL_IF(spanBase == &fTail);
271 } while ((spanBase = spanBase->upCast()->next()));
caryclark54359292015-03-26 07:52:43 -0700272 SkASSERT(0);
caryclark29b25632016-08-25 11:27:17 -0700273 return nullptr; // we never get here, but need this to satisfy compiler
caryclark54359292015-03-26 07:52:43 -0700274}
275
Cary Clark73e597d2017-04-18 12:08:58 -0400276SkOpPtT* SkOpSegment::addT(double t) {
277 return addT(t, this->ptAtT(t));
278}
279
caryclark55888e42016-07-18 10:01:36 -0700280void SkOpSegment::calcAngles() {
caryclark54359292015-03-26 07:52:43 -0700281 bool activePrior = !fHead.isCanceled();
282 if (activePrior && !fHead.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700283 addStartSpan();
reed0dc4dd62015-03-24 13:55:33 -0700284 }
caryclark54359292015-03-26 07:52:43 -0700285 SkOpSpan* prior = &fHead;
286 SkOpSpanBase* spanBase = fHead.next();
287 while (spanBase != &fTail) {
288 if (activePrior) {
Herb Derbyecc364c2017-04-19 15:09:48 -0400289 SkOpAngle* priorAngle = this->globalState()->allocator()->make<SkOpAngle>();
caryclark54359292015-03-26 07:52:43 -0700290 priorAngle->set(spanBase, prior);
291 spanBase->setFromAngle(priorAngle);
reed0dc4dd62015-03-24 13:55:33 -0700292 }
caryclark54359292015-03-26 07:52:43 -0700293 SkOpSpan* span = spanBase->upCast();
294 bool active = !span->isCanceled();
295 SkOpSpanBase* next = span->next();
296 if (active) {
Herb Derbyecc364c2017-04-19 15:09:48 -0400297 SkOpAngle* angle = this->globalState()->allocator()->make<SkOpAngle>();
caryclark54359292015-03-26 07:52:43 -0700298 angle->set(span, next);
299 span->setToAngle(angle);
reed0dc4dd62015-03-24 13:55:33 -0700300 }
reed0dc4dd62015-03-24 13:55:33 -0700301 activePrior = active;
caryclark54359292015-03-26 07:52:43 -0700302 prior = span;
303 spanBase = next;
reed0dc4dd62015-03-24 13:55:33 -0700304 }
caryclark54359292015-03-26 07:52:43 -0700305 if (activePrior && !fTail.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700306 addEndSpan();
reed0dc4dd62015-03-24 13:55:33 -0700307 }
reed0dc4dd62015-03-24 13:55:33 -0700308}
309
caryclark55888e42016-07-18 10:01:36 -0700310// Please keep this in sync with debugClearAll()
311void SkOpSegment::clearAll() {
312 SkOpSpan* span = &fHead;
313 do {
314 this->clearOne(span);
315 } while ((span = span->next()->upCastable()));
316 this->globalState()->coincidence()->release(this);
317}
318
319// Please keep this in sync with debugClearOne()
320void SkOpSegment::clearOne(SkOpSpan* span) {
321 span->setWindValue(0);
322 span->setOppValue(0);
323 this->markDone(span);
324}
325
caryclark30b9fdd2016-08-31 14:36:29 -0700326bool SkOpSegment::collapsed(double s, double e) const {
327 const SkOpSpanBase* span = &fHead;
328 do {
329 if (span->collapsed(s, e)) {
330 return true;
331 }
332 } while (span->upCastable() && (span = span->upCast()->next()));
333 return false;
334}
335
caryclark@google.com570863f2013-09-16 15:55:01 +0000336void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
337 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700338 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000339 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
340 int sumSuWinding;
341 bool binary = includeType >= SkOpAngle::kBinarySingle;
342 if (binary) {
343 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
344 if (baseSegment->operand()) {
345 SkTSwap<int>(sumMiWinding, sumSuWinding);
346 }
347 }
348 SkOpSegment* nextSegment = nextAngle->segment();
349 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700350 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000351 if (binary) {
352 int oppMaxWinding, oppSumWinding;
353 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
354 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
355 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000356 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000357 } else {
358 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
359 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000360 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000361 }
362 nextAngle->setLastMarked(last);
363}
364
caryclark624637c2015-05-11 07:21:27 -0700365void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
caryclark@google.com570863f2013-09-16 15:55:01 +0000366 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700367 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000368 int sumMiWinding = baseSegment->updateWinding(baseAngle);
369 int sumSuWinding;
370 bool binary = includeType >= SkOpAngle::kBinarySingle;
371 if (binary) {
372 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
373 if (baseSegment->operand()) {
374 SkTSwap<int>(sumMiWinding, sumSuWinding);
375 }
376 }
377 SkOpSegment* nextSegment = nextAngle->segment();
378 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700379 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000380 if (binary) {
381 int oppMaxWinding, oppSumWinding;
382 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
383 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
384 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000385 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000386 } else {
387 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
388 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000389 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000390 }
391 nextAngle->setLastMarked(last);
392}
393
caryclark54359292015-03-26 07:52:43 -0700394// at this point, the span is already ordered, or unorderable
395int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
396 SkOpAngle::IncludeType includeType) {
397 SkASSERT(includeType != SkOpAngle::kUnaryXor);
398 SkOpAngle* firstAngle = this->spanToAngle(end, start);
halcanary96fcdcc2015-08-27 07:41:13 -0700399 if (nullptr == firstAngle || nullptr == firstAngle->next()) {
caryclark54359292015-03-26 07:52:43 -0700400 return SK_NaN32;
401 }
402 // if all angles have a computed winding,
403 // or if no adjacent angles are orderable,
404 // or if adjacent orderable angles have no computed winding,
405 // there's nothing to do
406 // if two orderable angles are adjacent, and both are next to orderable angles,
407 // and one has winding computed, transfer to the other
halcanary96fcdcc2015-08-27 07:41:13 -0700408 SkOpAngle* baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700409 bool tryReverse = false;
410 // look for counterclockwise transfers
411 SkOpAngle* angle = firstAngle->previous();
412 SkOpAngle* next = angle->next();
413 firstAngle = next;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000414 do {
caryclark54359292015-03-26 07:52:43 -0700415 SkOpAngle* prior = angle;
416 angle = next;
417 next = angle->next();
418 SkASSERT(prior->next() == angle);
419 SkASSERT(angle->next() == next);
420 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700421 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700422 continue;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000423 }
caryclark54359292015-03-26 07:52:43 -0700424 int testWinding = angle->starter()->windSum();
425 if (SK_MinS32 != testWinding) {
426 baseAngle = angle;
427 tryReverse = true;
428 continue;
reed0dc4dd62015-03-24 13:55:33 -0700429 }
caryclark54359292015-03-26 07:52:43 -0700430 if (baseAngle) {
431 ComputeOneSum(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700432 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
caryclark54359292015-03-26 07:52:43 -0700433 }
434 } while (next != firstAngle);
435 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
436 firstAngle = baseAngle;
437 tryReverse = true;
438 }
439 if (tryReverse) {
halcanary96fcdcc2015-08-27 07:41:13 -0700440 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700441 SkOpAngle* prior = firstAngle;
442 do {
443 angle = prior;
444 prior = angle->previous();
445 SkASSERT(prior->next() == angle);
446 next = angle->next();
447 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700448 baseAngle = nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700449 continue;
450 }
caryclark54359292015-03-26 07:52:43 -0700451 int testWinding = angle->starter()->windSum();
452 if (SK_MinS32 != testWinding) {
453 baseAngle = angle;
454 continue;
reed0dc4dd62015-03-24 13:55:33 -0700455 }
caryclark54359292015-03-26 07:52:43 -0700456 if (baseAngle) {
457 ComputeOneSumReverse(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700458 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700459 }
caryclark54359292015-03-26 07:52:43 -0700460 } while (prior != firstAngle);
reed0dc4dd62015-03-24 13:55:33 -0700461 }
caryclark54359292015-03-26 07:52:43 -0700462 return start->starter(end)->windSum();
reed0dc4dd62015-03-24 13:55:33 -0700463}
464
caryclark55888e42016-07-18 10:01:36 -0700465bool SkOpSegment::contains(double newT) const {
466 const SkOpSpanBase* spanBase = &fHead;
467 do {
468 if (spanBase->ptT()->contains(this, newT)) {
469 return true;
470 }
471 if (spanBase == &fTail) {
472 break;
473 }
474 spanBase = spanBase->upCast()->next();
475 } while (true);
476 return false;
477}
478
mtklein18300a32016-03-16 13:53:35 -0700479void SkOpSegment::release(const SkOpSpan* span) {
caryclark54359292015-03-26 07:52:43 -0700480 if (span->done()) {
caryclark08bc8482015-04-24 09:08:57 -0700481 --fDoneCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000482 }
caryclark08bc8482015-04-24 09:08:57 -0700483 --fCount;
caryclark15976282016-07-21 05:48:43 -0700484 SkOPASSERT(fCount >= fDoneCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000485}
486
Cary Clarke47ae292016-10-05 08:51:39 -0400487#if DEBUG_ANGLE
488// called only by debugCheckNearCoincidence
caryclark26ad22a2015-10-16 09:03:38 -0700489double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
caryclark54359292015-03-26 07:52:43 -0700490 SkDPoint testPt = this->dPtAtT(t);
491 SkDLine testPerp = {{ testPt, testPt }};
492 SkDVector slope = this->dSlopeAtT(t);
493 testPerp[1].fX += slope.fY;
494 testPerp[1].fY -= slope.fX;
495 SkIntersections i;
caryclark26ad22a2015-10-16 09:03:38 -0700496 const SkOpSegment* oppSegment = oppAngle->segment();
caryclark1049f122015-04-20 08:31:59 -0700497 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
caryclark54359292015-03-26 07:52:43 -0700498 double closestDistSq = SK_ScalarInfinity;
499 for (int index = 0; index < i.used(); ++index) {
500 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000501 continue;
502 }
caryclark54359292015-03-26 07:52:43 -0700503 double testDistSq = testPt.distanceSquared(i.pt(index));
504 if (closestDistSq > testDistSq) {
505 closestDistSq = testDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000506 }
507 }
caryclark54359292015-03-26 07:52:43 -0700508 return closestDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000509}
Cary Clarke47ae292016-10-05 08:51:39 -0400510#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000511
caryclark@google.com07393ca2013-04-08 11:47:37 +0000512/*
513 The M and S variable name parts stand for the operators.
514 Mi stands for Minuend (see wiki subtraction, analogous to difference)
515 Su stands for Subtrahend
516 The Opp variable name part designates that the value is for the Opposite operator.
517 Opposite values result from combining coincident spans.
518 */
caryclark54359292015-03-26 07:52:43 -0700519SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
520 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) {
521 SkOpSpanBase* start = *nextStart;
522 SkOpSpanBase* end = *nextEnd;
523 SkASSERT(start != end);
524 int step = start->step(end);
525 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
526 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000527 // mark the smaller of startIndex, endIndex done, and all adjacent
528 // spans with the same T value (but not 'other' spans)
529#if DEBUG_WINDING
530 SkDebugf("%s simple\n", __FUNCTION__);
531#endif
caryclark54359292015-03-26 07:52:43 -0700532 SkOpSpan* startSpan = start->starter(end);
533 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700534 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000535 }
caryclark54359292015-03-26 07:52:43 -0700536 markDone(startSpan);
537 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000538 return other;
539 }
caryclark54359292015-03-26 07:52:43 -0700540 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
541 SkASSERT(endNear == end); // is this ever not end?
542 SkASSERT(endNear);
543 SkASSERT(start != endNear);
544 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000545 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700546 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
caryclark@google.com570863f2013-09-16 15:55:01 +0000547 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000548 if (!sortable) {
549 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700550 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700551 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000552 }
caryclark54359292015-03-26 07:52:43 -0700553 SkOpAngle* angle = this->spanToAngle(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000554 if (angle->unorderable()) {
555 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700556 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700557 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000558 }
559#if DEBUG_SORT
560 SkDebugf("%s\n", __FUNCTION__);
561 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000562#endif
caryclark54359292015-03-26 07:52:43 -0700563 int sumMiWinding = updateWinding(end, start);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000564 if (sumMiWinding == SK_MinS32) {
565 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700566 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700567 return nullptr;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000568 }
caryclark54359292015-03-26 07:52:43 -0700569 int sumSuWinding = updateOppWinding(end, start);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000570 if (operand()) {
571 SkTSwap<int>(sumMiWinding, sumSuWinding);
572 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000573 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700574 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000575 bool foundDone = false;
576 // iterate through the angle, and compute everyone's winding
577 SkOpSegment* nextSegment;
578 int activeCount = 0;
579 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000580 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000581 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000582 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000583 if (activeAngle) {
584 ++activeCount;
585 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000586 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +0000587 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000588 }
589 }
590 if (nextSegment->done()) {
591 continue;
592 }
reed0dc4dd62015-03-24 13:55:33 -0700593 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700594 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700595 }
caryclark54359292015-03-26 07:52:43 -0700596 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000597 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000598 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000599 *chase->append() = last;
600#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700601 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
602 last->segment()->debugID(), last->debugID());
603 if (!last->final()) {
604 SkDebugf(" windSum=%d", last->upCast()->windSum());
605 }
606 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000607#endif
608 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000609 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700610 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000611 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700612 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000613 }
614 *nextStart = foundAngle->start();
615 *nextEnd = foundAngle->end();
616 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000617#if DEBUG_WINDING
618 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
619 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
620 #endif
621 return nextSegment;
622}
623
caryclark54359292015-03-26 07:52:43 -0700624SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
625 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
626 SkOpSpanBase* start = *nextStart;
627 SkOpSpanBase* end = *nextEnd;
628 SkASSERT(start != end);
629 int step = start->step(end);
630 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
631 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000632 // mark the smaller of startIndex, endIndex done, and all adjacent
633 // spans with the same T value (but not 'other' spans)
634#if DEBUG_WINDING
635 SkDebugf("%s simple\n", __FUNCTION__);
636#endif
caryclark54359292015-03-26 07:52:43 -0700637 SkOpSpan* startSpan = start->starter(end);
638 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700639 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000640 }
caryclark54359292015-03-26 07:52:43 -0700641 markDone(startSpan);
642 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000643 return other;
644 }
caryclark54359292015-03-26 07:52:43 -0700645 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
646 SkASSERT(endNear == end); // is this ever not end?
647 SkASSERT(endNear);
648 SkASSERT(start != endNear);
649 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000650 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700651 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000652 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000653 if (!sortable) {
654 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700655 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700656 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000657 }
caryclark54359292015-03-26 07:52:43 -0700658 SkOpAngle* angle = this->spanToAngle(end, start);
659 if (angle->unorderable()) {
660 *unsortable = true;
661 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700662 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700663 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000664#if DEBUG_SORT
665 SkDebugf("%s\n", __FUNCTION__);
666 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000667#endif
caryclark54359292015-03-26 07:52:43 -0700668 int sumWinding = updateWinding(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000669 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700670 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000671 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700672 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000673 SkOpSegment* nextSegment;
674 int activeCount = 0;
675 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000676 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000677 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000678 &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000679 if (activeAngle) {
680 ++activeCount;
681 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000682 foundAngle = nextAngle;
683 foundDone = nextSegment->done(nextAngle);
684 }
685 }
686 if (nextSegment->done()) {
687 continue;
688 }
reed0dc4dd62015-03-24 13:55:33 -0700689 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700690 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700691 }
caryclark54359292015-03-26 07:52:43 -0700692 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000693 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000694 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000695 *chase->append() = last;
696#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700697 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
698 last->segment()->debugID(), last->debugID());
699 if (!last->final()) {
700 SkDebugf(" windSum=%d", last->upCast()->windSum());
701 }
702 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000703#endif
704 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000705 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700706 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000707 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700708 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000709 }
710 *nextStart = foundAngle->start();
711 *nextEnd = foundAngle->end();
712 nextSegment = foundAngle->segment();
713#if DEBUG_WINDING
714 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
715 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
716 #endif
717 return nextSegment;
718}
719
caryclark54359292015-03-26 07:52:43 -0700720SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
721 bool* unsortable) {
722 SkOpSpanBase* start = *nextStart;
723 SkOpSpanBase* end = *nextEnd;
724 SkASSERT(start != end);
725 int step = start->step(end);
726 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
727 if (other) {
728 // mark the smaller of startIndex, endIndex done, and all adjacent
729 // spans with the same T value (but not 'other' spans)
caryclark@google.com07393ca2013-04-08 11:47:37 +0000730#if DEBUG_WINDING
731 SkDebugf("%s simple\n", __FUNCTION__);
732#endif
caryclark54359292015-03-26 07:52:43 -0700733 SkOpSpan* startSpan = start->starter(end);
734 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700735 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000736 }
caryclark54359292015-03-26 07:52:43 -0700737 markDone(startSpan);
738 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000739 return other;
740 }
caryclark54359292015-03-26 07:52:43 -0700741 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
742 : (*nextStart)->prev());
743 SkASSERT(endNear == end); // is this ever not end?
744 SkASSERT(endNear);
745 SkASSERT(start != endNear);
746 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
747 SkOpAngle* angle = this->spanToAngle(end, start);
caryclark27c8eb82015-07-06 11:38:33 -0700748 if (!angle || angle->unorderable()) {
caryclark54359292015-03-26 07:52:43 -0700749 *unsortable = true;
750 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700751 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700752 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000753#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000754 SkDebugf("%s\n", __FUNCTION__);
755 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000756#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000757 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700758 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000759 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700760 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000761 SkOpSegment* nextSegment;
762 int activeCount = 0;
763 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000764 nextSegment = nextAngle->segment();
765 ++activeCount;
766 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000767 foundAngle = nextAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000768 if (!(foundDone = nextSegment->done(nextAngle))) {
769 break;
770 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000771 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000772 nextAngle = nextAngle->next();
773 } while (nextAngle != angle);
caryclark54359292015-03-26 07:52:43 -0700774 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000775 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700776 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000777 }
778 *nextStart = foundAngle->start();
779 *nextEnd = foundAngle->end();
780 nextSegment = foundAngle->segment();
781#if DEBUG_WINDING
782 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
783 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
784 #endif
785 return nextSegment;
786}
787
caryclark54359292015-03-26 07:52:43 -0700788SkOpGlobalState* SkOpSegment::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700789 return contour()->globalState();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000790}
791
caryclark1049f122015-04-20 08:31:59 -0700792void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
caryclark54359292015-03-26 07:52:43 -0700793 fContour = contour;
halcanary96fcdcc2015-08-27 07:41:13 -0700794 fNext = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000795 fPts = pts;
caryclark1049f122015-04-20 08:31:59 -0700796 fWeight = weight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000797 fVerb = verb;
caryclark54359292015-03-26 07:52:43 -0700798 fCount = 0;
799 fDoneCount = 0;
800 fVisited = false;
801 SkOpSpan* zeroSpan = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700802 zeroSpan->init(this, nullptr, 0, fPts[0]);
caryclark54359292015-03-26 07:52:43 -0700803 SkOpSpanBase* oneSpan = &fTail;
804 zeroSpan->setNext(oneSpan);
805 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
caryclark1049f122015-04-20 08:31:59 -0700806 SkDEBUGCODE(fID = globalState()->nextSegmentID());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000807}
808
caryclark54359292015-03-26 07:52:43 -0700809bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
810 SkDPoint cPt = this->dPtAtT(t);
caryclark1049f122015-04-20 08:31:59 -0700811 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
caryclark54359292015-03-26 07:52:43 -0700812 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
813 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -0700814 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
caryclark54359292015-03-26 07:52:43 -0700815 int used = i.used();
816 for (int index = 0; index < used; ++index) {
817 if (cPt.roughlyEqual(i.pt(index))) {
reed0dc4dd62015-03-24 13:55:33 -0700818 return true;
819 }
caryclark54359292015-03-26 07:52:43 -0700820 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000821 return false;
822}
823
caryclark54359292015-03-26 07:52:43 -0700824bool SkOpSegment::isXor() const {
825 return fContour->isXor();
826}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000827
caryclark5b5ddd72015-05-18 05:12:56 -0700828void SkOpSegment::markAllDone() {
829 SkOpSpan* span = this->head();
830 do {
831 this->markDone(span);
832 } while ((span = span->next()->upCastable()));
833}
834
caryclark54359292015-03-26 07:52:43 -0700835SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) {
836 int step = start->step(end);
837 SkOpSpan* minSpan = start->starter(end);
838 markDone(minSpan);
halcanary96fcdcc2015-08-27 07:41:13 -0700839 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000840 SkOpSegment* other = this;
Cary Clark918fb1f2016-11-15 13:22:25 -0500841 SkOpSpan* priorDone = nullptr;
842 SkOpSpan* lastDone = nullptr;
caryclark54359292015-03-26 07:52:43 -0700843 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000844 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -0700845 SkASSERT(!last);
846 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000847 }
Cary Clark918fb1f2016-11-15 13:22:25 -0500848 if (lastDone == minSpan || priorDone == minSpan) {
849 return nullptr;
850 }
caryclark54359292015-03-26 07:52:43 -0700851 other->markDone(minSpan);
Cary Clark918fb1f2016-11-15 13:22:25 -0500852 priorDone = lastDone;
853 lastDone = minSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000854 }
855 return last;
856}
857
caryclark54359292015-03-26 07:52:43 -0700858bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
859 SkOpSpanBase** lastPtr) {
860 SkOpSpan* spanStart = start->starter(end);
861 int step = start->step(end);
862 bool success = markWinding(spanStart, winding);
halcanary96fcdcc2015-08-27 07:41:13 -0700863 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000864 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700865 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
866 if (spanStart->windSum() != SK_MinS32) {
caryclarkb36a3cd2016-10-18 07:59:44 -0700867// SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive?
caryclarkdac1d172014-06-17 05:15:38 -0700868 SkASSERT(!last);
869 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000870 }
caryclark54359292015-03-26 07:52:43 -0700871 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000872 }
caryclark65f55312014-11-13 06:58:52 -0800873 if (lastPtr) {
874 *lastPtr = last;
875 }
876 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000877}
878
caryclark54359292015-03-26 07:52:43 -0700879bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
880 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
881 SkOpSpan* spanStart = start->starter(end);
882 int step = start->step(end);
883 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700884 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000885 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700886 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
887 if (spanStart->windSum() != SK_MinS32) {
888 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700889 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700890 this->globalState()->setWindingFailed();
891 return false;
caryclarkdac1d172014-06-17 05:15:38 -0700892 }
caryclark54359292015-03-26 07:52:43 -0700893 } else {
894 SkASSERT(spanStart->windSum() == oppWinding);
895 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700896 }
897 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700898 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000899 }
caryclark54359292015-03-26 07:52:43 -0700900 if (this->operand() == other->operand()) {
901 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700902 } else {
caryclark54359292015-03-26 07:52:43 -0700903 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700904 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000905 }
caryclark65f55312014-11-13 06:58:52 -0800906 if (lastPtr) {
907 *lastPtr = last;
908 }
909 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000910}
911
caryclark54359292015-03-26 07:52:43 -0700912SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000913 SkASSERT(angle->segment() == this);
914 if (UseInnerWinding(maxWinding, sumWinding)) {
915 maxWinding = sumWinding;
916 }
caryclark54359292015-03-26 07:52:43 -0700917 SkOpSpanBase* last;
918 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000919#if DEBUG_WINDING
920 if (last) {
caryclark54359292015-03-26 07:52:43 -0700921 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
922 last->segment()->debugID(), last->debugID());
923 if (!last->final()) {
924 SkDebugf(" windSum=");
925 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
926 }
927 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000928 }
929#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000930 return last;
931}
932
caryclark54359292015-03-26 07:52:43 -0700933SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
934 int oppSumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000935 SkASSERT(angle->segment() == this);
936 if (UseInnerWinding(maxWinding, sumWinding)) {
937 maxWinding = sumWinding;
938 }
939 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
940 oppMaxWinding = oppSumWinding;
941 }
halcanary96fcdcc2015-08-27 07:41:13 -0700942 SkOpSpanBase* last = nullptr;
caryclark65f55312014-11-13 06:58:52 -0800943 // caller doesn't require that this marks anything
caryclark54359292015-03-26 07:52:43 -0700944 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000945#if DEBUG_WINDING
946 if (last) {
caryclark54359292015-03-26 07:52:43 -0700947 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
948 last->segment()->debugID(), last->debugID());
949 if (!last->final()) {
950 SkDebugf(" windSum=");
951 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
952 }
953 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000954 }
955#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000956 return last;
957}
958
caryclark54359292015-03-26 07:52:43 -0700959void SkOpSegment::markDone(SkOpSpan* span) {
960 SkASSERT(this == span->segment());
961 if (span->done()) {
962 return;
963 }
964#if DEBUG_MARK_DONE
965 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
966#endif
967 span->setDone(true);
968 ++fDoneCount;
969 debugValidate();
970}
971
972bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
973 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -0700974 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -0700975 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -0700976 return false;
977 }
978#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -0700979 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -0700980#endif
caryclark54359292015-03-26 07:52:43 -0700981 span->setWindSum(winding);
982 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -0700983 return true;
984}
985
caryclark54359292015-03-26 07:52:43 -0700986bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
987 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000988 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -0700989 if (span->done()) {
990 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000991 }
caryclark54359292015-03-26 07:52:43 -0700992#if DEBUG_MARK_DONE
993 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
994#endif
995 span->setWindSum(winding);
996 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000997 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000998 return true;
999}
1000
caryclark54359292015-03-26 07:52:43 -07001001bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclarkef4f32a2016-08-24 09:24:18 -07001002 const SkPoint& testPt) const {
caryclark55888e42016-07-18 10:01:36 -07001003 SkASSERT(this == base->segment());
1004 if (this == testParent) {
1005 if (precisely_equal(base->fT, testT)) {
1006 return true;
1007 }
caryclark54359292015-03-26 07:52:43 -07001008 }
1009 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1010 return false;
1011 }
caryclark55888e42016-07-18 10:01:36 -07001012 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001013}
1014
1015static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1016 if (last) {
1017 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001018 }
halcanary96fcdcc2015-08-27 07:41:13 -07001019 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001020}
1021
caryclark54359292015-03-26 07:52:43 -07001022SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1023 SkOpSpanBase** last) const {
1024 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001025 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001026 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1027 SkASSERT(endSpan);
1028 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1029 SkOpSpanBase* foundSpan;
1030 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001031 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001032 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001033 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001034 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001035 }
caryclark54359292015-03-26 07:52:43 -07001036 SkOpPtT* otherPtT = endSpan->ptT()->next();
1037 other = otherPtT->segment();
1038 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001039 otherEnd = step > 0
1040 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1041 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001042 } else {
1043 int loopCount = angle->loopCount();
1044 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001045 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001046 }
1047 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001048 if (nullptr == next) {
1049 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001050 }
caryclarkdac1d172014-06-17 05:15:38 -07001051#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001052 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001053 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001054 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001055 }
caryclark54359292015-03-26 07:52:43 -07001056#endif
caryclarkdac1d172014-06-17 05:15:38 -07001057 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001058 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001059 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001060 }
caryclark343382e2016-06-29 08:18:38 -07001061 if (!otherEnd) {
1062 return nullptr;
1063 }
caryclark54359292015-03-26 07:52:43 -07001064 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001065 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001066 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001067 }
caryclark54359292015-03-26 07:52:43 -07001068 SkASSERT(*startPtr);
caryclark65b427c2014-09-18 10:32:57 -07001069// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001070 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1071 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1072 if (foundMin->windValue() != origMin->windValue()
1073 || foundMin->oppValue() != origMin->oppValue()) {
1074 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001075 }
caryclark54359292015-03-26 07:52:43 -07001076 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001077 *stepPtr = foundStep;
1078 if (minPtr) {
1079 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001080 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001081 return other;
1082}
1083
caryclark55888e42016-07-18 10:01:36 -07001084// Please keep this in sync with DebugClearVisited()
1085void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001086 // reset visited flag back to false
1087 do {
1088 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1089 while ((ptT = ptT->next()) != stopPtT) {
1090 SkOpSegment* opp = ptT->segment();
1091 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001092 }
caryclarkbca19f72015-05-13 08:23:48 -07001093 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001094}
1095
caryclark55888e42016-07-18 10:01:36 -07001096// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001097// look for pairs of undetected coincident curves
1098// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001099// Even though pairs of curves correct detect coincident runs, a run may be missed
1100// if the coincidence is a product of multiple intersections. For instance, given
1101// curves A, B, and C:
1102// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1103// the end of C that the intersection is replaced with the end of C.
1104// Even though A-B correctly do not detect an intersection at point 2,
1105// the resulting run from point 1 to point 2 is coincident on A and B.
1106bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001107 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001108 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001109 }
halcanary96fcdcc2015-08-27 07:41:13 -07001110 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001111 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001112 bool result = false;
caryclark54359292015-03-26 07:52:43 -07001113 do {
caryclarkbca19f72015-05-13 08:23:48 -07001114 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001115 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001116 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001117 if (ptT->deleted()) {
1118 continue;
1119 }
caryclark54359292015-03-26 07:52:43 -07001120 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001121 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001122 continue;
reed0dc4dd62015-03-24 13:55:33 -07001123 }
caryclarkbca19f72015-05-13 08:23:48 -07001124 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1125 if (!opp->visited()) {
1126 continue;
1127 }
1128 if (spanBase == &fHead) {
1129 continue;
1130 }
caryclark55888e42016-07-18 10:01:36 -07001131 if (ptT->segment() == this) {
1132 continue;
1133 }
caryclarkbca19f72015-05-13 08:23:48 -07001134 SkOpSpan* span = spanBase->upCastable();
1135 // FIXME?: this assumes that if the opposite segment is coincident then no more
1136 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001137 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001138 continue;
1139 }
caryclarkbca19f72015-05-13 08:23:48 -07001140 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001141 continue;
caryclark55888e42016-07-18 10:01:36 -07001142 }
halcanary96fcdcc2015-08-27 07:41:13 -07001143 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001144 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001145 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001146 SkOpSpan* priorTest = spanBase->prev();
1147 while (!priorOpp && priorTest) {
1148 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001149 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001150 if (priorPtT->deleted()) {
1151 continue;
1152 }
caryclark54359292015-03-26 07:52:43 -07001153 SkOpSegment* segment = priorPtT->span()->segment();
1154 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001155 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001156 priorOpp = opp;
1157 break;
1158 }
1159 }
caryclarkbca19f72015-05-13 08:23:48 -07001160 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001161 }
1162 if (!priorOpp) {
1163 continue;
1164 }
caryclark26ad22a2015-10-16 09:03:38 -07001165 if (priorPtT == ptT) {
1166 continue;
1167 }
caryclark54359292015-03-26 07:52:43 -07001168 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001169 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001170 bool swapped = priorPtT->fT > ptT->fT;
1171 if (swapped) {
1172 SkTSwap(priorPtT, ptT);
1173 SkTSwap(oppStart, oppEnd);
1174 }
caryclark55888e42016-07-18 10:01:36 -07001175 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1176 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1177 SkOpPtT* rootPtT = ptT->span()->ptT();
1178 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1179 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1180 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001181 goto swapBack;
1182 }
caryclark55888e42016-07-18 10:01:36 -07001183 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001184 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001185#if DEBUG_COINCIDENCE_VERBOSE
1186 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1187 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1188 rootOppEnd->debugID());
1189#endif
1190 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1191 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001192 }
caryclark55888e42016-07-18 10:01:36 -07001193#if DEBUG_COINCIDENCE
1194 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1195#endif
1196 result = true;
caryclark54359292015-03-26 07:52:43 -07001197 }
1198 swapBack:
1199 if (swapped) {
1200 SkTSwap(priorPtT, ptT);
1201 }
reed0dc4dd62015-03-24 13:55:33 -07001202 }
halcanary96fcdcc2015-08-27 07:41:13 -07001203 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001204 ClearVisited(&fHead);
1205 return result;
reed0dc4dd62015-03-24 13:55:33 -07001206}
1207
caryclark55888e42016-07-18 10:01:36 -07001208// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001209// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001210bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001211 debugValidate();
1212 SkOpSpanBase* test = &fHead;
1213 do {
1214 int addCount = test->spanAddsCount();
Cary Clark7eb01e02016-12-08 14:36:32 -05001215// FAIL_IF(addCount < 1);
1216 if (addCount <= 1) {
caryclark08bc8482015-04-24 09:08:57 -07001217 continue;
1218 }
1219 SkOpPtT* startPtT = test->ptT();
1220 SkOpPtT* testPtT = startPtT;
1221 do { // iterate through all spans associated with start
1222 SkOpSpanBase* oppSpan = testPtT->span();
1223 if (oppSpan->spanAddsCount() == addCount) {
1224 continue;
1225 }
1226 if (oppSpan->deleted()) {
1227 continue;
1228 }
1229 SkOpSegment* oppSegment = oppSpan->segment();
1230 if (oppSegment == this) {
1231 continue;
1232 }
1233 // find range of spans to consider merging
1234 SkOpSpanBase* oppPrev = oppSpan;
1235 SkOpSpanBase* oppFirst = oppSpan;
1236 while ((oppPrev = oppPrev->prev())) {
1237 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1238 break;
1239 }
1240 if (oppPrev->spanAddsCount() == addCount) {
1241 continue;
1242 }
1243 if (oppPrev->deleted()) {
1244 continue;
1245 }
1246 oppFirst = oppPrev;
1247 }
1248 SkOpSpanBase* oppNext = oppSpan;
1249 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001250 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001251 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1252 break;
1253 }
1254 if (oppNext->spanAddsCount() == addCount) {
1255 continue;
1256 }
1257 if (oppNext->deleted()) {
1258 continue;
1259 }
1260 oppLast = oppNext;
1261 }
1262 if (oppFirst == oppLast) {
1263 continue;
1264 }
1265 SkOpSpanBase* oppTest = oppFirst;
1266 do {
1267 if (oppTest == oppSpan) {
1268 continue;
1269 }
1270 // check to see if the candidate meets specific criteria:
1271 // it contains spans of segments in test's loop but not including 'this'
1272 SkOpPtT* oppStartPtT = oppTest->ptT();
1273 SkOpPtT* oppPtT = oppStartPtT;
1274 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1275 SkOpSegment* oppPtTSegment = oppPtT->segment();
1276 if (oppPtTSegment == this) {
1277 goto tryNextSpan;
1278 }
1279 SkOpPtT* matchPtT = startPtT;
1280 do {
1281 if (matchPtT->segment() == oppPtTSegment) {
1282 goto foundMatch;
1283 }
1284 } while ((matchPtT = matchPtT->next()) != startPtT);
1285 goto tryNextSpan;
1286 foundMatch: // merge oppTest and oppSpan
1287 oppSegment->debugValidate();
caryclark30b9fdd2016-08-31 14:36:29 -07001288 oppTest->mergeMatches(oppSpan);
1289 oppTest->addOpp(oppSpan);
caryclark08bc8482015-04-24 09:08:57 -07001290 oppSegment->debugValidate();
1291 goto checkNextSpan;
1292 }
caryclark55888e42016-07-18 10:01:36 -07001293 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001294 ;
1295 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1296 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001297checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001298 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001299 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001300 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001301 return true;
caryclark08bc8482015-04-24 09:08:57 -07001302}
1303
caryclark55888e42016-07-18 10:01:36 -07001304// adjacent spans may have points close by
Cary Clark28da2832017-03-21 10:30:50 -04001305bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan,
1306 bool* found) const {
caryclark55888e42016-07-18 10:01:36 -07001307 const SkOpPtT* refHead = refSpan->ptT();
1308 const SkOpPtT* checkHead = checkSpan->ptT();
1309// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
caryclark30b9fdd2016-08-31 14:36:29 -07001310 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
caryclark55888e42016-07-18 10:01:36 -07001311#if DEBUG_COINCIDENCE
1312 // verify that no combination of points are close
1313 const SkOpPtT* dBugRef = refHead;
1314 do {
1315 const SkOpPtT* dBugCheck = checkHead;
1316 do {
caryclark30b9fdd2016-08-31 14:36:29 -07001317 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
caryclark55888e42016-07-18 10:01:36 -07001318 dBugCheck = dBugCheck->next();
1319 } while (dBugCheck != checkHead);
1320 dBugRef = dBugRef->next();
1321 } while (dBugRef != refHead);
1322#endif
Cary Clark28da2832017-03-21 10:30:50 -04001323 *found = false;
1324 return true;
caryclark55888e42016-07-18 10:01:36 -07001325 }
1326 // check only unique points
1327 SkScalar distSqBest = SK_ScalarMax;
1328 const SkOpPtT* refBest = nullptr;
1329 const SkOpPtT* checkBest = nullptr;
1330 const SkOpPtT* ref = refHead;
1331 do {
1332 if (ref->deleted()) {
1333 continue;
1334 }
1335 while (ref->ptAlreadySeen(refHead)) {
1336 ref = ref->next();
1337 if (ref == refHead) {
1338 goto doneCheckingDistance;
1339 }
1340 }
1341 const SkOpPtT* check = checkHead;
1342 const SkOpSegment* refSeg = ref->segment();
Cary Clark28da2832017-03-21 10:30:50 -04001343 int escapeHatch = 100000; // defend against infinite loops
caryclark55888e42016-07-18 10:01:36 -07001344 do {
1345 if (check->deleted()) {
1346 continue;
1347 }
1348 while (check->ptAlreadySeen(checkHead)) {
1349 check = check->next();
1350 if (check == checkHead) {
1351 goto nextRef;
1352 }
1353 }
1354 SkScalar distSq = ref->fPt.distanceToSqd(check->fPt);
1355 if (distSqBest > distSq && (refSeg != check->segment()
1356 || !refSeg->ptsDisjoint(*ref, *check))) {
1357 distSqBest = distSq;
1358 refBest = ref;
1359 checkBest = check;
1360 }
Cary Clark28da2832017-03-21 10:30:50 -04001361 if (--escapeHatch <= 0) {
1362 return false;
1363 }
caryclark55888e42016-07-18 10:01:36 -07001364 } while ((check = check->next()) != checkHead);
Cary Clark28da2832017-03-21 10:30:50 -04001365 nextRef:
caryclark55888e42016-07-18 10:01:36 -07001366 ;
1367 } while ((ref = ref->next()) != refHead);
1368doneCheckingDistance:
Cary Clark28da2832017-03-21 10:30:50 -04001369 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001370 checkBest->fPt);
Cary Clark28da2832017-03-21 10:30:50 -04001371 return true;
caryclark55888e42016-07-18 10:01:36 -07001372}
1373
1374// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001375// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
Cary Clark28da2832017-03-21 10:30:50 -04001376bool SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001377 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001378 // release undeleted spans pointing to this seg that are linked to the primary span
1379 SkOpSpanBase* spanBase = &fHead;
caryclark54359292015-03-26 07:52:43 -07001380 do {
caryclark55888e42016-07-18 10:01:36 -07001381 SkOpPtT* ptT = spanBase->ptT();
1382 const SkOpPtT* headPtT = ptT;
1383 while ((ptT = ptT->next()) != headPtT) {
1384 SkOpSpanBase* test = ptT->span();
1385 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1386 && test->ptT() == ptT) {
1387 if (test->final()) {
1388 if (spanBase == &fHead) {
1389 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001390 return true;
caryclark55888e42016-07-18 10:01:36 -07001391 }
1392 spanBase->upCast()->release(ptT);
1393 } else if (test->prev()) {
1394 test->upCast()->release(headPtT);
1395 }
1396 break;
caryclark54359292015-03-26 07:52:43 -07001397 }
reed0dc4dd62015-03-24 13:55:33 -07001398 }
caryclark55888e42016-07-18 10:01:36 -07001399 spanBase = spanBase->upCast()->next();
1400 } while (!spanBase->final());
1401
1402 // This loop looks for adjacent spans which are near by
1403 spanBase = &fHead;
1404 do { // iterate through all spans associated with start
1405 SkOpSpanBase* test = spanBase->upCast()->next();
Cary Clark28da2832017-03-21 10:30:50 -04001406 bool found;
1407 if (!this->spansNearby(spanBase, test, &found)) {
1408 return false;
1409 }
1410 if (found) {
caryclark55888e42016-07-18 10:01:36 -07001411 if (test->final()) {
1412 if (spanBase->prev()) {
1413 test->merge(spanBase->upCast());
1414 } else {
1415 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001416 return true;
caryclark55888e42016-07-18 10:01:36 -07001417 }
1418 } else {
1419 spanBase->merge(test->upCast());
1420 }
1421 }
1422 spanBase = test;
1423 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001424 debugValidate();
Cary Clark28da2832017-03-21 10:30:50 -04001425 return true;
reed0dc4dd62015-03-24 13:55:33 -07001426}
1427
caryclark54359292015-03-26 07:52:43 -07001428bool SkOpSegment::operand() const {
1429 return fContour->operand();
1430}
1431
1432bool SkOpSegment::oppXor() const {
1433 return fContour->oppXor();
1434}
1435
1436bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1437 if (fVerb == SkPath::kLine_Verb) {
1438 return false;
1439 }
1440 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1441 // hits in two places with very different t values.
1442 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1443 // 'controls contained by ends' could avoid this check for common curves
1444 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1445 // on the other hand, the below check is relatively inexpensive
1446 double midT = (t1 + t2) / 2;
1447 SkPoint midPt = this->ptAtT(midT);
1448 double seDistSq = SkTMax(pt1.distanceToSqd(pt2) * 2, FLT_EPSILON * 2);
1449 return midPt.distanceToSqd(pt1) > seDistSq || midPt.distanceToSqd(pt2) > seDistSq;
1450}
1451
1452void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1453 int* maxWinding, int* sumWinding) {
1454 int deltaSum = SpanSign(start, end);
1455 *maxWinding = *sumMiWinding;
1456 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001457 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001458}
1459
1460void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1461 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1462 int* oppSumWinding) {
1463 int deltaSum = SpanSign(start, end);
1464 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001465 if (operand()) {
1466 *maxWinding = *sumSuWinding;
1467 *sumWinding = *sumSuWinding -= deltaSum;
1468 *oppMaxWinding = *sumMiWinding;
1469 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1470 } else {
1471 *maxWinding = *sumMiWinding;
1472 *sumWinding = *sumMiWinding -= deltaSum;
1473 *oppMaxWinding = *sumSuWinding;
1474 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1475 }
bungeman60e0fee2015-08-26 05:15:46 -07001476 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1477 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001478}
1479
caryclarkb36a3cd2016-10-18 07:59:44 -07001480bool SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001481 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001482 do {
caryclark54359292015-03-26 07:52:43 -07001483 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001484 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001485 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001486 continue;
1487 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001488#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001489 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001490#endif
caryclark54359292015-03-26 07:52:43 -07001491 SkOpAngle* baseAngle = fromAngle;
1492 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001493#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001494 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1495 span->debugID());
1496 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001497#endif
caryclarkb36a3cd2016-10-18 07:59:44 -07001498 FAIL_IF(!fromAngle->insert(toAngle));
caryclark54359292015-03-26 07:52:43 -07001499 } else if (!fromAngle) {
1500 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001501 }
caryclark54359292015-03-26 07:52:43 -07001502 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001503 do {
caryclark54359292015-03-26 07:52:43 -07001504 SkOpSpanBase* oSpan = ptT->span();
1505 if (oSpan == span) {
1506 continue;
1507 }
1508 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001509 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001510#if DEBUG_ANGLE
1511 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001512 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1513 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001514 wroteAfterHeader = true;
1515 }
1516#endif
caryclark54359292015-03-26 07:52:43 -07001517 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001518 baseAngle->insert(oAngle);
1519 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001520 }
caryclark54359292015-03-26 07:52:43 -07001521 if (!oSpan->final()) {
1522 oAngle = oSpan->upCast()->toAngle();
1523 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001524#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001525 if (!wroteAfterHeader) {
1526 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1527 span->t(), span->debugID());
1528 wroteAfterHeader = true;
1529 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001530#endif
caryclark54359292015-03-26 07:52:43 -07001531 if (!oAngle->loopContains(baseAngle)) {
1532 baseAngle->insert(oAngle);
1533 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001534 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001535 }
caryclark54359292015-03-26 07:52:43 -07001536 } while ((ptT = ptT->next()) != stopPtT);
1537 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001538 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001539 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001540 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001541 }
halcanary96fcdcc2015-08-27 07:41:13 -07001542 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001543 }
1544#if DEBUG_SORT
1545 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1546#endif
caryclark54359292015-03-26 07:52:43 -07001547 } while (!span->final() && (span = span->upCast()->next()));
caryclarkb36a3cd2016-10-18 07:59:44 -07001548 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +00001549}
1550
caryclark54359292015-03-26 07:52:43 -07001551bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001552 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001553 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001554 const SkOpPtT& startPtT = *start->ptT();
1555 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001556 SkDEBUGCODE(edge->fVerb = fVerb);
1557 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001558 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001559 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001560 if (fVerb == SkPath::kLine_Verb) {
1561 return false;
1562 }
caryclark54359292015-03-26 07:52:43 -07001563 double startT = startPtT.fT;
1564 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001565 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1566 // don't compute midpoints if we already have them
1567 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001568 edge->fLine[1].set(fPts[1]);
1569 return false;
1570 }
1571 if (fVerb == SkPath::kConic_Verb) {
1572 edge->fConic[1].set(fPts[1]);
1573 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001574 return false;
1575 }
1576 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001577 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001578 edge->fCubic[1].set(fPts[1]);
1579 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001580 return false;
1581 }
caryclark1049f122015-04-20 08:31:59 -07001582 edge->fCubic[1].set(fPts[2]);
1583 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001584 return false;
1585 }
1586 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001587 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1588 } else if (fVerb == SkPath::kConic_Verb) {
1589 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1590 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001591 } else {
1592 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001593 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001594 }
1595 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001596}
1597
caryclark27c8eb82015-07-06 11:38:33 -07001598bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001599 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001600 // average t, find mid pt
1601 double midT = (prior->t() + spanBase->t()) / 2;
1602 SkPoint midPt = this->ptAtT(midT);
1603 bool coincident = true;
1604 // if the mid pt is not near either end pt, project perpendicular through opp seg
1605 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1606 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001607 if (priorPtT->span() == ptT->span()) {
1608 return false;
1609 }
caryclark27c8eb82015-07-06 11:38:33 -07001610 coincident = false;
1611 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001612 SkDCurve curvePart;
1613 this->subDivide(prior, spanBase, &curvePart);
1614 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1615 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1616 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1617 SkDCurve oppPart;
1618 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1619 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001620 // measure distance and see if it's small enough to denote coincidence
1621 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001622 if (!between(0, i[0][index], 1)) {
1623 continue;
1624 }
caryclark27c8eb82015-07-06 11:38:33 -07001625 SkDPoint oppPt = i.pt(index);
caryclark30b9fdd2016-08-31 14:36:29 -07001626 if (oppPt.approximatelyDEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001627 // the coincidence can occur at almost any angle
1628 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001629 }
1630 }
1631 }
1632 return coincident;
1633}
1634
Cary Clarkab2d73b2016-12-16 17:17:25 -05001635SkOpSpan* SkOpSegment::undoneSpan() {
1636 SkOpSpan* span = &fHead;
1637 SkOpSpanBase* next;
caryclark54359292015-03-26 07:52:43 -07001638 do {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001639 next = span->next();
caryclark54359292015-03-26 07:52:43 -07001640 if (!span->done()) {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001641 return span;
reed0dc4dd62015-03-24 13:55:33 -07001642 }
Cary Clarkab2d73b2016-12-16 17:17:25 -05001643 } while (!next->final() && (span = next->upCast()));
1644 return nullptr;
reed0dc4dd62015-03-24 13:55:33 -07001645}
1646
caryclark54359292015-03-26 07:52:43 -07001647int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1648 const SkOpSpan* lesser = start->starter(end);
1649 int oppWinding = lesser->oppSum();
1650 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001651 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1652 && oppWinding != SK_MaxS32) {
1653 oppWinding -= oppSpanWinding;
1654 }
1655 return oppWinding;
1656}
1657
1658int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001659 const SkOpSpanBase* startSpan = angle->start();
1660 const SkOpSpanBase* endSpan = angle->end();
1661 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001662}
1663
1664int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001665 const SkOpSpanBase* startSpan = angle->start();
1666 const SkOpSpanBase* endSpan = angle->end();
1667 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001668}
1669
caryclark624637c2015-05-11 07:21:27 -07001670int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1671 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001672 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001673 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001674 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001675 }
1676 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001677 return winding;
1678 }
caryclark54359292015-03-26 07:52:43 -07001679 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001680 if (winding && UseInnerWinding(winding - spanWinding, winding)
1681 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001682 winding -= spanWinding;
1683 }
1684 return winding;
1685}
1686
caryclark624637c2015-05-11 07:21:27 -07001687int SkOpSegment::updateWinding(SkOpAngle* angle) {
1688 SkOpSpanBase* startSpan = angle->start();
1689 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001690 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001691}
1692
caryclark624637c2015-05-11 07:21:27 -07001693int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1694 SkOpSpanBase* startSpan = angle->start();
1695 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001696 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001697}
1698
1699// OPTIMIZATION: does the following also work, and is it any faster?
1700// return outerWinding * innerWinding > 0
1701// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1702bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1703 SkASSERT(outerWinding != SK_MaxS32);
1704 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001705 int absOut = SkTAbs(outerWinding);
1706 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001707 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1708 return result;
1709}
1710
caryclark@google.com07393ca2013-04-08 11:47:37 +00001711int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001712 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1713 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001714}