blob: 451a155c58a1bca83f0a7a2d60ce5c728830f47c [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
13/*
14After computing raw intersections, post process all segments to:
15- find small collections of points that can be collapsed to a single point
16- find missing intersections to resolve differences caused by different algorithms
17
18Consider segments containing tiny or small intervals. Consider coincident segments
19because coincidence finds intersections through distance measurement that non-coincident
20intersection tests cannot.
21 */
caryclark@google.com07393ca2013-04-08 11:47:37 +000022
23#define F (false) // discard the edge
24#define T (true) // keep the edge
25
26static const bool gUnaryActiveEdge[2][2] = {
27// from=0 from=1
28// to=0,1 to=0,1
29 {F, T}, {T, F},
30};
31
caryclark54359292015-03-26 07:52:43 -070032static const bool gActiveEdge[kXOR_SkPathOp + 1][2][2][2][2] = {
caryclark@google.com07393ca2013-04-08 11:47:37 +000033// miFrom=0 miFrom=1
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000034// miTo=0 miTo=1 miTo=0 miTo=1
35// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
caryclark@google.com07393ca2013-04-08 11:47:37 +000036// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
37 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
38 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
39 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
40 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su
41};
42
43#undef F
44#undef T
45
caryclark54359292015-03-26 07:52:43 -070046SkOpAngle* SkOpSegment::activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -070047 SkOpSpanBase** endPtr, bool* done) {
48 if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done)) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000049 return result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000050 }
caryclarkbca19f72015-05-13 08:23:48 -070051 if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done)) {
caryclark54359292015-03-26 07:52:43 -070052 return result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000053 }
halcanary96fcdcc2015-08-27 07:41:13 -070054 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +000055}
56
caryclark54359292015-03-26 07:52:43 -070057SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -070058 SkOpSpanBase** endPtr, bool* done) {
caryclark54359292015-03-26 07:52:43 -070059 SkOpSpan* upSpan = start->upCastable();
60 if (upSpan) {
61 if (upSpan->windValue() || upSpan->oppValue()) {
62 SkOpSpanBase* next = upSpan->next();
63 if (!*endPtr) {
64 *startPtr = start;
65 *endPtr = next;
caryclark@google.com07393ca2013-04-08 11:47:37 +000066 }
caryclark54359292015-03-26 07:52:43 -070067 if (!upSpan->done()) {
68 if (upSpan->windSum() != SK_MinS32) {
69 return spanToAngle(start, next);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000070 }
71 *done = false;
72 }
73 } else {
caryclark54359292015-03-26 07:52:43 -070074 SkASSERT(upSpan->done());
caryclark@google.com07393ca2013-04-08 11:47:37 +000075 }
76 }
caryclark54359292015-03-26 07:52:43 -070077 SkOpSpan* downSpan = start->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +000078 // edge leading into junction
caryclark54359292015-03-26 07:52:43 -070079 if (downSpan) {
80 if (downSpan->windValue() || downSpan->oppValue()) {
81 if (!*endPtr) {
82 *startPtr = start;
83 *endPtr = downSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +000084 }
caryclark54359292015-03-26 07:52:43 -070085 if (!downSpan->done()) {
86 if (downSpan->windSum() != SK_MinS32) {
87 return spanToAngle(start, downSpan);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000088 }
89 *done = false;
90 }
91 } else {
caryclark54359292015-03-26 07:52:43 -070092 SkASSERT(downSpan->done());
caryclark@google.com07393ca2013-04-08 11:47:37 +000093 }
94 }
halcanary96fcdcc2015-08-27 07:41:13 -070095 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000096}
97
caryclark54359292015-03-26 07:52:43 -070098SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -070099 SkOpSpanBase** endPtr, bool* done) {
caryclark54359292015-03-26 07:52:43 -0700100 SkOpPtT* oPtT = start->ptT()->next();
101 SkOpSegment* other = oPtT->segment();
102 SkOpSpanBase* oSpan = oPtT->span();
caryclarkbca19f72015-05-13 08:23:48 -0700103 return other->activeAngleInner(oSpan, startPtr, endPtr, done);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000104}
105
caryclark54359292015-03-26 07:52:43 -0700106bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xorSuMask,
107 SkPathOp op) {
108 int sumMiWinding = this->updateWinding(end, start);
109 int sumSuWinding = this->updateOppWinding(end, start);
caryclark65f55312014-11-13 06:58:52 -0800110#if DEBUG_LIMIT_WIND_SUM
111 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM);
112 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM);
113#endif
caryclark54359292015-03-26 07:52:43 -0700114 if (this->operand()) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000115 SkTSwap<int>(sumMiWinding, sumSuWinding);
116 }
caryclark54359292015-03-26 07:52:43 -0700117 return this->activeOp(xorMiMask, xorSuMask, start, end, op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000118}
119
caryclark54359292015-03-26 07:52:43 -0700120bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end,
121 SkPathOp op, int* sumMiWinding, int* sumSuWinding) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000122 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
caryclark54359292015-03-26 07:52:43 -0700123 this->setUpWindings(start, end, sumMiWinding, sumSuWinding,
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000124 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000125 bool miFrom;
126 bool miTo;
127 bool suFrom;
128 bool suTo;
129 if (operand()) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000130 miFrom = (oppMaxWinding & xorMiMask) != 0;
131 miTo = (oppSumWinding & xorMiMask) != 0;
132 suFrom = (maxWinding & xorSuMask) != 0;
133 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000134 } else {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000135 miFrom = (maxWinding & xorMiMask) != 0;
136 miTo = (sumWinding & xorMiMask) != 0;
137 suFrom = (oppMaxWinding & xorSuMask) != 0;
138 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000139 }
140 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
141#if DEBUG_ACTIVE_OP
caryclarkdac1d172014-06-17 05:15:38 -0700142 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 -0700143 __FUNCTION__, debugID(), start->t(), end->t(),
caryclark@google.com570863f2013-09-16 15:55:01 +0000144 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000145#endif
146 return result;
147}
148
caryclark54359292015-03-26 07:52:43 -0700149bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
150 int sumWinding = updateWinding(end, start);
151 return activeWinding(start, end, &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000152}
153
caryclark54359292015-03-26 07:52:43 -0700154bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000155 int maxWinding;
caryclark54359292015-03-26 07:52:43 -0700156 setUpWinding(start, end, &maxWinding, sumWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000157 bool from = maxWinding != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000158 bool to = *sumWinding != 0;
159 bool result = gUnaryActiveEdge[from][to];
160 return result;
161}
162
caryclarkef784fb2015-10-30 12:03:06 -0700163bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
164 SkPathWriter* path) const {
caryclark025b11e2016-08-25 05:21:14 -0700165 FAIL_IF(start->starter(end)->alreadyAdded());
caryclarkeed356d2016-09-14 07:18:20 -0700166 SkDCurveSweep curvePart;
167 start->segment()->subDivide(start, end, &curvePart.fCurve);
168 curvePart.setCurveHullSweep(fVerb);
169 SkPath::Verb verb = curvePart.isCurve() ? fVerb : SkPath::kLine_Verb;
170 path->deferredMove(start->ptT());
171 switch (verb) {
172 case SkPath::kLine_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700173 FAIL_IF(!path->deferredLine(end->ptT()));
caryclarkeed356d2016-09-14 07:18:20 -0700174 break;
175 case SkPath::kQuad_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700176 path->quadTo(curvePart.fCurve.fQuad[1].asSkPoint(), end->ptT());
caryclarkeed356d2016-09-14 07:18:20 -0700177 break;
178 case SkPath::kConic_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700179 path->conicTo(curvePart.fCurve.fConic[1].asSkPoint(), end->ptT(),
caryclarkeed356d2016-09-14 07:18:20 -0700180 curvePart.fCurve.fConic.fWeight);
181 break;
182 case SkPath::kCubic_Verb:
caryclarka35ab3e2016-10-20 08:32:18 -0700183 path->cubicTo(curvePart.fCurve.fCubic[1].asSkPoint(),
184 curvePart.fCurve.fCubic[2].asSkPoint(), end->ptT());
caryclarkeed356d2016-09-14 07:18:20 -0700185 break;
186 default:
187 SkASSERT(0);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000188 }
caryclarkef784fb2015-10-30 12:03:06 -0700189 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000190}
191
caryclark55888e42016-07-18 10:01:36 -0700192const SkOpPtT* SkOpSegment::existing(double t, const SkOpSegment* opp) const {
193 const SkOpSpanBase* test = &fHead;
194 const SkOpPtT* testPtT;
195 SkPoint pt = this->ptAtT(t);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000196 do {
caryclark55888e42016-07-18 10:01:36 -0700197 testPtT = test->ptT();
198 if (testPtT->fT == t) {
reed0dc4dd62015-03-24 13:55:33 -0700199 break;
200 }
caryclarkef4f32a2016-08-24 09:24:18 -0700201 if (!this->match(testPtT, this, t, pt)) {
caryclark55888e42016-07-18 10:01:36 -0700202 if (t < testPtT->fT) {
203 return nullptr;
204 }
205 continue;
206 }
207 if (!opp) {
208 return testPtT;
209 }
210 const SkOpPtT* loop = testPtT->next();
211 while (loop != testPtT) {
212 if (loop->segment() == this && loop->fT == t && loop->fPt == pt) {
213 goto foundMatch;
214 }
215 loop = loop->next();
216 }
217 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700218 } while ((test = test->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -0700219foundMatch:
220 return opp && !test->contains(opp) ? nullptr : testPtT;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000221}
222
caryclark55888e42016-07-18 10:01:36 -0700223// break the span so that the coincident part does not change the angle of the remainder
224bool SkOpSegment::addExpanded(double newT, const SkOpSpanBase* test, bool* startOver) {
225 if (this->contains(newT)) {
226 return true;
227 }
caryclark29b25632016-08-25 11:27:17 -0700228 this->globalState()->resetAllocatedOpSpan();
caryclarka35ab3e2016-10-20 08:32:18 -0700229 FAIL_IF(!between(0, newT, 1));
caryclark29b25632016-08-25 11:27:17 -0700230 SkOpPtT* newPtT = this->addT(newT);
231 *startOver |= this->globalState()->allocatedOpSpan();
caryclark55888e42016-07-18 10:01:36 -0700232 if (!newPtT) {
233 return false;
234 }
235 newPtT->fPt = this->ptAtT(newT);
caryclark29b25632016-08-25 11:27:17 -0700236 SkOpPtT* oppPrev = test->ptT()->oppPrev(newPtT);
237 if (oppPrev) {
caryclark8016b262016-09-06 05:59:47 -0700238 // const cast away to change linked list; pt/t values stays unchanged
caryclark29b25632016-08-25 11:27:17 -0700239 SkOpSpanBase* writableTest = const_cast<SkOpSpanBase*>(test);
caryclark30b9fdd2016-08-31 14:36:29 -0700240 writableTest->mergeMatches(newPtT->span());
caryclark29b25632016-08-25 11:27:17 -0700241 writableTest->ptT()->addOpp(newPtT, oppPrev);
caryclark55888e42016-07-18 10:01:36 -0700242 writableTest->checkForCollapsedCoincidence();
243 }
244 return true;
245}
246
247// Please keep this in sync with debugAddT()
Cary Clark73e597d2017-04-18 12:08:58 -0400248SkOpPtT* SkOpSegment::addT(double t, const SkPoint& pt) {
reed0dc4dd62015-03-24 13:55:33 -0700249 debugValidate();
caryclark29b25632016-08-25 11:27:17 -0700250 SkOpSpanBase* spanBase = &fHead;
caryclark54359292015-03-26 07:52:43 -0700251 do {
caryclark29b25632016-08-25 11:27:17 -0700252 SkOpPtT* result = spanBase->ptT();
caryclark27c015d2016-09-23 05:47:20 -0700253 if (t == result->fT || (!zero_or_one(t) && this->match(result, this, t, pt))) {
caryclark29b25632016-08-25 11:27:17 -0700254 spanBase->bumpSpanAdds();
caryclarkef4f32a2016-08-24 09:24:18 -0700255 return result;
reed0dc4dd62015-03-24 13:55:33 -0700256 }
caryclark54359292015-03-26 07:52:43 -0700257 if (t < result->fT) {
258 SkOpSpan* prev = result->span()->prev();
caryclark29b25632016-08-25 11:27:17 -0700259 FAIL_WITH_NULL_IF(!prev);
260 // marks in global state that new op span has been allocated
261 SkOpSpan* span = this->insert(prev);
caryclark54359292015-03-26 07:52:43 -0700262 span->init(this, prev, t, pt);
263 this->debugValidate();
264#if DEBUG_ADD_T
265 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
266 span->segment()->debugID(), span->debugID());
267#endif
caryclark08bc8482015-04-24 09:08:57 -0700268 span->bumpSpanAdds();
caryclark54359292015-03-26 07:52:43 -0700269 return span->ptT();
270 }
caryclark29b25632016-08-25 11:27:17 -0700271 FAIL_WITH_NULL_IF(spanBase == &fTail);
272 } while ((spanBase = spanBase->upCast()->next()));
caryclark54359292015-03-26 07:52:43 -0700273 SkASSERT(0);
caryclark29b25632016-08-25 11:27:17 -0700274 return nullptr; // we never get here, but need this to satisfy compiler
caryclark54359292015-03-26 07:52:43 -0700275}
276
Cary Clark73e597d2017-04-18 12:08:58 -0400277SkOpPtT* SkOpSegment::addT(double t) {
278 return addT(t, this->ptAtT(t));
279}
280
caryclark55888e42016-07-18 10:01:36 -0700281void SkOpSegment::calcAngles() {
caryclark54359292015-03-26 07:52:43 -0700282 bool activePrior = !fHead.isCanceled();
283 if (activePrior && !fHead.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700284 addStartSpan();
reed0dc4dd62015-03-24 13:55:33 -0700285 }
caryclark54359292015-03-26 07:52:43 -0700286 SkOpSpan* prior = &fHead;
287 SkOpSpanBase* spanBase = fHead.next();
288 while (spanBase != &fTail) {
289 if (activePrior) {
Herb Derbyecc364c2017-04-19 15:09:48 -0400290 SkOpAngle* priorAngle = this->globalState()->allocator()->make<SkOpAngle>();
caryclark54359292015-03-26 07:52:43 -0700291 priorAngle->set(spanBase, prior);
292 spanBase->setFromAngle(priorAngle);
reed0dc4dd62015-03-24 13:55:33 -0700293 }
caryclark54359292015-03-26 07:52:43 -0700294 SkOpSpan* span = spanBase->upCast();
295 bool active = !span->isCanceled();
296 SkOpSpanBase* next = span->next();
297 if (active) {
Herb Derbyecc364c2017-04-19 15:09:48 -0400298 SkOpAngle* angle = this->globalState()->allocator()->make<SkOpAngle>();
caryclark54359292015-03-26 07:52:43 -0700299 angle->set(span, next);
300 span->setToAngle(angle);
reed0dc4dd62015-03-24 13:55:33 -0700301 }
reed0dc4dd62015-03-24 13:55:33 -0700302 activePrior = active;
caryclark54359292015-03-26 07:52:43 -0700303 prior = span;
304 spanBase = next;
reed0dc4dd62015-03-24 13:55:33 -0700305 }
caryclark54359292015-03-26 07:52:43 -0700306 if (activePrior && !fTail.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700307 addEndSpan();
reed0dc4dd62015-03-24 13:55:33 -0700308 }
reed0dc4dd62015-03-24 13:55:33 -0700309}
310
caryclark55888e42016-07-18 10:01:36 -0700311// Please keep this in sync with debugClearAll()
312void SkOpSegment::clearAll() {
313 SkOpSpan* span = &fHead;
314 do {
315 this->clearOne(span);
316 } while ((span = span->next()->upCastable()));
317 this->globalState()->coincidence()->release(this);
318}
319
320// Please keep this in sync with debugClearOne()
321void SkOpSegment::clearOne(SkOpSpan* span) {
322 span->setWindValue(0);
323 span->setOppValue(0);
324 this->markDone(span);
325}
326
caryclark30b9fdd2016-08-31 14:36:29 -0700327bool SkOpSegment::collapsed(double s, double e) const {
328 const SkOpSpanBase* span = &fHead;
329 do {
330 if (span->collapsed(s, e)) {
331 return true;
332 }
333 } while (span->upCastable() && (span = span->upCast()->next()));
334 return false;
335}
336
caryclark@google.com570863f2013-09-16 15:55:01 +0000337void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
338 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700339 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000340 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
341 int sumSuWinding;
342 bool binary = includeType >= SkOpAngle::kBinarySingle;
343 if (binary) {
344 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
345 if (baseSegment->operand()) {
346 SkTSwap<int>(sumMiWinding, sumSuWinding);
347 }
348 }
349 SkOpSegment* nextSegment = nextAngle->segment();
350 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700351 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000352 if (binary) {
353 int oppMaxWinding, oppSumWinding;
354 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
355 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
356 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000357 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000358 } else {
359 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
360 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000361 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000362 }
363 nextAngle->setLastMarked(last);
364}
365
caryclark624637c2015-05-11 07:21:27 -0700366void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
caryclark@google.com570863f2013-09-16 15:55:01 +0000367 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700368 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000369 int sumMiWinding = baseSegment->updateWinding(baseAngle);
370 int sumSuWinding;
371 bool binary = includeType >= SkOpAngle::kBinarySingle;
372 if (binary) {
373 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
374 if (baseSegment->operand()) {
375 SkTSwap<int>(sumMiWinding, sumSuWinding);
376 }
377 }
378 SkOpSegment* nextSegment = nextAngle->segment();
379 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700380 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000381 if (binary) {
382 int oppMaxWinding, oppSumWinding;
383 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
384 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
385 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000386 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000387 } else {
388 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
389 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000390 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000391 }
392 nextAngle->setLastMarked(last);
393}
394
caryclark54359292015-03-26 07:52:43 -0700395// at this point, the span is already ordered, or unorderable
396int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
397 SkOpAngle::IncludeType includeType) {
398 SkASSERT(includeType != SkOpAngle::kUnaryXor);
399 SkOpAngle* firstAngle = this->spanToAngle(end, start);
halcanary96fcdcc2015-08-27 07:41:13 -0700400 if (nullptr == firstAngle || nullptr == firstAngle->next()) {
caryclark54359292015-03-26 07:52:43 -0700401 return SK_NaN32;
402 }
403 // if all angles have a computed winding,
404 // or if no adjacent angles are orderable,
405 // or if adjacent orderable angles have no computed winding,
406 // there's nothing to do
407 // if two orderable angles are adjacent, and both are next to orderable angles,
408 // and one has winding computed, transfer to the other
halcanary96fcdcc2015-08-27 07:41:13 -0700409 SkOpAngle* baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700410 bool tryReverse = false;
411 // look for counterclockwise transfers
412 SkOpAngle* angle = firstAngle->previous();
413 SkOpAngle* next = angle->next();
414 firstAngle = next;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000415 do {
caryclark54359292015-03-26 07:52:43 -0700416 SkOpAngle* prior = angle;
417 angle = next;
418 next = angle->next();
419 SkASSERT(prior->next() == angle);
420 SkASSERT(angle->next() == next);
421 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700422 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700423 continue;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000424 }
caryclark54359292015-03-26 07:52:43 -0700425 int testWinding = angle->starter()->windSum();
426 if (SK_MinS32 != testWinding) {
427 baseAngle = angle;
428 tryReverse = true;
429 continue;
reed0dc4dd62015-03-24 13:55:33 -0700430 }
caryclark54359292015-03-26 07:52:43 -0700431 if (baseAngle) {
432 ComputeOneSum(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700433 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
caryclark54359292015-03-26 07:52:43 -0700434 }
435 } while (next != firstAngle);
436 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
437 firstAngle = baseAngle;
438 tryReverse = true;
439 }
440 if (tryReverse) {
halcanary96fcdcc2015-08-27 07:41:13 -0700441 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700442 SkOpAngle* prior = firstAngle;
443 do {
444 angle = prior;
445 prior = angle->previous();
446 SkASSERT(prior->next() == angle);
447 next = angle->next();
448 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700449 baseAngle = nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700450 continue;
451 }
caryclark54359292015-03-26 07:52:43 -0700452 int testWinding = angle->starter()->windSum();
453 if (SK_MinS32 != testWinding) {
454 baseAngle = angle;
455 continue;
reed0dc4dd62015-03-24 13:55:33 -0700456 }
caryclark54359292015-03-26 07:52:43 -0700457 if (baseAngle) {
458 ComputeOneSumReverse(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700459 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700460 }
caryclark54359292015-03-26 07:52:43 -0700461 } while (prior != firstAngle);
reed0dc4dd62015-03-24 13:55:33 -0700462 }
caryclark54359292015-03-26 07:52:43 -0700463 return start->starter(end)->windSum();
reed0dc4dd62015-03-24 13:55:33 -0700464}
465
caryclark55888e42016-07-18 10:01:36 -0700466bool SkOpSegment::contains(double newT) const {
467 const SkOpSpanBase* spanBase = &fHead;
468 do {
469 if (spanBase->ptT()->contains(this, newT)) {
470 return true;
471 }
472 if (spanBase == &fTail) {
473 break;
474 }
475 spanBase = spanBase->upCast()->next();
476 } while (true);
477 return false;
478}
479
mtklein18300a32016-03-16 13:53:35 -0700480void SkOpSegment::release(const SkOpSpan* span) {
caryclark54359292015-03-26 07:52:43 -0700481 if (span->done()) {
caryclark08bc8482015-04-24 09:08:57 -0700482 --fDoneCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000483 }
caryclark08bc8482015-04-24 09:08:57 -0700484 --fCount;
caryclark15976282016-07-21 05:48:43 -0700485 SkOPASSERT(fCount >= fDoneCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000486}
487
Cary Clarke47ae292016-10-05 08:51:39 -0400488#if DEBUG_ANGLE
489// called only by debugCheckNearCoincidence
caryclark26ad22a2015-10-16 09:03:38 -0700490double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
caryclark54359292015-03-26 07:52:43 -0700491 SkDPoint testPt = this->dPtAtT(t);
492 SkDLine testPerp = {{ testPt, testPt }};
493 SkDVector slope = this->dSlopeAtT(t);
494 testPerp[1].fX += slope.fY;
495 testPerp[1].fY -= slope.fX;
496 SkIntersections i;
caryclark26ad22a2015-10-16 09:03:38 -0700497 const SkOpSegment* oppSegment = oppAngle->segment();
caryclark1049f122015-04-20 08:31:59 -0700498 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
caryclark54359292015-03-26 07:52:43 -0700499 double closestDistSq = SK_ScalarInfinity;
500 for (int index = 0; index < i.used(); ++index) {
501 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000502 continue;
503 }
caryclark54359292015-03-26 07:52:43 -0700504 double testDistSq = testPt.distanceSquared(i.pt(index));
505 if (closestDistSq > testDistSq) {
506 closestDistSq = testDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000507 }
508 }
caryclark54359292015-03-26 07:52:43 -0700509 return closestDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000510}
Cary Clarke47ae292016-10-05 08:51:39 -0400511#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000512
caryclark@google.com07393ca2013-04-08 11:47:37 +0000513/*
514 The M and S variable name parts stand for the operators.
515 Mi stands for Minuend (see wiki subtraction, analogous to difference)
516 Su stands for Subtrahend
517 The Opp variable name part designates that the value is for the Opposite operator.
518 Opposite values result from combining coincident spans.
519 */
caryclark54359292015-03-26 07:52:43 -0700520SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
521 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) {
522 SkOpSpanBase* start = *nextStart;
523 SkOpSpanBase* end = *nextEnd;
524 SkASSERT(start != end);
525 int step = start->step(end);
526 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
527 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000528 // mark the smaller of startIndex, endIndex done, and all adjacent
529 // spans with the same T value (but not 'other' spans)
530#if DEBUG_WINDING
531 SkDebugf("%s simple\n", __FUNCTION__);
532#endif
caryclark54359292015-03-26 07:52:43 -0700533 SkOpSpan* startSpan = start->starter(end);
534 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700535 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000536 }
caryclark54359292015-03-26 07:52:43 -0700537 markDone(startSpan);
538 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000539 return other;
540 }
caryclark54359292015-03-26 07:52:43 -0700541 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
542 SkASSERT(endNear == end); // is this ever not end?
543 SkASSERT(endNear);
544 SkASSERT(start != endNear);
545 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000546 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700547 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
caryclark@google.com570863f2013-09-16 15:55:01 +0000548 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000549 if (!sortable) {
550 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700551 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700552 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000553 }
caryclark54359292015-03-26 07:52:43 -0700554 SkOpAngle* angle = this->spanToAngle(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000555 if (angle->unorderable()) {
556 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700557 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700558 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000559 }
560#if DEBUG_SORT
561 SkDebugf("%s\n", __FUNCTION__);
562 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000563#endif
caryclark54359292015-03-26 07:52:43 -0700564 int sumMiWinding = updateWinding(end, start);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000565 if (sumMiWinding == SK_MinS32) {
566 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700567 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700568 return nullptr;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000569 }
caryclark54359292015-03-26 07:52:43 -0700570 int sumSuWinding = updateOppWinding(end, start);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000571 if (operand()) {
572 SkTSwap<int>(sumMiWinding, sumSuWinding);
573 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000574 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700575 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000576 bool foundDone = false;
577 // iterate through the angle, and compute everyone's winding
578 SkOpSegment* nextSegment;
579 int activeCount = 0;
580 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000581 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000582 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000583 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000584 if (activeAngle) {
585 ++activeCount;
586 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000587 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +0000588 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000589 }
590 }
591 if (nextSegment->done()) {
592 continue;
593 }
reed0dc4dd62015-03-24 13:55:33 -0700594 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700595 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700596 }
caryclark54359292015-03-26 07:52:43 -0700597 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000598 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000599 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000600 *chase->append() = last;
601#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700602 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
603 last->segment()->debugID(), last->debugID());
604 if (!last->final()) {
605 SkDebugf(" windSum=%d", last->upCast()->windSum());
606 }
607 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000608#endif
609 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000610 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700611 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000612 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700613 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000614 }
615 *nextStart = foundAngle->start();
616 *nextEnd = foundAngle->end();
617 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000618#if DEBUG_WINDING
619 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
620 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
621 #endif
622 return nextSegment;
623}
624
caryclark54359292015-03-26 07:52:43 -0700625SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
626 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
627 SkOpSpanBase* start = *nextStart;
628 SkOpSpanBase* end = *nextEnd;
629 SkASSERT(start != end);
630 int step = start->step(end);
631 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
632 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000633 // mark the smaller of startIndex, endIndex done, and all adjacent
634 // spans with the same T value (but not 'other' spans)
635#if DEBUG_WINDING
636 SkDebugf("%s simple\n", __FUNCTION__);
637#endif
caryclark54359292015-03-26 07:52:43 -0700638 SkOpSpan* startSpan = start->starter(end);
639 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700640 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000641 }
caryclark54359292015-03-26 07:52:43 -0700642 markDone(startSpan);
643 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000644 return other;
645 }
caryclark54359292015-03-26 07:52:43 -0700646 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
647 SkASSERT(endNear == end); // is this ever not end?
648 SkASSERT(endNear);
649 SkASSERT(start != endNear);
650 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000651 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700652 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000653 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000654 if (!sortable) {
655 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700656 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700657 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000658 }
caryclark54359292015-03-26 07:52:43 -0700659 SkOpAngle* angle = this->spanToAngle(end, start);
660 if (angle->unorderable()) {
661 *unsortable = true;
662 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700663 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700664 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000665#if DEBUG_SORT
666 SkDebugf("%s\n", __FUNCTION__);
667 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000668#endif
caryclark54359292015-03-26 07:52:43 -0700669 int sumWinding = updateWinding(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000670 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700671 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000672 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700673 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000674 SkOpSegment* nextSegment;
675 int activeCount = 0;
676 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000677 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000678 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000679 &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000680 if (activeAngle) {
681 ++activeCount;
682 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000683 foundAngle = nextAngle;
684 foundDone = nextSegment->done(nextAngle);
685 }
686 }
687 if (nextSegment->done()) {
688 continue;
689 }
reed0dc4dd62015-03-24 13:55:33 -0700690 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700691 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700692 }
caryclark54359292015-03-26 07:52:43 -0700693 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000694 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000695 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000696 *chase->append() = last;
697#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700698 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
699 last->segment()->debugID(), last->debugID());
700 if (!last->final()) {
701 SkDebugf(" windSum=%d", last->upCast()->windSum());
702 }
703 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000704#endif
705 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000706 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700707 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000708 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700709 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000710 }
711 *nextStart = foundAngle->start();
712 *nextEnd = foundAngle->end();
713 nextSegment = foundAngle->segment();
714#if DEBUG_WINDING
715 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
716 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
717 #endif
718 return nextSegment;
719}
720
caryclark54359292015-03-26 07:52:43 -0700721SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
722 bool* unsortable) {
723 SkOpSpanBase* start = *nextStart;
724 SkOpSpanBase* end = *nextEnd;
725 SkASSERT(start != end);
726 int step = start->step(end);
727 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
728 if (other) {
729 // mark the smaller of startIndex, endIndex done, and all adjacent
730 // spans with the same T value (but not 'other' spans)
caryclark@google.com07393ca2013-04-08 11:47:37 +0000731#if DEBUG_WINDING
732 SkDebugf("%s simple\n", __FUNCTION__);
733#endif
caryclark54359292015-03-26 07:52:43 -0700734 SkOpSpan* startSpan = start->starter(end);
735 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700736 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000737 }
caryclark54359292015-03-26 07:52:43 -0700738 markDone(startSpan);
739 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000740 return other;
741 }
caryclark54359292015-03-26 07:52:43 -0700742 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
743 : (*nextStart)->prev());
744 SkASSERT(endNear == end); // is this ever not end?
745 SkASSERT(endNear);
746 SkASSERT(start != endNear);
747 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
748 SkOpAngle* angle = this->spanToAngle(end, start);
caryclark27c8eb82015-07-06 11:38:33 -0700749 if (!angle || angle->unorderable()) {
caryclark54359292015-03-26 07:52:43 -0700750 *unsortable = true;
751 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700752 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700753 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000754#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000755 SkDebugf("%s\n", __FUNCTION__);
756 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000757#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000758 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700759 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000760 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700761 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000762 SkOpSegment* nextSegment;
763 int activeCount = 0;
764 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000765 nextSegment = nextAngle->segment();
766 ++activeCount;
767 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000768 foundAngle = nextAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000769 if (!(foundDone = nextSegment->done(nextAngle))) {
770 break;
771 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000772 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000773 nextAngle = nextAngle->next();
774 } while (nextAngle != angle);
caryclark54359292015-03-26 07:52:43 -0700775 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000776 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700777 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000778 }
779 *nextStart = foundAngle->start();
780 *nextEnd = foundAngle->end();
781 nextSegment = foundAngle->segment();
782#if DEBUG_WINDING
783 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
784 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
785 #endif
786 return nextSegment;
787}
788
caryclark54359292015-03-26 07:52:43 -0700789SkOpGlobalState* SkOpSegment::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700790 return contour()->globalState();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000791}
792
caryclark1049f122015-04-20 08:31:59 -0700793void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
caryclark54359292015-03-26 07:52:43 -0700794 fContour = contour;
halcanary96fcdcc2015-08-27 07:41:13 -0700795 fNext = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000796 fPts = pts;
caryclark1049f122015-04-20 08:31:59 -0700797 fWeight = weight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000798 fVerb = verb;
caryclark54359292015-03-26 07:52:43 -0700799 fCount = 0;
800 fDoneCount = 0;
801 fVisited = false;
802 SkOpSpan* zeroSpan = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700803 zeroSpan->init(this, nullptr, 0, fPts[0]);
caryclark54359292015-03-26 07:52:43 -0700804 SkOpSpanBase* oneSpan = &fTail;
805 zeroSpan->setNext(oneSpan);
806 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
caryclark1049f122015-04-20 08:31:59 -0700807 SkDEBUGCODE(fID = globalState()->nextSegmentID());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000808}
809
caryclark54359292015-03-26 07:52:43 -0700810bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
811 SkDPoint cPt = this->dPtAtT(t);
caryclark1049f122015-04-20 08:31:59 -0700812 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
caryclark54359292015-03-26 07:52:43 -0700813 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
814 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -0700815 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
caryclark54359292015-03-26 07:52:43 -0700816 int used = i.used();
817 for (int index = 0; index < used; ++index) {
818 if (cPt.roughlyEqual(i.pt(index))) {
reed0dc4dd62015-03-24 13:55:33 -0700819 return true;
820 }
caryclark54359292015-03-26 07:52:43 -0700821 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000822 return false;
823}
824
caryclark54359292015-03-26 07:52:43 -0700825bool SkOpSegment::isXor() const {
826 return fContour->isXor();
827}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000828
caryclark5b5ddd72015-05-18 05:12:56 -0700829void SkOpSegment::markAllDone() {
830 SkOpSpan* span = this->head();
831 do {
832 this->markDone(span);
833 } while ((span = span->next()->upCastable()));
834}
835
caryclark54359292015-03-26 07:52:43 -0700836SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) {
837 int step = start->step(end);
838 SkOpSpan* minSpan = start->starter(end);
839 markDone(minSpan);
halcanary96fcdcc2015-08-27 07:41:13 -0700840 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000841 SkOpSegment* other = this;
Cary Clark918fb1f2016-11-15 13:22:25 -0500842 SkOpSpan* priorDone = nullptr;
843 SkOpSpan* lastDone = nullptr;
caryclark54359292015-03-26 07:52:43 -0700844 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000845 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -0700846 SkASSERT(!last);
847 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000848 }
Cary Clark918fb1f2016-11-15 13:22:25 -0500849 if (lastDone == minSpan || priorDone == minSpan) {
850 return nullptr;
851 }
caryclark54359292015-03-26 07:52:43 -0700852 other->markDone(minSpan);
Cary Clark918fb1f2016-11-15 13:22:25 -0500853 priorDone = lastDone;
854 lastDone = minSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000855 }
856 return last;
857}
858
caryclark54359292015-03-26 07:52:43 -0700859bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
860 SkOpSpanBase** lastPtr) {
861 SkOpSpan* spanStart = start->starter(end);
862 int step = start->step(end);
863 bool success = markWinding(spanStart, winding);
halcanary96fcdcc2015-08-27 07:41:13 -0700864 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000865 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700866 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
867 if (spanStart->windSum() != SK_MinS32) {
caryclarkb36a3cd2016-10-18 07:59:44 -0700868// SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive?
caryclarkdac1d172014-06-17 05:15:38 -0700869 SkASSERT(!last);
870 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000871 }
caryclark54359292015-03-26 07:52:43 -0700872 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000873 }
caryclark65f55312014-11-13 06:58:52 -0800874 if (lastPtr) {
875 *lastPtr = last;
876 }
877 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000878}
879
caryclark54359292015-03-26 07:52:43 -0700880bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
881 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
882 SkOpSpan* spanStart = start->starter(end);
883 int step = start->step(end);
884 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700885 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000886 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700887 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
888 if (spanStart->windSum() != SK_MinS32) {
889 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700890 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700891 this->globalState()->setWindingFailed();
892 return false;
caryclarkdac1d172014-06-17 05:15:38 -0700893 }
caryclark54359292015-03-26 07:52:43 -0700894 } else {
895 SkASSERT(spanStart->windSum() == oppWinding);
896 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700897 }
898 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700899 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000900 }
caryclark54359292015-03-26 07:52:43 -0700901 if (this->operand() == other->operand()) {
902 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700903 } else {
caryclark54359292015-03-26 07:52:43 -0700904 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700905 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000906 }
caryclark65f55312014-11-13 06:58:52 -0800907 if (lastPtr) {
908 *lastPtr = last;
909 }
910 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000911}
912
caryclark54359292015-03-26 07:52:43 -0700913SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000914 SkASSERT(angle->segment() == this);
915 if (UseInnerWinding(maxWinding, sumWinding)) {
916 maxWinding = sumWinding;
917 }
caryclark54359292015-03-26 07:52:43 -0700918 SkOpSpanBase* last;
919 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000920#if DEBUG_WINDING
921 if (last) {
caryclark54359292015-03-26 07:52:43 -0700922 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
923 last->segment()->debugID(), last->debugID());
924 if (!last->final()) {
925 SkDebugf(" windSum=");
926 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
927 }
928 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000929 }
930#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000931 return last;
932}
933
caryclark54359292015-03-26 07:52:43 -0700934SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
935 int oppSumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000936 SkASSERT(angle->segment() == this);
937 if (UseInnerWinding(maxWinding, sumWinding)) {
938 maxWinding = sumWinding;
939 }
940 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
941 oppMaxWinding = oppSumWinding;
942 }
halcanary96fcdcc2015-08-27 07:41:13 -0700943 SkOpSpanBase* last = nullptr;
caryclark65f55312014-11-13 06:58:52 -0800944 // caller doesn't require that this marks anything
caryclark54359292015-03-26 07:52:43 -0700945 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000946#if DEBUG_WINDING
947 if (last) {
caryclark54359292015-03-26 07:52:43 -0700948 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
949 last->segment()->debugID(), last->debugID());
950 if (!last->final()) {
951 SkDebugf(" windSum=");
952 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
953 }
954 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000955 }
956#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000957 return last;
958}
959
caryclark54359292015-03-26 07:52:43 -0700960void SkOpSegment::markDone(SkOpSpan* span) {
961 SkASSERT(this == span->segment());
962 if (span->done()) {
963 return;
964 }
965#if DEBUG_MARK_DONE
966 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
967#endif
968 span->setDone(true);
969 ++fDoneCount;
970 debugValidate();
971}
972
973bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
974 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -0700975 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -0700976 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -0700977 return false;
978 }
979#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -0700980 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -0700981#endif
caryclark54359292015-03-26 07:52:43 -0700982 span->setWindSum(winding);
983 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -0700984 return true;
985}
986
caryclark54359292015-03-26 07:52:43 -0700987bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
988 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000989 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -0700990 if (span->done()) {
991 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000992 }
caryclark54359292015-03-26 07:52:43 -0700993#if DEBUG_MARK_DONE
994 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
995#endif
996 span->setWindSum(winding);
997 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000998 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000999 return true;
1000}
1001
caryclark54359292015-03-26 07:52:43 -07001002bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclarkef4f32a2016-08-24 09:24:18 -07001003 const SkPoint& testPt) const {
caryclark55888e42016-07-18 10:01:36 -07001004 SkASSERT(this == base->segment());
1005 if (this == testParent) {
1006 if (precisely_equal(base->fT, testT)) {
1007 return true;
1008 }
caryclark54359292015-03-26 07:52:43 -07001009 }
1010 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1011 return false;
1012 }
caryclark55888e42016-07-18 10:01:36 -07001013 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001014}
1015
1016static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1017 if (last) {
1018 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001019 }
halcanary96fcdcc2015-08-27 07:41:13 -07001020 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001021}
1022
caryclark54359292015-03-26 07:52:43 -07001023SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1024 SkOpSpanBase** last) const {
1025 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001026 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001027 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1028 SkASSERT(endSpan);
1029 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1030 SkOpSpanBase* foundSpan;
1031 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001032 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001033 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001034 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001035 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001036 }
caryclark54359292015-03-26 07:52:43 -07001037 SkOpPtT* otherPtT = endSpan->ptT()->next();
1038 other = otherPtT->segment();
1039 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001040 otherEnd = step > 0
1041 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1042 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001043 } else {
1044 int loopCount = angle->loopCount();
1045 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001046 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001047 }
1048 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001049 if (nullptr == next) {
1050 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001051 }
caryclarkdac1d172014-06-17 05:15:38 -07001052#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001053 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001054 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001055 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001056 }
caryclark54359292015-03-26 07:52:43 -07001057#endif
caryclarkdac1d172014-06-17 05:15:38 -07001058 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001059 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001060 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001061 }
caryclark343382e2016-06-29 08:18:38 -07001062 if (!otherEnd) {
1063 return nullptr;
1064 }
caryclark54359292015-03-26 07:52:43 -07001065 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001066 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001067 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001068 }
caryclark54359292015-03-26 07:52:43 -07001069 SkASSERT(*startPtr);
caryclark65b427c2014-09-18 10:32:57 -07001070// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001071 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1072 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1073 if (foundMin->windValue() != origMin->windValue()
1074 || foundMin->oppValue() != origMin->oppValue()) {
1075 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001076 }
caryclark54359292015-03-26 07:52:43 -07001077 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001078 *stepPtr = foundStep;
1079 if (minPtr) {
1080 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001081 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001082 return other;
1083}
1084
caryclark55888e42016-07-18 10:01:36 -07001085// Please keep this in sync with DebugClearVisited()
1086void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001087 // reset visited flag back to false
1088 do {
1089 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1090 while ((ptT = ptT->next()) != stopPtT) {
1091 SkOpSegment* opp = ptT->segment();
1092 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001093 }
caryclarkbca19f72015-05-13 08:23:48 -07001094 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001095}
1096
caryclark55888e42016-07-18 10:01:36 -07001097// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001098// look for pairs of undetected coincident curves
1099// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001100// Even though pairs of curves correct detect coincident runs, a run may be missed
1101// if the coincidence is a product of multiple intersections. For instance, given
1102// curves A, B, and C:
1103// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1104// the end of C that the intersection is replaced with the end of C.
1105// Even though A-B correctly do not detect an intersection at point 2,
1106// the resulting run from point 1 to point 2 is coincident on A and B.
1107bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001108 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001109 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001110 }
halcanary96fcdcc2015-08-27 07:41:13 -07001111 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001112 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001113 bool result = false;
caryclark54359292015-03-26 07:52:43 -07001114 do {
caryclarkbca19f72015-05-13 08:23:48 -07001115 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001116 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001117 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001118 if (ptT->deleted()) {
1119 continue;
1120 }
caryclark54359292015-03-26 07:52:43 -07001121 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001122 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001123 continue;
reed0dc4dd62015-03-24 13:55:33 -07001124 }
caryclarkbca19f72015-05-13 08:23:48 -07001125 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1126 if (!opp->visited()) {
1127 continue;
1128 }
1129 if (spanBase == &fHead) {
1130 continue;
1131 }
caryclark55888e42016-07-18 10:01:36 -07001132 if (ptT->segment() == this) {
1133 continue;
1134 }
caryclarkbca19f72015-05-13 08:23:48 -07001135 SkOpSpan* span = spanBase->upCastable();
1136 // FIXME?: this assumes that if the opposite segment is coincident then no more
1137 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001138 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001139 continue;
1140 }
caryclarkbca19f72015-05-13 08:23:48 -07001141 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001142 continue;
caryclark55888e42016-07-18 10:01:36 -07001143 }
halcanary96fcdcc2015-08-27 07:41:13 -07001144 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001145 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001146 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001147 SkOpSpan* priorTest = spanBase->prev();
1148 while (!priorOpp && priorTest) {
1149 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001150 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001151 if (priorPtT->deleted()) {
1152 continue;
1153 }
caryclark54359292015-03-26 07:52:43 -07001154 SkOpSegment* segment = priorPtT->span()->segment();
1155 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001156 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001157 priorOpp = opp;
1158 break;
1159 }
1160 }
caryclarkbca19f72015-05-13 08:23:48 -07001161 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001162 }
1163 if (!priorOpp) {
1164 continue;
1165 }
caryclark26ad22a2015-10-16 09:03:38 -07001166 if (priorPtT == ptT) {
1167 continue;
1168 }
caryclark54359292015-03-26 07:52:43 -07001169 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001170 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001171 bool swapped = priorPtT->fT > ptT->fT;
1172 if (swapped) {
1173 SkTSwap(priorPtT, ptT);
1174 SkTSwap(oppStart, oppEnd);
1175 }
caryclark55888e42016-07-18 10:01:36 -07001176 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1177 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1178 SkOpPtT* rootPtT = ptT->span()->ptT();
1179 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1180 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1181 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001182 goto swapBack;
1183 }
caryclark55888e42016-07-18 10:01:36 -07001184 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001185 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001186#if DEBUG_COINCIDENCE_VERBOSE
1187 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1188 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1189 rootOppEnd->debugID());
1190#endif
1191 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1192 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001193 }
caryclark55888e42016-07-18 10:01:36 -07001194#if DEBUG_COINCIDENCE
1195 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1196#endif
1197 result = true;
caryclark54359292015-03-26 07:52:43 -07001198 }
1199 swapBack:
1200 if (swapped) {
1201 SkTSwap(priorPtT, ptT);
1202 }
reed0dc4dd62015-03-24 13:55:33 -07001203 }
halcanary96fcdcc2015-08-27 07:41:13 -07001204 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001205 ClearVisited(&fHead);
1206 return result;
reed0dc4dd62015-03-24 13:55:33 -07001207}
1208
caryclark55888e42016-07-18 10:01:36 -07001209// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001210// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001211bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001212 debugValidate();
1213 SkOpSpanBase* test = &fHead;
1214 do {
1215 int addCount = test->spanAddsCount();
Cary Clark7eb01e02016-12-08 14:36:32 -05001216// FAIL_IF(addCount < 1);
1217 if (addCount <= 1) {
caryclark08bc8482015-04-24 09:08:57 -07001218 continue;
1219 }
1220 SkOpPtT* startPtT = test->ptT();
1221 SkOpPtT* testPtT = startPtT;
1222 do { // iterate through all spans associated with start
1223 SkOpSpanBase* oppSpan = testPtT->span();
1224 if (oppSpan->spanAddsCount() == addCount) {
1225 continue;
1226 }
1227 if (oppSpan->deleted()) {
1228 continue;
1229 }
1230 SkOpSegment* oppSegment = oppSpan->segment();
1231 if (oppSegment == this) {
1232 continue;
1233 }
1234 // find range of spans to consider merging
1235 SkOpSpanBase* oppPrev = oppSpan;
1236 SkOpSpanBase* oppFirst = oppSpan;
1237 while ((oppPrev = oppPrev->prev())) {
1238 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1239 break;
1240 }
1241 if (oppPrev->spanAddsCount() == addCount) {
1242 continue;
1243 }
1244 if (oppPrev->deleted()) {
1245 continue;
1246 }
1247 oppFirst = oppPrev;
1248 }
1249 SkOpSpanBase* oppNext = oppSpan;
1250 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001251 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001252 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1253 break;
1254 }
1255 if (oppNext->spanAddsCount() == addCount) {
1256 continue;
1257 }
1258 if (oppNext->deleted()) {
1259 continue;
1260 }
1261 oppLast = oppNext;
1262 }
1263 if (oppFirst == oppLast) {
1264 continue;
1265 }
1266 SkOpSpanBase* oppTest = oppFirst;
1267 do {
1268 if (oppTest == oppSpan) {
1269 continue;
1270 }
1271 // check to see if the candidate meets specific criteria:
1272 // it contains spans of segments in test's loop but not including 'this'
1273 SkOpPtT* oppStartPtT = oppTest->ptT();
1274 SkOpPtT* oppPtT = oppStartPtT;
1275 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1276 SkOpSegment* oppPtTSegment = oppPtT->segment();
1277 if (oppPtTSegment == this) {
1278 goto tryNextSpan;
1279 }
1280 SkOpPtT* matchPtT = startPtT;
1281 do {
1282 if (matchPtT->segment() == oppPtTSegment) {
1283 goto foundMatch;
1284 }
1285 } while ((matchPtT = matchPtT->next()) != startPtT);
1286 goto tryNextSpan;
1287 foundMatch: // merge oppTest and oppSpan
1288 oppSegment->debugValidate();
caryclark30b9fdd2016-08-31 14:36:29 -07001289 oppTest->mergeMatches(oppSpan);
1290 oppTest->addOpp(oppSpan);
caryclark08bc8482015-04-24 09:08:57 -07001291 oppSegment->debugValidate();
1292 goto checkNextSpan;
1293 }
caryclark55888e42016-07-18 10:01:36 -07001294 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001295 ;
1296 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1297 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001298checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001299 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001300 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001301 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001302 return true;
caryclark08bc8482015-04-24 09:08:57 -07001303}
1304
caryclark55888e42016-07-18 10:01:36 -07001305// adjacent spans may have points close by
Cary Clark28da2832017-03-21 10:30:50 -04001306bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan,
1307 bool* found) const {
caryclark55888e42016-07-18 10:01:36 -07001308 const SkOpPtT* refHead = refSpan->ptT();
1309 const SkOpPtT* checkHead = checkSpan->ptT();
1310// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
caryclark30b9fdd2016-08-31 14:36:29 -07001311 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
caryclark55888e42016-07-18 10:01:36 -07001312#if DEBUG_COINCIDENCE
1313 // verify that no combination of points are close
1314 const SkOpPtT* dBugRef = refHead;
1315 do {
1316 const SkOpPtT* dBugCheck = checkHead;
1317 do {
caryclark30b9fdd2016-08-31 14:36:29 -07001318 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
caryclark55888e42016-07-18 10:01:36 -07001319 dBugCheck = dBugCheck->next();
1320 } while (dBugCheck != checkHead);
1321 dBugRef = dBugRef->next();
1322 } while (dBugRef != refHead);
1323#endif
Cary Clark28da2832017-03-21 10:30:50 -04001324 *found = false;
1325 return true;
caryclark55888e42016-07-18 10:01:36 -07001326 }
1327 // check only unique points
1328 SkScalar distSqBest = SK_ScalarMax;
1329 const SkOpPtT* refBest = nullptr;
1330 const SkOpPtT* checkBest = nullptr;
1331 const SkOpPtT* ref = refHead;
1332 do {
1333 if (ref->deleted()) {
1334 continue;
1335 }
1336 while (ref->ptAlreadySeen(refHead)) {
1337 ref = ref->next();
1338 if (ref == refHead) {
1339 goto doneCheckingDistance;
1340 }
1341 }
1342 const SkOpPtT* check = checkHead;
1343 const SkOpSegment* refSeg = ref->segment();
Cary Clark28da2832017-03-21 10:30:50 -04001344 int escapeHatch = 100000; // defend against infinite loops
caryclark55888e42016-07-18 10:01:36 -07001345 do {
1346 if (check->deleted()) {
1347 continue;
1348 }
1349 while (check->ptAlreadySeen(checkHead)) {
1350 check = check->next();
1351 if (check == checkHead) {
1352 goto nextRef;
1353 }
1354 }
Cary Clarkdf429f32017-11-08 11:44:31 -05001355 SkScalar distSq = SkPointPriv::DistanceToSqd(ref->fPt, check->fPt);
caryclark55888e42016-07-18 10:01:36 -07001356 if (distSqBest > distSq && (refSeg != check->segment()
1357 || !refSeg->ptsDisjoint(*ref, *check))) {
1358 distSqBest = distSq;
1359 refBest = ref;
1360 checkBest = check;
1361 }
Cary Clark28da2832017-03-21 10:30:50 -04001362 if (--escapeHatch <= 0) {
1363 return false;
1364 }
caryclark55888e42016-07-18 10:01:36 -07001365 } while ((check = check->next()) != checkHead);
Cary Clark28da2832017-03-21 10:30:50 -04001366 nextRef:
caryclark55888e42016-07-18 10:01:36 -07001367 ;
1368 } while ((ref = ref->next()) != refHead);
1369doneCheckingDistance:
Cary Clark28da2832017-03-21 10:30:50 -04001370 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001371 checkBest->fPt);
Cary Clark28da2832017-03-21 10:30:50 -04001372 return true;
caryclark55888e42016-07-18 10:01:36 -07001373}
1374
1375// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001376// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
Cary Clark28da2832017-03-21 10:30:50 -04001377bool SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001378 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001379 // release undeleted spans pointing to this seg that are linked to the primary span
1380 SkOpSpanBase* spanBase = &fHead;
Cary Clark43938b82017-10-18 08:47:32 -04001381 int escapeHatch = 9999; // the largest count for a regular test is 50; for a fuzzer, 500
caryclark54359292015-03-26 07:52:43 -07001382 do {
caryclark55888e42016-07-18 10:01:36 -07001383 SkOpPtT* ptT = spanBase->ptT();
1384 const SkOpPtT* headPtT = ptT;
1385 while ((ptT = ptT->next()) != headPtT) {
Cary Clark43938b82017-10-18 08:47:32 -04001386 if (!--escapeHatch) {
1387 return false;
1388 }
caryclark55888e42016-07-18 10:01:36 -07001389 SkOpSpanBase* test = ptT->span();
1390 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1391 && test->ptT() == ptT) {
1392 if (test->final()) {
1393 if (spanBase == &fHead) {
1394 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001395 return true;
caryclark55888e42016-07-18 10:01:36 -07001396 }
1397 spanBase->upCast()->release(ptT);
1398 } else if (test->prev()) {
1399 test->upCast()->release(headPtT);
1400 }
1401 break;
caryclark54359292015-03-26 07:52:43 -07001402 }
reed0dc4dd62015-03-24 13:55:33 -07001403 }
caryclark55888e42016-07-18 10:01:36 -07001404 spanBase = spanBase->upCast()->next();
1405 } while (!spanBase->final());
caryclark55888e42016-07-18 10:01:36 -07001406 // This loop looks for adjacent spans which are near by
1407 spanBase = &fHead;
1408 do { // iterate through all spans associated with start
1409 SkOpSpanBase* test = spanBase->upCast()->next();
Cary Clark28da2832017-03-21 10:30:50 -04001410 bool found;
1411 if (!this->spansNearby(spanBase, test, &found)) {
1412 return false;
1413 }
1414 if (found) {
caryclark55888e42016-07-18 10:01:36 -07001415 if (test->final()) {
1416 if (spanBase->prev()) {
1417 test->merge(spanBase->upCast());
1418 } else {
1419 this->clearAll();
Cary Clark28da2832017-03-21 10:30:50 -04001420 return true;
caryclark55888e42016-07-18 10:01:36 -07001421 }
1422 } else {
1423 spanBase->merge(test->upCast());
1424 }
1425 }
1426 spanBase = test;
1427 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001428 debugValidate();
Cary Clark28da2832017-03-21 10:30:50 -04001429 return true;
reed0dc4dd62015-03-24 13:55:33 -07001430}
1431
caryclark54359292015-03-26 07:52:43 -07001432bool SkOpSegment::operand() const {
1433 return fContour->operand();
1434}
1435
1436bool SkOpSegment::oppXor() const {
1437 return fContour->oppXor();
1438}
1439
1440bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1441 if (fVerb == SkPath::kLine_Verb) {
1442 return false;
1443 }
1444 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1445 // hits in two places with very different t values.
1446 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1447 // 'controls contained by ends' could avoid this check for common curves
1448 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1449 // on the other hand, the below check is relatively inexpensive
1450 double midT = (t1 + t2) / 2;
1451 SkPoint midPt = this->ptAtT(midT);
Cary Clarkdf429f32017-11-08 11:44:31 -05001452 double seDistSq = SkTMax(SkPointPriv::DistanceToSqd(pt1, pt2) * 2, FLT_EPSILON * 2);
1453 return SkPointPriv::DistanceToSqd(midPt, pt1) > seDistSq ||
1454 SkPointPriv::DistanceToSqd(midPt, pt2) > seDistSq;
caryclark54359292015-03-26 07:52:43 -07001455}
1456
1457void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1458 int* maxWinding, int* sumWinding) {
1459 int deltaSum = SpanSign(start, end);
1460 *maxWinding = *sumMiWinding;
1461 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001462 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001463}
1464
1465void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1466 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1467 int* oppSumWinding) {
1468 int deltaSum = SpanSign(start, end);
1469 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001470 if (operand()) {
1471 *maxWinding = *sumSuWinding;
1472 *sumWinding = *sumSuWinding -= deltaSum;
1473 *oppMaxWinding = *sumMiWinding;
1474 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1475 } else {
1476 *maxWinding = *sumMiWinding;
1477 *sumWinding = *sumMiWinding -= deltaSum;
1478 *oppMaxWinding = *sumSuWinding;
1479 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1480 }
bungeman60e0fee2015-08-26 05:15:46 -07001481 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1482 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001483}
1484
caryclarkb36a3cd2016-10-18 07:59:44 -07001485bool SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001486 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001487 do {
caryclark54359292015-03-26 07:52:43 -07001488 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001489 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001490 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001491 continue;
1492 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001493#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001494 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001495#endif
caryclark54359292015-03-26 07:52:43 -07001496 SkOpAngle* baseAngle = fromAngle;
1497 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001498#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001499 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1500 span->debugID());
1501 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001502#endif
caryclarkb36a3cd2016-10-18 07:59:44 -07001503 FAIL_IF(!fromAngle->insert(toAngle));
caryclark54359292015-03-26 07:52:43 -07001504 } else if (!fromAngle) {
1505 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001506 }
caryclark54359292015-03-26 07:52:43 -07001507 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001508 do {
caryclark54359292015-03-26 07:52:43 -07001509 SkOpSpanBase* oSpan = ptT->span();
1510 if (oSpan == span) {
1511 continue;
1512 }
1513 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001514 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001515#if DEBUG_ANGLE
1516 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001517 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1518 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001519 wroteAfterHeader = true;
1520 }
1521#endif
caryclark54359292015-03-26 07:52:43 -07001522 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001523 baseAngle->insert(oAngle);
1524 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001525 }
caryclark54359292015-03-26 07:52:43 -07001526 if (!oSpan->final()) {
1527 oAngle = oSpan->upCast()->toAngle();
1528 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001529#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001530 if (!wroteAfterHeader) {
1531 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1532 span->t(), span->debugID());
1533 wroteAfterHeader = true;
1534 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001535#endif
caryclark54359292015-03-26 07:52:43 -07001536 if (!oAngle->loopContains(baseAngle)) {
1537 baseAngle->insert(oAngle);
1538 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001539 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001540 }
caryclark54359292015-03-26 07:52:43 -07001541 } while ((ptT = ptT->next()) != stopPtT);
1542 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001543 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001544 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001545 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001546 }
halcanary96fcdcc2015-08-27 07:41:13 -07001547 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001548 }
1549#if DEBUG_SORT
1550 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1551#endif
caryclark54359292015-03-26 07:52:43 -07001552 } while (!span->final() && (span = span->upCast()->next()));
caryclarkb36a3cd2016-10-18 07:59:44 -07001553 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +00001554}
1555
caryclark54359292015-03-26 07:52:43 -07001556bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001557 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001558 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001559 const SkOpPtT& startPtT = *start->ptT();
1560 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001561 SkDEBUGCODE(edge->fVerb = fVerb);
1562 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001563 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001564 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001565 if (fVerb == SkPath::kLine_Verb) {
1566 return false;
1567 }
caryclark54359292015-03-26 07:52:43 -07001568 double startT = startPtT.fT;
1569 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001570 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1571 // don't compute midpoints if we already have them
1572 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001573 edge->fLine[1].set(fPts[1]);
1574 return false;
1575 }
1576 if (fVerb == SkPath::kConic_Verb) {
1577 edge->fConic[1].set(fPts[1]);
1578 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001579 return false;
1580 }
1581 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001582 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001583 edge->fCubic[1].set(fPts[1]);
1584 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001585 return false;
1586 }
caryclark1049f122015-04-20 08:31:59 -07001587 edge->fCubic[1].set(fPts[2]);
1588 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001589 return false;
1590 }
1591 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001592 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1593 } else if (fVerb == SkPath::kConic_Verb) {
1594 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1595 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001596 } else {
1597 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001598 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001599 }
1600 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001601}
1602
caryclark27c8eb82015-07-06 11:38:33 -07001603bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001604 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001605 // average t, find mid pt
1606 double midT = (prior->t() + spanBase->t()) / 2;
1607 SkPoint midPt = this->ptAtT(midT);
1608 bool coincident = true;
1609 // if the mid pt is not near either end pt, project perpendicular through opp seg
1610 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1611 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001612 if (priorPtT->span() == ptT->span()) {
1613 return false;
1614 }
caryclark27c8eb82015-07-06 11:38:33 -07001615 coincident = false;
1616 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001617 SkDCurve curvePart;
1618 this->subDivide(prior, spanBase, &curvePart);
1619 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1620 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1621 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1622 SkDCurve oppPart;
1623 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1624 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001625 // measure distance and see if it's small enough to denote coincidence
1626 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001627 if (!between(0, i[0][index], 1)) {
1628 continue;
1629 }
caryclark27c8eb82015-07-06 11:38:33 -07001630 SkDPoint oppPt = i.pt(index);
caryclark30b9fdd2016-08-31 14:36:29 -07001631 if (oppPt.approximatelyDEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001632 // the coincidence can occur at almost any angle
1633 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001634 }
1635 }
1636 }
1637 return coincident;
1638}
1639
Cary Clarkab2d73b2016-12-16 17:17:25 -05001640SkOpSpan* SkOpSegment::undoneSpan() {
1641 SkOpSpan* span = &fHead;
1642 SkOpSpanBase* next;
caryclark54359292015-03-26 07:52:43 -07001643 do {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001644 next = span->next();
caryclark54359292015-03-26 07:52:43 -07001645 if (!span->done()) {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001646 return span;
reed0dc4dd62015-03-24 13:55:33 -07001647 }
Cary Clarkab2d73b2016-12-16 17:17:25 -05001648 } while (!next->final() && (span = next->upCast()));
1649 return nullptr;
reed0dc4dd62015-03-24 13:55:33 -07001650}
1651
caryclark54359292015-03-26 07:52:43 -07001652int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1653 const SkOpSpan* lesser = start->starter(end);
1654 int oppWinding = lesser->oppSum();
1655 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001656 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1657 && oppWinding != SK_MaxS32) {
1658 oppWinding -= oppSpanWinding;
1659 }
1660 return oppWinding;
1661}
1662
1663int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001664 const SkOpSpanBase* startSpan = angle->start();
1665 const SkOpSpanBase* endSpan = angle->end();
1666 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001667}
1668
1669int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001670 const SkOpSpanBase* startSpan = angle->start();
1671 const SkOpSpanBase* endSpan = angle->end();
1672 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001673}
1674
caryclark624637c2015-05-11 07:21:27 -07001675int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1676 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001677 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001678 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001679 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001680 }
1681 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001682 return winding;
1683 }
caryclark54359292015-03-26 07:52:43 -07001684 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001685 if (winding && UseInnerWinding(winding - spanWinding, winding)
1686 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001687 winding -= spanWinding;
1688 }
1689 return winding;
1690}
1691
caryclark624637c2015-05-11 07:21:27 -07001692int SkOpSegment::updateWinding(SkOpAngle* angle) {
1693 SkOpSpanBase* startSpan = angle->start();
1694 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001695 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001696}
1697
caryclark624637c2015-05-11 07:21:27 -07001698int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1699 SkOpSpanBase* startSpan = angle->start();
1700 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001701 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001702}
1703
1704// OPTIMIZATION: does the following also work, and is it any faster?
1705// return outerWinding * innerWinding > 0
1706// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1707bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1708 SkASSERT(outerWinding != SK_MaxS32);
1709 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001710 int absOut = SkTAbs(outerWinding);
1711 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001712 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1713 return result;
1714}
1715
caryclark@google.com07393ca2013-04-08 11:47:37 +00001716int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001717 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1718 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001719}