blob: 20f0013230f0bfa1094ae603641705b1eba224af [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 }
caryclarkef4f32a2016-08-24 09:24:18 -0700232 if (!this->match(testPtT, this, t, pt)) {
caryclark55888e42016-07-18 10:01:36 -0700233 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 }
caryclarkef4f32a2016-08-24 09:24:18 -0700259 SkOpPtT* newPtT = this->addT(newT, startOver);
caryclark55888e42016-07-18 10:01:36 -0700260 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()
caryclarkef4f32a2016-08-24 09:24:18 -0700273SkOpPtT* SkOpSegment::addT(double t, 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 }
caryclarkef4f32a2016-08-24 09:24:18 -0700284 if (this->match(result, this, t, pt)) {
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 }
caryclark08bc8482015-04-24 09:08:57 -0700296 bumpSpan:
caryclark08bc8482015-04-24 09:08:57 -0700297 span->bumpSpanAdds();
caryclarkef4f32a2016-08-24 09:24:18 -0700298 return result;
reed0dc4dd62015-03-24 13:55:33 -0700299 }
caryclark54359292015-03-26 07:52:43 -0700300 if (t < result->fT) {
301 SkOpSpan* prev = result->span()->prev();
caryclarka3375e42015-12-07 12:18:02 -0800302 if (!prev) {
303 return nullptr;
304 }
caryclark55888e42016-07-18 10:01:36 -0700305 SkOpSpan* span = insert(prev);
caryclark54359292015-03-26 07:52:43 -0700306 span->init(this, prev, t, pt);
307 this->debugValidate();
308#if DEBUG_ADD_T
309 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
310 span->segment()->debugID(), span->debugID());
311#endif
caryclark08bc8482015-04-24 09:08:57 -0700312 span->bumpSpanAdds();
caryclark55888e42016-07-18 10:01:36 -0700313 if (allocated) {
314 *allocated = true;
315 }
caryclark54359292015-03-26 07:52:43 -0700316 return span->ptT();
317 }
caryclark8bc90e22016-07-25 06:05:08 -0700318 if (span == &fTail) {
319 return nullptr;
320 }
caryclark54359292015-03-26 07:52:43 -0700321 } while ((span = span->upCast()->next()));
322 SkASSERT(0);
halcanary96fcdcc2015-08-27 07:41:13 -0700323 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700324}
325
caryclark55888e42016-07-18 10:01:36 -0700326void SkOpSegment::calcAngles() {
caryclark54359292015-03-26 07:52:43 -0700327 bool activePrior = !fHead.isCanceled();
328 if (activePrior && !fHead.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700329 addStartSpan();
reed0dc4dd62015-03-24 13:55:33 -0700330 }
caryclark54359292015-03-26 07:52:43 -0700331 SkOpSpan* prior = &fHead;
332 SkOpSpanBase* spanBase = fHead.next();
333 while (spanBase != &fTail) {
334 if (activePrior) {
caryclark55888e42016-07-18 10:01:36 -0700335 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(
336 this->globalState()->allocator());
caryclark54359292015-03-26 07:52:43 -0700337 priorAngle->set(spanBase, prior);
338 spanBase->setFromAngle(priorAngle);
reed0dc4dd62015-03-24 13:55:33 -0700339 }
caryclark54359292015-03-26 07:52:43 -0700340 SkOpSpan* span = spanBase->upCast();
341 bool active = !span->isCanceled();
342 SkOpSpanBase* next = span->next();
343 if (active) {
caryclark55888e42016-07-18 10:01:36 -0700344 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(
345 this->globalState()->allocator());
caryclark54359292015-03-26 07:52:43 -0700346 angle->set(span, next);
347 span->setToAngle(angle);
reed0dc4dd62015-03-24 13:55:33 -0700348 }
reed0dc4dd62015-03-24 13:55:33 -0700349 activePrior = active;
caryclark54359292015-03-26 07:52:43 -0700350 prior = span;
351 spanBase = next;
reed0dc4dd62015-03-24 13:55:33 -0700352 }
caryclark54359292015-03-26 07:52:43 -0700353 if (activePrior && !fTail.simple()) {
caryclark55888e42016-07-18 10:01:36 -0700354 addEndSpan();
reed0dc4dd62015-03-24 13:55:33 -0700355 }
reed0dc4dd62015-03-24 13:55:33 -0700356}
357
caryclark55888e42016-07-18 10:01:36 -0700358// Please keep this in sync with debugClearAll()
359void SkOpSegment::clearAll() {
360 SkOpSpan* span = &fHead;
361 do {
362 this->clearOne(span);
363 } while ((span = span->next()->upCastable()));
364 this->globalState()->coincidence()->release(this);
365}
366
367// Please keep this in sync with debugClearOne()
368void SkOpSegment::clearOne(SkOpSpan* span) {
369 span->setWindValue(0);
370 span->setOppValue(0);
371 this->markDone(span);
372}
373
374// Quads and conics collapse if the end points are the same, because
375// the curve doesn't enclose an area.
caryclarkbca19f72015-05-13 08:23:48 -0700376bool SkOpSegment::collapsed() const {
caryclark55888e42016-07-18 10:01:36 -0700377 // FIXME: cubics can have also collapsed -- need to check if the
378 // control points are on a line with the end points
379 return fVerb < SkPath::kCubic_Verb && fHead.pt() == fTail.pt();
caryclarkbca19f72015-05-13 08:23:48 -0700380}
381
caryclark@google.com570863f2013-09-16 15:55:01 +0000382void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
383 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700384 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000385 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
386 int sumSuWinding;
387 bool binary = includeType >= SkOpAngle::kBinarySingle;
388 if (binary) {
389 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
390 if (baseSegment->operand()) {
391 SkTSwap<int>(sumMiWinding, sumSuWinding);
392 }
393 }
394 SkOpSegment* nextSegment = nextAngle->segment();
395 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700396 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000397 if (binary) {
398 int oppMaxWinding, oppSumWinding;
399 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
400 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
401 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000402 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000403 } else {
404 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
405 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000406 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000407 }
408 nextAngle->setLastMarked(last);
409}
410
caryclark624637c2015-05-11 07:21:27 -0700411void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
caryclark@google.com570863f2013-09-16 15:55:01 +0000412 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700413 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000414 int sumMiWinding = baseSegment->updateWinding(baseAngle);
415 int sumSuWinding;
416 bool binary = includeType >= SkOpAngle::kBinarySingle;
417 if (binary) {
418 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
419 if (baseSegment->operand()) {
420 SkTSwap<int>(sumMiWinding, sumSuWinding);
421 }
422 }
423 SkOpSegment* nextSegment = nextAngle->segment();
424 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700425 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000426 if (binary) {
427 int oppMaxWinding, oppSumWinding;
428 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
429 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
430 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000431 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000432 } else {
433 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
434 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000435 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000436 }
437 nextAngle->setLastMarked(last);
438}
439
caryclark54359292015-03-26 07:52:43 -0700440// at this point, the span is already ordered, or unorderable
441int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
442 SkOpAngle::IncludeType includeType) {
443 SkASSERT(includeType != SkOpAngle::kUnaryXor);
444 SkOpAngle* firstAngle = this->spanToAngle(end, start);
halcanary96fcdcc2015-08-27 07:41:13 -0700445 if (nullptr == firstAngle || nullptr == firstAngle->next()) {
caryclark54359292015-03-26 07:52:43 -0700446 return SK_NaN32;
447 }
448 // if all angles have a computed winding,
449 // or if no adjacent angles are orderable,
450 // or if adjacent orderable angles have no computed winding,
451 // there's nothing to do
452 // if two orderable angles are adjacent, and both are next to orderable angles,
453 // and one has winding computed, transfer to the other
halcanary96fcdcc2015-08-27 07:41:13 -0700454 SkOpAngle* baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700455 bool tryReverse = false;
456 // look for counterclockwise transfers
457 SkOpAngle* angle = firstAngle->previous();
458 SkOpAngle* next = angle->next();
459 firstAngle = next;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000460 do {
caryclark54359292015-03-26 07:52:43 -0700461 SkOpAngle* prior = angle;
462 angle = next;
463 next = angle->next();
464 SkASSERT(prior->next() == angle);
465 SkASSERT(angle->next() == next);
466 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700467 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700468 continue;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000469 }
caryclark54359292015-03-26 07:52:43 -0700470 int testWinding = angle->starter()->windSum();
471 if (SK_MinS32 != testWinding) {
472 baseAngle = angle;
473 tryReverse = true;
474 continue;
reed0dc4dd62015-03-24 13:55:33 -0700475 }
caryclark54359292015-03-26 07:52:43 -0700476 if (baseAngle) {
477 ComputeOneSum(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700478 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
caryclark54359292015-03-26 07:52:43 -0700479 }
480 } while (next != firstAngle);
481 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
482 firstAngle = baseAngle;
483 tryReverse = true;
484 }
485 if (tryReverse) {
halcanary96fcdcc2015-08-27 07:41:13 -0700486 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700487 SkOpAngle* prior = firstAngle;
488 do {
489 angle = prior;
490 prior = angle->previous();
491 SkASSERT(prior->next() == angle);
492 next = angle->next();
493 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700494 baseAngle = nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700495 continue;
496 }
caryclark54359292015-03-26 07:52:43 -0700497 int testWinding = angle->starter()->windSum();
498 if (SK_MinS32 != testWinding) {
499 baseAngle = angle;
500 continue;
reed0dc4dd62015-03-24 13:55:33 -0700501 }
caryclark54359292015-03-26 07:52:43 -0700502 if (baseAngle) {
503 ComputeOneSumReverse(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700504 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700505 }
caryclark54359292015-03-26 07:52:43 -0700506 } while (prior != firstAngle);
reed0dc4dd62015-03-24 13:55:33 -0700507 }
caryclark54359292015-03-26 07:52:43 -0700508 return start->starter(end)->windSum();
reed0dc4dd62015-03-24 13:55:33 -0700509}
510
caryclark55888e42016-07-18 10:01:36 -0700511bool SkOpSegment::contains(double newT) const {
512 const SkOpSpanBase* spanBase = &fHead;
513 do {
514 if (spanBase->ptT()->contains(this, newT)) {
515 return true;
516 }
517 if (spanBase == &fTail) {
518 break;
519 }
520 spanBase = spanBase->upCast()->next();
521 } while (true);
522 return false;
523}
524
mtklein18300a32016-03-16 13:53:35 -0700525void SkOpSegment::release(const SkOpSpan* span) {
caryclark54359292015-03-26 07:52:43 -0700526 if (span->done()) {
caryclark08bc8482015-04-24 09:08:57 -0700527 --fDoneCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000528 }
caryclark08bc8482015-04-24 09:08:57 -0700529 --fCount;
caryclark15976282016-07-21 05:48:43 -0700530 SkOPASSERT(fCount >= fDoneCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000531}
532
caryclark26ad22a2015-10-16 09:03:38 -0700533double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
caryclark54359292015-03-26 07:52:43 -0700534 SkDPoint testPt = this->dPtAtT(t);
535 SkDLine testPerp = {{ testPt, testPt }};
536 SkDVector slope = this->dSlopeAtT(t);
537 testPerp[1].fX += slope.fY;
538 testPerp[1].fY -= slope.fX;
539 SkIntersections i;
caryclark26ad22a2015-10-16 09:03:38 -0700540 const SkOpSegment* oppSegment = oppAngle->segment();
caryclark1049f122015-04-20 08:31:59 -0700541 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
caryclark54359292015-03-26 07:52:43 -0700542 double closestDistSq = SK_ScalarInfinity;
543 for (int index = 0; index < i.used(); ++index) {
544 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000545 continue;
546 }
caryclark54359292015-03-26 07:52:43 -0700547 double testDistSq = testPt.distanceSquared(i.pt(index));
548 if (closestDistSq > testDistSq) {
549 closestDistSq = testDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000550 }
551 }
caryclark54359292015-03-26 07:52:43 -0700552 return closestDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000553}
554
caryclark@google.com07393ca2013-04-08 11:47:37 +0000555/*
556 The M and S variable name parts stand for the operators.
557 Mi stands for Minuend (see wiki subtraction, analogous to difference)
558 Su stands for Subtrahend
559 The Opp variable name part designates that the value is for the Opposite operator.
560 Opposite values result from combining coincident spans.
561 */
caryclark54359292015-03-26 07:52:43 -0700562SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
563 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) {
564 SkOpSpanBase* start = *nextStart;
565 SkOpSpanBase* end = *nextEnd;
566 SkASSERT(start != end);
567 int step = start->step(end);
568 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
569 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000570 // mark the smaller of startIndex, endIndex done, and all adjacent
571 // spans with the same T value (but not 'other' spans)
572#if DEBUG_WINDING
573 SkDebugf("%s simple\n", __FUNCTION__);
574#endif
caryclark54359292015-03-26 07:52:43 -0700575 SkOpSpan* startSpan = start->starter(end);
576 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700577 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000578 }
caryclark54359292015-03-26 07:52:43 -0700579 markDone(startSpan);
580 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000581 return other;
582 }
caryclark54359292015-03-26 07:52:43 -0700583 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
584 SkASSERT(endNear == end); // is this ever not end?
585 SkASSERT(endNear);
586 SkASSERT(start != endNear);
587 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000588 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700589 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
caryclark@google.com570863f2013-09-16 15:55:01 +0000590 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000591 if (!sortable) {
592 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700593 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700594 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000595 }
caryclark54359292015-03-26 07:52:43 -0700596 SkOpAngle* angle = this->spanToAngle(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000597 if (angle->unorderable()) {
598 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700599 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700600 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000601 }
602#if DEBUG_SORT
603 SkDebugf("%s\n", __FUNCTION__);
604 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000605#endif
caryclark54359292015-03-26 07:52:43 -0700606 int sumMiWinding = updateWinding(end, start);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000607 if (sumMiWinding == SK_MinS32) {
608 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700609 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700610 return nullptr;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000611 }
caryclark54359292015-03-26 07:52:43 -0700612 int sumSuWinding = updateOppWinding(end, start);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000613 if (operand()) {
614 SkTSwap<int>(sumMiWinding, sumSuWinding);
615 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000616 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700617 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000618 bool foundDone = false;
619 // iterate through the angle, and compute everyone's winding
620 SkOpSegment* nextSegment;
621 int activeCount = 0;
622 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000623 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000624 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000625 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000626 if (activeAngle) {
627 ++activeCount;
628 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000629 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +0000630 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000631 }
632 }
633 if (nextSegment->done()) {
634 continue;
635 }
reed0dc4dd62015-03-24 13:55:33 -0700636 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700637 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700638 }
caryclark54359292015-03-26 07:52:43 -0700639 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000640 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000641 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000642 *chase->append() = last;
643#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700644 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
645 last->segment()->debugID(), last->debugID());
646 if (!last->final()) {
647 SkDebugf(" windSum=%d", last->upCast()->windSum());
648 }
649 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000650#endif
651 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000652 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700653 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000654 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700655 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000656 }
657 *nextStart = foundAngle->start();
658 *nextEnd = foundAngle->end();
659 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000660#if DEBUG_WINDING
661 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
662 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
663 #endif
664 return nextSegment;
665}
666
caryclark54359292015-03-26 07:52:43 -0700667SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
668 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
669 SkOpSpanBase* start = *nextStart;
670 SkOpSpanBase* end = *nextEnd;
671 SkASSERT(start != end);
672 int step = start->step(end);
673 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
674 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000675 // mark the smaller of startIndex, endIndex done, and all adjacent
676 // spans with the same T value (but not 'other' spans)
677#if DEBUG_WINDING
678 SkDebugf("%s simple\n", __FUNCTION__);
679#endif
caryclark54359292015-03-26 07:52:43 -0700680 SkOpSpan* startSpan = start->starter(end);
681 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700682 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000683 }
caryclark54359292015-03-26 07:52:43 -0700684 markDone(startSpan);
685 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000686 return other;
687 }
caryclark54359292015-03-26 07:52:43 -0700688 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
689 SkASSERT(endNear == end); // is this ever not end?
690 SkASSERT(endNear);
691 SkASSERT(start != endNear);
692 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000693 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700694 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000695 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000696 if (!sortable) {
697 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700698 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700699 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000700 }
caryclark54359292015-03-26 07:52:43 -0700701 SkOpAngle* angle = this->spanToAngle(end, start);
702 if (angle->unorderable()) {
703 *unsortable = true;
704 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700705 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700706 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000707#if DEBUG_SORT
708 SkDebugf("%s\n", __FUNCTION__);
709 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000710#endif
caryclark54359292015-03-26 07:52:43 -0700711 int sumWinding = updateWinding(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000712 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700713 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000714 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700715 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000716 SkOpSegment* nextSegment;
717 int activeCount = 0;
718 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000719 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000720 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000721 &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000722 if (activeAngle) {
723 ++activeCount;
724 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000725 foundAngle = nextAngle;
726 foundDone = nextSegment->done(nextAngle);
727 }
728 }
729 if (nextSegment->done()) {
730 continue;
731 }
reed0dc4dd62015-03-24 13:55:33 -0700732 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700733 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700734 }
caryclark54359292015-03-26 07:52:43 -0700735 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000736 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000737 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000738 *chase->append() = last;
739#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700740 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
741 last->segment()->debugID(), last->debugID());
742 if (!last->final()) {
743 SkDebugf(" windSum=%d", last->upCast()->windSum());
744 }
745 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000746#endif
747 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000748 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700749 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000750 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700751 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000752 }
753 *nextStart = foundAngle->start();
754 *nextEnd = foundAngle->end();
755 nextSegment = foundAngle->segment();
756#if DEBUG_WINDING
757 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
758 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
759 #endif
760 return nextSegment;
761}
762
caryclark54359292015-03-26 07:52:43 -0700763SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
764 bool* unsortable) {
765 SkOpSpanBase* start = *nextStart;
766 SkOpSpanBase* end = *nextEnd;
767 SkASSERT(start != end);
768 int step = start->step(end);
769 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
770 if (other) {
771 // mark the smaller of startIndex, endIndex done, and all adjacent
772 // spans with the same T value (but not 'other' spans)
caryclark@google.com07393ca2013-04-08 11:47:37 +0000773#if DEBUG_WINDING
774 SkDebugf("%s simple\n", __FUNCTION__);
775#endif
caryclark54359292015-03-26 07:52:43 -0700776 SkOpSpan* startSpan = start->starter(end);
777 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700778 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000779 }
caryclark54359292015-03-26 07:52:43 -0700780 markDone(startSpan);
781 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000782 return other;
783 }
caryclark54359292015-03-26 07:52:43 -0700784 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
785 : (*nextStart)->prev());
786 SkASSERT(endNear == end); // is this ever not end?
787 SkASSERT(endNear);
788 SkASSERT(start != endNear);
789 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
790 SkOpAngle* angle = this->spanToAngle(end, start);
caryclark27c8eb82015-07-06 11:38:33 -0700791 if (!angle || angle->unorderable()) {
caryclark54359292015-03-26 07:52:43 -0700792 *unsortable = true;
793 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700794 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700795 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000796#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000797 SkDebugf("%s\n", __FUNCTION__);
798 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000799#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000800 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700801 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000802 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700803 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000804 SkOpSegment* nextSegment;
805 int activeCount = 0;
806 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000807 nextSegment = nextAngle->segment();
808 ++activeCount;
809 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000810 foundAngle = nextAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000811 if (!(foundDone = nextSegment->done(nextAngle))) {
812 break;
813 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000814 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000815 nextAngle = nextAngle->next();
816 } while (nextAngle != angle);
caryclark54359292015-03-26 07:52:43 -0700817 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000818 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700819 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000820 }
821 *nextStart = foundAngle->start();
822 *nextEnd = foundAngle->end();
823 nextSegment = foundAngle->segment();
824#if DEBUG_WINDING
825 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
826 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
827 #endif
828 return nextSegment;
829}
830
caryclark54359292015-03-26 07:52:43 -0700831SkOpGlobalState* SkOpSegment::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700832 return contour()->globalState();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000833}
834
caryclark1049f122015-04-20 08:31:59 -0700835void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
caryclark54359292015-03-26 07:52:43 -0700836 fContour = contour;
halcanary96fcdcc2015-08-27 07:41:13 -0700837 fNext = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000838 fPts = pts;
caryclark1049f122015-04-20 08:31:59 -0700839 fWeight = weight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000840 fVerb = verb;
caryclark54359292015-03-26 07:52:43 -0700841 fCount = 0;
842 fDoneCount = 0;
843 fVisited = false;
844 SkOpSpan* zeroSpan = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700845 zeroSpan->init(this, nullptr, 0, fPts[0]);
caryclark54359292015-03-26 07:52:43 -0700846 SkOpSpanBase* oneSpan = &fTail;
847 zeroSpan->setNext(oneSpan);
848 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
caryclark1049f122015-04-20 08:31:59 -0700849 SkDEBUGCODE(fID = globalState()->nextSegmentID());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000850}
851
caryclark54359292015-03-26 07:52:43 -0700852bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
853 SkDPoint cPt = this->dPtAtT(t);
caryclark1049f122015-04-20 08:31:59 -0700854 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
caryclark54359292015-03-26 07:52:43 -0700855 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
856 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -0700857 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
caryclark54359292015-03-26 07:52:43 -0700858 int used = i.used();
859 for (int index = 0; index < used; ++index) {
860 if (cPt.roughlyEqual(i.pt(index))) {
reed0dc4dd62015-03-24 13:55:33 -0700861 return true;
862 }
caryclark54359292015-03-26 07:52:43 -0700863 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000864 return false;
865}
866
caryclark54359292015-03-26 07:52:43 -0700867bool SkOpSegment::isXor() const {
868 return fContour->isXor();
869}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000870
caryclark5b5ddd72015-05-18 05:12:56 -0700871void SkOpSegment::markAllDone() {
872 SkOpSpan* span = this->head();
873 do {
874 this->markDone(span);
875 } while ((span = span->next()->upCastable()));
876}
877
caryclark54359292015-03-26 07:52:43 -0700878SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) {
879 int step = start->step(end);
880 SkOpSpan* minSpan = start->starter(end);
881 markDone(minSpan);
halcanary96fcdcc2015-08-27 07:41:13 -0700882 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000883 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700884 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000885 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -0700886 SkASSERT(!last);
887 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000888 }
caryclark54359292015-03-26 07:52:43 -0700889 other->markDone(minSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000890 }
891 return last;
892}
893
caryclark54359292015-03-26 07:52:43 -0700894bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
895 SkOpSpanBase** lastPtr) {
896 SkOpSpan* spanStart = start->starter(end);
897 int step = start->step(end);
898 bool success = markWinding(spanStart, winding);
halcanary96fcdcc2015-08-27 07:41:13 -0700899 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000900 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700901 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
902 if (spanStart->windSum() != SK_MinS32) {
903 SkASSERT(spanStart->windSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700904 SkASSERT(!last);
905 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000906 }
caryclark54359292015-03-26 07:52:43 -0700907 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000908 }
caryclark65f55312014-11-13 06:58:52 -0800909 if (lastPtr) {
910 *lastPtr = last;
911 }
912 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000913}
914
caryclark54359292015-03-26 07:52:43 -0700915bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
916 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
917 SkOpSpan* spanStart = start->starter(end);
918 int step = start->step(end);
919 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700920 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000921 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700922 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
923 if (spanStart->windSum() != SK_MinS32) {
924 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700925 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700926 this->globalState()->setWindingFailed();
927 return false;
caryclarkdac1d172014-06-17 05:15:38 -0700928 }
caryclark54359292015-03-26 07:52:43 -0700929 } else {
930 SkASSERT(spanStart->windSum() == oppWinding);
931 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700932 }
933 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700934 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000935 }
caryclark54359292015-03-26 07:52:43 -0700936 if (this->operand() == other->operand()) {
937 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700938 } else {
caryclark54359292015-03-26 07:52:43 -0700939 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700940 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000941 }
caryclark65f55312014-11-13 06:58:52 -0800942 if (lastPtr) {
943 *lastPtr = last;
944 }
945 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000946}
947
caryclark54359292015-03-26 07:52:43 -0700948SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000949 SkASSERT(angle->segment() == this);
950 if (UseInnerWinding(maxWinding, sumWinding)) {
951 maxWinding = sumWinding;
952 }
caryclark54359292015-03-26 07:52:43 -0700953 SkOpSpanBase* last;
954 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000955#if DEBUG_WINDING
956 if (last) {
caryclark54359292015-03-26 07:52:43 -0700957 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
958 last->segment()->debugID(), last->debugID());
959 if (!last->final()) {
960 SkDebugf(" windSum=");
961 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
962 }
963 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000964 }
965#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000966 return last;
967}
968
caryclark54359292015-03-26 07:52:43 -0700969SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
970 int oppSumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000971 SkASSERT(angle->segment() == this);
972 if (UseInnerWinding(maxWinding, sumWinding)) {
973 maxWinding = sumWinding;
974 }
975 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
976 oppMaxWinding = oppSumWinding;
977 }
halcanary96fcdcc2015-08-27 07:41:13 -0700978 SkOpSpanBase* last = nullptr;
caryclark65f55312014-11-13 06:58:52 -0800979 // caller doesn't require that this marks anything
caryclark54359292015-03-26 07:52:43 -0700980 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +0000981#if DEBUG_WINDING
982 if (last) {
caryclark54359292015-03-26 07:52:43 -0700983 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
984 last->segment()->debugID(), last->debugID());
985 if (!last->final()) {
986 SkDebugf(" windSum=");
987 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
988 }
989 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +0000990 }
991#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000992 return last;
993}
994
caryclark54359292015-03-26 07:52:43 -0700995void SkOpSegment::markDone(SkOpSpan* span) {
996 SkASSERT(this == span->segment());
997 if (span->done()) {
998 return;
999 }
1000#if DEBUG_MARK_DONE
1001 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
1002#endif
1003 span->setDone(true);
1004 ++fDoneCount;
1005 debugValidate();
1006}
1007
1008bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
1009 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -07001010 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -07001011 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001012 return false;
1013 }
1014#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -07001015 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -07001016#endif
caryclark54359292015-03-26 07:52:43 -07001017 span->setWindSum(winding);
1018 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001019 return true;
1020}
1021
caryclark54359292015-03-26 07:52:43 -07001022bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
1023 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +00001024 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -07001025 if (span->done()) {
1026 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001027 }
caryclark54359292015-03-26 07:52:43 -07001028#if DEBUG_MARK_DONE
1029 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1030#endif
1031 span->setWindSum(winding);
1032 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001033 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001034 return true;
1035}
1036
caryclark54359292015-03-26 07:52:43 -07001037bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
caryclarkef4f32a2016-08-24 09:24:18 -07001038 const SkPoint& testPt) const {
caryclark55888e42016-07-18 10:01:36 -07001039 SkASSERT(this == base->segment());
1040 if (this == testParent) {
1041 if (precisely_equal(base->fT, testT)) {
1042 return true;
1043 }
caryclark54359292015-03-26 07:52:43 -07001044 }
1045 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1046 return false;
1047 }
caryclark55888e42016-07-18 10:01:36 -07001048 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001049}
1050
1051static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1052 if (last) {
1053 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001054 }
halcanary96fcdcc2015-08-27 07:41:13 -07001055 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001056}
1057
caryclark54359292015-03-26 07:52:43 -07001058SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1059 SkOpSpanBase** last) const {
1060 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001061 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001062 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1063 SkASSERT(endSpan);
1064 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1065 SkOpSpanBase* foundSpan;
1066 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001067 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001068 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001069 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001070 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001071 }
caryclark54359292015-03-26 07:52:43 -07001072 SkOpPtT* otherPtT = endSpan->ptT()->next();
1073 other = otherPtT->segment();
1074 foundSpan = otherPtT->span();
caryclark343382e2016-06-29 08:18:38 -07001075 otherEnd = step > 0
1076 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1077 : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001078 } else {
1079 int loopCount = angle->loopCount();
1080 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001081 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001082 }
1083 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001084 if (nullptr == next) {
1085 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001086 }
caryclarkdac1d172014-06-17 05:15:38 -07001087#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001088 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001089 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001090 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001091 }
caryclark54359292015-03-26 07:52:43 -07001092#endif
caryclarkdac1d172014-06-17 05:15:38 -07001093 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001094 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001095 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001096 }
caryclark343382e2016-06-29 08:18:38 -07001097 if (!otherEnd) {
1098 return nullptr;
1099 }
caryclark54359292015-03-26 07:52:43 -07001100 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001101 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001102 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001103 }
caryclark54359292015-03-26 07:52:43 -07001104 SkASSERT(*startPtr);
1105 if (!otherEnd) {
halcanary96fcdcc2015-08-27 07:41:13 -07001106 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001107 }
1108// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001109 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1110 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1111 if (foundMin->windValue() != origMin->windValue()
1112 || foundMin->oppValue() != origMin->oppValue()) {
1113 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001114 }
caryclark54359292015-03-26 07:52:43 -07001115 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001116 *stepPtr = foundStep;
1117 if (minPtr) {
1118 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001119 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001120 return other;
1121}
1122
caryclark55888e42016-07-18 10:01:36 -07001123// Please keep this in sync with DebugClearVisited()
1124void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001125 // reset visited flag back to false
1126 do {
1127 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1128 while ((ptT = ptT->next()) != stopPtT) {
1129 SkOpSegment* opp = ptT->segment();
1130 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001131 }
caryclarkbca19f72015-05-13 08:23:48 -07001132 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001133}
1134
caryclark55888e42016-07-18 10:01:36 -07001135// Please keep this in sync with debugMissingCoincidence()
caryclark54359292015-03-26 07:52:43 -07001136// look for pairs of undetected coincident curves
1137// assumes that segments going in have visited flag clear
caryclark55888e42016-07-18 10:01:36 -07001138// Even though pairs of curves correct detect coincident runs, a run may be missed
1139// if the coincidence is a product of multiple intersections. For instance, given
1140// curves A, B, and C:
1141// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1142// the end of C that the intersection is replaced with the end of C.
1143// Even though A-B correctly do not detect an intersection at point 2,
1144// the resulting run from point 1 to point 2 is coincident on A and B.
1145bool SkOpSegment::missingCoincidence() {
caryclarkbca19f72015-05-13 08:23:48 -07001146 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001147 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001148 }
halcanary96fcdcc2015-08-27 07:41:13 -07001149 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001150 SkOpSpanBase* spanBase = &fHead;
caryclark55888e42016-07-18 10:01:36 -07001151 bool result = false;
caryclark54359292015-03-26 07:52:43 -07001152 do {
caryclarkbca19f72015-05-13 08:23:48 -07001153 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
caryclarkc6d855f2016-08-11 11:59:48 -07001154 SkOPASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001155 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001156 if (ptT->deleted()) {
1157 continue;
1158 }
caryclark54359292015-03-26 07:52:43 -07001159 SkOpSegment* opp = ptT->span()->segment();
caryclarkbca19f72015-05-13 08:23:48 -07001160 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001161 continue;
reed0dc4dd62015-03-24 13:55:33 -07001162 }
caryclarkbca19f72015-05-13 08:23:48 -07001163 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1164 if (!opp->visited()) {
1165 continue;
1166 }
1167 if (spanBase == &fHead) {
1168 continue;
1169 }
caryclark55888e42016-07-18 10:01:36 -07001170 if (ptT->segment() == this) {
1171 continue;
1172 }
caryclarkbca19f72015-05-13 08:23:48 -07001173 SkOpSpan* span = spanBase->upCastable();
1174 // FIXME?: this assumes that if the opposite segment is coincident then no more
1175 // coincidence needs to be detected. This may not be true.
caryclark55888e42016-07-18 10:01:36 -07001176 if (span && span->containsCoincidence(opp)) {
caryclark26ad22a2015-10-16 09:03:38 -07001177 continue;
1178 }
caryclarkbca19f72015-05-13 08:23:48 -07001179 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001180 continue;
caryclark55888e42016-07-18 10:01:36 -07001181 }
halcanary96fcdcc2015-08-27 07:41:13 -07001182 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001183 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001184 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001185 SkOpSpan* priorTest = spanBase->prev();
1186 while (!priorOpp && priorTest) {
1187 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001188 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001189 if (priorPtT->deleted()) {
1190 continue;
1191 }
caryclark54359292015-03-26 07:52:43 -07001192 SkOpSegment* segment = priorPtT->span()->segment();
1193 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001194 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001195 priorOpp = opp;
1196 break;
1197 }
1198 }
caryclarkbca19f72015-05-13 08:23:48 -07001199 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001200 }
1201 if (!priorOpp) {
1202 continue;
1203 }
caryclark26ad22a2015-10-16 09:03:38 -07001204 if (priorPtT == ptT) {
1205 continue;
1206 }
caryclark54359292015-03-26 07:52:43 -07001207 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001208 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001209 bool swapped = priorPtT->fT > ptT->fT;
1210 if (swapped) {
1211 SkTSwap(priorPtT, ptT);
1212 SkTSwap(oppStart, oppEnd);
1213 }
caryclark55888e42016-07-18 10:01:36 -07001214 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1215 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1216 SkOpPtT* rootPtT = ptT->span()->ptT();
1217 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1218 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1219 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
caryclark54359292015-03-26 07:52:43 -07001220 goto swapBack;
1221 }
caryclark55888e42016-07-18 10:01:36 -07001222 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
caryclark54359292015-03-26 07:52:43 -07001223 // mark coincidence
caryclark55888e42016-07-18 10:01:36 -07001224#if DEBUG_COINCIDENCE_VERBOSE
1225 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1226 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1227 rootOppEnd->debugID());
1228#endif
1229 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1230 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
caryclarkbca19f72015-05-13 08:23:48 -07001231 }
caryclark55888e42016-07-18 10:01:36 -07001232#if DEBUG_COINCIDENCE
1233 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1234#endif
1235 result = true;
caryclark54359292015-03-26 07:52:43 -07001236 }
1237 swapBack:
1238 if (swapped) {
1239 SkTSwap(priorPtT, ptT);
1240 }
reed0dc4dd62015-03-24 13:55:33 -07001241 }
halcanary96fcdcc2015-08-27 07:41:13 -07001242 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark55888e42016-07-18 10:01:36 -07001243 ClearVisited(&fHead);
1244 return result;
reed0dc4dd62015-03-24 13:55:33 -07001245}
1246
caryclark55888e42016-07-18 10:01:36 -07001247// please keep this in sync with debugMoveMultiples()
caryclark08bc8482015-04-24 09:08:57 -07001248// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001249bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001250 debugValidate();
1251 SkOpSpanBase* test = &fHead;
1252 do {
1253 int addCount = test->spanAddsCount();
caryclark55888e42016-07-18 10:01:36 -07001254 FAIL_IF(addCount < 1);
caryclark08bc8482015-04-24 09:08:57 -07001255 if (addCount == 1) {
1256 continue;
1257 }
1258 SkOpPtT* startPtT = test->ptT();
1259 SkOpPtT* testPtT = startPtT;
1260 do { // iterate through all spans associated with start
1261 SkOpSpanBase* oppSpan = testPtT->span();
1262 if (oppSpan->spanAddsCount() == addCount) {
1263 continue;
1264 }
1265 if (oppSpan->deleted()) {
1266 continue;
1267 }
1268 SkOpSegment* oppSegment = oppSpan->segment();
1269 if (oppSegment == this) {
1270 continue;
1271 }
1272 // find range of spans to consider merging
1273 SkOpSpanBase* oppPrev = oppSpan;
1274 SkOpSpanBase* oppFirst = oppSpan;
1275 while ((oppPrev = oppPrev->prev())) {
1276 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1277 break;
1278 }
1279 if (oppPrev->spanAddsCount() == addCount) {
1280 continue;
1281 }
1282 if (oppPrev->deleted()) {
1283 continue;
1284 }
1285 oppFirst = oppPrev;
1286 }
1287 SkOpSpanBase* oppNext = oppSpan;
1288 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001289 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001290 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1291 break;
1292 }
1293 if (oppNext->spanAddsCount() == addCount) {
1294 continue;
1295 }
1296 if (oppNext->deleted()) {
1297 continue;
1298 }
1299 oppLast = oppNext;
1300 }
1301 if (oppFirst == oppLast) {
1302 continue;
1303 }
1304 SkOpSpanBase* oppTest = oppFirst;
1305 do {
1306 if (oppTest == oppSpan) {
1307 continue;
1308 }
1309 // check to see if the candidate meets specific criteria:
1310 // it contains spans of segments in test's loop but not including 'this'
1311 SkOpPtT* oppStartPtT = oppTest->ptT();
1312 SkOpPtT* oppPtT = oppStartPtT;
1313 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1314 SkOpSegment* oppPtTSegment = oppPtT->segment();
1315 if (oppPtTSegment == this) {
1316 goto tryNextSpan;
1317 }
1318 SkOpPtT* matchPtT = startPtT;
1319 do {
1320 if (matchPtT->segment() == oppPtTSegment) {
1321 goto foundMatch;
1322 }
1323 } while ((matchPtT = matchPtT->next()) != startPtT);
1324 goto tryNextSpan;
1325 foundMatch: // merge oppTest and oppSpan
1326 oppSegment->debugValidate();
1327 if (oppTest == &oppSegment->fTail || oppTest == &oppSegment->fHead) {
1328 SkASSERT(oppSpan != &oppSegment->fHead); // don't expect collapse
1329 SkASSERT(oppSpan != &oppSegment->fTail);
1330 oppTest->merge(oppSpan->upCast());
1331 } else {
1332 oppSpan->merge(oppTest->upCast());
1333 }
1334 oppSegment->debugValidate();
1335 goto checkNextSpan;
1336 }
caryclark55888e42016-07-18 10:01:36 -07001337 tryNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001338 ;
1339 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1340 } while ((testPtT = testPtT->next()) != startPtT);
caryclark55888e42016-07-18 10:01:36 -07001341checkNextSpan:
caryclark08bc8482015-04-24 09:08:57 -07001342 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001343 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001344 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001345 return true;
caryclark08bc8482015-04-24 09:08:57 -07001346}
1347
caryclark55888e42016-07-18 10:01:36 -07001348// adjacent spans may have points close by
1349bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan) const {
1350 const SkOpPtT* refHead = refSpan->ptT();
1351 const SkOpPtT* checkHead = checkSpan->ptT();
1352// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
1353 if (!SkDPoint::RoughlyEqual(refHead->fPt, checkHead->fPt)) {
1354#if DEBUG_COINCIDENCE
1355 // verify that no combination of points are close
1356 const SkOpPtT* dBugRef = refHead;
1357 do {
1358 const SkOpPtT* dBugCheck = checkHead;
1359 do {
1360 SkASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
1361 dBugCheck = dBugCheck->next();
1362 } while (dBugCheck != checkHead);
1363 dBugRef = dBugRef->next();
1364 } while (dBugRef != refHead);
1365#endif
1366 return false;
1367 }
1368 // check only unique points
1369 SkScalar distSqBest = SK_ScalarMax;
1370 const SkOpPtT* refBest = nullptr;
1371 const SkOpPtT* checkBest = nullptr;
1372 const SkOpPtT* ref = refHead;
1373 do {
1374 if (ref->deleted()) {
1375 continue;
1376 }
1377 while (ref->ptAlreadySeen(refHead)) {
1378 ref = ref->next();
1379 if (ref == refHead) {
1380 goto doneCheckingDistance;
1381 }
1382 }
1383 const SkOpPtT* check = checkHead;
1384 const SkOpSegment* refSeg = ref->segment();
1385 do {
1386 if (check->deleted()) {
1387 continue;
1388 }
1389 while (check->ptAlreadySeen(checkHead)) {
1390 check = check->next();
1391 if (check == checkHead) {
1392 goto nextRef;
1393 }
1394 }
1395 SkScalar distSq = ref->fPt.distanceToSqd(check->fPt);
1396 if (distSqBest > distSq && (refSeg != check->segment()
1397 || !refSeg->ptsDisjoint(*ref, *check))) {
1398 distSqBest = distSq;
1399 refBest = ref;
1400 checkBest = check;
1401 }
1402 } while ((check = check->next()) != checkHead);
1403nextRef:
1404 ;
1405 } while ((ref = ref->next()) != refHead);
1406doneCheckingDistance:
1407 return checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
caryclarkef4f32a2016-08-24 09:24:18 -07001408 checkBest->fPt);
caryclark55888e42016-07-18 10:01:36 -07001409}
1410
1411// Please keep this function in sync with debugMoveNearby()
caryclark54359292015-03-26 07:52:43 -07001412// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
caryclark08bc8482015-04-24 09:08:57 -07001413void SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001414 debugValidate();
caryclark55888e42016-07-18 10:01:36 -07001415 // release undeleted spans pointing to this seg that are linked to the primary span
1416 SkOpSpanBase* spanBase = &fHead;
caryclark54359292015-03-26 07:52:43 -07001417 do {
caryclark55888e42016-07-18 10:01:36 -07001418 SkOpPtT* ptT = spanBase->ptT();
1419 const SkOpPtT* headPtT = ptT;
1420 while ((ptT = ptT->next()) != headPtT) {
1421 SkOpSpanBase* test = ptT->span();
1422 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1423 && test->ptT() == ptT) {
1424 if (test->final()) {
1425 if (spanBase == &fHead) {
1426 this->clearAll();
1427 return;
1428 }
1429 spanBase->upCast()->release(ptT);
1430 } else if (test->prev()) {
1431 test->upCast()->release(headPtT);
1432 }
1433 break;
caryclark54359292015-03-26 07:52:43 -07001434 }
reed0dc4dd62015-03-24 13:55:33 -07001435 }
caryclark55888e42016-07-18 10:01:36 -07001436 spanBase = spanBase->upCast()->next();
1437 } while (!spanBase->final());
1438
1439 // This loop looks for adjacent spans which are near by
1440 spanBase = &fHead;
1441 do { // iterate through all spans associated with start
1442 SkOpSpanBase* test = spanBase->upCast()->next();
1443 if (this->spansNearby(spanBase, test)) {
1444 if (test->final()) {
1445 if (spanBase->prev()) {
1446 test->merge(spanBase->upCast());
1447 } else {
1448 this->clearAll();
1449 return;
1450 }
1451 } else {
1452 spanBase->merge(test->upCast());
1453 }
1454 }
1455 spanBase = test;
1456 } while (!spanBase->final());
caryclark54359292015-03-26 07:52:43 -07001457 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001458}
1459
caryclark54359292015-03-26 07:52:43 -07001460bool SkOpSegment::operand() const {
1461 return fContour->operand();
1462}
1463
1464bool SkOpSegment::oppXor() const {
1465 return fContour->oppXor();
1466}
1467
1468bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1469 if (fVerb == SkPath::kLine_Verb) {
1470 return false;
1471 }
1472 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1473 // hits in two places with very different t values.
1474 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1475 // 'controls contained by ends' could avoid this check for common curves
1476 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1477 // on the other hand, the below check is relatively inexpensive
1478 double midT = (t1 + t2) / 2;
1479 SkPoint midPt = this->ptAtT(midT);
1480 double seDistSq = SkTMax(pt1.distanceToSqd(pt2) * 2, FLT_EPSILON * 2);
1481 return midPt.distanceToSqd(pt1) > seDistSq || midPt.distanceToSqd(pt2) > seDistSq;
1482}
1483
1484void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1485 int* maxWinding, int* sumWinding) {
1486 int deltaSum = SpanSign(start, end);
1487 *maxWinding = *sumMiWinding;
1488 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001489 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001490}
1491
1492void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1493 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1494 int* oppSumWinding) {
1495 int deltaSum = SpanSign(start, end);
1496 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001497 if (operand()) {
1498 *maxWinding = *sumSuWinding;
1499 *sumWinding = *sumSuWinding -= deltaSum;
1500 *oppMaxWinding = *sumMiWinding;
1501 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1502 } else {
1503 *maxWinding = *sumMiWinding;
1504 *sumWinding = *sumMiWinding -= deltaSum;
1505 *oppMaxWinding = *sumSuWinding;
1506 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1507 }
bungeman60e0fee2015-08-26 05:15:46 -07001508 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1509 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001510}
1511
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001512void SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001513 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001514 do {
caryclark54359292015-03-26 07:52:43 -07001515 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001516 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001517 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001518 continue;
1519 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001520#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001521 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001522#endif
caryclark54359292015-03-26 07:52:43 -07001523 SkOpAngle* baseAngle = fromAngle;
1524 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001525#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001526 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1527 span->debugID());
1528 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001529#endif
caryclark54359292015-03-26 07:52:43 -07001530 fromAngle->insert(toAngle);
1531 } else if (!fromAngle) {
1532 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001533 }
caryclark54359292015-03-26 07:52:43 -07001534 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001535 do {
caryclark54359292015-03-26 07:52:43 -07001536 SkOpSpanBase* oSpan = ptT->span();
1537 if (oSpan == span) {
1538 continue;
1539 }
1540 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001541 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001542#if DEBUG_ANGLE
1543 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001544 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1545 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001546 wroteAfterHeader = true;
1547 }
1548#endif
caryclark54359292015-03-26 07:52:43 -07001549 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001550 baseAngle->insert(oAngle);
1551 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001552 }
caryclark54359292015-03-26 07:52:43 -07001553 if (!oSpan->final()) {
1554 oAngle = oSpan->upCast()->toAngle();
1555 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001556#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001557 if (!wroteAfterHeader) {
1558 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1559 span->t(), span->debugID());
1560 wroteAfterHeader = true;
1561 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001562#endif
caryclark54359292015-03-26 07:52:43 -07001563 if (!oAngle->loopContains(baseAngle)) {
1564 baseAngle->insert(oAngle);
1565 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001566 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001567 }
caryclark54359292015-03-26 07:52:43 -07001568 } while ((ptT = ptT->next()) != stopPtT);
1569 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001570 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001571 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001572 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001573 }
halcanary96fcdcc2015-08-27 07:41:13 -07001574 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001575 }
1576#if DEBUG_SORT
1577 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1578#endif
caryclark54359292015-03-26 07:52:43 -07001579 } while (!span->final() && (span = span->upCast()->next()));
caryclark@google.com570863f2013-09-16 15:55:01 +00001580}
1581
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001582// return true if midpoints were computed
caryclark54359292015-03-26 07:52:43 -07001583bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001584 SkOpCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001585 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001586 const SkOpPtT& startPtT = *start->ptT();
1587 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001588 SkDEBUGCODE(edge->fVerb = fVerb);
1589 edge->fPts[0] = startPtT.fPt;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001590 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001591 edge->fPts[points] = endPtT.fPt;
1592 edge->fWeight = 1;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001593 if (fVerb == SkPath::kLine_Verb) {
1594 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001595 }
caryclark54359292015-03-26 07:52:43 -07001596 double startT = startPtT.fT;
1597 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001598 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1599 // don't compute midpoints if we already have them
1600 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001601 edge->fPts[1] = fPts[1];
1602 return false;
1603 }
1604 if (fVerb == SkPath::kConic_Verb) {
1605 edge->fPts[1] = fPts[1];
1606 edge->fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001607 return false;
1608 }
1609 SkASSERT(fVerb == SkPath::kCubic_Verb);
1610 if (start < end) {
caryclark1049f122015-04-20 08:31:59 -07001611 edge->fPts[1] = fPts[1];
1612 edge->fPts[2] = fPts[2];
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001613 return false;
1614 }
caryclark1049f122015-04-20 08:31:59 -07001615 edge->fPts[1] = fPts[2];
1616 edge->fPts[2] = fPts[1];
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001617 return false;
1618 }
caryclark1049f122015-04-20 08:31:59 -07001619 const SkDPoint sub[2] = {{ edge->fPts[0].fX, edge->fPts[0].fY},
1620 {edge->fPts[points].fX, edge->fPts[points].fY }};
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001621 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001622 edge->fPts[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
1623 } else if (fVerb == SkPath::kConic_Verb) {
1624 edge->fPts[1] = SkDConic::SubDivide(fPts, fWeight, sub[0], sub[1],
1625 startT, endT, &edge->fWeight).asSkPoint();
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001626 } else {
1627 SkASSERT(fVerb == SkPath::kCubic_Verb);
1628 SkDPoint ctrl[2];
1629 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
caryclark1049f122015-04-20 08:31:59 -07001630 edge->fPts[1] = ctrl[0].asSkPoint();
1631 edge->fPts[2] = ctrl[1].asSkPoint();
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001632 }
1633 return true;
1634}
1635
caryclark54359292015-03-26 07:52:43 -07001636bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001637 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001638 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001639 const SkOpPtT& startPtT = *start->ptT();
1640 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001641 SkDEBUGCODE(edge->fVerb = fVerb);
1642 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001643 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001644 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001645 if (fVerb == SkPath::kLine_Verb) {
1646 return false;
1647 }
caryclark54359292015-03-26 07:52:43 -07001648 double startT = startPtT.fT;
1649 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001650 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1651 // don't compute midpoints if we already have them
1652 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001653 edge->fLine[1].set(fPts[1]);
1654 return false;
1655 }
1656 if (fVerb == SkPath::kConic_Verb) {
1657 edge->fConic[1].set(fPts[1]);
1658 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001659 return false;
1660 }
1661 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001662 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001663 edge->fCubic[1].set(fPts[1]);
1664 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001665 return false;
1666 }
caryclark1049f122015-04-20 08:31:59 -07001667 edge->fCubic[1].set(fPts[2]);
1668 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001669 return false;
1670 }
1671 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001672 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1673 } else if (fVerb == SkPath::kConic_Verb) {
1674 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1675 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001676 } else {
1677 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001678 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001679 }
1680 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001681}
1682
caryclark27c8eb82015-07-06 11:38:33 -07001683bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
caryclark55888e42016-07-18 10:01:36 -07001684 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
caryclark27c8eb82015-07-06 11:38:33 -07001685 // average t, find mid pt
1686 double midT = (prior->t() + spanBase->t()) / 2;
1687 SkPoint midPt = this->ptAtT(midT);
1688 bool coincident = true;
1689 // if the mid pt is not near either end pt, project perpendicular through opp seg
1690 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1691 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001692 if (priorPtT->span() == ptT->span()) {
1693 return false;
1694 }
caryclark27c8eb82015-07-06 11:38:33 -07001695 coincident = false;
1696 SkIntersections i;
caryclark55888e42016-07-18 10:01:36 -07001697 SkDCurve curvePart;
1698 this->subDivide(prior, spanBase, &curvePart);
1699 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1700 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1701 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1702 SkDCurve oppPart;
1703 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1704 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
caryclark27c8eb82015-07-06 11:38:33 -07001705 // measure distance and see if it's small enough to denote coincidence
1706 for (int index = 0; index < i.used(); ++index) {
caryclark55888e42016-07-18 10:01:36 -07001707 if (!between(0, i[0][index], 1)) {
1708 continue;
1709 }
caryclark27c8eb82015-07-06 11:38:33 -07001710 SkDPoint oppPt = i.pt(index);
1711 if (oppPt.approximatelyEqual(midPt)) {
caryclark55888e42016-07-18 10:01:36 -07001712 // the coincidence can occur at almost any angle
1713 coincident = true;
caryclark27c8eb82015-07-06 11:38:33 -07001714 }
1715 }
1716 }
1717 return coincident;
1718}
1719
caryclark54359292015-03-26 07:52:43 -07001720void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
1721 SkOpSpan* span = this->head();
1722 do {
1723 if (!span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001724 break;
1725 }
caryclark54359292015-03-26 07:52:43 -07001726 } while ((span = span->next()->upCastable()));
1727 SkASSERT(span);
1728 *start = span;
1729 *end = span->next();
reed0dc4dd62015-03-24 13:55:33 -07001730}
1731
caryclark54359292015-03-26 07:52:43 -07001732int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1733 const SkOpSpan* lesser = start->starter(end);
1734 int oppWinding = lesser->oppSum();
1735 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001736 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1737 && oppWinding != SK_MaxS32) {
1738 oppWinding -= oppSpanWinding;
1739 }
1740 return oppWinding;
1741}
1742
1743int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001744 const SkOpSpanBase* startSpan = angle->start();
1745 const SkOpSpanBase* endSpan = angle->end();
1746 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001747}
1748
1749int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001750 const SkOpSpanBase* startSpan = angle->start();
1751 const SkOpSpanBase* endSpan = angle->end();
1752 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001753}
1754
caryclark624637c2015-05-11 07:21:27 -07001755int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1756 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001757 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001758 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001759 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001760 }
1761 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001762 return winding;
1763 }
caryclark54359292015-03-26 07:52:43 -07001764 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001765 if (winding && UseInnerWinding(winding - spanWinding, winding)
1766 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001767 winding -= spanWinding;
1768 }
1769 return winding;
1770}
1771
caryclark624637c2015-05-11 07:21:27 -07001772int SkOpSegment::updateWinding(SkOpAngle* angle) {
1773 SkOpSpanBase* startSpan = angle->start();
1774 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001775 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001776}
1777
caryclark624637c2015-05-11 07:21:27 -07001778int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1779 SkOpSpanBase* startSpan = angle->start();
1780 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001781 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001782}
1783
1784// OPTIMIZATION: does the following also work, and is it any faster?
1785// return outerWinding * innerWinding > 0
1786// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1787bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1788 SkASSERT(outerWinding != SK_MaxS32);
1789 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001790 int absOut = SkTAbs(outerWinding);
1791 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001792 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1793 return result;
1794}
1795
caryclark@google.com07393ca2013-04-08 11:47:37 +00001796int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001797 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1798 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001799}