blob: 58c71af43719f004b8a6912b80d6cf30b8efe6fb [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()
caryclark29b25632016-08-25 11:27:17 -0700247SkOpPtT* SkOpSegment::addT(double t) {
reed0dc4dd62015-03-24 13:55:33 -0700248 debugValidate();
caryclark54359292015-03-26 07:52:43 -0700249 SkPoint pt = this->ptAtT(t);
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
caryclark55888e42016-07-18 10:01:36 -0700277void SkOpSegment::calcAngles() {
caryclark54359292015-03-26 07:52:43 -0700278 bool activePrior = !fHead.isCanceled();
279 if (activePrior && !fHead.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700280 addStartSpan();
reed0dc4dd62015-03-24 13:55:33 -0700281 }
caryclark54359292015-03-26 07:52:43 -0700282 SkOpSpan* prior = &fHead;
283 SkOpSpanBase* spanBase = fHead.next();
284 while (spanBase != &fTail) {
285 if (activePrior) {
caryclark55888e42016-07-18 10:01:36 -0700286 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(
287 this->globalState()->allocator());
caryclark54359292015-03-26 07:52:43 -0700288 priorAngle->set(spanBase, prior);
289 spanBase->setFromAngle(priorAngle);
reed0dc4dd62015-03-24 13:55:33 -0700290 }
caryclark54359292015-03-26 07:52:43 -0700291 SkOpSpan* span = spanBase->upCast();
292 bool active = !span->isCanceled();
293 SkOpSpanBase* next = span->next();
294 if (active) {
caryclark55888e42016-07-18 10:01:36 -0700295 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(
296 this->globalState()->allocator());
caryclark54359292015-03-26 07:52:43 -0700297 angle->set(span, next);
298 span->setToAngle(angle);
reed0dc4dd62015-03-24 13:55:33 -0700299 }
reed0dc4dd62015-03-24 13:55:33 -0700300 activePrior = active;
caryclark54359292015-03-26 07:52:43 -0700301 prior = span;
302 spanBase = next;
reed0dc4dd62015-03-24 13:55:33 -0700303 }
caryclark54359292015-03-26 07:52:43 -0700304 if (activePrior && !fTail.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700305 addEndSpan();
reed0dc4dd62015-03-24 13:55:33 -0700306 }
reed0dc4dd62015-03-24 13:55:33 -0700307}
308
caryclark55888e42016-07-18 10:01:36 -0700309// Please keep this in sync with debugClearAll()
310void SkOpSegment::clearAll() {
311 SkOpSpan* span = &fHead;
312 do {
313 this->clearOne(span);
314 } while ((span = span->next()->upCastable()));
315 this->globalState()->coincidence()->release(this);
316}
317
318// Please keep this in sync with debugClearOne()
319void SkOpSegment::clearOne(SkOpSpan* span) {
320 span->setWindValue(0);
321 span->setOppValue(0);
322 this->markDone(span);
323}
324
caryclark30b9fdd2016-08-31 14:36:29 -0700325bool SkOpSegment::collapsed(double s, double e) const {
326 const SkOpSpanBase* span = &fHead;
327 do {
328 if (span->collapsed(s, e)) {
329 return true;
330 }
331 } while (span->upCastable() && (span = span->upCast()->next()));
332 return false;
333}
334
caryclark@google.com570863f2013-09-16 15:55:01 +0000335void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
336 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700337 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000338 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
339 int sumSuWinding;
340 bool binary = includeType >= SkOpAngle::kBinarySingle;
341 if (binary) {
342 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
343 if (baseSegment->operand()) {
344 SkTSwap<int>(sumMiWinding, sumSuWinding);
345 }
346 }
347 SkOpSegment* nextSegment = nextAngle->segment();
348 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700349 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000350 if (binary) {
351 int oppMaxWinding, oppSumWinding;
352 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
353 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
354 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000355 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000356 } else {
357 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
358 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000359 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000360 }
361 nextAngle->setLastMarked(last);
362}
363
caryclark624637c2015-05-11 07:21:27 -0700364void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
caryclark@google.com570863f2013-09-16 15:55:01 +0000365 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700366 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000367 int sumMiWinding = baseSegment->updateWinding(baseAngle);
368 int sumSuWinding;
369 bool binary = includeType >= SkOpAngle::kBinarySingle;
370 if (binary) {
371 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
372 if (baseSegment->operand()) {
373 SkTSwap<int>(sumMiWinding, sumSuWinding);
374 }
375 }
376 SkOpSegment* nextSegment = nextAngle->segment();
377 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700378 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000379 if (binary) {
380 int oppMaxWinding, oppSumWinding;
381 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
382 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
383 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000384 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000385 } else {
386 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
387 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000388 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000389 }
390 nextAngle->setLastMarked(last);
391}
392
caryclark54359292015-03-26 07:52:43 -0700393// at this point, the span is already ordered, or unorderable
394int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
395 SkOpAngle::IncludeType includeType) {
396 SkASSERT(includeType != SkOpAngle::kUnaryXor);
397 SkOpAngle* firstAngle = this->spanToAngle(end, start);
halcanary96fcdcc2015-08-27 07:41:13 -0700398 if (nullptr == firstAngle || nullptr == firstAngle->next()) {
caryclark54359292015-03-26 07:52:43 -0700399 return SK_NaN32;
400 }
401 // if all angles have a computed winding,
402 // or if no adjacent angles are orderable,
403 // or if adjacent orderable angles have no computed winding,
404 // there's nothing to do
405 // if two orderable angles are adjacent, and both are next to orderable angles,
406 // and one has winding computed, transfer to the other
halcanary96fcdcc2015-08-27 07:41:13 -0700407 SkOpAngle* baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700408 bool tryReverse = false;
409 // look for counterclockwise transfers
410 SkOpAngle* angle = firstAngle->previous();
411 SkOpAngle* next = angle->next();
412 firstAngle = next;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000413 do {
caryclark54359292015-03-26 07:52:43 -0700414 SkOpAngle* prior = angle;
415 angle = next;
416 next = angle->next();
417 SkASSERT(prior->next() == angle);
418 SkASSERT(angle->next() == next);
419 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700420 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700421 continue;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000422 }
caryclark54359292015-03-26 07:52:43 -0700423 int testWinding = angle->starter()->windSum();
424 if (SK_MinS32 != testWinding) {
425 baseAngle = angle;
426 tryReverse = true;
427 continue;
reed0dc4dd62015-03-24 13:55:33 -0700428 }
caryclark54359292015-03-26 07:52:43 -0700429 if (baseAngle) {
430 ComputeOneSum(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700431 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
caryclark54359292015-03-26 07:52:43 -0700432 }
433 } while (next != firstAngle);
434 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
435 firstAngle = baseAngle;
436 tryReverse = true;
437 }
438 if (tryReverse) {
halcanary96fcdcc2015-08-27 07:41:13 -0700439 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700440 SkOpAngle* prior = firstAngle;
441 do {
442 angle = prior;
443 prior = angle->previous();
444 SkASSERT(prior->next() == angle);
445 next = angle->next();
446 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700447 baseAngle = nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700448 continue;
449 }
caryclark54359292015-03-26 07:52:43 -0700450 int testWinding = angle->starter()->windSum();
451 if (SK_MinS32 != testWinding) {
452 baseAngle = angle;
453 continue;
reed0dc4dd62015-03-24 13:55:33 -0700454 }
caryclark54359292015-03-26 07:52:43 -0700455 if (baseAngle) {
456 ComputeOneSumReverse(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700457 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700458 }
caryclark54359292015-03-26 07:52:43 -0700459 } while (prior != firstAngle);
reed0dc4dd62015-03-24 13:55:33 -0700460 }
caryclark54359292015-03-26 07:52:43 -0700461 return start->starter(end)->windSum();
reed0dc4dd62015-03-24 13:55:33 -0700462}
463
caryclark55888e42016-07-18 10:01:36 -0700464bool SkOpSegment::contains(double newT) const {
465 const SkOpSpanBase* spanBase = &fHead;
466 do {
467 if (spanBase->ptT()->contains(this, newT)) {
468 return true;
469 }
470 if (spanBase == &fTail) {
471 break;
472 }
473 spanBase = spanBase->upCast()->next();
474 } while (true);
475 return false;
476}
477
mtklein18300a32016-03-16 13:53:35 -0700478void SkOpSegment::release(const SkOpSpan* span) {
caryclark54359292015-03-26 07:52:43 -0700479 if (span->done()) {
caryclark08bc8482015-04-24 09:08:57 -0700480 --fDoneCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000481 }
caryclark08bc8482015-04-24 09:08:57 -0700482 --fCount;
caryclark15976282016-07-21 05:48:43 -0700483 SkOPASSERT(fCount >= fDoneCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000484}
485
Cary Clarke47ae292016-10-05 08:51:39 -0400486#if DEBUG_ANGLE
487// called only by debugCheckNearCoincidence
caryclark26ad22a2015-10-16 09:03:38 -0700488double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
caryclark54359292015-03-26 07:52:43 -0700489 SkDPoint testPt = this->dPtAtT(t);
490 SkDLine testPerp = {{ testPt, testPt }};
491 SkDVector slope = this->dSlopeAtT(t);
492 testPerp[1].fX += slope.fY;
493 testPerp[1].fY -= slope.fX;
494 SkIntersections i;
caryclark26ad22a2015-10-16 09:03:38 -0700495 const SkOpSegment* oppSegment = oppAngle->segment();
caryclark1049f122015-04-20 08:31:59 -0700496 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
caryclark54359292015-03-26 07:52:43 -0700497 double closestDistSq = SK_ScalarInfinity;
498 for (int index = 0; index < i.used(); ++index) {
499 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000500 continue;
501 }
caryclark54359292015-03-26 07:52:43 -0700502 double testDistSq = testPt.distanceSquared(i.pt(index));
503 if (closestDistSq > testDistSq) {
504 closestDistSq = testDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000505 }
506 }
caryclark54359292015-03-26 07:52:43 -0700507 return closestDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000508}
Cary Clarke47ae292016-10-05 08:51:39 -0400509#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000510
caryclark@google.com07393ca2013-04-08 11:47:37 +0000511/*
512 The M and S variable name parts stand for the operators.
513 Mi stands for Minuend (see wiki subtraction, analogous to difference)
514 Su stands for Subtrahend
515 The Opp variable name part designates that the value is for the Opposite operator.
516 Opposite values result from combining coincident spans.
517 */
caryclark54359292015-03-26 07:52:43 -0700518SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
519 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) {
520 SkOpSpanBase* start = *nextStart;
521 SkOpSpanBase* end = *nextEnd;
522 SkASSERT(start != end);
523 int step = start->step(end);
524 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
525 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000526 // mark the smaller of startIndex, endIndex done, and all adjacent
527 // spans with the same T value (but not 'other' spans)
528#if DEBUG_WINDING
529 SkDebugf("%s simple\n", __FUNCTION__);
530#endif
caryclark54359292015-03-26 07:52:43 -0700531 SkOpSpan* startSpan = start->starter(end);
532 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700533 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000534 }
caryclark54359292015-03-26 07:52:43 -0700535 markDone(startSpan);
536 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000537 return other;
538 }
caryclark54359292015-03-26 07:52:43 -0700539 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
540 SkASSERT(endNear == end); // is this ever not end?
541 SkASSERT(endNear);
542 SkASSERT(start != endNear);
543 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000544 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700545 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
caryclark@google.com570863f2013-09-16 15:55:01 +0000546 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000547 if (!sortable) {
548 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700549 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700550 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000551 }
caryclark54359292015-03-26 07:52:43 -0700552 SkOpAngle* angle = this->spanToAngle(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000553 if (angle->unorderable()) {
554 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700555 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700556 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000557 }
558#if DEBUG_SORT
559 SkDebugf("%s\n", __FUNCTION__);
560 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000561#endif
caryclark54359292015-03-26 07:52:43 -0700562 int sumMiWinding = updateWinding(end, start);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000563 if (sumMiWinding == SK_MinS32) {
564 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700565 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700566 return nullptr;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000567 }
caryclark54359292015-03-26 07:52:43 -0700568 int sumSuWinding = updateOppWinding(end, start);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000569 if (operand()) {
570 SkTSwap<int>(sumMiWinding, sumSuWinding);
571 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000572 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700573 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000574 bool foundDone = false;
575 // iterate through the angle, and compute everyone's winding
576 SkOpSegment* nextSegment;
577 int activeCount = 0;
578 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000579 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000580 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000581 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000582 if (activeAngle) {
583 ++activeCount;
584 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000585 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +0000586 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000587 }
588 }
589 if (nextSegment->done()) {
590 continue;
591 }
reed0dc4dd62015-03-24 13:55:33 -0700592 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700593 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700594 }
caryclark54359292015-03-26 07:52:43 -0700595 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000596 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000597 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000598 *chase->append() = last;
599#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700600 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
601 last->segment()->debugID(), last->debugID());
602 if (!last->final()) {
603 SkDebugf(" windSum=%d", last->upCast()->windSum());
604 }
605 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000606#endif
607 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000608 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700609 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000610 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700611 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000612 }
613 *nextStart = foundAngle->start();
614 *nextEnd = foundAngle->end();
615 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000616#if DEBUG_WINDING
617 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
618 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
619 #endif
620 return nextSegment;
621}
622
caryclark54359292015-03-26 07:52:43 -0700623SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
624 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
625 SkOpSpanBase* start = *nextStart;
626 SkOpSpanBase* end = *nextEnd;
627 SkASSERT(start != end);
628 int step = start->step(end);
629 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
630 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000631 // mark the smaller of startIndex, endIndex done, and all adjacent
632 // spans with the same T value (but not 'other' spans)
633#if DEBUG_WINDING
634 SkDebugf("%s simple\n", __FUNCTION__);
635#endif
caryclark54359292015-03-26 07:52:43 -0700636 SkOpSpan* startSpan = start->starter(end);
637 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700638 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000639 }
caryclark54359292015-03-26 07:52:43 -0700640 markDone(startSpan);
641 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000642 return other;
643 }
caryclark54359292015-03-26 07:52:43 -0700644 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
645 SkASSERT(endNear == end); // is this ever not end?
646 SkASSERT(endNear);
647 SkASSERT(start != endNear);
648 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000649 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700650 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000651 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000652 if (!sortable) {
653 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700654 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700655 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000656 }
caryclark54359292015-03-26 07:52:43 -0700657 SkOpAngle* angle = this->spanToAngle(end, start);
658 if (angle->unorderable()) {
659 *unsortable = true;
660 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700661 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700662 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000663#if DEBUG_SORT
664 SkDebugf("%s\n", __FUNCTION__);
665 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000666#endif
caryclark54359292015-03-26 07:52:43 -0700667 int sumWinding = updateWinding(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000668 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700669 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000670 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700671 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000672 SkOpSegment* nextSegment;
673 int activeCount = 0;
674 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000675 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000676 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000677 &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000678 if (activeAngle) {
679 ++activeCount;
680 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000681 foundAngle = nextAngle;
682 foundDone = nextSegment->done(nextAngle);
683 }
684 }
685 if (nextSegment->done()) {
686 continue;
687 }
reed0dc4dd62015-03-24 13:55:33 -0700688 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700689 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700690 }
caryclark54359292015-03-26 07:52:43 -0700691 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000692 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000693 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000694 *chase->append() = last;
695#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700696 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
697 last->segment()->debugID(), last->debugID());
698 if (!last->final()) {
699 SkDebugf(" windSum=%d", last->upCast()->windSum());
700 }
701 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000702#endif
703 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000704 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700705 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000706 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700707 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000708 }
709 *nextStart = foundAngle->start();
710 *nextEnd = foundAngle->end();
711 nextSegment = foundAngle->segment();
712#if DEBUG_WINDING
713 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
714 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
715 #endif
716 return nextSegment;
717}
718
caryclark54359292015-03-26 07:52:43 -0700719SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
720 bool* unsortable) {
721 SkOpSpanBase* start = *nextStart;
722 SkOpSpanBase* end = *nextEnd;
723 SkASSERT(start != end);
724 int step = start->step(end);
725 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
726 if (other) {
727 // mark the smaller of startIndex, endIndex done, and all adjacent
728 // spans with the same T value (but not 'other' spans)
caryclark@google.com07393ca2013-04-08 11:47:37 +0000729#if DEBUG_WINDING
730 SkDebugf("%s simple\n", __FUNCTION__);
731#endif
caryclark54359292015-03-26 07:52:43 -0700732 SkOpSpan* startSpan = start->starter(end);
733 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700734 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000735 }
caryclark54359292015-03-26 07:52:43 -0700736 markDone(startSpan);
737 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000738 return other;
739 }
caryclark54359292015-03-26 07:52:43 -0700740 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
741 : (*nextStart)->prev());
742 SkASSERT(endNear == end); // is this ever not end?
743 SkASSERT(endNear);
744 SkASSERT(start != endNear);
745 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
746 SkOpAngle* angle = this->spanToAngle(end, start);
caryclark27c8eb82015-07-06 11:38:33 -0700747 if (!angle || angle->unorderable()) {
caryclark54359292015-03-26 07:52:43 -0700748 *unsortable = true;
749 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700750 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700751 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000752#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000753 SkDebugf("%s\n", __FUNCTION__);
754 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000755#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000756 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700757 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000758 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700759 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000760 SkOpSegment* nextSegment;
761 int activeCount = 0;
762 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000763 nextSegment = nextAngle->segment();
764 ++activeCount;
765 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000766 foundAngle = nextAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000767 if (!(foundDone = nextSegment->done(nextAngle))) {
768 break;
769 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000770 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000771 nextAngle = nextAngle->next();
772 } while (nextAngle != angle);
caryclark54359292015-03-26 07:52:43 -0700773 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000774 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700775 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000776 }
777 *nextStart = foundAngle->start();
778 *nextEnd = foundAngle->end();
779 nextSegment = foundAngle->segment();
780#if DEBUG_WINDING
781 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
782 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
783 #endif
784 return nextSegment;
785}
786
caryclark54359292015-03-26 07:52:43 -0700787SkOpGlobalState* SkOpSegment::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700788 return contour()->globalState();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000789}
790
caryclark1049f122015-04-20 08:31:59 -0700791void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
caryclark54359292015-03-26 07:52:43 -0700792 fContour = contour;
halcanary96fcdcc2015-08-27 07:41:13 -0700793 fNext = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000794 fPts = pts;
caryclark1049f122015-04-20 08:31:59 -0700795 fWeight = weight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000796 fVerb = verb;
caryclark54359292015-03-26 07:52:43 -0700797 fCount = 0;
798 fDoneCount = 0;
799 fVisited = false;
800 SkOpSpan* zeroSpan = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700801 zeroSpan->init(this, nullptr, 0, fPts[0]);
caryclark54359292015-03-26 07:52:43 -0700802 SkOpSpanBase* oneSpan = &fTail;
803 zeroSpan->setNext(oneSpan);
804 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
caryclark1049f122015-04-20 08:31:59 -0700805 SkDEBUGCODE(fID = globalState()->nextSegmentID());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000806}
807
caryclark54359292015-03-26 07:52:43 -0700808bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
809 SkDPoint cPt = this->dPtAtT(t);
caryclark1049f122015-04-20 08:31:59 -0700810 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
caryclark54359292015-03-26 07:52:43 -0700811 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
812 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -0700813 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
caryclark54359292015-03-26 07:52:43 -0700814 int used = i.used();
815 for (int index = 0; index < used; ++index) {
816 if (cPt.roughlyEqual(i.pt(index))) {
reed0dc4dd62015-03-24 13:55:33 -0700817 return true;
818 }
caryclark54359292015-03-26 07:52:43 -0700819 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000820 return false;
821}
822
caryclark54359292015-03-26 07:52:43 -0700823bool SkOpSegment::isXor() const {
824 return fContour->isXor();
825}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000826
caryclark5b5ddd72015-05-18 05:12:56 -0700827void SkOpSegment::markAllDone() {
828 SkOpSpan* span = this->head();
829 do {
830 this->markDone(span);
831 } while ((span = span->next()->upCastable()));
832}
833
caryclark54359292015-03-26 07:52:43 -0700834SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) {
835 int step = start->step(end);
836 SkOpSpan* minSpan = start->starter(end);
837 markDone(minSpan);
halcanary96fcdcc2015-08-27 07:41:13 -0700838 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000839 SkOpSegment* other = this;
Cary Clark918fb1f2016-11-15 13:22:25 -0500840 SkOpSpan* priorDone = nullptr;
841 SkOpSpan* lastDone = nullptr;
caryclark54359292015-03-26 07:52:43 -0700842 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000843 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -0700844 SkASSERT(!last);
845 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000846 }
Cary Clark918fb1f2016-11-15 13:22:25 -0500847 if (lastDone == minSpan || priorDone == minSpan) {
848 return nullptr;
849 }
caryclark54359292015-03-26 07:52:43 -0700850 other->markDone(minSpan);
Cary Clark918fb1f2016-11-15 13:22:25 -0500851 priorDone = lastDone;
852 lastDone = minSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000853 }
854 return last;
855}
856
caryclark54359292015-03-26 07:52:43 -0700857bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
858 SkOpSpanBase** lastPtr) {
859 SkOpSpan* spanStart = start->starter(end);
860 int step = start->step(end);
861 bool success = markWinding(spanStart, winding);
halcanary96fcdcc2015-08-27 07:41:13 -0700862 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000863 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700864 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
865 if (spanStart->windSum() != SK_MinS32) {
caryclarkb36a3cd2016-10-18 07:59:44 -0700866// SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive?
caryclarkdac1d172014-06-17 05:15:38 -0700867 SkASSERT(!last);
868 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000869 }
caryclark54359292015-03-26 07:52:43 -0700870 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000871 }
caryclark65f55312014-11-13 06:58:52 -0800872 if (lastPtr) {
873 *lastPtr = last;
874 }
875 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000876}
877
caryclark54359292015-03-26 07:52:43 -0700878bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
879 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
880 SkOpSpan* spanStart = start->starter(end);
881 int step = start->step(end);
882 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700883 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000884 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700885 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
886 if (spanStart->windSum() != SK_MinS32) {
887 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700888 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700889 this->globalState()->setWindingFailed();
890 return false;
caryclarkdac1d172014-06-17 05:15:38 -0700891 }
caryclark54359292015-03-26 07:52:43 -0700892 } else {
893 SkASSERT(spanStart->windSum() == oppWinding);
894 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700895 }
896 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700897 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000898 }
caryclark54359292015-03-26 07:52:43 -0700899 if (this->operand() == other->operand()) {
900 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700901 } else {
caryclark54359292015-03-26 07:52:43 -0700902 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700903 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000904 }
caryclark65f55312014-11-13 06:58:52 -0800905 if (lastPtr) {
906 *lastPtr = last;
907 }
908 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000909}
910
caryclark54359292015-03-26 07:52:43 -0700911SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000912 SkASSERT(angle->segment() == this);
913 if (UseInnerWinding(maxWinding, sumWinding)) {
914 maxWinding = sumWinding;
915 }
caryclark54359292015-03-26 07:52:43 -0700916 SkOpSpanBase* last;
917 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000918#if DEBUG_WINDING
919 if (last) {
caryclark54359292015-03-26 07:52:43 -0700920 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
921 last->segment()->debugID(), last->debugID());
922 if (!last->final()) {
923 SkDebugf(" windSum=");
924 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
925 }
926 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000927 }
928#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000929 return last;
930}
931
caryclark54359292015-03-26 07:52:43 -0700932SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
933 int oppSumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000934 SkASSERT(angle->segment() == this);
935 if (UseInnerWinding(maxWinding, sumWinding)) {
936 maxWinding = sumWinding;
937 }
938 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
939 oppMaxWinding = oppSumWinding;
940 }
halcanary96fcdcc2015-08-27 07:41:13 -0700941 SkOpSpanBase* last = nullptr;
caryclark65f55312014-11-13 06:58:52 -0800942 // caller doesn't require that this marks anything
caryclark54359292015-03-26 07:52:43 -0700943 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000944#if DEBUG_WINDING
945 if (last) {
caryclark54359292015-03-26 07:52:43 -0700946 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
947 last->segment()->debugID(), last->debugID());
948 if (!last->final()) {
949 SkDebugf(" windSum=");
950 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
951 }
952 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000953 }
954#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000955 return last;
956}
957
caryclark54359292015-03-26 07:52:43 -0700958void SkOpSegment::markDone(SkOpSpan* span) {
959 SkASSERT(this == span->segment());
960 if (span->done()) {
961 return;
962 }
963#if DEBUG_MARK_DONE
964 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
965#endif
966 span->setDone(true);
967 ++fDoneCount;
968 debugValidate();
969}
970
971bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
972 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -0700973 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -0700974 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -0700975 return false;
976 }
977#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -0700978 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -0700979#endif
caryclark54359292015-03-26 07:52:43 -0700980 span->setWindSum(winding);
981 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -0700982 return true;
983}
984
caryclark54359292015-03-26 07:52:43 -0700985bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
986 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000987 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -0700988 if (span->done()) {
989 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000990 }
caryclark54359292015-03-26 07:52:43 -0700991#if DEBUG_MARK_DONE
992 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
993#endif
994 span->setWindSum(winding);
995 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000996 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000997 return true;
998}
999
caryclark54359292015-03-26 07:52:43 -07001000bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclarkef4f32a2016-08-24 09:24:18 -07001001 const SkPoint& testPt) const {
caryclark55888e42016-07-18 10:01:36 -07001002 SkASSERT(this == base->segment());
1003 if (this == testParent) {
1004 if (precisely_equal(base->fT, testT)) {
1005 return true;
1006 }
caryclark54359292015-03-26 07:52:43 -07001007 }
1008 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1009 return false;
1010 }
caryclark55888e42016-07-18 10:01:36 -07001011 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001012}
1013
1014static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1015 if (last) {
1016 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001017 }
halcanary96fcdcc2015-08-27 07:41:13 -07001018 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001019}
1020
caryclark54359292015-03-26 07:52:43 -07001021SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1022 SkOpSpanBase** last) const {
1023 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001024 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001025 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1026 SkASSERT(endSpan);
1027 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1028 SkOpSpanBase* foundSpan;
1029 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001030 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001031 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001032 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001033 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001034 }
caryclark54359292015-03-26 07:52:43 -07001035 SkOpPtT* otherPtT = endSpan->ptT()->next();
1036 other = otherPtT->segment();
1037 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001038 otherEnd = step > 0
1039 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1040 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001041 } else {
1042 int loopCount = angle->loopCount();
1043 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001044 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001045 }
1046 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001047 if (nullptr == next) {
1048 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001049 }
caryclarkdac1d172014-06-17 05:15:38 -07001050#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001051 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001052 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001053 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001054 }
caryclark54359292015-03-26 07:52:43 -07001055#endif
caryclarkdac1d172014-06-17 05:15:38 -07001056 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001057 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001058 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001059 }
caryclark343382e2016-06-29 08:18:38 -07001060 if (!otherEnd) {
1061 return nullptr;
1062 }
caryclark54359292015-03-26 07:52:43 -07001063 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001064 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001065 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001066 }
caryclark54359292015-03-26 07:52:43 -07001067 SkASSERT(*startPtr);
caryclark65b427c2014-09-18 10:32:57 -07001068// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001069 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1070 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1071 if (foundMin->windValue() != origMin->windValue()
1072 || foundMin->oppValue() != origMin->oppValue()) {
1073 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001074 }
caryclark54359292015-03-26 07:52:43 -07001075 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001076 *stepPtr = foundStep;
1077 if (minPtr) {
1078 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001079 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001080 return other;
1081}
1082
caryclark55888e42016-07-18 10:01:36 -07001083// Please keep this in sync with DebugClearVisited()
1084void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001085 // reset visited flag back to false
1086 do {
1087 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1088 while ((ptT = ptT->next()) != stopPtT) {
1089 SkOpSegment* opp = ptT->segment();
1090 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001091 }
caryclarkbca19f72015-05-13 08:23:48 -07001092 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001093}
1094
caryclark55888e42016-07-18 10:01:36 -07001095// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001096// look for pairs of undetected coincident curves
1097// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001098// Even though pairs of curves correct detect coincident runs, a run may be missed
1099// if the coincidence is a product of multiple intersections. For instance, given
1100// curves A, B, and C:
1101// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1102// the end of C that the intersection is replaced with the end of C.
1103// Even though A-B correctly do not detect an intersection at point 2,
1104// the resulting run from point 1 to point 2 is coincident on A and B.
1105bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001106 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001107 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001108 }
halcanary96fcdcc2015-08-27 07:41:13 -07001109 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001110 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001111 bool result = false;
caryclark54359292015-03-26 07:52:43 -07001112 do {
caryclarkbca19f72015-05-13 08:23:48 -07001113 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001114 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001115 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001116 if (ptT->deleted()) {
1117 continue;
1118 }
caryclark54359292015-03-26 07:52:43 -07001119 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001120 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001121 continue;
reed0dc4dd62015-03-24 13:55:33 -07001122 }
caryclarkbca19f72015-05-13 08:23:48 -07001123 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1124 if (!opp->visited()) {
1125 continue;
1126 }
1127 if (spanBase == &fHead) {
1128 continue;
1129 }
caryclark55888e42016-07-18 10:01:36 -07001130 if (ptT->segment() == this) {
1131 continue;
1132 }
caryclarkbca19f72015-05-13 08:23:48 -07001133 SkOpSpan* span = spanBase->upCastable();
1134 // FIXME?: this assumes that if the opposite segment is coincident then no more
1135 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001136 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001137 continue;
1138 }
caryclarkbca19f72015-05-13 08:23:48 -07001139 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001140 continue;
caryclark55888e42016-07-18 10:01:36 -07001141 }
halcanary96fcdcc2015-08-27 07:41:13 -07001142 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001143 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001144 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001145 SkOpSpan* priorTest = spanBase->prev();
1146 while (!priorOpp && priorTest) {
1147 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001148 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001149 if (priorPtT->deleted()) {
1150 continue;
1151 }
caryclark54359292015-03-26 07:52:43 -07001152 SkOpSegment* segment = priorPtT->span()->segment();
1153 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001154 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001155 priorOpp = opp;
1156 break;
1157 }
1158 }
caryclarkbca19f72015-05-13 08:23:48 -07001159 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001160 }
1161 if (!priorOpp) {
1162 continue;
1163 }
caryclark26ad22a2015-10-16 09:03:38 -07001164 if (priorPtT == ptT) {
1165 continue;
1166 }
caryclark54359292015-03-26 07:52:43 -07001167 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001168 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001169 bool swapped = priorPtT->fT > ptT->fT;
1170 if (swapped) {
1171 SkTSwap(priorPtT, ptT);
1172 SkTSwap(oppStart, oppEnd);
1173 }
caryclark55888e42016-07-18 10:01:36 -07001174 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1175 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1176 SkOpPtT* rootPtT = ptT->span()->ptT();
1177 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1178 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1179 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001180 goto swapBack;
1181 }
caryclark55888e42016-07-18 10:01:36 -07001182 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001183 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001184#if DEBUG_COINCIDENCE_VERBOSE
1185 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1186 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1187 rootOppEnd->debugID());
1188#endif
1189 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1190 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001191 }
caryclark55888e42016-07-18 10:01:36 -07001192#if DEBUG_COINCIDENCE
1193 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1194#endif
1195 result = true;
caryclark54359292015-03-26 07:52:43 -07001196 }
1197 swapBack:
1198 if (swapped) {
1199 SkTSwap(priorPtT, ptT);
1200 }
reed0dc4dd62015-03-24 13:55:33 -07001201 }
halcanary96fcdcc2015-08-27 07:41:13 -07001202 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001203 ClearVisited(&fHead);
1204 return result;
reed0dc4dd62015-03-24 13:55:33 -07001205}
1206
caryclark55888e42016-07-18 10:01:36 -07001207// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001208// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001209bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001210 debugValidate();
1211 SkOpSpanBase* test = &fHead;
1212 do {
1213 int addCount = test->spanAddsCount();
Cary Clark7eb01e02016-12-08 14:36:32 -05001214// FAIL_IF(addCount < 1);
1215 if (addCount <= 1) {
caryclark08bc8482015-04-24 09:08:57 -07001216 continue;
1217 }
1218 SkOpPtT* startPtT = test->ptT();
1219 SkOpPtT* testPtT = startPtT;
1220 do { // iterate through all spans associated with start
1221 SkOpSpanBase* oppSpan = testPtT->span();
1222 if (oppSpan->spanAddsCount() == addCount) {
1223 continue;
1224 }
1225 if (oppSpan->deleted()) {
1226 continue;
1227 }
1228 SkOpSegment* oppSegment = oppSpan->segment();
1229 if (oppSegment == this) {
1230 continue;
1231 }
1232 // find range of spans to consider merging
1233 SkOpSpanBase* oppPrev = oppSpan;
1234 SkOpSpanBase* oppFirst = oppSpan;
1235 while ((oppPrev = oppPrev->prev())) {
1236 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1237 break;
1238 }
1239 if (oppPrev->spanAddsCount() == addCount) {
1240 continue;
1241 }
1242 if (oppPrev->deleted()) {
1243 continue;
1244 }
1245 oppFirst = oppPrev;
1246 }
1247 SkOpSpanBase* oppNext = oppSpan;
1248 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001249 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001250 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1251 break;
1252 }
1253 if (oppNext->spanAddsCount() == addCount) {
1254 continue;
1255 }
1256 if (oppNext->deleted()) {
1257 continue;
1258 }
1259 oppLast = oppNext;
1260 }
1261 if (oppFirst == oppLast) {
1262 continue;
1263 }
1264 SkOpSpanBase* oppTest = oppFirst;
1265 do {
1266 if (oppTest == oppSpan) {
1267 continue;
1268 }
1269 // check to see if the candidate meets specific criteria:
1270 // it contains spans of segments in test's loop but not including 'this'
1271 SkOpPtT* oppStartPtT = oppTest->ptT();
1272 SkOpPtT* oppPtT = oppStartPtT;
1273 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1274 SkOpSegment* oppPtTSegment = oppPtT->segment();
1275 if (oppPtTSegment == this) {
1276 goto tryNextSpan;
1277 }
1278 SkOpPtT* matchPtT = startPtT;
1279 do {
1280 if (matchPtT->segment() == oppPtTSegment) {
1281 goto foundMatch;
1282 }
1283 } while ((matchPtT = matchPtT->next()) != startPtT);
1284 goto tryNextSpan;
1285 foundMatch: // merge oppTest and oppSpan
1286 oppSegment->debugValidate();
caryclark30b9fdd2016-08-31 14:36:29 -07001287 oppTest->mergeMatches(oppSpan);
1288 oppTest->addOpp(oppSpan);
caryclark08bc8482015-04-24 09:08:57 -07001289 oppSegment->debugValidate();
1290 goto checkNextSpan;
1291 }
caryclark55888e42016-07-18 10:01:36 -07001292 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001293 ;
1294 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1295 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001296checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001297 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001298 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001299 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001300 return true;
caryclark08bc8482015-04-24 09:08:57 -07001301}
1302
caryclark55888e42016-07-18 10:01:36 -07001303// adjacent spans may have points close by
1304bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan) const {
1305 const SkOpPtT* refHead = refSpan->ptT();
1306 const SkOpPtT* checkHead = checkSpan->ptT();
1307// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
caryclark30b9fdd2016-08-31 14:36:29 -07001308 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
caryclark55888e42016-07-18 10:01:36 -07001309#if DEBUG_COINCIDENCE
1310 // verify that no combination of points are close
1311 const SkOpPtT* dBugRef = refHead;
1312 do {
1313 const SkOpPtT* dBugCheck = checkHead;
1314 do {
caryclark30b9fdd2016-08-31 14:36:29 -07001315 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
caryclark55888e42016-07-18 10:01:36 -07001316 dBugCheck = dBugCheck->next();
1317 } while (dBugCheck != checkHead);
1318 dBugRef = dBugRef->next();
1319 } while (dBugRef != refHead);
1320#endif
1321 return false;
1322 }
1323 // check only unique points
1324 SkScalar distSqBest = SK_ScalarMax;
1325 const SkOpPtT* refBest = nullptr;
1326 const SkOpPtT* checkBest = nullptr;
1327 const SkOpPtT* ref = refHead;
1328 do {
1329 if (ref->deleted()) {
1330 continue;
1331 }
1332 while (ref->ptAlreadySeen(refHead)) {
1333 ref = ref->next();
1334 if (ref == refHead) {
1335 goto doneCheckingDistance;
1336 }
1337 }
1338 const SkOpPtT* check = checkHead;
1339 const SkOpSegment* refSeg = ref->segment();
1340 do {
1341 if (check->deleted()) {
1342 continue;
1343 }
1344 while (check->ptAlreadySeen(checkHead)) {
1345 check = check->next();
1346 if (check == checkHead) {
1347 goto nextRef;
1348 }
1349 }
1350 SkScalar distSq = ref->fPt.distanceToSqd(check->fPt);
1351 if (distSqBest > distSq && (refSeg != check->segment()
1352 || !refSeg->ptsDisjoint(*ref, *check))) {
1353 distSqBest = distSq;
1354 refBest = ref;
1355 checkBest = check;
1356 }
1357 } while ((check = check->next()) != checkHead);
1358nextRef:
1359 ;
1360 } while ((ref = ref->next()) != refHead);
1361doneCheckingDistance:
1362 return checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001363 checkBest->fPt);
caryclark55888e42016-07-18 10:01:36 -07001364}
1365
1366// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001367// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
caryclark08bc8482015-04-24 09:08:57 -07001368void SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001369 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001370 // release undeleted spans pointing to this seg that are linked to the primary span
1371 SkOpSpanBase* spanBase = &fHead;
caryclark54359292015-03-26 07:52:43 -07001372 do {
caryclark55888e42016-07-18 10:01:36 -07001373 SkOpPtT* ptT = spanBase->ptT();
1374 const SkOpPtT* headPtT = ptT;
1375 while ((ptT = ptT->next()) != headPtT) {
1376 SkOpSpanBase* test = ptT->span();
1377 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1378 && test->ptT() == ptT) {
1379 if (test->final()) {
1380 if (spanBase == &fHead) {
1381 this->clearAll();
1382 return;
1383 }
1384 spanBase->upCast()->release(ptT);
1385 } else if (test->prev()) {
1386 test->upCast()->release(headPtT);
1387 }
1388 break;
caryclark54359292015-03-26 07:52:43 -07001389 }
reed0dc4dd62015-03-24 13:55:33 -07001390 }
caryclark55888e42016-07-18 10:01:36 -07001391 spanBase = spanBase->upCast()->next();
1392 } while (!spanBase->final());
1393
1394 // This loop looks for adjacent spans which are near by
1395 spanBase = &fHead;
1396 do { // iterate through all spans associated with start
1397 SkOpSpanBase* test = spanBase->upCast()->next();
1398 if (this->spansNearby(spanBase, test)) {
1399 if (test->final()) {
1400 if (spanBase->prev()) {
1401 test->merge(spanBase->upCast());
1402 } else {
1403 this->clearAll();
1404 return;
1405 }
1406 } else {
1407 spanBase->merge(test->upCast());
1408 }
1409 }
1410 spanBase = test;
1411 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001412 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001413}
1414
caryclark54359292015-03-26 07:52:43 -07001415bool SkOpSegment::operand() const {
1416 return fContour->operand();
1417}
1418
1419bool SkOpSegment::oppXor() const {
1420 return fContour->oppXor();
1421}
1422
1423bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1424 if (fVerb == SkPath::kLine_Verb) {
1425 return false;
1426 }
1427 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1428 // hits in two places with very different t values.
1429 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1430 // 'controls contained by ends' could avoid this check for common curves
1431 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1432 // on the other hand, the below check is relatively inexpensive
1433 double midT = (t1 + t2) / 2;
1434 SkPoint midPt = this->ptAtT(midT);
1435 double seDistSq = SkTMax(pt1.distanceToSqd(pt2) * 2, FLT_EPSILON * 2);
1436 return midPt.distanceToSqd(pt1) > seDistSq || midPt.distanceToSqd(pt2) > seDistSq;
1437}
1438
1439void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1440 int* maxWinding, int* sumWinding) {
1441 int deltaSum = SpanSign(start, end);
1442 *maxWinding = *sumMiWinding;
1443 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001444 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001445}
1446
1447void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1448 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1449 int* oppSumWinding) {
1450 int deltaSum = SpanSign(start, end);
1451 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001452 if (operand()) {
1453 *maxWinding = *sumSuWinding;
1454 *sumWinding = *sumSuWinding -= deltaSum;
1455 *oppMaxWinding = *sumMiWinding;
1456 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1457 } else {
1458 *maxWinding = *sumMiWinding;
1459 *sumWinding = *sumMiWinding -= deltaSum;
1460 *oppMaxWinding = *sumSuWinding;
1461 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1462 }
bungeman60e0fee2015-08-26 05:15:46 -07001463 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1464 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001465}
1466
caryclarkb36a3cd2016-10-18 07:59:44 -07001467bool SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001468 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001469 do {
caryclark54359292015-03-26 07:52:43 -07001470 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001471 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001472 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001473 continue;
1474 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001475#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001476 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001477#endif
caryclark54359292015-03-26 07:52:43 -07001478 SkOpAngle* baseAngle = fromAngle;
1479 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001480#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001481 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1482 span->debugID());
1483 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001484#endif
caryclarkb36a3cd2016-10-18 07:59:44 -07001485 FAIL_IF(!fromAngle->insert(toAngle));
caryclark54359292015-03-26 07:52:43 -07001486 } else if (!fromAngle) {
1487 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001488 }
caryclark54359292015-03-26 07:52:43 -07001489 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001490 do {
caryclark54359292015-03-26 07:52:43 -07001491 SkOpSpanBase* oSpan = ptT->span();
1492 if (oSpan == span) {
1493 continue;
1494 }
1495 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001496 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001497#if DEBUG_ANGLE
1498 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001499 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1500 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001501 wroteAfterHeader = true;
1502 }
1503#endif
caryclark54359292015-03-26 07:52:43 -07001504 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001505 baseAngle->insert(oAngle);
1506 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001507 }
caryclark54359292015-03-26 07:52:43 -07001508 if (!oSpan->final()) {
1509 oAngle = oSpan->upCast()->toAngle();
1510 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001511#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001512 if (!wroteAfterHeader) {
1513 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1514 span->t(), span->debugID());
1515 wroteAfterHeader = true;
1516 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001517#endif
caryclark54359292015-03-26 07:52:43 -07001518 if (!oAngle->loopContains(baseAngle)) {
1519 baseAngle->insert(oAngle);
1520 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001521 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001522 }
caryclark54359292015-03-26 07:52:43 -07001523 } while ((ptT = ptT->next()) != stopPtT);
1524 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001525 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001526 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001527 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001528 }
halcanary96fcdcc2015-08-27 07:41:13 -07001529 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001530 }
1531#if DEBUG_SORT
1532 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1533#endif
caryclark54359292015-03-26 07:52:43 -07001534 } while (!span->final() && (span = span->upCast()->next()));
caryclarkb36a3cd2016-10-18 07:59:44 -07001535 return true;
caryclark@google.com570863f2013-09-16 15:55:01 +00001536}
1537
caryclark54359292015-03-26 07:52:43 -07001538bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001539 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001540 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001541 const SkOpPtT& startPtT = *start->ptT();
1542 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001543 SkDEBUGCODE(edge->fVerb = fVerb);
1544 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001545 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001546 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001547 if (fVerb == SkPath::kLine_Verb) {
1548 return false;
1549 }
caryclark54359292015-03-26 07:52:43 -07001550 double startT = startPtT.fT;
1551 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001552 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1553 // don't compute midpoints if we already have them
1554 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001555 edge->fLine[1].set(fPts[1]);
1556 return false;
1557 }
1558 if (fVerb == SkPath::kConic_Verb) {
1559 edge->fConic[1].set(fPts[1]);
1560 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001561 return false;
1562 }
1563 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001564 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001565 edge->fCubic[1].set(fPts[1]);
1566 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001567 return false;
1568 }
caryclark1049f122015-04-20 08:31:59 -07001569 edge->fCubic[1].set(fPts[2]);
1570 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001571 return false;
1572 }
1573 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001574 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1575 } else if (fVerb == SkPath::kConic_Verb) {
1576 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1577 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001578 } else {
1579 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001580 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001581 }
1582 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001583}
1584
caryclark27c8eb82015-07-06 11:38:33 -07001585bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001586 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001587 // average t, find mid pt
1588 double midT = (prior->t() + spanBase->t()) / 2;
1589 SkPoint midPt = this->ptAtT(midT);
1590 bool coincident = true;
1591 // if the mid pt is not near either end pt, project perpendicular through opp seg
1592 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1593 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001594 if (priorPtT->span() == ptT->span()) {
1595 return false;
1596 }
caryclark27c8eb82015-07-06 11:38:33 -07001597 coincident = false;
1598 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001599 SkDCurve curvePart;
1600 this->subDivide(prior, spanBase, &curvePart);
1601 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1602 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1603 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1604 SkDCurve oppPart;
1605 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1606 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001607 // measure distance and see if it's small enough to denote coincidence
1608 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001609 if (!between(0, i[0][index], 1)) {
1610 continue;
1611 }
caryclark27c8eb82015-07-06 11:38:33 -07001612 SkDPoint oppPt = i.pt(index);
caryclark30b9fdd2016-08-31 14:36:29 -07001613 if (oppPt.approximatelyDEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001614 // the coincidence can occur at almost any angle
1615 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001616 }
1617 }
1618 }
1619 return coincident;
1620}
1621
Cary Clarkab2d73b2016-12-16 17:17:25 -05001622SkOpSpan* SkOpSegment::undoneSpan() {
1623 SkOpSpan* span = &fHead;
1624 SkOpSpanBase* next;
caryclark54359292015-03-26 07:52:43 -07001625 do {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001626 next = span->next();
caryclark54359292015-03-26 07:52:43 -07001627 if (!span->done()) {
Cary Clarkab2d73b2016-12-16 17:17:25 -05001628 return span;
reed0dc4dd62015-03-24 13:55:33 -07001629 }
Cary Clarkab2d73b2016-12-16 17:17:25 -05001630 } while (!next->final() && (span = next->upCast()));
1631 return nullptr;
reed0dc4dd62015-03-24 13:55:33 -07001632}
1633
caryclark54359292015-03-26 07:52:43 -07001634int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1635 const SkOpSpan* lesser = start->starter(end);
1636 int oppWinding = lesser->oppSum();
1637 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001638 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1639 && oppWinding != SK_MaxS32) {
1640 oppWinding -= oppSpanWinding;
1641 }
1642 return oppWinding;
1643}
1644
1645int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001646 const SkOpSpanBase* startSpan = angle->start();
1647 const SkOpSpanBase* endSpan = angle->end();
1648 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001649}
1650
1651int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001652 const SkOpSpanBase* startSpan = angle->start();
1653 const SkOpSpanBase* endSpan = angle->end();
1654 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001655}
1656
caryclark624637c2015-05-11 07:21:27 -07001657int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1658 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001659 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001660 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001661 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001662 }
1663 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001664 return winding;
1665 }
caryclark54359292015-03-26 07:52:43 -07001666 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001667 if (winding && UseInnerWinding(winding - spanWinding, winding)
1668 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001669 winding -= spanWinding;
1670 }
1671 return winding;
1672}
1673
caryclark624637c2015-05-11 07:21:27 -07001674int SkOpSegment::updateWinding(SkOpAngle* angle) {
1675 SkOpSpanBase* startSpan = angle->start();
1676 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001677 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001678}
1679
caryclark624637c2015-05-11 07:21:27 -07001680int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1681 SkOpSpanBase* startSpan = angle->start();
1682 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001683 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001684}
1685
1686// OPTIMIZATION: does the following also work, and is it any faster?
1687// return outerWinding * innerWinding > 0
1688// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1689bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1690 SkASSERT(outerWinding != SK_MaxS32);
1691 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001692 int absOut = SkTAbs(outerWinding);
1693 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001694 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1695 return result;
1696}
1697
caryclark@google.com07393ca2013-04-08 11:47:37 +00001698int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001699 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1700 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001701}