blob: de74f7d55714d1e63c24d0b454a5c09a5cdae58b [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
caryclark55888e42016-07-18 10:01:36 -070012#define FAIL_IF(cond) do { if (cond) return false; } while (false)
13
caryclark54359292015-03-26 07:52:43 -070014/*
15After computing raw intersections, post process all segments to:
16- find small collections of points that can be collapsed to a single point
17- find missing intersections to resolve differences caused by different algorithms
18
19Consider segments containing tiny or small intervals. Consider coincident segments
20because coincidence finds intersections through distance measurement that non-coincident
21intersection tests cannot.
22 */
caryclark@google.com07393ca2013-04-08 11:47:37 +000023
24#define F (false) // discard the edge
25#define T (true) // keep the edge
26
27static const bool gUnaryActiveEdge[2][2] = {
28// from=0 from=1
29// to=0,1 to=0,1
30 {F, T}, {T, F},
31};
32
caryclark54359292015-03-26 07:52:43 -070033static const bool gActiveEdge[kXOR_SkPathOp + 1][2][2][2][2] = {
caryclark@google.com07393ca2013-04-08 11:47:37 +000034// miFrom=0 miFrom=1
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000035// miTo=0 miTo=1 miTo=0 miTo=1
36// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
caryclark@google.com07393ca2013-04-08 11:47:37 +000037// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
38 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
39 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
40 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
41 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su
42};
43
44#undef F
45#undef T
46
caryclark54359292015-03-26 07:52:43 -070047SkOpAngle* SkOpSegment::activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -070048 SkOpSpanBase** endPtr, bool* done) {
49 if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done)) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000050 return result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000051 }
caryclarkbca19f72015-05-13 08:23:48 -070052 if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done)) {
caryclark54359292015-03-26 07:52:43 -070053 return result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000054 }
halcanary96fcdcc2015-08-27 07:41:13 -070055 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +000056}
57
caryclark54359292015-03-26 07:52:43 -070058SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -070059 SkOpSpanBase** endPtr, bool* done) {
caryclark54359292015-03-26 07:52:43 -070060 SkOpSpan* upSpan = start->upCastable();
61 if (upSpan) {
62 if (upSpan->windValue() || upSpan->oppValue()) {
63 SkOpSpanBase* next = upSpan->next();
64 if (!*endPtr) {
65 *startPtr = start;
66 *endPtr = next;
caryclark@google.com07393ca2013-04-08 11:47:37 +000067 }
caryclark54359292015-03-26 07:52:43 -070068 if (!upSpan->done()) {
69 if (upSpan->windSum() != SK_MinS32) {
70 return spanToAngle(start, next);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000071 }
72 *done = false;
73 }
74 } else {
caryclark54359292015-03-26 07:52:43 -070075 SkASSERT(upSpan->done());
caryclark@google.com07393ca2013-04-08 11:47:37 +000076 }
77 }
caryclark54359292015-03-26 07:52:43 -070078 SkOpSpan* downSpan = start->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +000079 // edge leading into junction
caryclark54359292015-03-26 07:52:43 -070080 if (downSpan) {
81 if (downSpan->windValue() || downSpan->oppValue()) {
82 if (!*endPtr) {
83 *startPtr = start;
84 *endPtr = downSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +000085 }
caryclark54359292015-03-26 07:52:43 -070086 if (!downSpan->done()) {
87 if (downSpan->windSum() != SK_MinS32) {
88 return spanToAngle(start, downSpan);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000089 }
90 *done = false;
91 }
92 } else {
caryclark54359292015-03-26 07:52:43 -070093 SkASSERT(downSpan->done());
caryclark@google.com07393ca2013-04-08 11:47:37 +000094 }
95 }
halcanary96fcdcc2015-08-27 07:41:13 -070096 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000097}
98
caryclark54359292015-03-26 07:52:43 -070099SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -0700100 SkOpSpanBase** endPtr, bool* done) {
caryclark54359292015-03-26 07:52:43 -0700101 SkOpPtT* oPtT = start->ptT()->next();
102 SkOpSegment* other = oPtT->segment();
103 SkOpSpanBase* oSpan = oPtT->span();
caryclarkbca19f72015-05-13 08:23:48 -0700104 return other->activeAngleInner(oSpan, startPtr, endPtr, done);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000105}
106
caryclark54359292015-03-26 07:52:43 -0700107bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xorSuMask,
108 SkPathOp op) {
109 int sumMiWinding = this->updateWinding(end, start);
110 int sumSuWinding = this->updateOppWinding(end, start);
caryclark65f55312014-11-13 06:58:52 -0800111#if DEBUG_LIMIT_WIND_SUM
112 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM);
113 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM);
114#endif
caryclark54359292015-03-26 07:52:43 -0700115 if (this->operand()) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000116 SkTSwap<int>(sumMiWinding, sumSuWinding);
117 }
caryclark54359292015-03-26 07:52:43 -0700118 return this->activeOp(xorMiMask, xorSuMask, start, end, op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000119}
120
caryclark54359292015-03-26 07:52:43 -0700121bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end,
122 SkPathOp op, int* sumMiWinding, int* sumSuWinding) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000123 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
caryclark54359292015-03-26 07:52:43 -0700124 this->setUpWindings(start, end, sumMiWinding, sumSuWinding,
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000125 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000126 bool miFrom;
127 bool miTo;
128 bool suFrom;
129 bool suTo;
130 if (operand()) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000131 miFrom = (oppMaxWinding & xorMiMask) != 0;
132 miTo = (oppSumWinding & xorMiMask) != 0;
133 suFrom = (maxWinding & xorSuMask) != 0;
134 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000135 } else {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000136 miFrom = (maxWinding & xorMiMask) != 0;
137 miTo = (sumWinding & xorMiMask) != 0;
138 suFrom = (oppMaxWinding & xorSuMask) != 0;
139 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000140 }
141 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
142#if DEBUG_ACTIVE_OP
caryclarkdac1d172014-06-17 05:15:38 -0700143 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 -0700144 __FUNCTION__, debugID(), start->t(), end->t(),
caryclark@google.com570863f2013-09-16 15:55:01 +0000145 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000146#endif
147 return result;
148}
149
caryclark54359292015-03-26 07:52:43 -0700150bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
151 int sumWinding = updateWinding(end, start);
152 return activeWinding(start, end, &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000153}
154
caryclark54359292015-03-26 07:52:43 -0700155bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000156 int maxWinding;
caryclark54359292015-03-26 07:52:43 -0700157 setUpWinding(start, end, &maxWinding, sumWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000158 bool from = maxWinding != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000159 bool to = *sumWinding != 0;
160 bool result = gUnaryActiveEdge[from][to];
161 return result;
162}
163
caryclarkef784fb2015-10-30 12:03:06 -0700164bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
165 SkPathWriter* path) const {
166 if (start->starter(end)->alreadyAdded()) {
caryclark55888e42016-07-18 10:01:36 -0700167 SkDEBUGF(("same curve added twice aborted pathops\n"));
caryclarkef784fb2015-10-30 12:03:06 -0700168 return false;
169 }
caryclark1049f122015-04-20 08:31:59 -0700170 SkOpCurve edge;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000171 const SkPoint* ePtr;
caryclark1049f122015-04-20 08:31:59 -0700172 SkScalar eWeight;
caryclark54359292015-03-26 07:52:43 -0700173 if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000174 ePtr = fPts;
caryclark1049f122015-04-20 08:31:59 -0700175 eWeight = fWeight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000176 } else {
177 // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
caryclark1049f122015-04-20 08:31:59 -0700178 subDivide(start, end, &edge);
179 ePtr = edge.fPts;
180 eWeight = edge.fWeight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000181 }
caryclarkef784fb2015-10-30 12:03:06 -0700182 bool reverse = ePtr == fPts && start != &fHead;
183 if (reverse) {
184 path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]);
185 switch (fVerb) {
186 case SkPath::kLine_Verb:
187 path->deferredLine(ePtr[0]);
188 break;
189 case SkPath::kQuad_Verb:
190 path->quadTo(ePtr[1], ePtr[0]);
191 break;
192 case SkPath::kConic_Verb:
193 path->conicTo(ePtr[1], ePtr[0], eWeight);
194 break;
195 case SkPath::kCubic_Verb:
196 path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
197 break;
198 default:
199 SkASSERT(0);
200 }
201 } else {
202 path->deferredMoveLine(ePtr[0]);
203 switch (fVerb) {
204 case SkPath::kLine_Verb:
205 path->deferredLine(ePtr[1]);
206 break;
207 case SkPath::kQuad_Verb:
208 path->quadTo(ePtr[1], ePtr[2]);
209 break;
210 case SkPath::kConic_Verb:
211 path->conicTo(ePtr[1], ePtr[2], eWeight);
212 break;
213 case SkPath::kCubic_Verb:
214 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
215 break;
216 default:
217 SkASSERT(0);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000218 }
219 }
caryclarkef784fb2015-10-30 12:03:06 -0700220 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000221}
222
caryclark55888e42016-07-18 10:01:36 -0700223const SkOpPtT* SkOpSegment::existing(double t, const SkOpSegment* opp) const {
224 const SkOpSpanBase* test = &fHead;
225 const SkOpPtT* testPtT;
226 SkPoint pt = this->ptAtT(t);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000227 do {
caryclark55888e42016-07-18 10:01:36 -0700228 testPtT = test->ptT();
229 if (testPtT->fT == t) {
reed0dc4dd62015-03-24 13:55:33 -0700230 break;
231 }
caryclark55888e42016-07-18 10:01:36 -0700232 if (!this->match(testPtT, this, t, pt, opp ? kAllowAliasMatch : kNoAliasMatch)) {
233 if (t < testPtT->fT) {
234 return nullptr;
235 }
236 continue;
237 }
238 if (!opp) {
239 return testPtT;
240 }
241 const SkOpPtT* loop = testPtT->next();
242 while (loop != testPtT) {
243 if (loop->segment() == this && loop->fT == t && loop->fPt == pt) {
244 goto foundMatch;
245 }
246 loop = loop->next();
247 }
248 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700249 } while ((test = test->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -0700250foundMatch:
251 return opp && !test->contains(opp) ? nullptr : testPtT;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000252}
253
caryclark55888e42016-07-18 10:01:36 -0700254// break the span so that the coincident part does not change the angle of the remainder
255bool SkOpSegment::addExpanded(double newT, const SkOpSpanBase* test, bool* startOver) {
256 if (this->contains(newT)) {
257 return true;
258 }
259 SkOpPtT* newPtT = this->addT(newT, kAllowAliasMatch, startOver);
260 if (!newPtT) {
261 return false;
262 }
263 newPtT->fPt = this->ptAtT(newT);
264 // const cast away to change linked list; pt/t values stays unchanged
265 SkOpSpanBase* writableTest = const_cast<SkOpSpanBase*>(test);
266 if (writableTest->ptT()->addOpp(newPtT)) {
267 writableTest->checkForCollapsedCoincidence();
268 }
269 return true;
270}
271
272// Please keep this in sync with debugAddT()
273SkOpPtT* SkOpSegment::addT(double t, AliasMatch allowAlias, bool* allocated) {
reed0dc4dd62015-03-24 13:55:33 -0700274 debugValidate();
caryclark54359292015-03-26 07:52:43 -0700275 SkPoint pt = this->ptAtT(t);
276 SkOpSpanBase* span = &fHead;
277 do {
278 SkOpPtT* result = span->ptT();
caryclark08bc8482015-04-24 09:08:57 -0700279 SkOpPtT* loop;
280 bool duplicatePt;
caryclark54359292015-03-26 07:52:43 -0700281 if (t == result->fT) {
caryclark08bc8482015-04-24 09:08:57 -0700282 goto bumpSpan;
reed0dc4dd62015-03-24 13:55:33 -0700283 }
caryclark55888e42016-07-18 10:01:36 -0700284 if (this->match(result, this, t, pt, allowAlias)) {
caryclark54359292015-03-26 07:52:43 -0700285 // see if any existing alias matches segment, pt, and t
caryclark55888e42016-07-18 10:01:36 -0700286 loop = result->next();
caryclark08bc8482015-04-24 09:08:57 -0700287 duplicatePt = false;
caryclark54359292015-03-26 07:52:43 -0700288 while (loop != result) {
289 bool ptMatch = loop->fPt == pt;
290 if (loop->segment() == this && loop->fT == t && ptMatch) {
caryclark08bc8482015-04-24 09:08:57 -0700291 goto bumpSpan;
reed0dc4dd62015-03-24 13:55:33 -0700292 }
caryclark54359292015-03-26 07:52:43 -0700293 duplicatePt |= ptMatch;
294 loop = loop->next();
reed0dc4dd62015-03-24 13:55:33 -0700295 }
caryclark55888e42016-07-18 10:01:36 -0700296 if (kNoAliasMatch == allowAlias) {
caryclark08bc8482015-04-24 09:08:57 -0700297 bumpSpan:
298 span->bumpSpanAdds();
caryclark54359292015-03-26 07:52:43 -0700299 return result;
300 }
caryclark55888e42016-07-18 10:01:36 -0700301 SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(this->globalState()->allocator());
caryclark54359292015-03-26 07:52:43 -0700302 alias->init(result->span(), t, pt, duplicatePt);
303 result->insert(alias);
304 result->span()->unaligned();
305 this->debugValidate();
306#if DEBUG_ADD_T
307 SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
308 alias->segment()->debugID(), alias->span()->debugID());
309#endif
caryclark08bc8482015-04-24 09:08:57 -0700310 span->bumpSpanAdds();
caryclark55888e42016-07-18 10:01:36 -0700311 if (allocated) {
312 *allocated = true;
313 }
caryclark54359292015-03-26 07:52:43 -0700314 return alias;
reed0dc4dd62015-03-24 13:55:33 -0700315 }
caryclark54359292015-03-26 07:52:43 -0700316 if (t < result->fT) {
317 SkOpSpan* prev = result->span()->prev();
caryclarka3375e42015-12-07 12:18:02 -0800318 if (!prev) {
319 return nullptr;
320 }
caryclark55888e42016-07-18 10:01:36 -0700321 SkOpSpan* span = insert(prev);
caryclark54359292015-03-26 07:52:43 -0700322 span->init(this, prev, t, pt);
323 this->debugValidate();
324#if DEBUG_ADD_T
325 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
326 span->segment()->debugID(), span->debugID());
327#endif
caryclark08bc8482015-04-24 09:08:57 -0700328 span->bumpSpanAdds();
caryclark55888e42016-07-18 10:01:36 -0700329 if (allocated) {
330 *allocated = true;
331 }
caryclark54359292015-03-26 07:52:43 -0700332 return span->ptT();
333 }
caryclark8bc90e22016-07-25 06:05:08 -0700334 if (span == &fTail) {
335 return nullptr;
336 }
caryclark54359292015-03-26 07:52:43 -0700337 } while ((span = span->upCast()->next()));
338 SkASSERT(0);
halcanary96fcdcc2015-08-27 07:41:13 -0700339 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700340}
341
caryclark55888e42016-07-18 10:01:36 -0700342void SkOpSegment::calcAngles() {
caryclark54359292015-03-26 07:52:43 -0700343 bool activePrior = !fHead.isCanceled();
344 if (activePrior && !fHead.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700345 addStartSpan();
reed0dc4dd62015-03-24 13:55:33 -0700346 }
caryclark54359292015-03-26 07:52:43 -0700347 SkOpSpan* prior = &fHead;
348 SkOpSpanBase* spanBase = fHead.next();
349 while (spanBase != &fTail) {
350 if (activePrior) {
caryclark55888e42016-07-18 10:01:36 -0700351 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(
352 this->globalState()->allocator());
caryclark54359292015-03-26 07:52:43 -0700353 priorAngle->set(spanBase, prior);
354 spanBase->setFromAngle(priorAngle);
reed0dc4dd62015-03-24 13:55:33 -0700355 }
caryclark54359292015-03-26 07:52:43 -0700356 SkOpSpan* span = spanBase->upCast();
357 bool active = !span->isCanceled();
358 SkOpSpanBase* next = span->next();
359 if (active) {
caryclark55888e42016-07-18 10:01:36 -0700360 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(
361 this->globalState()->allocator());
caryclark54359292015-03-26 07:52:43 -0700362 angle->set(span, next);
363 span->setToAngle(angle);
reed0dc4dd62015-03-24 13:55:33 -0700364 }
reed0dc4dd62015-03-24 13:55:33 -0700365 activePrior = active;
caryclark54359292015-03-26 07:52:43 -0700366 prior = span;
367 spanBase = next;
reed0dc4dd62015-03-24 13:55:33 -0700368 }
caryclark54359292015-03-26 07:52:43 -0700369 if (activePrior && !fTail.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700370 addEndSpan();
reed0dc4dd62015-03-24 13:55:33 -0700371 }
reed0dc4dd62015-03-24 13:55:33 -0700372}
373
caryclark55888e42016-07-18 10:01:36 -0700374// Please keep this in sync with debugClearAll()
375void SkOpSegment::clearAll() {
376 SkOpSpan* span = &fHead;
377 do {
378 this->clearOne(span);
379 } while ((span = span->next()->upCastable()));
380 this->globalState()->coincidence()->release(this);
381}
382
383// Please keep this in sync with debugClearOne()
384void SkOpSegment::clearOne(SkOpSpan* span) {
385 span->setWindValue(0);
386 span->setOppValue(0);
387 this->markDone(span);
388}
389
390// Quads and conics collapse if the end points are the same, because
391// the curve doesn't enclose an area.
caryclarkbca19f72015-05-13 08:23:48 -0700392bool SkOpSegment::collapsed() const {
caryclark55888e42016-07-18 10:01:36 -0700393 // FIXME: cubics can have also collapsed -- need to check if the
394 // control points are on a line with the end points
395 return fVerb < SkPath::kCubic_Verb && fHead.pt() == fTail.pt();
caryclarkbca19f72015-05-13 08:23:48 -0700396}
397
caryclark@google.com570863f2013-09-16 15:55:01 +0000398void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
399 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700400 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000401 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
402 int sumSuWinding;
403 bool binary = includeType >= SkOpAngle::kBinarySingle;
404 if (binary) {
405 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
406 if (baseSegment->operand()) {
407 SkTSwap<int>(sumMiWinding, sumSuWinding);
408 }
409 }
410 SkOpSegment* nextSegment = nextAngle->segment();
411 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700412 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000413 if (binary) {
414 int oppMaxWinding, oppSumWinding;
415 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
416 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
417 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000418 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000419 } else {
420 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
421 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000422 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000423 }
424 nextAngle->setLastMarked(last);
425}
426
caryclark624637c2015-05-11 07:21:27 -0700427void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
caryclark@google.com570863f2013-09-16 15:55:01 +0000428 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700429 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000430 int sumMiWinding = baseSegment->updateWinding(baseAngle);
431 int sumSuWinding;
432 bool binary = includeType >= SkOpAngle::kBinarySingle;
433 if (binary) {
434 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
435 if (baseSegment->operand()) {
436 SkTSwap<int>(sumMiWinding, sumSuWinding);
437 }
438 }
439 SkOpSegment* nextSegment = nextAngle->segment();
440 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700441 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000442 if (binary) {
443 int oppMaxWinding, oppSumWinding;
444 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
445 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
446 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000447 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000448 } else {
449 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
450 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000451 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000452 }
453 nextAngle->setLastMarked(last);
454}
455
caryclark54359292015-03-26 07:52:43 -0700456// at this point, the span is already ordered, or unorderable
457int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
458 SkOpAngle::IncludeType includeType) {
459 SkASSERT(includeType != SkOpAngle::kUnaryXor);
460 SkOpAngle* firstAngle = this->spanToAngle(end, start);
halcanary96fcdcc2015-08-27 07:41:13 -0700461 if (nullptr == firstAngle || nullptr == firstAngle->next()) {
caryclark54359292015-03-26 07:52:43 -0700462 return SK_NaN32;
463 }
464 // if all angles have a computed winding,
465 // or if no adjacent angles are orderable,
466 // or if adjacent orderable angles have no computed winding,
467 // there's nothing to do
468 // if two orderable angles are adjacent, and both are next to orderable angles,
469 // and one has winding computed, transfer to the other
halcanary96fcdcc2015-08-27 07:41:13 -0700470 SkOpAngle* baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700471 bool tryReverse = false;
472 // look for counterclockwise transfers
473 SkOpAngle* angle = firstAngle->previous();
474 SkOpAngle* next = angle->next();
475 firstAngle = next;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000476 do {
caryclark54359292015-03-26 07:52:43 -0700477 SkOpAngle* prior = angle;
478 angle = next;
479 next = angle->next();
480 SkASSERT(prior->next() == angle);
481 SkASSERT(angle->next() == next);
482 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700483 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700484 continue;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000485 }
caryclark54359292015-03-26 07:52:43 -0700486 int testWinding = angle->starter()->windSum();
487 if (SK_MinS32 != testWinding) {
488 baseAngle = angle;
489 tryReverse = true;
490 continue;
reed0dc4dd62015-03-24 13:55:33 -0700491 }
caryclark54359292015-03-26 07:52:43 -0700492 if (baseAngle) {
493 ComputeOneSum(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700494 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
caryclark54359292015-03-26 07:52:43 -0700495 }
496 } while (next != firstAngle);
497 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
498 firstAngle = baseAngle;
499 tryReverse = true;
500 }
501 if (tryReverse) {
halcanary96fcdcc2015-08-27 07:41:13 -0700502 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700503 SkOpAngle* prior = firstAngle;
504 do {
505 angle = prior;
506 prior = angle->previous();
507 SkASSERT(prior->next() == angle);
508 next = angle->next();
509 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700510 baseAngle = nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700511 continue;
512 }
caryclark54359292015-03-26 07:52:43 -0700513 int testWinding = angle->starter()->windSum();
514 if (SK_MinS32 != testWinding) {
515 baseAngle = angle;
516 continue;
reed0dc4dd62015-03-24 13:55:33 -0700517 }
caryclark54359292015-03-26 07:52:43 -0700518 if (baseAngle) {
519 ComputeOneSumReverse(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700520 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700521 }
caryclark54359292015-03-26 07:52:43 -0700522 } while (prior != firstAngle);
reed0dc4dd62015-03-24 13:55:33 -0700523 }
caryclark54359292015-03-26 07:52:43 -0700524 return start->starter(end)->windSum();
reed0dc4dd62015-03-24 13:55:33 -0700525}
526
caryclark55888e42016-07-18 10:01:36 -0700527bool SkOpSegment::contains(double newT) const {
528 const SkOpSpanBase* spanBase = &fHead;
529 do {
530 if (spanBase->ptT()->contains(this, newT)) {
531 return true;
532 }
533 if (spanBase == &fTail) {
534 break;
535 }
536 spanBase = spanBase->upCast()->next();
537 } while (true);
538 return false;
539}
540
mtklein18300a32016-03-16 13:53:35 -0700541void SkOpSegment::release(const SkOpSpan* span) {
caryclark54359292015-03-26 07:52:43 -0700542 if (span->done()) {
caryclark08bc8482015-04-24 09:08:57 -0700543 --fDoneCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000544 }
caryclark08bc8482015-04-24 09:08:57 -0700545 --fCount;
caryclark15976282016-07-21 05:48:43 -0700546 SkOPASSERT(fCount >= fDoneCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000547}
548
caryclark26ad22a2015-10-16 09:03:38 -0700549double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
caryclark54359292015-03-26 07:52:43 -0700550 SkDPoint testPt = this->dPtAtT(t);
551 SkDLine testPerp = {{ testPt, testPt }};
552 SkDVector slope = this->dSlopeAtT(t);
553 testPerp[1].fX += slope.fY;
554 testPerp[1].fY -= slope.fX;
555 SkIntersections i;
caryclark26ad22a2015-10-16 09:03:38 -0700556 const SkOpSegment* oppSegment = oppAngle->segment();
caryclark1049f122015-04-20 08:31:59 -0700557 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
caryclark54359292015-03-26 07:52:43 -0700558 double closestDistSq = SK_ScalarInfinity;
559 for (int index = 0; index < i.used(); ++index) {
560 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000561 continue;
562 }
caryclark54359292015-03-26 07:52:43 -0700563 double testDistSq = testPt.distanceSquared(i.pt(index));
564 if (closestDistSq > testDistSq) {
565 closestDistSq = testDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000566 }
567 }
caryclark54359292015-03-26 07:52:43 -0700568 return closestDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000569}
570
caryclark@google.com07393ca2013-04-08 11:47:37 +0000571/*
572 The M and S variable name parts stand for the operators.
573 Mi stands for Minuend (see wiki subtraction, analogous to difference)
574 Su stands for Subtrahend
575 The Opp variable name part designates that the value is for the Opposite operator.
576 Opposite values result from combining coincident spans.
577 */
caryclark54359292015-03-26 07:52:43 -0700578SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
579 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) {
580 SkOpSpanBase* start = *nextStart;
581 SkOpSpanBase* end = *nextEnd;
582 SkASSERT(start != end);
583 int step = start->step(end);
584 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
585 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000586 // mark the smaller of startIndex, endIndex done, and all adjacent
587 // spans with the same T value (but not 'other' spans)
588#if DEBUG_WINDING
589 SkDebugf("%s simple\n", __FUNCTION__);
590#endif
caryclark54359292015-03-26 07:52:43 -0700591 SkOpSpan* startSpan = start->starter(end);
592 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700593 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000594 }
caryclark54359292015-03-26 07:52:43 -0700595 markDone(startSpan);
596 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000597 return other;
598 }
caryclark54359292015-03-26 07:52:43 -0700599 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
600 SkASSERT(endNear == end); // is this ever not end?
601 SkASSERT(endNear);
602 SkASSERT(start != endNear);
603 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000604 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700605 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
caryclark@google.com570863f2013-09-16 15:55:01 +0000606 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000607 if (!sortable) {
608 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700609 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700610 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000611 }
caryclark54359292015-03-26 07:52:43 -0700612 SkOpAngle* angle = this->spanToAngle(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000613 if (angle->unorderable()) {
614 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700615 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700616 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000617 }
618#if DEBUG_SORT
619 SkDebugf("%s\n", __FUNCTION__);
620 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000621#endif
caryclark54359292015-03-26 07:52:43 -0700622 int sumMiWinding = updateWinding(end, start);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000623 if (sumMiWinding == SK_MinS32) {
624 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700625 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700626 return nullptr;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000627 }
caryclark54359292015-03-26 07:52:43 -0700628 int sumSuWinding = updateOppWinding(end, start);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000629 if (operand()) {
630 SkTSwap<int>(sumMiWinding, sumSuWinding);
631 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000632 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700633 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000634 bool foundDone = false;
635 // iterate through the angle, and compute everyone's winding
636 SkOpSegment* nextSegment;
637 int activeCount = 0;
638 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000639 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000640 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000641 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000642 if (activeAngle) {
643 ++activeCount;
644 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000645 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +0000646 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000647 }
648 }
649 if (nextSegment->done()) {
650 continue;
651 }
reed0dc4dd62015-03-24 13:55:33 -0700652 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700653 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700654 }
caryclark54359292015-03-26 07:52:43 -0700655 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000656 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000657 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000658 *chase->append() = last;
659#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700660 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
661 last->segment()->debugID(), last->debugID());
662 if (!last->final()) {
663 SkDebugf(" windSum=%d", last->upCast()->windSum());
664 }
665 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000666#endif
667 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000668 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700669 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000670 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700671 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000672 }
673 *nextStart = foundAngle->start();
674 *nextEnd = foundAngle->end();
675 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000676#if DEBUG_WINDING
677 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
678 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
679 #endif
680 return nextSegment;
681}
682
caryclark54359292015-03-26 07:52:43 -0700683SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
684 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
685 SkOpSpanBase* start = *nextStart;
686 SkOpSpanBase* end = *nextEnd;
687 SkASSERT(start != end);
688 int step = start->step(end);
689 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
690 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000691 // mark the smaller of startIndex, endIndex done, and all adjacent
692 // spans with the same T value (but not 'other' spans)
693#if DEBUG_WINDING
694 SkDebugf("%s simple\n", __FUNCTION__);
695#endif
caryclark54359292015-03-26 07:52:43 -0700696 SkOpSpan* startSpan = start->starter(end);
697 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700698 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000699 }
caryclark54359292015-03-26 07:52:43 -0700700 markDone(startSpan);
701 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000702 return other;
703 }
caryclark54359292015-03-26 07:52:43 -0700704 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
705 SkASSERT(endNear == end); // is this ever not end?
706 SkASSERT(endNear);
707 SkASSERT(start != endNear);
708 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000709 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700710 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000711 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000712 if (!sortable) {
713 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700714 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700715 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000716 }
caryclark54359292015-03-26 07:52:43 -0700717 SkOpAngle* angle = this->spanToAngle(end, start);
718 if (angle->unorderable()) {
719 *unsortable = true;
720 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700721 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700722 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000723#if DEBUG_SORT
724 SkDebugf("%s\n", __FUNCTION__);
725 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000726#endif
caryclark54359292015-03-26 07:52:43 -0700727 int sumWinding = updateWinding(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000728 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700729 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000730 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700731 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000732 SkOpSegment* nextSegment;
733 int activeCount = 0;
734 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000735 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000736 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000737 &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000738 if (activeAngle) {
739 ++activeCount;
740 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000741 foundAngle = nextAngle;
742 foundDone = nextSegment->done(nextAngle);
743 }
744 }
745 if (nextSegment->done()) {
746 continue;
747 }
reed0dc4dd62015-03-24 13:55:33 -0700748 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700749 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700750 }
caryclark54359292015-03-26 07:52:43 -0700751 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000752 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000753 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000754 *chase->append() = last;
755#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700756 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
757 last->segment()->debugID(), last->debugID());
758 if (!last->final()) {
759 SkDebugf(" windSum=%d", last->upCast()->windSum());
760 }
761 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000762#endif
763 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000764 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700765 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000766 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700767 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000768 }
769 *nextStart = foundAngle->start();
770 *nextEnd = foundAngle->end();
771 nextSegment = foundAngle->segment();
772#if DEBUG_WINDING
773 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
774 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
775 #endif
776 return nextSegment;
777}
778
caryclark54359292015-03-26 07:52:43 -0700779SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
780 bool* unsortable) {
781 SkOpSpanBase* start = *nextStart;
782 SkOpSpanBase* end = *nextEnd;
783 SkASSERT(start != end);
784 int step = start->step(end);
785 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
786 if (other) {
787 // mark the smaller of startIndex, endIndex done, and all adjacent
788 // spans with the same T value (but not 'other' spans)
caryclark@google.com07393ca2013-04-08 11:47:37 +0000789#if DEBUG_WINDING
790 SkDebugf("%s simple\n", __FUNCTION__);
791#endif
caryclark54359292015-03-26 07:52:43 -0700792 SkOpSpan* startSpan = start->starter(end);
793 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700794 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000795 }
caryclark54359292015-03-26 07:52:43 -0700796 markDone(startSpan);
797 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000798 return other;
799 }
caryclark54359292015-03-26 07:52:43 -0700800 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
801 : (*nextStart)->prev());
802 SkASSERT(endNear == end); // is this ever not end?
803 SkASSERT(endNear);
804 SkASSERT(start != endNear);
805 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
806 SkOpAngle* angle = this->spanToAngle(end, start);
caryclark27c8eb82015-07-06 11:38:33 -0700807 if (!angle || angle->unorderable()) {
caryclark54359292015-03-26 07:52:43 -0700808 *unsortable = true;
809 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700810 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700811 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000812#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000813 SkDebugf("%s\n", __FUNCTION__);
814 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000815#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000816 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700817 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000818 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700819 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000820 SkOpSegment* nextSegment;
821 int activeCount = 0;
822 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000823 nextSegment = nextAngle->segment();
824 ++activeCount;
825 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000826 foundAngle = nextAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000827 if (!(foundDone = nextSegment->done(nextAngle))) {
828 break;
829 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000830 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000831 nextAngle = nextAngle->next();
832 } while (nextAngle != angle);
caryclark54359292015-03-26 07:52:43 -0700833 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000834 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700835 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000836 }
837 *nextStart = foundAngle->start();
838 *nextEnd = foundAngle->end();
839 nextSegment = foundAngle->segment();
840#if DEBUG_WINDING
841 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
842 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
843 #endif
844 return nextSegment;
845}
846
caryclark54359292015-03-26 07:52:43 -0700847SkOpGlobalState* SkOpSegment::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700848 return contour()->globalState();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000849}
850
caryclark1049f122015-04-20 08:31:59 -0700851void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
caryclark54359292015-03-26 07:52:43 -0700852 fContour = contour;
halcanary96fcdcc2015-08-27 07:41:13 -0700853 fNext = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000854 fPts = pts;
caryclark1049f122015-04-20 08:31:59 -0700855 fWeight = weight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000856 fVerb = verb;
caryclark54359292015-03-26 07:52:43 -0700857 fCount = 0;
858 fDoneCount = 0;
859 fVisited = false;
860 SkOpSpan* zeroSpan = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700861 zeroSpan->init(this, nullptr, 0, fPts[0]);
caryclark54359292015-03-26 07:52:43 -0700862 SkOpSpanBase* oneSpan = &fTail;
863 zeroSpan->setNext(oneSpan);
864 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
caryclark1049f122015-04-20 08:31:59 -0700865 SkDEBUGCODE(fID = globalState()->nextSegmentID());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000866}
867
caryclark54359292015-03-26 07:52:43 -0700868bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
869 SkDPoint cPt = this->dPtAtT(t);
caryclark1049f122015-04-20 08:31:59 -0700870 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
caryclark54359292015-03-26 07:52:43 -0700871 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
872 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -0700873 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
caryclark54359292015-03-26 07:52:43 -0700874 int used = i.used();
875 for (int index = 0; index < used; ++index) {
876 if (cPt.roughlyEqual(i.pt(index))) {
reed0dc4dd62015-03-24 13:55:33 -0700877 return true;
878 }
caryclark54359292015-03-26 07:52:43 -0700879 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000880 return false;
881}
882
caryclark54359292015-03-26 07:52:43 -0700883bool SkOpSegment::isXor() const {
884 return fContour->isXor();
885}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000886
caryclark5b5ddd72015-05-18 05:12:56 -0700887void SkOpSegment::markAllDone() {
888 SkOpSpan* span = this->head();
889 do {
890 this->markDone(span);
891 } while ((span = span->next()->upCastable()));
892}
893
caryclark54359292015-03-26 07:52:43 -0700894SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) {
895 int step = start->step(end);
896 SkOpSpan* minSpan = start->starter(end);
897 markDone(minSpan);
halcanary96fcdcc2015-08-27 07:41:13 -0700898 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000899 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700900 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000901 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -0700902 SkASSERT(!last);
903 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000904 }
caryclark54359292015-03-26 07:52:43 -0700905 other->markDone(minSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000906 }
907 return last;
908}
909
caryclark54359292015-03-26 07:52:43 -0700910bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
911 SkOpSpanBase** lastPtr) {
912 SkOpSpan* spanStart = start->starter(end);
913 int step = start->step(end);
914 bool success = markWinding(spanStart, winding);
halcanary96fcdcc2015-08-27 07:41:13 -0700915 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000916 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700917 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
918 if (spanStart->windSum() != SK_MinS32) {
919 SkASSERT(spanStart->windSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700920 SkASSERT(!last);
921 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000922 }
caryclark54359292015-03-26 07:52:43 -0700923 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000924 }
caryclark65f55312014-11-13 06:58:52 -0800925 if (lastPtr) {
926 *lastPtr = last;
927 }
928 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000929}
930
caryclark54359292015-03-26 07:52:43 -0700931bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
932 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
933 SkOpSpan* spanStart = start->starter(end);
934 int step = start->step(end);
935 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700936 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000937 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700938 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
939 if (spanStart->windSum() != SK_MinS32) {
940 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700941 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700942 this->globalState()->setWindingFailed();
943 return false;
caryclarkdac1d172014-06-17 05:15:38 -0700944 }
caryclark54359292015-03-26 07:52:43 -0700945 } else {
946 SkASSERT(spanStart->windSum() == oppWinding);
947 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700948 }
949 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700950 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000951 }
caryclark54359292015-03-26 07:52:43 -0700952 if (this->operand() == other->operand()) {
953 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700954 } else {
caryclark54359292015-03-26 07:52:43 -0700955 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700956 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000957 }
caryclark65f55312014-11-13 06:58:52 -0800958 if (lastPtr) {
959 *lastPtr = last;
960 }
961 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000962}
963
caryclark54359292015-03-26 07:52:43 -0700964SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000965 SkASSERT(angle->segment() == this);
966 if (UseInnerWinding(maxWinding, sumWinding)) {
967 maxWinding = sumWinding;
968 }
caryclark54359292015-03-26 07:52:43 -0700969 SkOpSpanBase* last;
970 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000971#if DEBUG_WINDING
972 if (last) {
caryclark54359292015-03-26 07:52:43 -0700973 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
974 last->segment()->debugID(), last->debugID());
975 if (!last->final()) {
976 SkDebugf(" windSum=");
977 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
978 }
979 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000980 }
981#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000982 return last;
983}
984
caryclark54359292015-03-26 07:52:43 -0700985SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
986 int oppSumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000987 SkASSERT(angle->segment() == this);
988 if (UseInnerWinding(maxWinding, sumWinding)) {
989 maxWinding = sumWinding;
990 }
991 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
992 oppMaxWinding = oppSumWinding;
993 }
halcanary96fcdcc2015-08-27 07:41:13 -0700994 SkOpSpanBase* last = nullptr;
caryclark65f55312014-11-13 06:58:52 -0800995 // caller doesn't require that this marks anything
caryclark54359292015-03-26 07:52:43 -0700996 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000997#if DEBUG_WINDING
998 if (last) {
caryclark54359292015-03-26 07:52:43 -0700999 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
1000 last->segment()->debugID(), last->debugID());
1001 if (!last->final()) {
1002 SkDebugf(" windSum=");
1003 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
1004 }
1005 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +00001006 }
1007#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00001008 return last;
1009}
1010
caryclark54359292015-03-26 07:52:43 -07001011void SkOpSegment::markDone(SkOpSpan* span) {
1012 SkASSERT(this == span->segment());
1013 if (span->done()) {
1014 return;
1015 }
1016#if DEBUG_MARK_DONE
1017 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
1018#endif
1019 span->setDone(true);
1020 ++fDoneCount;
1021 debugValidate();
1022}
1023
1024bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
1025 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -07001026 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -07001027 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001028 return false;
1029 }
1030#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -07001031 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -07001032#endif
caryclark54359292015-03-26 07:52:43 -07001033 span->setWindSum(winding);
1034 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001035 return true;
1036}
1037
caryclark54359292015-03-26 07:52:43 -07001038bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
1039 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +00001040 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -07001041 if (span->done()) {
1042 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001043 }
caryclark54359292015-03-26 07:52:43 -07001044#if DEBUG_MARK_DONE
1045 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1046#endif
1047 span->setWindSum(winding);
1048 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001049 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001050 return true;
1051}
1052
caryclark54359292015-03-26 07:52:43 -07001053bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclark55888e42016-07-18 10:01:36 -07001054 const SkPoint& testPt, AliasMatch aliasMatch) const {
1055 SkASSERT(this == base->segment());
1056 if (this == testParent) {
1057 if (precisely_equal(base->fT, testT)) {
1058 return true;
1059 }
caryclark54359292015-03-26 07:52:43 -07001060 }
1061 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1062 return false;
1063 }
caryclark55888e42016-07-18 10:01:36 -07001064 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001065}
1066
1067static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1068 if (last) {
1069 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001070 }
halcanary96fcdcc2015-08-27 07:41:13 -07001071 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001072}
1073
caryclark54359292015-03-26 07:52:43 -07001074SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1075 SkOpSpanBase** last) const {
1076 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001077 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001078 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1079 SkASSERT(endSpan);
1080 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1081 SkOpSpanBase* foundSpan;
1082 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001083 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001084 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001085 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001086 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001087 }
caryclark54359292015-03-26 07:52:43 -07001088 SkOpPtT* otherPtT = endSpan->ptT()->next();
1089 other = otherPtT->segment();
1090 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001091 otherEnd = step > 0
1092 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1093 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001094 } else {
1095 int loopCount = angle->loopCount();
1096 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001097 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001098 }
1099 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001100 if (nullptr == next) {
1101 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001102 }
caryclarkdac1d172014-06-17 05:15:38 -07001103#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001104 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001105 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001106 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001107 }
caryclark54359292015-03-26 07:52:43 -07001108#endif
caryclarkdac1d172014-06-17 05:15:38 -07001109 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001110 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001111 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001112 }
caryclark343382e2016-06-29 08:18:38 -07001113 if (!otherEnd) {
1114 return nullptr;
1115 }
caryclark54359292015-03-26 07:52:43 -07001116 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001117 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001118 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001119 }
caryclark54359292015-03-26 07:52:43 -07001120 SkASSERT(*startPtr);
1121 if (!otherEnd) {
halcanary96fcdcc2015-08-27 07:41:13 -07001122 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001123 }
1124// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001125 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1126 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1127 if (foundMin->windValue() != origMin->windValue()
1128 || foundMin->oppValue() != origMin->oppValue()) {
1129 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001130 }
caryclark54359292015-03-26 07:52:43 -07001131 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001132 *stepPtr = foundStep;
1133 if (minPtr) {
1134 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001135 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001136 return other;
1137}
1138
caryclark55888e42016-07-18 10:01:36 -07001139// Please keep this in sync with DebugClearVisited()
1140void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001141 // reset visited flag back to false
1142 do {
1143 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1144 while ((ptT = ptT->next()) != stopPtT) {
1145 SkOpSegment* opp = ptT->segment();
1146 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001147 }
caryclarkbca19f72015-05-13 08:23:48 -07001148 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001149}
1150
caryclark55888e42016-07-18 10:01:36 -07001151// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001152// look for pairs of undetected coincident curves
1153// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001154// Even though pairs of curves correct detect coincident runs, a run may be missed
1155// if the coincidence is a product of multiple intersections. For instance, given
1156// curves A, B, and C:
1157// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1158// the end of C that the intersection is replaced with the end of C.
1159// Even though A-B correctly do not detect an intersection at point 2,
1160// the resulting run from point 1 to point 2 is coincident on A and B.
1161bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001162 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001163 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001164 }
halcanary96fcdcc2015-08-27 07:41:13 -07001165 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001166 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001167 bool result = false;
caryclark54359292015-03-26 07:52:43 -07001168 do {
caryclarkbca19f72015-05-13 08:23:48 -07001169 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001170 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001171 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001172 if (ptT->deleted()) {
1173 continue;
1174 }
caryclark54359292015-03-26 07:52:43 -07001175 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001176 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001177 continue;
reed0dc4dd62015-03-24 13:55:33 -07001178 }
caryclarkbca19f72015-05-13 08:23:48 -07001179 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1180 if (!opp->visited()) {
1181 continue;
1182 }
1183 if (spanBase == &fHead) {
1184 continue;
1185 }
caryclark55888e42016-07-18 10:01:36 -07001186 if (ptT->segment() == this) {
1187 continue;
1188 }
caryclarkbca19f72015-05-13 08:23:48 -07001189 SkOpSpan* span = spanBase->upCastable();
1190 // FIXME?: this assumes that if the opposite segment is coincident then no more
1191 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001192 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001193 continue;
1194 }
caryclarkbca19f72015-05-13 08:23:48 -07001195 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001196 continue;
caryclark55888e42016-07-18 10:01:36 -07001197 }
halcanary96fcdcc2015-08-27 07:41:13 -07001198 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001199 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001200 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001201 SkOpSpan* priorTest = spanBase->prev();
1202 while (!priorOpp && priorTest) {
1203 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001204 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001205 if (priorPtT->deleted()) {
1206 continue;
1207 }
caryclark54359292015-03-26 07:52:43 -07001208 SkOpSegment* segment = priorPtT->span()->segment();
1209 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001210 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001211 priorOpp = opp;
1212 break;
1213 }
1214 }
caryclarkbca19f72015-05-13 08:23:48 -07001215 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001216 }
1217 if (!priorOpp) {
1218 continue;
1219 }
caryclark26ad22a2015-10-16 09:03:38 -07001220 if (priorPtT == ptT) {
1221 continue;
1222 }
caryclark54359292015-03-26 07:52:43 -07001223 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001224 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001225 bool swapped = priorPtT->fT > ptT->fT;
1226 if (swapped) {
1227 SkTSwap(priorPtT, ptT);
1228 SkTSwap(oppStart, oppEnd);
1229 }
caryclark55888e42016-07-18 10:01:36 -07001230 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1231 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1232 SkOpPtT* rootPtT = ptT->span()->ptT();
1233 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1234 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1235 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001236 goto swapBack;
1237 }
caryclark55888e42016-07-18 10:01:36 -07001238 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001239 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001240#if DEBUG_COINCIDENCE_VERBOSE
1241 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1242 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1243 rootOppEnd->debugID());
1244#endif
1245 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1246 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001247 }
caryclark55888e42016-07-18 10:01:36 -07001248#if DEBUG_COINCIDENCE
1249 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1250#endif
1251 result = true;
caryclark54359292015-03-26 07:52:43 -07001252 }
1253 swapBack:
1254 if (swapped) {
1255 SkTSwap(priorPtT, ptT);
1256 }
reed0dc4dd62015-03-24 13:55:33 -07001257 }
halcanary96fcdcc2015-08-27 07:41:13 -07001258 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001259 ClearVisited(&fHead);
1260 return result;
reed0dc4dd62015-03-24 13:55:33 -07001261}
1262
caryclark55888e42016-07-18 10:01:36 -07001263// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001264// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001265bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001266 debugValidate();
1267 SkOpSpanBase* test = &fHead;
1268 do {
1269 int addCount = test->spanAddsCount();
caryclark55888e42016-07-18 10:01:36 -07001270 FAIL_IF(addCount < 1);
caryclark08bc8482015-04-24 09:08:57 -07001271 if (addCount == 1) {
1272 continue;
1273 }
1274 SkOpPtT* startPtT = test->ptT();
1275 SkOpPtT* testPtT = startPtT;
1276 do { // iterate through all spans associated with start
1277 SkOpSpanBase* oppSpan = testPtT->span();
1278 if (oppSpan->spanAddsCount() == addCount) {
1279 continue;
1280 }
1281 if (oppSpan->deleted()) {
1282 continue;
1283 }
1284 SkOpSegment* oppSegment = oppSpan->segment();
1285 if (oppSegment == this) {
1286 continue;
1287 }
1288 // find range of spans to consider merging
1289 SkOpSpanBase* oppPrev = oppSpan;
1290 SkOpSpanBase* oppFirst = oppSpan;
1291 while ((oppPrev = oppPrev->prev())) {
1292 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1293 break;
1294 }
1295 if (oppPrev->spanAddsCount() == addCount) {
1296 continue;
1297 }
1298 if (oppPrev->deleted()) {
1299 continue;
1300 }
1301 oppFirst = oppPrev;
1302 }
1303 SkOpSpanBase* oppNext = oppSpan;
1304 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001305 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001306 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1307 break;
1308 }
1309 if (oppNext->spanAddsCount() == addCount) {
1310 continue;
1311 }
1312 if (oppNext->deleted()) {
1313 continue;
1314 }
1315 oppLast = oppNext;
1316 }
1317 if (oppFirst == oppLast) {
1318 continue;
1319 }
1320 SkOpSpanBase* oppTest = oppFirst;
1321 do {
1322 if (oppTest == oppSpan) {
1323 continue;
1324 }
1325 // check to see if the candidate meets specific criteria:
1326 // it contains spans of segments in test's loop but not including 'this'
1327 SkOpPtT* oppStartPtT = oppTest->ptT();
1328 SkOpPtT* oppPtT = oppStartPtT;
1329 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1330 SkOpSegment* oppPtTSegment = oppPtT->segment();
1331 if (oppPtTSegment == this) {
1332 goto tryNextSpan;
1333 }
1334 SkOpPtT* matchPtT = startPtT;
1335 do {
1336 if (matchPtT->segment() == oppPtTSegment) {
1337 goto foundMatch;
1338 }
1339 } while ((matchPtT = matchPtT->next()) != startPtT);
1340 goto tryNextSpan;
1341 foundMatch: // merge oppTest and oppSpan
1342 oppSegment->debugValidate();
1343 if (oppTest == &oppSegment->fTail || oppTest == &oppSegment->fHead) {
1344 SkASSERT(oppSpan != &oppSegment->fHead); // don't expect collapse
1345 SkASSERT(oppSpan != &oppSegment->fTail);
1346 oppTest->merge(oppSpan->upCast());
1347 } else {
1348 oppSpan->merge(oppTest->upCast());
1349 }
1350 oppSegment->debugValidate();
1351 goto checkNextSpan;
1352 }
caryclark55888e42016-07-18 10:01:36 -07001353 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001354 ;
1355 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1356 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001357checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001358 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001359 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001360 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001361 return true;
caryclark08bc8482015-04-24 09:08:57 -07001362}
1363
caryclark55888e42016-07-18 10:01:36 -07001364// adjacent spans may have points close by
1365bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan) const {
1366 const SkOpPtT* refHead = refSpan->ptT();
1367 const SkOpPtT* checkHead = checkSpan->ptT();
1368// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
1369 if (!SkDPoint::RoughlyEqual(refHead->fPt, checkHead->fPt)) {
1370#if DEBUG_COINCIDENCE
1371 // verify that no combination of points are close
1372 const SkOpPtT* dBugRef = refHead;
1373 do {
1374 const SkOpPtT* dBugCheck = checkHead;
1375 do {
1376 SkASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
1377 dBugCheck = dBugCheck->next();
1378 } while (dBugCheck != checkHead);
1379 dBugRef = dBugRef->next();
1380 } while (dBugRef != refHead);
1381#endif
1382 return false;
1383 }
1384 // check only unique points
1385 SkScalar distSqBest = SK_ScalarMax;
1386 const SkOpPtT* refBest = nullptr;
1387 const SkOpPtT* checkBest = nullptr;
1388 const SkOpPtT* ref = refHead;
1389 do {
1390 if (ref->deleted()) {
1391 continue;
1392 }
1393 while (ref->ptAlreadySeen(refHead)) {
1394 ref = ref->next();
1395 if (ref == refHead) {
1396 goto doneCheckingDistance;
1397 }
1398 }
1399 const SkOpPtT* check = checkHead;
1400 const SkOpSegment* refSeg = ref->segment();
1401 do {
1402 if (check->deleted()) {
1403 continue;
1404 }
1405 while (check->ptAlreadySeen(checkHead)) {
1406 check = check->next();
1407 if (check == checkHead) {
1408 goto nextRef;
1409 }
1410 }
1411 SkScalar distSq = ref->fPt.distanceToSqd(check->fPt);
1412 if (distSqBest > distSq && (refSeg != check->segment()
1413 || !refSeg->ptsDisjoint(*ref, *check))) {
1414 distSqBest = distSq;
1415 refBest = ref;
1416 checkBest = check;
1417 }
1418 } while ((check = check->next()) != checkHead);
1419nextRef:
1420 ;
1421 } while ((ref = ref->next()) != refHead);
1422doneCheckingDistance:
1423 return checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
1424 checkBest->fPt, kAllowAliasMatch);
1425}
1426
1427// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001428// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
caryclark08bc8482015-04-24 09:08:57 -07001429void SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001430 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001431 // release undeleted spans pointing to this seg that are linked to the primary span
1432 SkOpSpanBase* spanBase = &fHead;
caryclark54359292015-03-26 07:52:43 -07001433 do {
caryclark55888e42016-07-18 10:01:36 -07001434 SkOpPtT* ptT = spanBase->ptT();
1435 const SkOpPtT* headPtT = ptT;
1436 while ((ptT = ptT->next()) != headPtT) {
1437 SkOpSpanBase* test = ptT->span();
1438 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1439 && test->ptT() == ptT) {
1440 if (test->final()) {
1441 if (spanBase == &fHead) {
1442 this->clearAll();
1443 return;
1444 }
1445 spanBase->upCast()->release(ptT);
1446 } else if (test->prev()) {
1447 test->upCast()->release(headPtT);
1448 }
1449 break;
caryclark54359292015-03-26 07:52:43 -07001450 }
reed0dc4dd62015-03-24 13:55:33 -07001451 }
caryclark55888e42016-07-18 10:01:36 -07001452 spanBase = spanBase->upCast()->next();
1453 } while (!spanBase->final());
1454
1455 // This loop looks for adjacent spans which are near by
1456 spanBase = &fHead;
1457 do { // iterate through all spans associated with start
1458 SkOpSpanBase* test = spanBase->upCast()->next();
1459 if (this->spansNearby(spanBase, test)) {
1460 if (test->final()) {
1461 if (spanBase->prev()) {
1462 test->merge(spanBase->upCast());
1463 } else {
1464 this->clearAll();
1465 return;
1466 }
1467 } else {
1468 spanBase->merge(test->upCast());
1469 }
1470 }
1471 spanBase = test;
1472 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001473 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001474}
1475
caryclark54359292015-03-26 07:52:43 -07001476bool SkOpSegment::operand() const {
1477 return fContour->operand();
1478}
1479
1480bool SkOpSegment::oppXor() const {
1481 return fContour->oppXor();
1482}
1483
1484bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1485 if (fVerb == SkPath::kLine_Verb) {
1486 return false;
1487 }
1488 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1489 // hits in two places with very different t values.
1490 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1491 // 'controls contained by ends' could avoid this check for common curves
1492 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1493 // on the other hand, the below check is relatively inexpensive
1494 double midT = (t1 + t2) / 2;
1495 SkPoint midPt = this->ptAtT(midT);
1496 double seDistSq = SkTMax(pt1.distanceToSqd(pt2) * 2, FLT_EPSILON * 2);
1497 return midPt.distanceToSqd(pt1) > seDistSq || midPt.distanceToSqd(pt2) > seDistSq;
1498}
1499
1500void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1501 int* maxWinding, int* sumWinding) {
1502 int deltaSum = SpanSign(start, end);
1503 *maxWinding = *sumMiWinding;
1504 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001505 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001506}
1507
1508void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1509 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1510 int* oppSumWinding) {
1511 int deltaSum = SpanSign(start, end);
1512 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001513 if (operand()) {
1514 *maxWinding = *sumSuWinding;
1515 *sumWinding = *sumSuWinding -= deltaSum;
1516 *oppMaxWinding = *sumMiWinding;
1517 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1518 } else {
1519 *maxWinding = *sumMiWinding;
1520 *sumWinding = *sumMiWinding -= deltaSum;
1521 *oppMaxWinding = *sumSuWinding;
1522 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1523 }
bungeman60e0fee2015-08-26 05:15:46 -07001524 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1525 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001526}
1527
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001528void SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001529 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001530 do {
caryclark54359292015-03-26 07:52:43 -07001531 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001532 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001533 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001534 continue;
1535 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001536#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001537 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001538#endif
caryclark54359292015-03-26 07:52:43 -07001539 SkOpAngle* baseAngle = fromAngle;
1540 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001541#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001542 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1543 span->debugID());
1544 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001545#endif
caryclark54359292015-03-26 07:52:43 -07001546 fromAngle->insert(toAngle);
1547 } else if (!fromAngle) {
1548 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001549 }
caryclark54359292015-03-26 07:52:43 -07001550 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001551 do {
caryclark54359292015-03-26 07:52:43 -07001552 SkOpSpanBase* oSpan = ptT->span();
1553 if (oSpan == span) {
1554 continue;
1555 }
1556 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001557 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001558#if DEBUG_ANGLE
1559 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001560 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1561 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001562 wroteAfterHeader = true;
1563 }
1564#endif
caryclark54359292015-03-26 07:52:43 -07001565 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001566 baseAngle->insert(oAngle);
1567 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001568 }
caryclark54359292015-03-26 07:52:43 -07001569 if (!oSpan->final()) {
1570 oAngle = oSpan->upCast()->toAngle();
1571 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001572#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001573 if (!wroteAfterHeader) {
1574 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1575 span->t(), span->debugID());
1576 wroteAfterHeader = true;
1577 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001578#endif
caryclark54359292015-03-26 07:52:43 -07001579 if (!oAngle->loopContains(baseAngle)) {
1580 baseAngle->insert(oAngle);
1581 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001582 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001583 }
caryclark54359292015-03-26 07:52:43 -07001584 } while ((ptT = ptT->next()) != stopPtT);
1585 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001586 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001587 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001588 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001589 }
halcanary96fcdcc2015-08-27 07:41:13 -07001590 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001591 }
1592#if DEBUG_SORT
1593 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1594#endif
caryclark54359292015-03-26 07:52:43 -07001595 } while (!span->final() && (span = span->upCast()->next()));
caryclark@google.com570863f2013-09-16 15:55:01 +00001596}
1597
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001598// return true if midpoints were computed
caryclark54359292015-03-26 07:52:43 -07001599bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001600 SkOpCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001601 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001602 const SkOpPtT& startPtT = *start->ptT();
1603 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001604 SkDEBUGCODE(edge->fVerb = fVerb);
1605 edge->fPts[0] = startPtT.fPt;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001606 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001607 edge->fPts[points] = endPtT.fPt;
1608 edge->fWeight = 1;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001609 if (fVerb == SkPath::kLine_Verb) {
1610 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001611 }
caryclark54359292015-03-26 07:52:43 -07001612 double startT = startPtT.fT;
1613 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001614 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1615 // don't compute midpoints if we already have them
1616 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001617 edge->fPts[1] = fPts[1];
1618 return false;
1619 }
1620 if (fVerb == SkPath::kConic_Verb) {
1621 edge->fPts[1] = fPts[1];
1622 edge->fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001623 return false;
1624 }
1625 SkASSERT(fVerb == SkPath::kCubic_Verb);
1626 if (start < end) {
caryclark1049f122015-04-20 08:31:59 -07001627 edge->fPts[1] = fPts[1];
1628 edge->fPts[2] = fPts[2];
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001629 return false;
1630 }
caryclark1049f122015-04-20 08:31:59 -07001631 edge->fPts[1] = fPts[2];
1632 edge->fPts[2] = fPts[1];
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001633 return false;
1634 }
caryclark1049f122015-04-20 08:31:59 -07001635 const SkDPoint sub[2] = {{ edge->fPts[0].fX, edge->fPts[0].fY},
1636 {edge->fPts[points].fX, edge->fPts[points].fY }};
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001637 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001638 edge->fPts[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
1639 } else if (fVerb == SkPath::kConic_Verb) {
1640 edge->fPts[1] = SkDConic::SubDivide(fPts, fWeight, sub[0], sub[1],
1641 startT, endT, &edge->fWeight).asSkPoint();
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001642 } else {
1643 SkASSERT(fVerb == SkPath::kCubic_Verb);
1644 SkDPoint ctrl[2];
1645 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
caryclark1049f122015-04-20 08:31:59 -07001646 edge->fPts[1] = ctrl[0].asSkPoint();
1647 edge->fPts[2] = ctrl[1].asSkPoint();
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001648 }
1649 return true;
1650}
1651
caryclark54359292015-03-26 07:52:43 -07001652bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001653 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001654 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001655 const SkOpPtT& startPtT = *start->ptT();
1656 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001657 SkDEBUGCODE(edge->fVerb = fVerb);
1658 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001659 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001660 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001661 if (fVerb == SkPath::kLine_Verb) {
1662 return false;
1663 }
caryclark54359292015-03-26 07:52:43 -07001664 double startT = startPtT.fT;
1665 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001666 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1667 // don't compute midpoints if we already have them
1668 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001669 edge->fLine[1].set(fPts[1]);
1670 return false;
1671 }
1672 if (fVerb == SkPath::kConic_Verb) {
1673 edge->fConic[1].set(fPts[1]);
1674 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001675 return false;
1676 }
1677 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001678 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001679 edge->fCubic[1].set(fPts[1]);
1680 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001681 return false;
1682 }
caryclark1049f122015-04-20 08:31:59 -07001683 edge->fCubic[1].set(fPts[2]);
1684 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001685 return false;
1686 }
1687 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001688 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1689 } else if (fVerb == SkPath::kConic_Verb) {
1690 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1691 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001692 } else {
1693 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001694 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001695 }
1696 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001697}
1698
caryclark27c8eb82015-07-06 11:38:33 -07001699bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001700 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001701 // average t, find mid pt
1702 double midT = (prior->t() + spanBase->t()) / 2;
1703 SkPoint midPt = this->ptAtT(midT);
1704 bool coincident = true;
1705 // if the mid pt is not near either end pt, project perpendicular through opp seg
1706 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1707 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001708 if (priorPtT->span() == ptT->span()) {
1709 return false;
1710 }
caryclark27c8eb82015-07-06 11:38:33 -07001711 coincident = false;
1712 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001713 SkDCurve curvePart;
1714 this->subDivide(prior, spanBase, &curvePart);
1715 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1716 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1717 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1718 SkDCurve oppPart;
1719 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1720 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001721 // measure distance and see if it's small enough to denote coincidence
1722 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001723 if (!between(0, i[0][index], 1)) {
1724 continue;
1725 }
caryclark27c8eb82015-07-06 11:38:33 -07001726 SkDPoint oppPt = i.pt(index);
1727 if (oppPt.approximatelyEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001728 // the coincidence can occur at almost any angle
1729 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001730 }
1731 }
1732 }
1733 return coincident;
1734}
1735
caryclark54359292015-03-26 07:52:43 -07001736void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
1737 SkOpSpan* span = this->head();
1738 do {
1739 if (!span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001740 break;
1741 }
caryclark54359292015-03-26 07:52:43 -07001742 } while ((span = span->next()->upCastable()));
1743 SkASSERT(span);
1744 *start = span;
1745 *end = span->next();
reed0dc4dd62015-03-24 13:55:33 -07001746}
1747
caryclark54359292015-03-26 07:52:43 -07001748int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1749 const SkOpSpan* lesser = start->starter(end);
1750 int oppWinding = lesser->oppSum();
1751 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001752 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1753 && oppWinding != SK_MaxS32) {
1754 oppWinding -= oppSpanWinding;
1755 }
1756 return oppWinding;
1757}
1758
1759int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001760 const SkOpSpanBase* startSpan = angle->start();
1761 const SkOpSpanBase* endSpan = angle->end();
1762 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001763}
1764
1765int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001766 const SkOpSpanBase* startSpan = angle->start();
1767 const SkOpSpanBase* endSpan = angle->end();
1768 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001769}
1770
caryclark624637c2015-05-11 07:21:27 -07001771int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1772 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001773 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001774 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001775 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001776 }
1777 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001778 return winding;
1779 }
caryclark54359292015-03-26 07:52:43 -07001780 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001781 if (winding && UseInnerWinding(winding - spanWinding, winding)
1782 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001783 winding -= spanWinding;
1784 }
1785 return winding;
1786}
1787
caryclark624637c2015-05-11 07:21:27 -07001788int SkOpSegment::updateWinding(SkOpAngle* angle) {
1789 SkOpSpanBase* startSpan = angle->start();
1790 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001791 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001792}
1793
caryclark624637c2015-05-11 07:21:27 -07001794int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1795 SkOpSpanBase* startSpan = angle->start();
1796 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001797 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001798}
1799
1800// OPTIMIZATION: does the following also work, and is it any faster?
1801// return outerWinding * innerWinding > 0
1802// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1803bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1804 SkASSERT(outerWinding != SK_MaxS32);
1805 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001806 int absOut = SkTAbs(outerWinding);
1807 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001808 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1809 return result;
1810}
1811
caryclark@google.com07393ca2013-04-08 11:47:37 +00001812int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001813 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1814 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001815}