blob: 2246f36ff217b4aa33375c8537d166d971347c07 [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:
172 path->deferredLine(end->ptT());
173 break;
174 case SkPath::kQuad_Verb:
175 path->quadTo(curvePart.fCurve.fQuad.fPts[1].asSkPoint(), end->ptT());
176 break;
177 case SkPath::kConic_Verb:
178 path->conicTo(curvePart.fCurve.fConic.fPts[1].asSkPoint(), end->ptT(),
179 curvePart.fCurve.fConic.fWeight);
180 break;
181 case SkPath::kCubic_Verb:
182 path->cubicTo(curvePart.fCurve.fCubic.fPts[1].asSkPoint(),
183 curvePart.fCurve.fCubic.fPts[2].asSkPoint(), end->ptT());
184 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();
228 SkOpPtT* newPtT = this->addT(newT);
229 *startOver |= this->globalState()->allocatedOpSpan();
caryclark55888e42016-07-18 10:01:36 -0700230 if (!newPtT) {
231 return false;
232 }
233 newPtT->fPt = this->ptAtT(newT);
caryclark29b25632016-08-25 11:27:17 -0700234 SkOpPtT* oppPrev = test->ptT()->oppPrev(newPtT);
235 if (oppPrev) {
caryclark8016b262016-09-06 05:59:47 -0700236 // const cast away to change linked list; pt/t values stays unchanged
caryclark29b25632016-08-25 11:27:17 -0700237 SkOpSpanBase* writableTest = const_cast<SkOpSpanBase*>(test);
caryclark30b9fdd2016-08-31 14:36:29 -0700238 writableTest->mergeMatches(newPtT->span());
caryclark29b25632016-08-25 11:27:17 -0700239 writableTest->ptT()->addOpp(newPtT, oppPrev);
caryclark55888e42016-07-18 10:01:36 -0700240 writableTest->checkForCollapsedCoincidence();
241 }
242 return true;
243}
244
245// Please keep this in sync with debugAddT()
caryclark29b25632016-08-25 11:27:17 -0700246SkOpPtT* SkOpSegment::addT(double t) {
reed0dc4dd62015-03-24 13:55:33 -0700247 debugValidate();
caryclark54359292015-03-26 07:52:43 -0700248 SkPoint pt = this->ptAtT(t);
caryclark29b25632016-08-25 11:27:17 -0700249 SkOpSpanBase* spanBase = &fHead;
caryclark54359292015-03-26 07:52:43 -0700250 do {
caryclark29b25632016-08-25 11:27:17 -0700251 SkOpPtT* result = spanBase->ptT();
caryclark27c015d2016-09-23 05:47:20 -0700252 if (t == result->fT || (!zero_or_one(t) && this->match(result, this, t, pt))) {
caryclark29b25632016-08-25 11:27:17 -0700253 spanBase->bumpSpanAdds();
caryclarkef4f32a2016-08-24 09:24:18 -0700254 return result;
reed0dc4dd62015-03-24 13:55:33 -0700255 }
caryclark54359292015-03-26 07:52:43 -0700256 if (t < result->fT) {
257 SkOpSpan* prev = result->span()->prev();
caryclark29b25632016-08-25 11:27:17 -0700258 FAIL_WITH_NULL_IF(!prev);
259 // marks in global state that new op span has been allocated
260 SkOpSpan* span = this->insert(prev);
caryclark54359292015-03-26 07:52:43 -0700261 span->init(this, prev, t, pt);
262 this->debugValidate();
263#if DEBUG_ADD_T
264 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
265 span->segment()->debugID(), span->debugID());
266#endif
caryclark08bc8482015-04-24 09:08:57 -0700267 span->bumpSpanAdds();
caryclark54359292015-03-26 07:52:43 -0700268 return span->ptT();
269 }
caryclark29b25632016-08-25 11:27:17 -0700270 FAIL_WITH_NULL_IF(spanBase == &fTail);
271 } while ((spanBase = spanBase->upCast()->next()));
caryclark54359292015-03-26 07:52:43 -0700272 SkASSERT(0);
caryclark29b25632016-08-25 11:27:17 -0700273 return nullptr; // we never get here, but need this to satisfy compiler
caryclark54359292015-03-26 07:52:43 -0700274}
275
caryclark55888e42016-07-18 10:01:36 -0700276void SkOpSegment::calcAngles() {
caryclark54359292015-03-26 07:52:43 -0700277 bool activePrior = !fHead.isCanceled();
278 if (activePrior && !fHead.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700279 addStartSpan();
reed0dc4dd62015-03-24 13:55:33 -0700280 }
caryclark54359292015-03-26 07:52:43 -0700281 SkOpSpan* prior = &fHead;
282 SkOpSpanBase* spanBase = fHead.next();
283 while (spanBase != &fTail) {
284 if (activePrior) {
caryclark55888e42016-07-18 10:01:36 -0700285 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(
286 this->globalState()->allocator());
caryclark54359292015-03-26 07:52:43 -0700287 priorAngle->set(spanBase, prior);
288 spanBase->setFromAngle(priorAngle);
reed0dc4dd62015-03-24 13:55:33 -0700289 }
caryclark54359292015-03-26 07:52:43 -0700290 SkOpSpan* span = spanBase->upCast();
291 bool active = !span->isCanceled();
292 SkOpSpanBase* next = span->next();
293 if (active) {
caryclark55888e42016-07-18 10:01:36 -0700294 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(
295 this->globalState()->allocator());
caryclark54359292015-03-26 07:52:43 -0700296 angle->set(span, next);
297 span->setToAngle(angle);
reed0dc4dd62015-03-24 13:55:33 -0700298 }
reed0dc4dd62015-03-24 13:55:33 -0700299 activePrior = active;
caryclark54359292015-03-26 07:52:43 -0700300 prior = span;
301 spanBase = next;
reed0dc4dd62015-03-24 13:55:33 -0700302 }
caryclark54359292015-03-26 07:52:43 -0700303 if (activePrior && !fTail.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700304 addEndSpan();
reed0dc4dd62015-03-24 13:55:33 -0700305 }
reed0dc4dd62015-03-24 13:55:33 -0700306}
307
caryclark55888e42016-07-18 10:01:36 -0700308// Please keep this in sync with debugClearAll()
309void SkOpSegment::clearAll() {
310 SkOpSpan* span = &fHead;
311 do {
312 this->clearOne(span);
313 } while ((span = span->next()->upCastable()));
314 this->globalState()->coincidence()->release(this);
315}
316
317// Please keep this in sync with debugClearOne()
318void SkOpSegment::clearOne(SkOpSpan* span) {
319 span->setWindValue(0);
320 span->setOppValue(0);
321 this->markDone(span);
322}
323
caryclark30b9fdd2016-08-31 14:36:29 -0700324bool SkOpSegment::collapsed(double s, double e) const {
325 const SkOpSpanBase* span = &fHead;
326 do {
327 if (span->collapsed(s, e)) {
328 return true;
329 }
330 } while (span->upCastable() && (span = span->upCast()->next()));
331 return false;
332}
333
caryclark@google.com570863f2013-09-16 15:55:01 +0000334void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
335 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700336 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000337 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
338 int sumSuWinding;
339 bool binary = includeType >= SkOpAngle::kBinarySingle;
340 if (binary) {
341 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
342 if (baseSegment->operand()) {
343 SkTSwap<int>(sumMiWinding, sumSuWinding);
344 }
345 }
346 SkOpSegment* nextSegment = nextAngle->segment();
347 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700348 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000349 if (binary) {
350 int oppMaxWinding, oppSumWinding;
351 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
352 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
353 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000354 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000355 } else {
356 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
357 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000358 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000359 }
360 nextAngle->setLastMarked(last);
361}
362
caryclark624637c2015-05-11 07:21:27 -0700363void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
caryclark@google.com570863f2013-09-16 15:55:01 +0000364 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700365 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000366 int sumMiWinding = baseSegment->updateWinding(baseAngle);
367 int sumSuWinding;
368 bool binary = includeType >= SkOpAngle::kBinarySingle;
369 if (binary) {
370 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
371 if (baseSegment->operand()) {
372 SkTSwap<int>(sumMiWinding, sumSuWinding);
373 }
374 }
375 SkOpSegment* nextSegment = nextAngle->segment();
376 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700377 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000378 if (binary) {
379 int oppMaxWinding, oppSumWinding;
380 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
381 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
382 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000383 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000384 } else {
385 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
386 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000387 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000388 }
389 nextAngle->setLastMarked(last);
390}
391
caryclark54359292015-03-26 07:52:43 -0700392// at this point, the span is already ordered, or unorderable
393int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
394 SkOpAngle::IncludeType includeType) {
395 SkASSERT(includeType != SkOpAngle::kUnaryXor);
396 SkOpAngle* firstAngle = this->spanToAngle(end, start);
halcanary96fcdcc2015-08-27 07:41:13 -0700397 if (nullptr == firstAngle || nullptr == firstAngle->next()) {
caryclark54359292015-03-26 07:52:43 -0700398 return SK_NaN32;
399 }
400 // if all angles have a computed winding,
401 // or if no adjacent angles are orderable,
402 // or if adjacent orderable angles have no computed winding,
403 // there's nothing to do
404 // if two orderable angles are adjacent, and both are next to orderable angles,
405 // and one has winding computed, transfer to the other
halcanary96fcdcc2015-08-27 07:41:13 -0700406 SkOpAngle* baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700407 bool tryReverse = false;
408 // look for counterclockwise transfers
409 SkOpAngle* angle = firstAngle->previous();
410 SkOpAngle* next = angle->next();
411 firstAngle = next;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000412 do {
caryclark54359292015-03-26 07:52:43 -0700413 SkOpAngle* prior = angle;
414 angle = next;
415 next = angle->next();
416 SkASSERT(prior->next() == angle);
417 SkASSERT(angle->next() == next);
418 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700419 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700420 continue;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000421 }
caryclark54359292015-03-26 07:52:43 -0700422 int testWinding = angle->starter()->windSum();
423 if (SK_MinS32 != testWinding) {
424 baseAngle = angle;
425 tryReverse = true;
426 continue;
reed0dc4dd62015-03-24 13:55:33 -0700427 }
caryclark54359292015-03-26 07:52:43 -0700428 if (baseAngle) {
429 ComputeOneSum(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700430 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
caryclark54359292015-03-26 07:52:43 -0700431 }
432 } while (next != firstAngle);
433 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
434 firstAngle = baseAngle;
435 tryReverse = true;
436 }
437 if (tryReverse) {
halcanary96fcdcc2015-08-27 07:41:13 -0700438 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700439 SkOpAngle* prior = firstAngle;
440 do {
441 angle = prior;
442 prior = angle->previous();
443 SkASSERT(prior->next() == angle);
444 next = angle->next();
445 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700446 baseAngle = nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700447 continue;
448 }
caryclark54359292015-03-26 07:52:43 -0700449 int testWinding = angle->starter()->windSum();
450 if (SK_MinS32 != testWinding) {
451 baseAngle = angle;
452 continue;
reed0dc4dd62015-03-24 13:55:33 -0700453 }
caryclark54359292015-03-26 07:52:43 -0700454 if (baseAngle) {
455 ComputeOneSumReverse(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700456 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700457 }
caryclark54359292015-03-26 07:52:43 -0700458 } while (prior != firstAngle);
reed0dc4dd62015-03-24 13:55:33 -0700459 }
caryclark54359292015-03-26 07:52:43 -0700460 return start->starter(end)->windSum();
reed0dc4dd62015-03-24 13:55:33 -0700461}
462
caryclark55888e42016-07-18 10:01:36 -0700463bool SkOpSegment::contains(double newT) const {
464 const SkOpSpanBase* spanBase = &fHead;
465 do {
466 if (spanBase->ptT()->contains(this, newT)) {
467 return true;
468 }
469 if (spanBase == &fTail) {
470 break;
471 }
472 spanBase = spanBase->upCast()->next();
473 } while (true);
474 return false;
475}
476
mtklein18300a32016-03-16 13:53:35 -0700477void SkOpSegment::release(const SkOpSpan* span) {
caryclark54359292015-03-26 07:52:43 -0700478 if (span->done()) {
caryclark08bc8482015-04-24 09:08:57 -0700479 --fDoneCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000480 }
caryclark08bc8482015-04-24 09:08:57 -0700481 --fCount;
caryclark15976282016-07-21 05:48:43 -0700482 SkOPASSERT(fCount >= fDoneCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000483}
484
Cary Clarke47ae292016-10-05 08:51:39 -0400485#if DEBUG_ANGLE
486// called only by debugCheckNearCoincidence
caryclark26ad22a2015-10-16 09:03:38 -0700487double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
caryclark54359292015-03-26 07:52:43 -0700488 SkDPoint testPt = this->dPtAtT(t);
489 SkDLine testPerp = {{ testPt, testPt }};
490 SkDVector slope = this->dSlopeAtT(t);
491 testPerp[1].fX += slope.fY;
492 testPerp[1].fY -= slope.fX;
493 SkIntersections i;
caryclark26ad22a2015-10-16 09:03:38 -0700494 const SkOpSegment* oppSegment = oppAngle->segment();
caryclark1049f122015-04-20 08:31:59 -0700495 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
caryclark54359292015-03-26 07:52:43 -0700496 double closestDistSq = SK_ScalarInfinity;
497 for (int index = 0; index < i.used(); ++index) {
498 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000499 continue;
500 }
caryclark54359292015-03-26 07:52:43 -0700501 double testDistSq = testPt.distanceSquared(i.pt(index));
502 if (closestDistSq > testDistSq) {
503 closestDistSq = testDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000504 }
505 }
caryclark54359292015-03-26 07:52:43 -0700506 return closestDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000507}
Cary Clarke47ae292016-10-05 08:51:39 -0400508#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000509
caryclark@google.com07393ca2013-04-08 11:47:37 +0000510/*
511 The M and S variable name parts stand for the operators.
512 Mi stands for Minuend (see wiki subtraction, analogous to difference)
513 Su stands for Subtrahend
514 The Opp variable name part designates that the value is for the Opposite operator.
515 Opposite values result from combining coincident spans.
516 */
caryclark54359292015-03-26 07:52:43 -0700517SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
518 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) {
519 SkOpSpanBase* start = *nextStart;
520 SkOpSpanBase* end = *nextEnd;
521 SkASSERT(start != end);
522 int step = start->step(end);
523 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
524 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000525 // mark the smaller of startIndex, endIndex done, and all adjacent
526 // spans with the same T value (but not 'other' spans)
527#if DEBUG_WINDING
528 SkDebugf("%s simple\n", __FUNCTION__);
529#endif
caryclark54359292015-03-26 07:52:43 -0700530 SkOpSpan* startSpan = start->starter(end);
531 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700532 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000533 }
caryclark54359292015-03-26 07:52:43 -0700534 markDone(startSpan);
535 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000536 return other;
537 }
caryclark54359292015-03-26 07:52:43 -0700538 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
539 SkASSERT(endNear == end); // is this ever not end?
540 SkASSERT(endNear);
541 SkASSERT(start != endNear);
542 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000543 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700544 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
caryclark@google.com570863f2013-09-16 15:55:01 +0000545 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000546 if (!sortable) {
547 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700548 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700549 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000550 }
caryclark54359292015-03-26 07:52:43 -0700551 SkOpAngle* angle = this->spanToAngle(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000552 if (angle->unorderable()) {
553 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700554 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700555 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000556 }
557#if DEBUG_SORT
558 SkDebugf("%s\n", __FUNCTION__);
559 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000560#endif
caryclark54359292015-03-26 07:52:43 -0700561 int sumMiWinding = updateWinding(end, start);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000562 if (sumMiWinding == SK_MinS32) {
563 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700564 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700565 return nullptr;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000566 }
caryclark54359292015-03-26 07:52:43 -0700567 int sumSuWinding = updateOppWinding(end, start);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000568 if (operand()) {
569 SkTSwap<int>(sumMiWinding, sumSuWinding);
570 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000571 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700572 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000573 bool foundDone = false;
574 // iterate through the angle, and compute everyone's winding
575 SkOpSegment* nextSegment;
576 int activeCount = 0;
577 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000578 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000579 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000580 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000581 if (activeAngle) {
582 ++activeCount;
583 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000584 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +0000585 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000586 }
587 }
588 if (nextSegment->done()) {
589 continue;
590 }
reed0dc4dd62015-03-24 13:55:33 -0700591 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700592 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700593 }
caryclark54359292015-03-26 07:52:43 -0700594 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000595 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000596 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000597 *chase->append() = last;
598#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700599 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
600 last->segment()->debugID(), last->debugID());
601 if (!last->final()) {
602 SkDebugf(" windSum=%d", last->upCast()->windSum());
603 }
604 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000605#endif
606 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000607 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700608 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000609 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700610 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000611 }
612 *nextStart = foundAngle->start();
613 *nextEnd = foundAngle->end();
614 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000615#if DEBUG_WINDING
616 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
617 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
618 #endif
619 return nextSegment;
620}
621
caryclark54359292015-03-26 07:52:43 -0700622SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
623 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
624 SkOpSpanBase* start = *nextStart;
625 SkOpSpanBase* end = *nextEnd;
626 SkASSERT(start != end);
627 int step = start->step(end);
628 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
629 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000630 // mark the smaller of startIndex, endIndex done, and all adjacent
631 // spans with the same T value (but not 'other' spans)
632#if DEBUG_WINDING
633 SkDebugf("%s simple\n", __FUNCTION__);
634#endif
caryclark54359292015-03-26 07:52:43 -0700635 SkOpSpan* startSpan = start->starter(end);
636 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700637 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000638 }
caryclark54359292015-03-26 07:52:43 -0700639 markDone(startSpan);
640 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000641 return other;
642 }
caryclark54359292015-03-26 07:52:43 -0700643 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
644 SkASSERT(endNear == end); // is this ever not end?
645 SkASSERT(endNear);
646 SkASSERT(start != endNear);
647 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000648 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700649 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000650 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000651 if (!sortable) {
652 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700653 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700654 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000655 }
caryclark54359292015-03-26 07:52:43 -0700656 SkOpAngle* angle = this->spanToAngle(end, start);
657 if (angle->unorderable()) {
658 *unsortable = true;
659 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700660 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700661 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000662#if DEBUG_SORT
663 SkDebugf("%s\n", __FUNCTION__);
664 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000665#endif
caryclark54359292015-03-26 07:52:43 -0700666 int sumWinding = updateWinding(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000667 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700668 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000669 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700670 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000671 SkOpSegment* nextSegment;
672 int activeCount = 0;
673 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000674 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000675 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000676 &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000677 if (activeAngle) {
678 ++activeCount;
679 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000680 foundAngle = nextAngle;
681 foundDone = nextSegment->done(nextAngle);
682 }
683 }
684 if (nextSegment->done()) {
685 continue;
686 }
reed0dc4dd62015-03-24 13:55:33 -0700687 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700688 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700689 }
caryclark54359292015-03-26 07:52:43 -0700690 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000691 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000692 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000693 *chase->append() = last;
694#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700695 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
696 last->segment()->debugID(), last->debugID());
697 if (!last->final()) {
698 SkDebugf(" windSum=%d", last->upCast()->windSum());
699 }
700 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000701#endif
702 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000703 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700704 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000705 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700706 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000707 }
708 *nextStart = foundAngle->start();
709 *nextEnd = foundAngle->end();
710 nextSegment = foundAngle->segment();
711#if DEBUG_WINDING
712 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
713 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
714 #endif
715 return nextSegment;
716}
717
caryclark54359292015-03-26 07:52:43 -0700718SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
719 bool* unsortable) {
720 SkOpSpanBase* start = *nextStart;
721 SkOpSpanBase* end = *nextEnd;
722 SkASSERT(start != end);
723 int step = start->step(end);
724 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
725 if (other) {
726 // mark the smaller of startIndex, endIndex done, and all adjacent
727 // spans with the same T value (but not 'other' spans)
caryclark@google.com07393ca2013-04-08 11:47:37 +0000728#if DEBUG_WINDING
729 SkDebugf("%s simple\n", __FUNCTION__);
730#endif
caryclark54359292015-03-26 07:52:43 -0700731 SkOpSpan* startSpan = start->starter(end);
732 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700733 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000734 }
caryclark54359292015-03-26 07:52:43 -0700735 markDone(startSpan);
736 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000737 return other;
738 }
caryclark54359292015-03-26 07:52:43 -0700739 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
740 : (*nextStart)->prev());
741 SkASSERT(endNear == end); // is this ever not end?
742 SkASSERT(endNear);
743 SkASSERT(start != endNear);
744 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
745 SkOpAngle* angle = this->spanToAngle(end, start);
caryclark27c8eb82015-07-06 11:38:33 -0700746 if (!angle || angle->unorderable()) {
caryclark54359292015-03-26 07:52:43 -0700747 *unsortable = true;
748 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700749 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700750 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000751#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000752 SkDebugf("%s\n", __FUNCTION__);
753 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000754#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000755 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700756 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000757 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700758 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000759 SkOpSegment* nextSegment;
760 int activeCount = 0;
761 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000762 nextSegment = nextAngle->segment();
763 ++activeCount;
764 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000765 foundAngle = nextAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000766 if (!(foundDone = nextSegment->done(nextAngle))) {
767 break;
768 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000769 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000770 nextAngle = nextAngle->next();
771 } while (nextAngle != angle);
caryclark54359292015-03-26 07:52:43 -0700772 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000773 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700774 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000775 }
776 *nextStart = foundAngle->start();
777 *nextEnd = foundAngle->end();
778 nextSegment = foundAngle->segment();
779#if DEBUG_WINDING
780 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
781 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
782 #endif
783 return nextSegment;
784}
785
caryclark54359292015-03-26 07:52:43 -0700786SkOpGlobalState* SkOpSegment::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700787 return contour()->globalState();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000788}
789
caryclark1049f122015-04-20 08:31:59 -0700790void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
caryclark54359292015-03-26 07:52:43 -0700791 fContour = contour;
halcanary96fcdcc2015-08-27 07:41:13 -0700792 fNext = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000793 fPts = pts;
caryclark1049f122015-04-20 08:31:59 -0700794 fWeight = weight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000795 fVerb = verb;
caryclark54359292015-03-26 07:52:43 -0700796 fCount = 0;
797 fDoneCount = 0;
798 fVisited = false;
799 SkOpSpan* zeroSpan = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700800 zeroSpan->init(this, nullptr, 0, fPts[0]);
caryclark54359292015-03-26 07:52:43 -0700801 SkOpSpanBase* oneSpan = &fTail;
802 zeroSpan->setNext(oneSpan);
803 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
caryclark1049f122015-04-20 08:31:59 -0700804 SkDEBUGCODE(fID = globalState()->nextSegmentID());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000805}
806
caryclark54359292015-03-26 07:52:43 -0700807bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
808 SkDPoint cPt = this->dPtAtT(t);
caryclark1049f122015-04-20 08:31:59 -0700809 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
caryclark54359292015-03-26 07:52:43 -0700810 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
811 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -0700812 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
caryclark54359292015-03-26 07:52:43 -0700813 int used = i.used();
814 for (int index = 0; index < used; ++index) {
815 if (cPt.roughlyEqual(i.pt(index))) {
reed0dc4dd62015-03-24 13:55:33 -0700816 return true;
817 }
caryclark54359292015-03-26 07:52:43 -0700818 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000819 return false;
820}
821
caryclark54359292015-03-26 07:52:43 -0700822bool SkOpSegment::isXor() const {
823 return fContour->isXor();
824}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000825
caryclark5b5ddd72015-05-18 05:12:56 -0700826void SkOpSegment::markAllDone() {
827 SkOpSpan* span = this->head();
828 do {
829 this->markDone(span);
830 } while ((span = span->next()->upCastable()));
831}
832
caryclark54359292015-03-26 07:52:43 -0700833SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) {
834 int step = start->step(end);
835 SkOpSpan* minSpan = start->starter(end);
836 markDone(minSpan);
halcanary96fcdcc2015-08-27 07:41:13 -0700837 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000838 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700839 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000840 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -0700841 SkASSERT(!last);
842 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000843 }
caryclark54359292015-03-26 07:52:43 -0700844 other->markDone(minSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000845 }
846 return last;
847}
848
caryclark54359292015-03-26 07:52:43 -0700849bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
850 SkOpSpanBase** lastPtr) {
851 SkOpSpan* spanStart = start->starter(end);
852 int step = start->step(end);
853 bool success = markWinding(spanStart, winding);
halcanary96fcdcc2015-08-27 07:41:13 -0700854 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000855 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700856 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
857 if (spanStart->windSum() != SK_MinS32) {
858 SkASSERT(spanStart->windSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700859 SkASSERT(!last);
860 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000861 }
caryclark54359292015-03-26 07:52:43 -0700862 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000863 }
caryclark65f55312014-11-13 06:58:52 -0800864 if (lastPtr) {
865 *lastPtr = last;
866 }
867 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000868}
869
caryclark54359292015-03-26 07:52:43 -0700870bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
871 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
872 SkOpSpan* spanStart = start->starter(end);
873 int step = start->step(end);
874 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700875 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000876 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700877 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
878 if (spanStart->windSum() != SK_MinS32) {
879 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700880 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700881 this->globalState()->setWindingFailed();
882 return false;
caryclarkdac1d172014-06-17 05:15:38 -0700883 }
caryclark54359292015-03-26 07:52:43 -0700884 } else {
885 SkASSERT(spanStart->windSum() == oppWinding);
886 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700887 }
888 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700889 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000890 }
caryclark54359292015-03-26 07:52:43 -0700891 if (this->operand() == other->operand()) {
892 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700893 } else {
caryclark54359292015-03-26 07:52:43 -0700894 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700895 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000896 }
caryclark65f55312014-11-13 06:58:52 -0800897 if (lastPtr) {
898 *lastPtr = last;
899 }
900 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000901}
902
caryclark54359292015-03-26 07:52:43 -0700903SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000904 SkASSERT(angle->segment() == this);
905 if (UseInnerWinding(maxWinding, sumWinding)) {
906 maxWinding = sumWinding;
907 }
caryclark54359292015-03-26 07:52:43 -0700908 SkOpSpanBase* last;
909 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000910#if DEBUG_WINDING
911 if (last) {
caryclark54359292015-03-26 07:52:43 -0700912 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
913 last->segment()->debugID(), last->debugID());
914 if (!last->final()) {
915 SkDebugf(" windSum=");
916 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
917 }
918 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000919 }
920#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000921 return last;
922}
923
caryclark54359292015-03-26 07:52:43 -0700924SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
925 int oppSumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000926 SkASSERT(angle->segment() == this);
927 if (UseInnerWinding(maxWinding, sumWinding)) {
928 maxWinding = sumWinding;
929 }
930 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
931 oppMaxWinding = oppSumWinding;
932 }
halcanary96fcdcc2015-08-27 07:41:13 -0700933 SkOpSpanBase* last = nullptr;
caryclark65f55312014-11-13 06:58:52 -0800934 // caller doesn't require that this marks anything
caryclark54359292015-03-26 07:52:43 -0700935 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000936#if DEBUG_WINDING
937 if (last) {
caryclark54359292015-03-26 07:52:43 -0700938 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
939 last->segment()->debugID(), last->debugID());
940 if (!last->final()) {
941 SkDebugf(" windSum=");
942 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
943 }
944 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000945 }
946#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000947 return last;
948}
949
caryclark54359292015-03-26 07:52:43 -0700950void SkOpSegment::markDone(SkOpSpan* span) {
951 SkASSERT(this == span->segment());
952 if (span->done()) {
953 return;
954 }
955#if DEBUG_MARK_DONE
956 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
957#endif
958 span->setDone(true);
959 ++fDoneCount;
960 debugValidate();
961}
962
963bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
964 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -0700965 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -0700966 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -0700967 return false;
968 }
969#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -0700970 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -0700971#endif
caryclark54359292015-03-26 07:52:43 -0700972 span->setWindSum(winding);
973 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -0700974 return true;
975}
976
caryclark54359292015-03-26 07:52:43 -0700977bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
978 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000979 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -0700980 if (span->done()) {
981 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000982 }
caryclark54359292015-03-26 07:52:43 -0700983#if DEBUG_MARK_DONE
984 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
985#endif
986 span->setWindSum(winding);
987 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000988 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000989 return true;
990}
991
caryclark54359292015-03-26 07:52:43 -0700992bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclarkef4f32a2016-08-24 09:24:18 -0700993 const SkPoint& testPt) const {
caryclark55888e42016-07-18 10:01:36 -0700994 SkASSERT(this == base->segment());
995 if (this == testParent) {
996 if (precisely_equal(base->fT, testT)) {
997 return true;
998 }
caryclark54359292015-03-26 07:52:43 -0700999 }
1000 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1001 return false;
1002 }
caryclark55888e42016-07-18 10:01:36 -07001003 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001004}
1005
1006static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1007 if (last) {
1008 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001009 }
halcanary96fcdcc2015-08-27 07:41:13 -07001010 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001011}
1012
caryclark54359292015-03-26 07:52:43 -07001013SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1014 SkOpSpanBase** last) const {
1015 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001016 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001017 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1018 SkASSERT(endSpan);
1019 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1020 SkOpSpanBase* foundSpan;
1021 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001022 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001023 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001024 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001025 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001026 }
caryclark54359292015-03-26 07:52:43 -07001027 SkOpPtT* otherPtT = endSpan->ptT()->next();
1028 other = otherPtT->segment();
1029 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001030 otherEnd = step > 0
1031 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1032 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001033 } else {
1034 int loopCount = angle->loopCount();
1035 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001036 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001037 }
1038 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001039 if (nullptr == next) {
1040 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001041 }
caryclarkdac1d172014-06-17 05:15:38 -07001042#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001043 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001044 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001045 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001046 }
caryclark54359292015-03-26 07:52:43 -07001047#endif
caryclarkdac1d172014-06-17 05:15:38 -07001048 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001049 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001050 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001051 }
caryclark343382e2016-06-29 08:18:38 -07001052 if (!otherEnd) {
1053 return nullptr;
1054 }
caryclark54359292015-03-26 07:52:43 -07001055 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001056 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001057 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001058 }
caryclark54359292015-03-26 07:52:43 -07001059 SkASSERT(*startPtr);
1060 if (!otherEnd) {
halcanary96fcdcc2015-08-27 07:41:13 -07001061 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001062 }
1063// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001064 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1065 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1066 if (foundMin->windValue() != origMin->windValue()
1067 || foundMin->oppValue() != origMin->oppValue()) {
1068 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001069 }
caryclark54359292015-03-26 07:52:43 -07001070 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001071 *stepPtr = foundStep;
1072 if (minPtr) {
1073 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001074 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001075 return other;
1076}
1077
caryclark55888e42016-07-18 10:01:36 -07001078// Please keep this in sync with DebugClearVisited()
1079void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001080 // reset visited flag back to false
1081 do {
1082 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1083 while ((ptT = ptT->next()) != stopPtT) {
1084 SkOpSegment* opp = ptT->segment();
1085 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001086 }
caryclarkbca19f72015-05-13 08:23:48 -07001087 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001088}
1089
caryclark55888e42016-07-18 10:01:36 -07001090// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001091// look for pairs of undetected coincident curves
1092// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001093// Even though pairs of curves correct detect coincident runs, a run may be missed
1094// if the coincidence is a product of multiple intersections. For instance, given
1095// curves A, B, and C:
1096// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1097// the end of C that the intersection is replaced with the end of C.
1098// Even though A-B correctly do not detect an intersection at point 2,
1099// the resulting run from point 1 to point 2 is coincident on A and B.
1100bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001101 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001102 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001103 }
halcanary96fcdcc2015-08-27 07:41:13 -07001104 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001105 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001106 bool result = false;
caryclark54359292015-03-26 07:52:43 -07001107 do {
caryclarkbca19f72015-05-13 08:23:48 -07001108 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001109 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001110 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001111 if (ptT->deleted()) {
1112 continue;
1113 }
caryclark54359292015-03-26 07:52:43 -07001114 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001115 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001116 continue;
reed0dc4dd62015-03-24 13:55:33 -07001117 }
caryclarkbca19f72015-05-13 08:23:48 -07001118 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1119 if (!opp->visited()) {
1120 continue;
1121 }
1122 if (spanBase == &fHead) {
1123 continue;
1124 }
caryclark55888e42016-07-18 10:01:36 -07001125 if (ptT->segment() == this) {
1126 continue;
1127 }
caryclarkbca19f72015-05-13 08:23:48 -07001128 SkOpSpan* span = spanBase->upCastable();
1129 // FIXME?: this assumes that if the opposite segment is coincident then no more
1130 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001131 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001132 continue;
1133 }
caryclarkbca19f72015-05-13 08:23:48 -07001134 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001135 continue;
caryclark55888e42016-07-18 10:01:36 -07001136 }
halcanary96fcdcc2015-08-27 07:41:13 -07001137 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001138 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001139 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001140 SkOpSpan* priorTest = spanBase->prev();
1141 while (!priorOpp && priorTest) {
1142 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001143 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001144 if (priorPtT->deleted()) {
1145 continue;
1146 }
caryclark54359292015-03-26 07:52:43 -07001147 SkOpSegment* segment = priorPtT->span()->segment();
1148 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001149 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001150 priorOpp = opp;
1151 break;
1152 }
1153 }
caryclarkbca19f72015-05-13 08:23:48 -07001154 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001155 }
1156 if (!priorOpp) {
1157 continue;
1158 }
caryclark26ad22a2015-10-16 09:03:38 -07001159 if (priorPtT == ptT) {
1160 continue;
1161 }
caryclark54359292015-03-26 07:52:43 -07001162 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001163 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001164 bool swapped = priorPtT->fT > ptT->fT;
1165 if (swapped) {
1166 SkTSwap(priorPtT, ptT);
1167 SkTSwap(oppStart, oppEnd);
1168 }
caryclark55888e42016-07-18 10:01:36 -07001169 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1170 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1171 SkOpPtT* rootPtT = ptT->span()->ptT();
1172 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1173 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1174 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001175 goto swapBack;
1176 }
caryclark55888e42016-07-18 10:01:36 -07001177 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001178 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001179#if DEBUG_COINCIDENCE_VERBOSE
1180 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1181 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1182 rootOppEnd->debugID());
1183#endif
1184 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1185 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001186 }
caryclark55888e42016-07-18 10:01:36 -07001187#if DEBUG_COINCIDENCE
1188 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1189#endif
1190 result = true;
caryclark54359292015-03-26 07:52:43 -07001191 }
1192 swapBack:
1193 if (swapped) {
1194 SkTSwap(priorPtT, ptT);
1195 }
reed0dc4dd62015-03-24 13:55:33 -07001196 }
halcanary96fcdcc2015-08-27 07:41:13 -07001197 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001198 ClearVisited(&fHead);
1199 return result;
reed0dc4dd62015-03-24 13:55:33 -07001200}
1201
caryclark55888e42016-07-18 10:01:36 -07001202// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001203// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001204bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001205 debugValidate();
1206 SkOpSpanBase* test = &fHead;
1207 do {
1208 int addCount = test->spanAddsCount();
caryclark55888e42016-07-18 10:01:36 -07001209 FAIL_IF(addCount < 1);
caryclark08bc8482015-04-24 09:08:57 -07001210 if (addCount == 1) {
1211 continue;
1212 }
1213 SkOpPtT* startPtT = test->ptT();
1214 SkOpPtT* testPtT = startPtT;
1215 do { // iterate through all spans associated with start
1216 SkOpSpanBase* oppSpan = testPtT->span();
1217 if (oppSpan->spanAddsCount() == addCount) {
1218 continue;
1219 }
1220 if (oppSpan->deleted()) {
1221 continue;
1222 }
1223 SkOpSegment* oppSegment = oppSpan->segment();
1224 if (oppSegment == this) {
1225 continue;
1226 }
1227 // find range of spans to consider merging
1228 SkOpSpanBase* oppPrev = oppSpan;
1229 SkOpSpanBase* oppFirst = oppSpan;
1230 while ((oppPrev = oppPrev->prev())) {
1231 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1232 break;
1233 }
1234 if (oppPrev->spanAddsCount() == addCount) {
1235 continue;
1236 }
1237 if (oppPrev->deleted()) {
1238 continue;
1239 }
1240 oppFirst = oppPrev;
1241 }
1242 SkOpSpanBase* oppNext = oppSpan;
1243 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001244 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001245 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1246 break;
1247 }
1248 if (oppNext->spanAddsCount() == addCount) {
1249 continue;
1250 }
1251 if (oppNext->deleted()) {
1252 continue;
1253 }
1254 oppLast = oppNext;
1255 }
1256 if (oppFirst == oppLast) {
1257 continue;
1258 }
1259 SkOpSpanBase* oppTest = oppFirst;
1260 do {
1261 if (oppTest == oppSpan) {
1262 continue;
1263 }
1264 // check to see if the candidate meets specific criteria:
1265 // it contains spans of segments in test's loop but not including 'this'
1266 SkOpPtT* oppStartPtT = oppTest->ptT();
1267 SkOpPtT* oppPtT = oppStartPtT;
1268 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1269 SkOpSegment* oppPtTSegment = oppPtT->segment();
1270 if (oppPtTSegment == this) {
1271 goto tryNextSpan;
1272 }
1273 SkOpPtT* matchPtT = startPtT;
1274 do {
1275 if (matchPtT->segment() == oppPtTSegment) {
1276 goto foundMatch;
1277 }
1278 } while ((matchPtT = matchPtT->next()) != startPtT);
1279 goto tryNextSpan;
1280 foundMatch: // merge oppTest and oppSpan
1281 oppSegment->debugValidate();
caryclark30b9fdd2016-08-31 14:36:29 -07001282 oppTest->mergeMatches(oppSpan);
1283 oppTest->addOpp(oppSpan);
caryclark08bc8482015-04-24 09:08:57 -07001284 oppSegment->debugValidate();
1285 goto checkNextSpan;
1286 }
caryclark55888e42016-07-18 10:01:36 -07001287 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001288 ;
1289 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1290 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001291checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001292 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001293 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001294 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001295 return true;
caryclark08bc8482015-04-24 09:08:57 -07001296}
1297
caryclark55888e42016-07-18 10:01:36 -07001298// adjacent spans may have points close by
1299bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan) const {
1300 const SkOpPtT* refHead = refSpan->ptT();
1301 const SkOpPtT* checkHead = checkSpan->ptT();
1302// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
caryclark30b9fdd2016-08-31 14:36:29 -07001303 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
caryclark55888e42016-07-18 10:01:36 -07001304#if DEBUG_COINCIDENCE
1305 // verify that no combination of points are close
1306 const SkOpPtT* dBugRef = refHead;
1307 do {
1308 const SkOpPtT* dBugCheck = checkHead;
1309 do {
caryclark30b9fdd2016-08-31 14:36:29 -07001310 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
caryclark55888e42016-07-18 10:01:36 -07001311 dBugCheck = dBugCheck->next();
1312 } while (dBugCheck != checkHead);
1313 dBugRef = dBugRef->next();
1314 } while (dBugRef != refHead);
1315#endif
1316 return false;
1317 }
1318 // check only unique points
1319 SkScalar distSqBest = SK_ScalarMax;
1320 const SkOpPtT* refBest = nullptr;
1321 const SkOpPtT* checkBest = nullptr;
1322 const SkOpPtT* ref = refHead;
1323 do {
1324 if (ref->deleted()) {
1325 continue;
1326 }
1327 while (ref->ptAlreadySeen(refHead)) {
1328 ref = ref->next();
1329 if (ref == refHead) {
1330 goto doneCheckingDistance;
1331 }
1332 }
1333 const SkOpPtT* check = checkHead;
1334 const SkOpSegment* refSeg = ref->segment();
1335 do {
1336 if (check->deleted()) {
1337 continue;
1338 }
1339 while (check->ptAlreadySeen(checkHead)) {
1340 check = check->next();
1341 if (check == checkHead) {
1342 goto nextRef;
1343 }
1344 }
1345 SkScalar distSq = ref->fPt.distanceToSqd(check->fPt);
1346 if (distSqBest > distSq && (refSeg != check->segment()
1347 || !refSeg->ptsDisjoint(*ref, *check))) {
1348 distSqBest = distSq;
1349 refBest = ref;
1350 checkBest = check;
1351 }
1352 } while ((check = check->next()) != checkHead);
1353nextRef:
1354 ;
1355 } while ((ref = ref->next()) != refHead);
1356doneCheckingDistance:
1357 return checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001358 checkBest->fPt);
caryclark55888e42016-07-18 10:01:36 -07001359}
1360
1361// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001362// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
caryclark08bc8482015-04-24 09:08:57 -07001363void SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001364 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001365 // release undeleted spans pointing to this seg that are linked to the primary span
1366 SkOpSpanBase* spanBase = &fHead;
caryclark54359292015-03-26 07:52:43 -07001367 do {
caryclark55888e42016-07-18 10:01:36 -07001368 SkOpPtT* ptT = spanBase->ptT();
1369 const SkOpPtT* headPtT = ptT;
1370 while ((ptT = ptT->next()) != headPtT) {
1371 SkOpSpanBase* test = ptT->span();
1372 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1373 && test->ptT() == ptT) {
1374 if (test->final()) {
1375 if (spanBase == &fHead) {
1376 this->clearAll();
1377 return;
1378 }
1379 spanBase->upCast()->release(ptT);
1380 } else if (test->prev()) {
1381 test->upCast()->release(headPtT);
1382 }
1383 break;
caryclark54359292015-03-26 07:52:43 -07001384 }
reed0dc4dd62015-03-24 13:55:33 -07001385 }
caryclark55888e42016-07-18 10:01:36 -07001386 spanBase = spanBase->upCast()->next();
1387 } while (!spanBase->final());
1388
1389 // This loop looks for adjacent spans which are near by
1390 spanBase = &fHead;
1391 do { // iterate through all spans associated with start
1392 SkOpSpanBase* test = spanBase->upCast()->next();
1393 if (this->spansNearby(spanBase, test)) {
1394 if (test->final()) {
1395 if (spanBase->prev()) {
1396 test->merge(spanBase->upCast());
1397 } else {
1398 this->clearAll();
1399 return;
1400 }
1401 } else {
1402 spanBase->merge(test->upCast());
1403 }
1404 }
1405 spanBase = test;
1406 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001407 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001408}
1409
caryclark54359292015-03-26 07:52:43 -07001410bool SkOpSegment::operand() const {
1411 return fContour->operand();
1412}
1413
1414bool SkOpSegment::oppXor() const {
1415 return fContour->oppXor();
1416}
1417
1418bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1419 if (fVerb == SkPath::kLine_Verb) {
1420 return false;
1421 }
1422 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1423 // hits in two places with very different t values.
1424 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1425 // 'controls contained by ends' could avoid this check for common curves
1426 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1427 // on the other hand, the below check is relatively inexpensive
1428 double midT = (t1 + t2) / 2;
1429 SkPoint midPt = this->ptAtT(midT);
1430 double seDistSq = SkTMax(pt1.distanceToSqd(pt2) * 2, FLT_EPSILON * 2);
1431 return midPt.distanceToSqd(pt1) > seDistSq || midPt.distanceToSqd(pt2) > seDistSq;
1432}
1433
1434void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1435 int* maxWinding, int* sumWinding) {
1436 int deltaSum = SpanSign(start, end);
1437 *maxWinding = *sumMiWinding;
1438 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001439 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001440}
1441
1442void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1443 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1444 int* oppSumWinding) {
1445 int deltaSum = SpanSign(start, end);
1446 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001447 if (operand()) {
1448 *maxWinding = *sumSuWinding;
1449 *sumWinding = *sumSuWinding -= deltaSum;
1450 *oppMaxWinding = *sumMiWinding;
1451 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1452 } else {
1453 *maxWinding = *sumMiWinding;
1454 *sumWinding = *sumMiWinding -= deltaSum;
1455 *oppMaxWinding = *sumSuWinding;
1456 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1457 }
bungeman60e0fee2015-08-26 05:15:46 -07001458 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1459 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001460}
1461
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001462void SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001463 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001464 do {
caryclark54359292015-03-26 07:52:43 -07001465 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001466 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001467 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001468 continue;
1469 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001470#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001471 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001472#endif
caryclark54359292015-03-26 07:52:43 -07001473 SkOpAngle* baseAngle = fromAngle;
1474 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001475#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001476 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1477 span->debugID());
1478 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001479#endif
caryclark54359292015-03-26 07:52:43 -07001480 fromAngle->insert(toAngle);
1481 } else if (!fromAngle) {
1482 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001483 }
caryclark54359292015-03-26 07:52:43 -07001484 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001485 do {
caryclark54359292015-03-26 07:52:43 -07001486 SkOpSpanBase* oSpan = ptT->span();
1487 if (oSpan == span) {
1488 continue;
1489 }
1490 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001491 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001492#if DEBUG_ANGLE
1493 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001494 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1495 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001496 wroteAfterHeader = true;
1497 }
1498#endif
caryclark54359292015-03-26 07:52:43 -07001499 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001500 baseAngle->insert(oAngle);
1501 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001502 }
caryclark54359292015-03-26 07:52:43 -07001503 if (!oSpan->final()) {
1504 oAngle = oSpan->upCast()->toAngle();
1505 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001506#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001507 if (!wroteAfterHeader) {
1508 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1509 span->t(), span->debugID());
1510 wroteAfterHeader = true;
1511 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001512#endif
caryclark54359292015-03-26 07:52:43 -07001513 if (!oAngle->loopContains(baseAngle)) {
1514 baseAngle->insert(oAngle);
1515 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001516 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001517 }
caryclark54359292015-03-26 07:52:43 -07001518 } while ((ptT = ptT->next()) != stopPtT);
1519 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001520 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001521 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001522 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001523 }
halcanary96fcdcc2015-08-27 07:41:13 -07001524 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001525 }
1526#if DEBUG_SORT
1527 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1528#endif
caryclark54359292015-03-26 07:52:43 -07001529 } while (!span->final() && (span = span->upCast()->next()));
caryclark@google.com570863f2013-09-16 15:55:01 +00001530}
1531
caryclark54359292015-03-26 07:52:43 -07001532bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001533 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001534 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001535 const SkOpPtT& startPtT = *start->ptT();
1536 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001537 SkDEBUGCODE(edge->fVerb = fVerb);
1538 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001539 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001540 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001541 if (fVerb == SkPath::kLine_Verb) {
1542 return false;
1543 }
caryclark54359292015-03-26 07:52:43 -07001544 double startT = startPtT.fT;
1545 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001546 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1547 // don't compute midpoints if we already have them
1548 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001549 edge->fLine[1].set(fPts[1]);
1550 return false;
1551 }
1552 if (fVerb == SkPath::kConic_Verb) {
1553 edge->fConic[1].set(fPts[1]);
1554 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001555 return false;
1556 }
1557 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001558 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001559 edge->fCubic[1].set(fPts[1]);
1560 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001561 return false;
1562 }
caryclark1049f122015-04-20 08:31:59 -07001563 edge->fCubic[1].set(fPts[2]);
1564 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001565 return false;
1566 }
1567 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001568 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1569 } else if (fVerb == SkPath::kConic_Verb) {
1570 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1571 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001572 } else {
1573 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001574 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001575 }
1576 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001577}
1578
caryclark27c8eb82015-07-06 11:38:33 -07001579bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001580 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001581 // average t, find mid pt
1582 double midT = (prior->t() + spanBase->t()) / 2;
1583 SkPoint midPt = this->ptAtT(midT);
1584 bool coincident = true;
1585 // if the mid pt is not near either end pt, project perpendicular through opp seg
1586 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1587 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001588 if (priorPtT->span() == ptT->span()) {
1589 return false;
1590 }
caryclark27c8eb82015-07-06 11:38:33 -07001591 coincident = false;
1592 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001593 SkDCurve curvePart;
1594 this->subDivide(prior, spanBase, &curvePart);
1595 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1596 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1597 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1598 SkDCurve oppPart;
1599 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1600 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001601 // measure distance and see if it's small enough to denote coincidence
1602 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001603 if (!between(0, i[0][index], 1)) {
1604 continue;
1605 }
caryclark27c8eb82015-07-06 11:38:33 -07001606 SkDPoint oppPt = i.pt(index);
caryclark30b9fdd2016-08-31 14:36:29 -07001607 if (oppPt.approximatelyDEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001608 // the coincidence can occur at almost any angle
1609 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001610 }
1611 }
1612 }
1613 return coincident;
1614}
1615
caryclark54359292015-03-26 07:52:43 -07001616void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
1617 SkOpSpan* span = this->head();
1618 do {
1619 if (!span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001620 break;
1621 }
caryclark54359292015-03-26 07:52:43 -07001622 } while ((span = span->next()->upCastable()));
1623 SkASSERT(span);
1624 *start = span;
1625 *end = span->next();
reed0dc4dd62015-03-24 13:55:33 -07001626}
1627
caryclark54359292015-03-26 07:52:43 -07001628int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1629 const SkOpSpan* lesser = start->starter(end);
1630 int oppWinding = lesser->oppSum();
1631 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001632 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1633 && oppWinding != SK_MaxS32) {
1634 oppWinding -= oppSpanWinding;
1635 }
1636 return oppWinding;
1637}
1638
1639int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001640 const SkOpSpanBase* startSpan = angle->start();
1641 const SkOpSpanBase* endSpan = angle->end();
1642 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001643}
1644
1645int SkOpSegment::updateOppWindingReverse(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(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001649}
1650
caryclark624637c2015-05-11 07:21:27 -07001651int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1652 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001653 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001654 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001655 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001656 }
1657 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001658 return winding;
1659 }
caryclark54359292015-03-26 07:52:43 -07001660 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001661 if (winding && UseInnerWinding(winding - spanWinding, winding)
1662 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001663 winding -= spanWinding;
1664 }
1665 return winding;
1666}
1667
caryclark624637c2015-05-11 07:21:27 -07001668int SkOpSegment::updateWinding(SkOpAngle* angle) {
1669 SkOpSpanBase* startSpan = angle->start();
1670 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001671 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001672}
1673
caryclark624637c2015-05-11 07:21:27 -07001674int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1675 SkOpSpanBase* startSpan = angle->start();
1676 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001677 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001678}
1679
1680// OPTIMIZATION: does the following also work, and is it any faster?
1681// return outerWinding * innerWinding > 0
1682// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1683bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1684 SkASSERT(outerWinding != SK_MaxS32);
1685 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001686 int absOut = SkTAbs(outerWinding);
1687 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001688 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1689 return result;
1690}
1691
caryclark@google.com07393ca2013-04-08 11:47:37 +00001692int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001693 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1694 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001695}