blob: 2ba7d79b30976110ea585658d83f90b7f80009e0 [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
caryclark54359292015-03-26 07:52:43 -07007#include "SkOpCoincidence.h"
caryclarkdac1d172014-06-17 05:15:38 -07008#include "SkOpContour.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +00009#include "SkOpSegment.h"
10#include "SkPathWriter.h"
caryclark54359292015-03-26 07:52:43 -070011
12/*
13After computing raw intersections, post process all segments to:
14- find small collections of points that can be collapsed to a single point
15- find missing intersections to resolve differences caused by different algorithms
16
17Consider segments containing tiny or small intervals. Consider coincident segments
18because coincidence finds intersections through distance measurement that non-coincident
19intersection tests cannot.
20 */
caryclark@google.com07393ca2013-04-08 11:47:37 +000021
22#define F (false) // discard the edge
23#define T (true) // keep the edge
24
25static const bool gUnaryActiveEdge[2][2] = {
26// from=0 from=1
27// to=0,1 to=0,1
28 {F, T}, {T, F},
29};
30
caryclark54359292015-03-26 07:52:43 -070031static const bool gActiveEdge[kXOR_SkPathOp + 1][2][2][2][2] = {
caryclark@google.com07393ca2013-04-08 11:47:37 +000032// miFrom=0 miFrom=1
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000033// miTo=0 miTo=1 miTo=0 miTo=1
34// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
caryclark@google.com07393ca2013-04-08 11:47:37 +000035// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
36 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
37 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
38 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
39 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su
40};
41
42#undef F
43#undef T
44
caryclark54359292015-03-26 07:52:43 -070045SkOpAngle* SkOpSegment::activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -070046 SkOpSpanBase** endPtr, bool* done) {
47 if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done)) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000048 return result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000049 }
caryclarkbca19f72015-05-13 08:23:48 -070050 if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done)) {
caryclark54359292015-03-26 07:52:43 -070051 return result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000052 }
halcanary96fcdcc2015-08-27 07:41:13 -070053 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +000054}
55
caryclark54359292015-03-26 07:52:43 -070056SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -070057 SkOpSpanBase** endPtr, bool* done) {
caryclark54359292015-03-26 07:52:43 -070058 SkOpSpan* upSpan = start->upCastable();
59 if (upSpan) {
60 if (upSpan->windValue() || upSpan->oppValue()) {
61 SkOpSpanBase* next = upSpan->next();
62 if (!*endPtr) {
63 *startPtr = start;
64 *endPtr = next;
caryclark@google.com07393ca2013-04-08 11:47:37 +000065 }
caryclark54359292015-03-26 07:52:43 -070066 if (!upSpan->done()) {
67 if (upSpan->windSum() != SK_MinS32) {
68 return spanToAngle(start, next);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000069 }
70 *done = false;
71 }
72 } else {
caryclark54359292015-03-26 07:52:43 -070073 SkASSERT(upSpan->done());
caryclark@google.com07393ca2013-04-08 11:47:37 +000074 }
75 }
caryclark54359292015-03-26 07:52:43 -070076 SkOpSpan* downSpan = start->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +000077 // edge leading into junction
caryclark54359292015-03-26 07:52:43 -070078 if (downSpan) {
79 if (downSpan->windValue() || downSpan->oppValue()) {
80 if (!*endPtr) {
81 *startPtr = start;
82 *endPtr = downSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +000083 }
caryclark54359292015-03-26 07:52:43 -070084 if (!downSpan->done()) {
85 if (downSpan->windSum() != SK_MinS32) {
86 return spanToAngle(start, downSpan);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000087 }
88 *done = false;
89 }
90 } else {
caryclark54359292015-03-26 07:52:43 -070091 SkASSERT(downSpan->done());
caryclark@google.com07393ca2013-04-08 11:47:37 +000092 }
93 }
halcanary96fcdcc2015-08-27 07:41:13 -070094 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000095}
96
caryclark54359292015-03-26 07:52:43 -070097SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** startPtr,
caryclarkbca19f72015-05-13 08:23:48 -070098 SkOpSpanBase** endPtr, bool* done) {
caryclark54359292015-03-26 07:52:43 -070099 SkOpPtT* oPtT = start->ptT()->next();
100 SkOpSegment* other = oPtT->segment();
101 SkOpSpanBase* oSpan = oPtT->span();
caryclarkbca19f72015-05-13 08:23:48 -0700102 return other->activeAngleInner(oSpan, startPtr, endPtr, done);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000103}
104
caryclark54359292015-03-26 07:52:43 -0700105bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xorSuMask,
106 SkPathOp op) {
107 int sumMiWinding = this->updateWinding(end, start);
108 int sumSuWinding = this->updateOppWinding(end, start);
caryclark65f55312014-11-13 06:58:52 -0800109#if DEBUG_LIMIT_WIND_SUM
110 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM);
111 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM);
112#endif
caryclark54359292015-03-26 07:52:43 -0700113 if (this->operand()) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000114 SkTSwap<int>(sumMiWinding, sumSuWinding);
115 }
caryclark54359292015-03-26 07:52:43 -0700116 return this->activeOp(xorMiMask, xorSuMask, start, end, op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000117}
118
caryclark54359292015-03-26 07:52:43 -0700119bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end,
120 SkPathOp op, int* sumMiWinding, int* sumSuWinding) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000121 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
caryclark54359292015-03-26 07:52:43 -0700122 this->setUpWindings(start, end, sumMiWinding, sumSuWinding,
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000123 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000124 bool miFrom;
125 bool miTo;
126 bool suFrom;
127 bool suTo;
128 if (operand()) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000129 miFrom = (oppMaxWinding & xorMiMask) != 0;
130 miTo = (oppSumWinding & xorMiMask) != 0;
131 suFrom = (maxWinding & xorSuMask) != 0;
132 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000133 } else {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000134 miFrom = (maxWinding & xorMiMask) != 0;
135 miTo = (sumWinding & xorMiMask) != 0;
136 suFrom = (oppMaxWinding & xorSuMask) != 0;
137 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000138 }
139 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
140#if DEBUG_ACTIVE_OP
caryclarkdac1d172014-06-17 05:15:38 -0700141 SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n",
caryclark54359292015-03-26 07:52:43 -0700142 __FUNCTION__, debugID(), start->t(), end->t(),
caryclark@google.com570863f2013-09-16 15:55:01 +0000143 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000144#endif
145 return result;
146}
147
caryclark54359292015-03-26 07:52:43 -0700148bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
149 int sumWinding = updateWinding(end, start);
150 return activeWinding(start, end, &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000151}
152
caryclark54359292015-03-26 07:52:43 -0700153bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000154 int maxWinding;
caryclark54359292015-03-26 07:52:43 -0700155 setUpWinding(start, end, &maxWinding, sumWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000156 bool from = maxWinding != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000157 bool to = *sumWinding != 0;
158 bool result = gUnaryActiveEdge[from][to];
159 return result;
160}
161
caryclark27c8eb82015-07-06 11:38:33 -0700162void SkOpSegment::addAlignIntersection(SkOpPtT& endPtT, SkPoint& oldPt,
163 SkOpContourHead* contourList, SkChunkAlloc* allocator) {
164 const SkPoint& newPt = endPtT.fPt;
165 if (newPt == oldPt) {
166 return;
167 }
168 SkPoint line[2] = { newPt, oldPt };
169 SkPathOpsBounds lineBounds;
170 lineBounds.setBounds(line, 2);
171 SkDLine aLine;
172 aLine.set(line);
173 SkOpContour* current = contourList;
174 do {
175 if (!SkPathOpsBounds::Intersects(current->bounds(), lineBounds)) {
176 continue;
177 }
178 SkOpSegment* segment = current->first();
179 do {
180 if (!SkPathOpsBounds::Intersects(segment->bounds(), lineBounds)) {
181 continue;
182 }
183 if (newPt == segment->fPts[0]) {
184 continue;
185 }
186 if (newPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) {
187 continue;
188 }
189 if (oldPt == segment->fPts[0]) {
190 continue;
191 }
192 if (oldPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) {
193 continue;
194 }
195 if (endPtT.contains(segment)) {
196 continue;
197 }
198 SkIntersections i;
199 switch (segment->fVerb) {
200 case SkPath::kLine_Verb: {
201 SkDLine bLine;
202 bLine.set(segment->fPts);
203 i.intersect(bLine, aLine);
204 } break;
205 case SkPath::kQuad_Verb: {
206 SkDQuad bQuad;
207 bQuad.set(segment->fPts);
208 i.intersect(bQuad, aLine);
209 } break;
210 case SkPath::kConic_Verb: {
211 SkDConic bConic;
212 bConic.set(segment->fPts, segment->fWeight);
213 i.intersect(bConic, aLine);
214 } break;
215 case SkPath::kCubic_Verb: {
216 SkDCubic bCubic;
217 bCubic.set(segment->fPts);
218 i.intersect(bCubic, aLine);
219 } break;
220 default:
221 SkASSERT(0);
222 }
223 if (i.used()) {
224 SkASSERT(i.used() == 1);
225 SkASSERT(!zero_or_one(i[0][0]));
226 SkOpSpanBase* checkSpan = fHead.next();
227 while (!checkSpan->final()) {
228 if (checkSpan->contains(segment)) {
229 goto nextSegment;
230 }
231 checkSpan = checkSpan->upCast()->next();
232 }
233 SkOpPtT* ptT = segment->addT(i[0][0], SkOpSegment::kAllowAlias, allocator);
234 ptT->fPt = newPt;
235 endPtT.addOpp(ptT);
236 }
237 nextSegment:
238 ;
239 } while ((segment = segment->next()));
240 } while ((current = current->next()));
241}
242
caryclarkef784fb2015-10-30 12:03:06 -0700243bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
244 SkPathWriter* path) const {
245 if (start->starter(end)->alreadyAdded()) {
246 return false;
247 }
caryclark1049f122015-04-20 08:31:59 -0700248 SkOpCurve edge;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000249 const SkPoint* ePtr;
caryclark1049f122015-04-20 08:31:59 -0700250 SkScalar eWeight;
caryclark54359292015-03-26 07:52:43 -0700251 if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000252 ePtr = fPts;
caryclark1049f122015-04-20 08:31:59 -0700253 eWeight = fWeight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000254 } else {
255 // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
caryclark1049f122015-04-20 08:31:59 -0700256 subDivide(start, end, &edge);
257 ePtr = edge.fPts;
258 eWeight = edge.fWeight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000259 }
caryclarkef784fb2015-10-30 12:03:06 -0700260 bool reverse = ePtr == fPts && start != &fHead;
261 if (reverse) {
262 path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]);
263 switch (fVerb) {
264 case SkPath::kLine_Verb:
265 path->deferredLine(ePtr[0]);
266 break;
267 case SkPath::kQuad_Verb:
268 path->quadTo(ePtr[1], ePtr[0]);
269 break;
270 case SkPath::kConic_Verb:
271 path->conicTo(ePtr[1], ePtr[0], eWeight);
272 break;
273 case SkPath::kCubic_Verb:
274 path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
275 break;
276 default:
277 SkASSERT(0);
278 }
279 } else {
280 path->deferredMoveLine(ePtr[0]);
281 switch (fVerb) {
282 case SkPath::kLine_Verb:
283 path->deferredLine(ePtr[1]);
284 break;
285 case SkPath::kQuad_Verb:
286 path->quadTo(ePtr[1], ePtr[2]);
287 break;
288 case SkPath::kConic_Verb:
289 path->conicTo(ePtr[1], ePtr[2], eWeight);
290 break;
291 case SkPath::kCubic_Verb:
292 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
293 break;
294 default:
295 SkASSERT(0);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000296 }
297 }
caryclarkef784fb2015-10-30 12:03:06 -0700298 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000299}
300
caryclark54359292015-03-26 07:52:43 -0700301SkOpPtT* SkOpSegment::addMissing(double t, SkOpSegment* opp, SkChunkAlloc* allocator) {
halcanary96fcdcc2015-08-27 07:41:13 -0700302 SkOpSpanBase* existing = nullptr;
caryclark54359292015-03-26 07:52:43 -0700303 SkOpSpanBase* test = &fHead;
304 double testT;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000305 do {
caryclark54359292015-03-26 07:52:43 -0700306 if ((testT = test->ptT()->fT) >= t) {
307 if (testT == t) {
308 existing = test;
309 }
reed0dc4dd62015-03-24 13:55:33 -0700310 break;
311 }
caryclark54359292015-03-26 07:52:43 -0700312 } while ((test = test->upCast()->next()));
313 SkOpPtT* result;
314 if (existing && existing->contains(opp)) {
315 result = existing->ptT();
316 } else {
317 result = this->addT(t, SkOpSegment::kNoAlias, allocator);
318 }
319 SkASSERT(result);
320 return result;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000321}
322
caryclark54359292015-03-26 07:52:43 -0700323SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* allocator) {
reed0dc4dd62015-03-24 13:55:33 -0700324 debugValidate();
caryclark54359292015-03-26 07:52:43 -0700325 SkPoint pt = this->ptAtT(t);
326 SkOpSpanBase* span = &fHead;
327 do {
328 SkOpPtT* result = span->ptT();
caryclark08bc8482015-04-24 09:08:57 -0700329 SkOpPtT* loop;
330 bool duplicatePt;
caryclark54359292015-03-26 07:52:43 -0700331 if (t == result->fT) {
caryclark08bc8482015-04-24 09:08:57 -0700332 goto bumpSpan;
reed0dc4dd62015-03-24 13:55:33 -0700333 }
caryclark54359292015-03-26 07:52:43 -0700334 if (this->match(result, this, t, pt)) {
335 // see if any existing alias matches segment, pt, and t
caryclark08bc8482015-04-24 09:08:57 -0700336 loop = result->next();
337 duplicatePt = false;
caryclark54359292015-03-26 07:52:43 -0700338 while (loop != result) {
339 bool ptMatch = loop->fPt == pt;
340 if (loop->segment() == this && loop->fT == t && ptMatch) {
caryclark08bc8482015-04-24 09:08:57 -0700341 goto bumpSpan;
reed0dc4dd62015-03-24 13:55:33 -0700342 }
caryclark54359292015-03-26 07:52:43 -0700343 duplicatePt |= ptMatch;
344 loop = loop->next();
reed0dc4dd62015-03-24 13:55:33 -0700345 }
caryclark54359292015-03-26 07:52:43 -0700346 if (kNoAlias == allowAlias) {
caryclark08bc8482015-04-24 09:08:57 -0700347 bumpSpan:
348 span->bumpSpanAdds();
caryclark54359292015-03-26 07:52:43 -0700349 return result;
350 }
351 SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(allocator);
352 alias->init(result->span(), t, pt, duplicatePt);
353 result->insert(alias);
354 result->span()->unaligned();
355 this->debugValidate();
356#if DEBUG_ADD_T
357 SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
358 alias->segment()->debugID(), alias->span()->debugID());
359#endif
caryclark08bc8482015-04-24 09:08:57 -0700360 span->bumpSpanAdds();
caryclark54359292015-03-26 07:52:43 -0700361 return alias;
reed0dc4dd62015-03-24 13:55:33 -0700362 }
caryclark54359292015-03-26 07:52:43 -0700363 if (t < result->fT) {
364 SkOpSpan* prev = result->span()->prev();
caryclarka3375e42015-12-07 12:18:02 -0800365 if (!prev) {
366 return nullptr;
367 }
caryclark54359292015-03-26 07:52:43 -0700368 SkOpSpan* span = insert(prev, allocator);
369 span->init(this, prev, t, pt);
370 this->debugValidate();
371#if DEBUG_ADD_T
372 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
373 span->segment()->debugID(), span->debugID());
374#endif
caryclark08bc8482015-04-24 09:08:57 -0700375 span->bumpSpanAdds();
caryclark54359292015-03-26 07:52:43 -0700376 return span->ptT();
377 }
378 SkASSERT(span != &fTail);
379 } while ((span = span->upCast()->next()));
380 SkASSERT(0);
halcanary96fcdcc2015-08-27 07:41:13 -0700381 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700382}
383
384// choose a solitary t and pt value; remove aliases; align the opposite ends
385void SkOpSegment::align() {
386 debugValidate();
387 SkOpSpanBase* span = &fHead;
388 if (!span->aligned()) {
389 span->alignEnd(0, fPts[0]);
390 }
391 while ((span = span->upCast()->next())) {
392 if (span == &fTail) {
393 break;
394 }
395 span->align();
396 }
397 if (!span->aligned()) {
398 span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]);
reed0dc4dd62015-03-24 13:55:33 -0700399 }
caryclarkbca19f72015-05-13 08:23:48 -0700400 if (this->collapsed()) {
401 SkOpSpan* span = &fHead;
402 do {
403 span->setWindValue(0);
404 span->setOppValue(0);
405 this->markDone(span);
406 } while ((span = span->next()->upCastable()));
407 }
reed0dc4dd62015-03-24 13:55:33 -0700408 debugValidate();
409}
410
caryclark54359292015-03-26 07:52:43 -0700411void SkOpSegment::calcAngles(SkChunkAlloc* allocator) {
412 bool activePrior = !fHead.isCanceled();
413 if (activePrior && !fHead.simple()) {
414 addStartSpan(allocator);
reed0dc4dd62015-03-24 13:55:33 -0700415 }
caryclark54359292015-03-26 07:52:43 -0700416 SkOpSpan* prior = &fHead;
417 SkOpSpanBase* spanBase = fHead.next();
418 while (spanBase != &fTail) {
419 if (activePrior) {
420 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
421 priorAngle->set(spanBase, prior);
422 spanBase->setFromAngle(priorAngle);
reed0dc4dd62015-03-24 13:55:33 -0700423 }
caryclark54359292015-03-26 07:52:43 -0700424 SkOpSpan* span = spanBase->upCast();
425 bool active = !span->isCanceled();
426 SkOpSpanBase* next = span->next();
427 if (active) {
428 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
429 angle->set(span, next);
430 span->setToAngle(angle);
reed0dc4dd62015-03-24 13:55:33 -0700431 }
reed0dc4dd62015-03-24 13:55:33 -0700432 activePrior = active;
caryclark54359292015-03-26 07:52:43 -0700433 prior = span;
434 spanBase = next;
reed0dc4dd62015-03-24 13:55:33 -0700435 }
caryclark54359292015-03-26 07:52:43 -0700436 if (activePrior && !fTail.simple()) {
437 addEndSpan(allocator);
reed0dc4dd62015-03-24 13:55:33 -0700438 }
reed0dc4dd62015-03-24 13:55:33 -0700439}
440
caryclarkbca19f72015-05-13 08:23:48 -0700441bool SkOpSegment::collapsed() const {
442 return fVerb == SkPath::kLine_Verb && fHead.pt() == fTail.pt();
443}
444
caryclark@google.com570863f2013-09-16 15:55:01 +0000445void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
446 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700447 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000448 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
449 int sumSuWinding;
450 bool binary = includeType >= SkOpAngle::kBinarySingle;
451 if (binary) {
452 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
453 if (baseSegment->operand()) {
454 SkTSwap<int>(sumMiWinding, sumSuWinding);
455 }
456 }
457 SkOpSegment* nextSegment = nextAngle->segment();
458 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700459 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000460 if (binary) {
461 int oppMaxWinding, oppSumWinding;
462 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
463 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
464 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000465 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000466 } else {
467 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
468 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000469 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000470 }
471 nextAngle->setLastMarked(last);
472}
473
caryclark624637c2015-05-11 07:21:27 -0700474void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
caryclark@google.com570863f2013-09-16 15:55:01 +0000475 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700476 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000477 int sumMiWinding = baseSegment->updateWinding(baseAngle);
478 int sumSuWinding;
479 bool binary = includeType >= SkOpAngle::kBinarySingle;
480 if (binary) {
481 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
482 if (baseSegment->operand()) {
483 SkTSwap<int>(sumMiWinding, sumSuWinding);
484 }
485 }
486 SkOpSegment* nextSegment = nextAngle->segment();
487 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700488 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000489 if (binary) {
490 int oppMaxWinding, oppSumWinding;
491 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
492 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
493 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000494 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000495 } else {
496 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
497 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000498 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000499 }
500 nextAngle->setLastMarked(last);
501}
502
caryclark54359292015-03-26 07:52:43 -0700503// at this point, the span is already ordered, or unorderable
504int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
505 SkOpAngle::IncludeType includeType) {
506 SkASSERT(includeType != SkOpAngle::kUnaryXor);
507 SkOpAngle* firstAngle = this->spanToAngle(end, start);
halcanary96fcdcc2015-08-27 07:41:13 -0700508 if (nullptr == firstAngle || nullptr == firstAngle->next()) {
caryclark54359292015-03-26 07:52:43 -0700509 return SK_NaN32;
510 }
511 // if all angles have a computed winding,
512 // or if no adjacent angles are orderable,
513 // or if adjacent orderable angles have no computed winding,
514 // there's nothing to do
515 // if two orderable angles are adjacent, and both are next to orderable angles,
516 // and one has winding computed, transfer to the other
halcanary96fcdcc2015-08-27 07:41:13 -0700517 SkOpAngle* baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700518 bool tryReverse = false;
519 // look for counterclockwise transfers
520 SkOpAngle* angle = firstAngle->previous();
521 SkOpAngle* next = angle->next();
522 firstAngle = next;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000523 do {
caryclark54359292015-03-26 07:52:43 -0700524 SkOpAngle* prior = angle;
525 angle = next;
526 next = angle->next();
527 SkASSERT(prior->next() == angle);
528 SkASSERT(angle->next() == next);
529 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700530 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700531 continue;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000532 }
caryclark54359292015-03-26 07:52:43 -0700533 int testWinding = angle->starter()->windSum();
534 if (SK_MinS32 != testWinding) {
535 baseAngle = angle;
536 tryReverse = true;
537 continue;
reed0dc4dd62015-03-24 13:55:33 -0700538 }
caryclark54359292015-03-26 07:52:43 -0700539 if (baseAngle) {
540 ComputeOneSum(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700541 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
caryclark54359292015-03-26 07:52:43 -0700542 }
543 } while (next != firstAngle);
544 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
545 firstAngle = baseAngle;
546 tryReverse = true;
547 }
548 if (tryReverse) {
halcanary96fcdcc2015-08-27 07:41:13 -0700549 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700550 SkOpAngle* prior = firstAngle;
551 do {
552 angle = prior;
553 prior = angle->previous();
554 SkASSERT(prior->next() == angle);
555 next = angle->next();
556 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700557 baseAngle = nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700558 continue;
559 }
caryclark54359292015-03-26 07:52:43 -0700560 int testWinding = angle->starter()->windSum();
561 if (SK_MinS32 != testWinding) {
562 baseAngle = angle;
563 continue;
reed0dc4dd62015-03-24 13:55:33 -0700564 }
caryclark54359292015-03-26 07:52:43 -0700565 if (baseAngle) {
566 ComputeOneSumReverse(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700567 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700568 }
caryclark54359292015-03-26 07:52:43 -0700569 } while (prior != firstAngle);
reed0dc4dd62015-03-24 13:55:33 -0700570 }
caryclark54359292015-03-26 07:52:43 -0700571 return start->starter(end)->windSum();
reed0dc4dd62015-03-24 13:55:33 -0700572}
573
caryclark54359292015-03-26 07:52:43 -0700574void SkOpSegment::detach(const SkOpSpan* span) {
575 if (span->done()) {
caryclark08bc8482015-04-24 09:08:57 -0700576 --fDoneCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000577 }
caryclark08bc8482015-04-24 09:08:57 -0700578 --fCount;
579 SkASSERT(fCount >= fDoneCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000580}
581
caryclark26ad22a2015-10-16 09:03:38 -0700582double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
caryclark54359292015-03-26 07:52:43 -0700583 SkDPoint testPt = this->dPtAtT(t);
584 SkDLine testPerp = {{ testPt, testPt }};
585 SkDVector slope = this->dSlopeAtT(t);
586 testPerp[1].fX += slope.fY;
587 testPerp[1].fY -= slope.fX;
588 SkIntersections i;
caryclark26ad22a2015-10-16 09:03:38 -0700589 const SkOpSegment* oppSegment = oppAngle->segment();
caryclark1049f122015-04-20 08:31:59 -0700590 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
caryclark54359292015-03-26 07:52:43 -0700591 double closestDistSq = SK_ScalarInfinity;
592 for (int index = 0; index < i.used(); ++index) {
593 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000594 continue;
595 }
caryclark54359292015-03-26 07:52:43 -0700596 double testDistSq = testPt.distanceSquared(i.pt(index));
597 if (closestDistSq > testDistSq) {
598 closestDistSq = testDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000599 }
600 }
caryclark54359292015-03-26 07:52:43 -0700601 return closestDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000602}
603
caryclarkd4349722015-07-23 12:40:22 -0700604void SkOpSegment::findCollapsed() {
605 if (fHead.contains(&fTail)) {
606 markAllDone();
607 // move start and end to the same point
608 fHead.alignEnd(0, fHead.pt());
609 fTail.setAligned();
610 }
611}
612
caryclark@google.com07393ca2013-04-08 11:47:37 +0000613/*
614 The M and S variable name parts stand for the operators.
615 Mi stands for Minuend (see wiki subtraction, analogous to difference)
616 Su stands for Subtrahend
617 The Opp variable name part designates that the value is for the Opposite operator.
618 Opposite values result from combining coincident spans.
619 */
caryclark54359292015-03-26 07:52:43 -0700620SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
621 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) {
622 SkOpSpanBase* start = *nextStart;
623 SkOpSpanBase* end = *nextEnd;
624 SkASSERT(start != end);
625 int step = start->step(end);
626 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
627 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000628 // mark the smaller of startIndex, endIndex done, and all adjacent
629 // spans with the same T value (but not 'other' spans)
630#if DEBUG_WINDING
631 SkDebugf("%s simple\n", __FUNCTION__);
632#endif
caryclark54359292015-03-26 07:52:43 -0700633 SkOpSpan* startSpan = start->starter(end);
634 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700635 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000636 }
caryclark54359292015-03-26 07:52:43 -0700637 markDone(startSpan);
638 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000639 return other;
640 }
caryclark54359292015-03-26 07:52:43 -0700641 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
642 SkASSERT(endNear == end); // is this ever not end?
643 SkASSERT(endNear);
644 SkASSERT(start != endNear);
645 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000646 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700647 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
caryclark@google.com570863f2013-09-16 15:55:01 +0000648 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000649 if (!sortable) {
650 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700651 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700652 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000653 }
caryclark54359292015-03-26 07:52:43 -0700654 SkOpAngle* angle = this->spanToAngle(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000655 if (angle->unorderable()) {
656 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700657 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700658 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000659 }
660#if DEBUG_SORT
661 SkDebugf("%s\n", __FUNCTION__);
662 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000663#endif
caryclark54359292015-03-26 07:52:43 -0700664 int sumMiWinding = updateWinding(end, start);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000665 if (sumMiWinding == SK_MinS32) {
666 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700667 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700668 return nullptr;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000669 }
caryclark54359292015-03-26 07:52:43 -0700670 int sumSuWinding = updateOppWinding(end, start);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000671 if (operand()) {
672 SkTSwap<int>(sumMiWinding, sumSuWinding);
673 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000674 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700675 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000676 bool foundDone = false;
677 // iterate through the angle, and compute everyone's winding
678 SkOpSegment* nextSegment;
679 int activeCount = 0;
680 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000681 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000682 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000683 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000684 if (activeAngle) {
685 ++activeCount;
686 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000687 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +0000688 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000689 }
690 }
691 if (nextSegment->done()) {
692 continue;
693 }
reed0dc4dd62015-03-24 13:55:33 -0700694 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700695 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700696 }
caryclark54359292015-03-26 07:52:43 -0700697 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000698 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000699 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000700 *chase->append() = last;
701#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700702 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
703 last->segment()->debugID(), last->debugID());
704 if (!last->final()) {
705 SkDebugf(" windSum=%d", last->upCast()->windSum());
706 }
707 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000708#endif
709 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000710 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700711 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000712 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700713 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000714 }
715 *nextStart = foundAngle->start();
716 *nextEnd = foundAngle->end();
717 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000718#if DEBUG_WINDING
719 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
720 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
721 #endif
722 return nextSegment;
723}
724
caryclark54359292015-03-26 07:52:43 -0700725SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
726 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
727 SkOpSpanBase* start = *nextStart;
728 SkOpSpanBase* end = *nextEnd;
729 SkASSERT(start != end);
730 int step = start->step(end);
731 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
732 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000733 // mark the smaller of startIndex, endIndex done, and all adjacent
734 // spans with the same T value (but not 'other' spans)
735#if DEBUG_WINDING
736 SkDebugf("%s simple\n", __FUNCTION__);
737#endif
caryclark54359292015-03-26 07:52:43 -0700738 SkOpSpan* startSpan = start->starter(end);
739 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700740 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000741 }
caryclark54359292015-03-26 07:52:43 -0700742 markDone(startSpan);
743 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000744 return other;
745 }
caryclark54359292015-03-26 07:52:43 -0700746 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
747 SkASSERT(endNear == end); // is this ever not end?
748 SkASSERT(endNear);
749 SkASSERT(start != endNear);
750 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000751 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700752 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000753 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000754 if (!sortable) {
755 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700756 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700757 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000758 }
caryclark54359292015-03-26 07:52:43 -0700759 SkOpAngle* angle = this->spanToAngle(end, start);
760 if (angle->unorderable()) {
761 *unsortable = true;
762 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700763 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700764 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000765#if DEBUG_SORT
766 SkDebugf("%s\n", __FUNCTION__);
767 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000768#endif
caryclark54359292015-03-26 07:52:43 -0700769 int sumWinding = updateWinding(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000770 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700771 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000772 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700773 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000774 SkOpSegment* nextSegment;
775 int activeCount = 0;
776 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000777 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000778 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000779 &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000780 if (activeAngle) {
781 ++activeCount;
782 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000783 foundAngle = nextAngle;
784 foundDone = nextSegment->done(nextAngle);
785 }
786 }
787 if (nextSegment->done()) {
788 continue;
789 }
reed0dc4dd62015-03-24 13:55:33 -0700790 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700791 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700792 }
caryclark54359292015-03-26 07:52:43 -0700793 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000794 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000795 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000796 *chase->append() = last;
797#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700798 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
799 last->segment()->debugID(), last->debugID());
800 if (!last->final()) {
801 SkDebugf(" windSum=%d", last->upCast()->windSum());
802 }
803 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000804#endif
805 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000806 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700807 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000808 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700809 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000810 }
811 *nextStart = foundAngle->start();
812 *nextEnd = foundAngle->end();
813 nextSegment = foundAngle->segment();
814#if DEBUG_WINDING
815 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
816 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
817 #endif
818 return nextSegment;
819}
820
caryclark54359292015-03-26 07:52:43 -0700821SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
822 bool* unsortable) {
823 SkOpSpanBase* start = *nextStart;
824 SkOpSpanBase* end = *nextEnd;
825 SkASSERT(start != end);
826 int step = start->step(end);
827 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
828 if (other) {
829 // mark the smaller of startIndex, endIndex done, and all adjacent
830 // spans with the same T value (but not 'other' spans)
caryclark@google.com07393ca2013-04-08 11:47:37 +0000831#if DEBUG_WINDING
832 SkDebugf("%s simple\n", __FUNCTION__);
833#endif
caryclark54359292015-03-26 07:52:43 -0700834 SkOpSpan* startSpan = start->starter(end);
835 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700836 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000837 }
caryclark54359292015-03-26 07:52:43 -0700838 markDone(startSpan);
839 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000840 return other;
841 }
caryclark54359292015-03-26 07:52:43 -0700842 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
843 : (*nextStart)->prev());
844 SkASSERT(endNear == end); // is this ever not end?
845 SkASSERT(endNear);
846 SkASSERT(start != endNear);
847 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
848 SkOpAngle* angle = this->spanToAngle(end, start);
caryclark27c8eb82015-07-06 11:38:33 -0700849 if (!angle || angle->unorderable()) {
caryclark54359292015-03-26 07:52:43 -0700850 *unsortable = true;
851 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700852 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700853 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000854#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000855 SkDebugf("%s\n", __FUNCTION__);
856 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000857#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000858 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700859 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000860 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700861 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000862 SkOpSegment* nextSegment;
863 int activeCount = 0;
864 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000865 nextSegment = nextAngle->segment();
866 ++activeCount;
867 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000868 foundAngle = nextAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000869 if (!(foundDone = nextSegment->done(nextAngle))) {
870 break;
871 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000872 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000873 nextAngle = nextAngle->next();
874 } while (nextAngle != angle);
caryclark54359292015-03-26 07:52:43 -0700875 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000876 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700877 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000878 }
879 *nextStart = foundAngle->start();
880 *nextEnd = foundAngle->end();
881 nextSegment = foundAngle->segment();
882#if DEBUG_WINDING
883 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
884 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
885 #endif
886 return nextSegment;
887}
888
caryclark54359292015-03-26 07:52:43 -0700889SkOpGlobalState* SkOpSegment::globalState() const {
890 return contour()->globalState();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000891}
892
caryclark1049f122015-04-20 08:31:59 -0700893void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
caryclark54359292015-03-26 07:52:43 -0700894 fContour = contour;
halcanary96fcdcc2015-08-27 07:41:13 -0700895 fNext = nullptr;
caryclark27c8eb82015-07-06 11:38:33 -0700896 fOriginal[0] = pts[0];
897 fOriginal[1] = pts[SkPathOpsVerbToPoints(verb)];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000898 fPts = pts;
caryclark1049f122015-04-20 08:31:59 -0700899 fWeight = weight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000900 fVerb = verb;
caryclark54359292015-03-26 07:52:43 -0700901 fCount = 0;
902 fDoneCount = 0;
903 fVisited = false;
904 SkOpSpan* zeroSpan = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700905 zeroSpan->init(this, nullptr, 0, fPts[0]);
caryclark54359292015-03-26 07:52:43 -0700906 SkOpSpanBase* oneSpan = &fTail;
907 zeroSpan->setNext(oneSpan);
908 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
caryclark1049f122015-04-20 08:31:59 -0700909 SkDEBUGCODE(fID = globalState()->nextSegmentID());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000910}
911
caryclark54359292015-03-26 07:52:43 -0700912bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
913 SkDPoint cPt = this->dPtAtT(t);
caryclark1049f122015-04-20 08:31:59 -0700914 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
caryclark54359292015-03-26 07:52:43 -0700915 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
916 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -0700917 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
caryclark54359292015-03-26 07:52:43 -0700918 int used = i.used();
919 for (int index = 0; index < used; ++index) {
920 if (cPt.roughlyEqual(i.pt(index))) {
reed0dc4dd62015-03-24 13:55:33 -0700921 return true;
922 }
caryclark54359292015-03-26 07:52:43 -0700923 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000924 return false;
925}
926
caryclark54359292015-03-26 07:52:43 -0700927bool SkOpSegment::isXor() const {
928 return fContour->isXor();
929}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000930
caryclark5b5ddd72015-05-18 05:12:56 -0700931void SkOpSegment::markAllDone() {
932 SkOpSpan* span = this->head();
933 do {
934 this->markDone(span);
935 } while ((span = span->next()->upCastable()));
936}
937
caryclark54359292015-03-26 07:52:43 -0700938SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) {
939 int step = start->step(end);
940 SkOpSpan* minSpan = start->starter(end);
941 markDone(minSpan);
halcanary96fcdcc2015-08-27 07:41:13 -0700942 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000943 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700944 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000945 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -0700946 SkASSERT(!last);
947 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000948 }
caryclark54359292015-03-26 07:52:43 -0700949 other->markDone(minSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000950 }
951 return last;
952}
953
caryclark54359292015-03-26 07:52:43 -0700954bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
955 SkOpSpanBase** lastPtr) {
956 SkOpSpan* spanStart = start->starter(end);
957 int step = start->step(end);
958 bool success = markWinding(spanStart, winding);
halcanary96fcdcc2015-08-27 07:41:13 -0700959 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000960 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700961 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
962 if (spanStart->windSum() != SK_MinS32) {
963 SkASSERT(spanStart->windSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700964 SkASSERT(!last);
965 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000966 }
caryclark54359292015-03-26 07:52:43 -0700967 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000968 }
caryclark65f55312014-11-13 06:58:52 -0800969 if (lastPtr) {
970 *lastPtr = last;
971 }
972 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000973}
974
caryclark54359292015-03-26 07:52:43 -0700975bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
976 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
977 SkOpSpan* spanStart = start->starter(end);
978 int step = start->step(end);
979 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700980 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000981 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700982 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
983 if (spanStart->windSum() != SK_MinS32) {
984 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700985 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700986 this->globalState()->setWindingFailed();
987 return false;
caryclarkdac1d172014-06-17 05:15:38 -0700988 }
caryclark54359292015-03-26 07:52:43 -0700989 } else {
990 SkASSERT(spanStart->windSum() == oppWinding);
991 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700992 }
993 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700994 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000995 }
caryclark54359292015-03-26 07:52:43 -0700996 if (this->operand() == other->operand()) {
997 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700998 } else {
caryclark54359292015-03-26 07:52:43 -0700999 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -07001000 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001001 }
caryclark65f55312014-11-13 06:58:52 -08001002 if (lastPtr) {
1003 *lastPtr = last;
1004 }
1005 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001006}
1007
caryclark54359292015-03-26 07:52:43 -07001008SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001009 SkASSERT(angle->segment() == this);
1010 if (UseInnerWinding(maxWinding, sumWinding)) {
1011 maxWinding = sumWinding;
1012 }
caryclark54359292015-03-26 07:52:43 -07001013 SkOpSpanBase* last;
1014 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +00001015#if DEBUG_WINDING
1016 if (last) {
caryclark54359292015-03-26 07:52:43 -07001017 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
1018 last->segment()->debugID(), last->debugID());
1019 if (!last->final()) {
1020 SkDebugf(" windSum=");
1021 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
1022 }
1023 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +00001024 }
1025#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00001026 return last;
1027}
1028
caryclark54359292015-03-26 07:52:43 -07001029SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
1030 int oppSumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001031 SkASSERT(angle->segment() == this);
1032 if (UseInnerWinding(maxWinding, sumWinding)) {
1033 maxWinding = sumWinding;
1034 }
1035 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
1036 oppMaxWinding = oppSumWinding;
1037 }
halcanary96fcdcc2015-08-27 07:41:13 -07001038 SkOpSpanBase* last = nullptr;
caryclark65f55312014-11-13 06:58:52 -08001039 // caller doesn't require that this marks anything
caryclark54359292015-03-26 07:52:43 -07001040 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +00001041#if DEBUG_WINDING
1042 if (last) {
caryclark54359292015-03-26 07:52:43 -07001043 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
1044 last->segment()->debugID(), last->debugID());
1045 if (!last->final()) {
1046 SkDebugf(" windSum=");
1047 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
1048 }
1049 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +00001050 }
1051#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00001052 return last;
1053}
1054
caryclark54359292015-03-26 07:52:43 -07001055void SkOpSegment::markDone(SkOpSpan* span) {
1056 SkASSERT(this == span->segment());
1057 if (span->done()) {
1058 return;
1059 }
1060#if DEBUG_MARK_DONE
1061 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
1062#endif
1063 span->setDone(true);
1064 ++fDoneCount;
1065 debugValidate();
1066}
1067
1068bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
1069 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -07001070 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -07001071 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001072 return false;
1073 }
1074#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -07001075 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -07001076#endif
caryclark54359292015-03-26 07:52:43 -07001077 span->setWindSum(winding);
1078 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001079 return true;
1080}
1081
caryclark54359292015-03-26 07:52:43 -07001082bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
1083 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +00001084 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -07001085 if (span->done()) {
1086 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001087 }
caryclark54359292015-03-26 07:52:43 -07001088#if DEBUG_MARK_DONE
1089 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1090#endif
1091 span->setWindSum(winding);
1092 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001093 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001094 return true;
1095}
1096
caryclark54359292015-03-26 07:52:43 -07001097bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
1098 const SkPoint& testPt) const {
1099 const SkOpSegment* baseParent = base->segment();
1100 if (this == baseParent && this == testParent && precisely_equal(base->fT, testT)) {
1101 return true;
1102 }
1103 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1104 return false;
1105 }
caryclark08bc8482015-04-24 09:08:57 -07001106 return !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001107}
1108
1109static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1110 if (last) {
1111 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001112 }
halcanary96fcdcc2015-08-27 07:41:13 -07001113 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001114}
1115
caryclark54359292015-03-26 07:52:43 -07001116SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1117 SkOpSpanBase** last) const {
1118 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001119 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001120 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1121 SkASSERT(endSpan);
1122 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1123 SkOpSpanBase* foundSpan;
1124 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001125 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001126 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001127 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001128 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001129 }
caryclark54359292015-03-26 07:52:43 -07001130 SkOpPtT* otherPtT = endSpan->ptT()->next();
1131 other = otherPtT->segment();
1132 foundSpan = otherPtT->span();
1133 otherEnd = step > 0 ? foundSpan->upCast()->next() : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001134 } else {
1135 int loopCount = angle->loopCount();
1136 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001137 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001138 }
1139 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001140 if (nullptr == next) {
1141 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001142 }
caryclarkdac1d172014-06-17 05:15:38 -07001143#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001144 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001145 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001146 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001147 }
caryclark54359292015-03-26 07:52:43 -07001148#endif
caryclarkdac1d172014-06-17 05:15:38 -07001149 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001150 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001151 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001152 }
caryclark54359292015-03-26 07:52:43 -07001153 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001154 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001155 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001156 }
caryclark54359292015-03-26 07:52:43 -07001157 SkASSERT(*startPtr);
1158 if (!otherEnd) {
halcanary96fcdcc2015-08-27 07:41:13 -07001159 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001160 }
1161// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001162 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1163 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1164 if (foundMin->windValue() != origMin->windValue()
1165 || foundMin->oppValue() != origMin->oppValue()) {
1166 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001167 }
caryclark54359292015-03-26 07:52:43 -07001168 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001169 *stepPtr = foundStep;
1170 if (minPtr) {
1171 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001172 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001173 return other;
1174}
1175
caryclarkbca19f72015-05-13 08:23:48 -07001176static void clear_visited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001177 // reset visited flag back to false
1178 do {
1179 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1180 while ((ptT = ptT->next()) != stopPtT) {
1181 SkOpSegment* opp = ptT->segment();
1182 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001183 }
caryclarkbca19f72015-05-13 08:23:48 -07001184 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001185}
1186
caryclark54359292015-03-26 07:52:43 -07001187// look for pairs of undetected coincident curves
1188// assumes that segments going in have visited flag clear
1189// curve/curve intersection should now do a pretty good job of finding coincident runs so
1190// this may be only be necessary for line/curve pairs -- so skip unless this is a line and the
1191// the opp is not a line
caryclark27c8eb82015-07-06 11:38:33 -07001192bool SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) {
caryclark54359292015-03-26 07:52:43 -07001193 if (this->verb() != SkPath::kLine_Verb) {
caryclark27c8eb82015-07-06 11:38:33 -07001194 return false;
caryclark54359292015-03-26 07:52:43 -07001195 }
caryclarkbca19f72015-05-13 08:23:48 -07001196 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001197 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001198 }
halcanary96fcdcc2015-08-27 07:41:13 -07001199 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001200 SkOpSpanBase* spanBase = &fHead;
caryclark54359292015-03-26 07:52:43 -07001201 do {
caryclarkbca19f72015-05-13 08:23:48 -07001202 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
1203 SkASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001204 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001205 if (ptT->deleted()) {
1206 continue;
1207 }
caryclark54359292015-03-26 07:52:43 -07001208 SkOpSegment* opp = ptT->span()->segment();
caryclark26ad22a2015-10-16 09:03:38 -07001209// if (opp->verb() == SkPath::kLine_Verb) {
1210// continue;
1211// }
caryclarkbca19f72015-05-13 08:23:48 -07001212 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001213 continue;
reed0dc4dd62015-03-24 13:55:33 -07001214 }
caryclarkbca19f72015-05-13 08:23:48 -07001215 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1216 if (!opp->visited()) {
1217 continue;
1218 }
1219 if (spanBase == &fHead) {
1220 continue;
1221 }
1222 SkOpSpan* span = spanBase->upCastable();
1223 // FIXME?: this assumes that if the opposite segment is coincident then no more
1224 // coincidence needs to be detected. This may not be true.
1225 if (span && span->containsCoincidence(opp)) {
1226 continue;
1227 }
caryclark26ad22a2015-10-16 09:03:38 -07001228 if (spanBase->segment() == opp) {
1229 continue;
1230 }
caryclarkbca19f72015-05-13 08:23:48 -07001231 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001232 continue;
1233 }
halcanary96fcdcc2015-08-27 07:41:13 -07001234 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001235 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001236 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001237 SkOpSpan* priorTest = spanBase->prev();
1238 while (!priorOpp && priorTest) {
1239 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001240 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001241 if (priorPtT->deleted()) {
1242 continue;
1243 }
caryclark54359292015-03-26 07:52:43 -07001244 SkOpSegment* segment = priorPtT->span()->segment();
1245 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001246 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001247 priorOpp = opp;
1248 break;
1249 }
1250 }
caryclarkbca19f72015-05-13 08:23:48 -07001251 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001252 }
1253 if (!priorOpp) {
1254 continue;
1255 }
caryclark26ad22a2015-10-16 09:03:38 -07001256 if (priorPtT == ptT) {
1257 continue;
1258 }
caryclark54359292015-03-26 07:52:43 -07001259 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001260 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001261 bool swapped = priorPtT->fT > ptT->fT;
1262 if (swapped) {
1263 SkTSwap(priorPtT, ptT);
1264 SkTSwap(oppStart, oppEnd);
1265 }
1266 bool flipped = oppStart->fT > oppEnd->fT;
caryclark26ad22a2015-10-16 09:03:38 -07001267 bool coincident = false;
caryclark54359292015-03-26 07:52:43 -07001268 if (coincidences->contains(priorPtT, ptT, oppStart, oppEnd, flipped)) {
1269 goto swapBack;
1270 }
caryclark26ad22a2015-10-16 09:03:38 -07001271 if (opp->verb() == SkPath::kLine_Verb) {
1272 coincident = (SkDPoint::ApproximatelyEqual(priorPtT->fPt, oppStart->fPt) ||
1273 SkDPoint::ApproximatelyEqual(priorPtT->fPt, oppEnd->fPt)) &&
1274 (SkDPoint::ApproximatelyEqual(ptT->fPt, oppStart->fPt) ||
1275 SkDPoint::ApproximatelyEqual(ptT->fPt, oppEnd->fPt));
1276 }
1277 if (!coincident) {
1278 coincident = testForCoincidence(priorPtT, ptT, prior, spanBase, opp, 5000);
1279 }
caryclark54359292015-03-26 07:52:43 -07001280 if (coincident) {
1281 // mark coincidence
caryclark182b4992015-05-14 05:45:54 -07001282 if (!coincidences->extend(priorPtT, ptT, oppStart, oppEnd)
1283 && !coincidences->extend(oppStart, oppEnd, priorPtT, ptT)) {
caryclarkbca19f72015-05-13 08:23:48 -07001284 coincidences->add(priorPtT, ptT, oppStart, oppEnd, allocator);
1285 }
caryclark54359292015-03-26 07:52:43 -07001286 clear_visited(&fHead);
caryclark27c8eb82015-07-06 11:38:33 -07001287 return true;
caryclark54359292015-03-26 07:52:43 -07001288 }
1289 swapBack:
1290 if (swapped) {
1291 SkTSwap(priorPtT, ptT);
1292 }
reed0dc4dd62015-03-24 13:55:33 -07001293 }
halcanary96fcdcc2015-08-27 07:41:13 -07001294 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark54359292015-03-26 07:52:43 -07001295 clear_visited(&fHead);
caryclark27c8eb82015-07-06 11:38:33 -07001296 return false;
reed0dc4dd62015-03-24 13:55:33 -07001297}
1298
caryclark08bc8482015-04-24 09:08:57 -07001299// if a span has more than one intersection, merge the other segments' span as needed
caryclarkd78c0882016-02-24 09:03:07 -08001300bool SkOpSegment::moveMultiples() {
caryclark08bc8482015-04-24 09:08:57 -07001301 debugValidate();
1302 SkOpSpanBase* test = &fHead;
1303 do {
1304 int addCount = test->spanAddsCount();
caryclarkd78c0882016-02-24 09:03:07 -08001305 if (addCount < 1) {
1306 return false;
1307 }
caryclark08bc8482015-04-24 09:08:57 -07001308 if (addCount == 1) {
1309 continue;
1310 }
1311 SkOpPtT* startPtT = test->ptT();
1312 SkOpPtT* testPtT = startPtT;
1313 do { // iterate through all spans associated with start
1314 SkOpSpanBase* oppSpan = testPtT->span();
1315 if (oppSpan->spanAddsCount() == addCount) {
1316 continue;
1317 }
1318 if (oppSpan->deleted()) {
1319 continue;
1320 }
1321 SkOpSegment* oppSegment = oppSpan->segment();
1322 if (oppSegment == this) {
1323 continue;
1324 }
1325 // find range of spans to consider merging
1326 SkOpSpanBase* oppPrev = oppSpan;
1327 SkOpSpanBase* oppFirst = oppSpan;
1328 while ((oppPrev = oppPrev->prev())) {
1329 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1330 break;
1331 }
1332 if (oppPrev->spanAddsCount() == addCount) {
1333 continue;
1334 }
1335 if (oppPrev->deleted()) {
1336 continue;
1337 }
1338 oppFirst = oppPrev;
1339 }
1340 SkOpSpanBase* oppNext = oppSpan;
1341 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001342 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001343 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1344 break;
1345 }
1346 if (oppNext->spanAddsCount() == addCount) {
1347 continue;
1348 }
1349 if (oppNext->deleted()) {
1350 continue;
1351 }
1352 oppLast = oppNext;
1353 }
1354 if (oppFirst == oppLast) {
1355 continue;
1356 }
1357 SkOpSpanBase* oppTest = oppFirst;
1358 do {
1359 if (oppTest == oppSpan) {
1360 continue;
1361 }
1362 // check to see if the candidate meets specific criteria:
1363 // it contains spans of segments in test's loop but not including 'this'
1364 SkOpPtT* oppStartPtT = oppTest->ptT();
1365 SkOpPtT* oppPtT = oppStartPtT;
1366 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1367 SkOpSegment* oppPtTSegment = oppPtT->segment();
1368 if (oppPtTSegment == this) {
1369 goto tryNextSpan;
1370 }
1371 SkOpPtT* matchPtT = startPtT;
1372 do {
1373 if (matchPtT->segment() == oppPtTSegment) {
1374 goto foundMatch;
1375 }
1376 } while ((matchPtT = matchPtT->next()) != startPtT);
1377 goto tryNextSpan;
1378 foundMatch: // merge oppTest and oppSpan
1379 oppSegment->debugValidate();
1380 if (oppTest == &oppSegment->fTail || oppTest == &oppSegment->fHead) {
1381 SkASSERT(oppSpan != &oppSegment->fHead); // don't expect collapse
1382 SkASSERT(oppSpan != &oppSegment->fTail);
1383 oppTest->merge(oppSpan->upCast());
1384 } else {
1385 oppSpan->merge(oppTest->upCast());
1386 }
1387 oppSegment->debugValidate();
1388 goto checkNextSpan;
1389 }
1390 tryNextSpan:
1391 ;
1392 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1393 } while ((testPtT = testPtT->next()) != startPtT);
1394checkNextSpan:
1395 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001396 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001397 debugValidate();
caryclarkd78c0882016-02-24 09:03:07 -08001398 return true;
caryclark08bc8482015-04-24 09:08:57 -07001399}
1400
caryclark54359292015-03-26 07:52:43 -07001401// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
caryclark08bc8482015-04-24 09:08:57 -07001402void SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001403 debugValidate();
1404 SkOpSpanBase* spanS = &fHead;
1405 do {
1406 SkOpSpanBase* test = spanS->upCast()->next();
1407 SkOpSpanBase* next;
1408 if (spanS->contains(test)) {
1409 if (!test->final()) {
1410 test->upCast()->detach(spanS->ptT());
1411 continue;
1412 } else if (spanS != &fHead) {
1413 spanS->upCast()->detach(test->ptT());
1414 spanS = test;
1415 continue;
1416 }
reed0dc4dd62015-03-24 13:55:33 -07001417 }
caryclark54359292015-03-26 07:52:43 -07001418 do { // iterate through all spans associated with start
1419 SkOpPtT* startBase = spanS->ptT();
halcanary96fcdcc2015-08-27 07:41:13 -07001420 next = test->final() ? nullptr : test->upCast()->next();
caryclark54359292015-03-26 07:52:43 -07001421 do {
1422 SkOpPtT* testBase = test->ptT();
1423 do {
1424 if (startBase == testBase) {
1425 goto checkNextSpan;
1426 }
1427 if (testBase->duplicate()) {
1428 continue;
1429 }
1430 if (this->match(startBase, testBase->segment(), testBase->fT, testBase->fPt)) {
1431 if (test == &this->fTail) {
1432 if (spanS == &fHead) {
1433 debugValidate();
caryclark08bc8482015-04-24 09:08:57 -07001434 return; // if this span has collapsed, remove it from parent
caryclark54359292015-03-26 07:52:43 -07001435 }
1436 this->fTail.merge(spanS->upCast());
1437 debugValidate();
caryclark08bc8482015-04-24 09:08:57 -07001438 return;
caryclark54359292015-03-26 07:52:43 -07001439 }
1440 spanS->merge(test->upCast());
caryclark54359292015-03-26 07:52:43 -07001441 goto checkNextSpan;
1442 }
1443 } while ((testBase = testBase->next()) != test->ptT());
1444 } while ((startBase = startBase->next()) != spanS->ptT());
1445 checkNextSpan:
1446 ;
1447 } while ((test = next));
1448 spanS = spanS->upCast()->next();
1449 } while (!spanS->final());
1450 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001451}
1452
caryclark54359292015-03-26 07:52:43 -07001453bool SkOpSegment::operand() const {
1454 return fContour->operand();
1455}
1456
1457bool SkOpSegment::oppXor() const {
1458 return fContour->oppXor();
1459}
1460
1461bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1462 if (fVerb == SkPath::kLine_Verb) {
1463 return false;
1464 }
1465 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1466 // hits in two places with very different t values.
1467 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1468 // 'controls contained by ends' could avoid this check for common curves
1469 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1470 // on the other hand, the below check is relatively inexpensive
1471 double midT = (t1 + t2) / 2;
1472 SkPoint midPt = this->ptAtT(midT);
1473 double seDistSq = SkTMax(pt1.distanceToSqd(pt2) * 2, FLT_EPSILON * 2);
1474 return midPt.distanceToSqd(pt1) > seDistSq || midPt.distanceToSqd(pt2) > seDistSq;
1475}
1476
1477void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1478 int* maxWinding, int* sumWinding) {
1479 int deltaSum = SpanSign(start, end);
1480 *maxWinding = *sumMiWinding;
1481 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001482 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001483}
1484
1485void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1486 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1487 int* oppSumWinding) {
1488 int deltaSum = SpanSign(start, end);
1489 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001490 if (operand()) {
1491 *maxWinding = *sumSuWinding;
1492 *sumWinding = *sumSuWinding -= deltaSum;
1493 *oppMaxWinding = *sumMiWinding;
1494 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1495 } else {
1496 *maxWinding = *sumMiWinding;
1497 *sumWinding = *sumMiWinding -= deltaSum;
1498 *oppMaxWinding = *sumSuWinding;
1499 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1500 }
bungeman60e0fee2015-08-26 05:15:46 -07001501 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1502 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001503}
1504
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001505void SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001506 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001507 do {
caryclark54359292015-03-26 07:52:43 -07001508 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001509 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001510 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001511 continue;
1512 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001513#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001514 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001515#endif
caryclark54359292015-03-26 07:52:43 -07001516 SkOpAngle* baseAngle = fromAngle;
1517 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001518#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001519 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1520 span->debugID());
1521 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001522#endif
caryclark54359292015-03-26 07:52:43 -07001523 fromAngle->insert(toAngle);
1524 } else if (!fromAngle) {
1525 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001526 }
caryclark54359292015-03-26 07:52:43 -07001527 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001528 do {
caryclark54359292015-03-26 07:52:43 -07001529 SkOpSpanBase* oSpan = ptT->span();
1530 if (oSpan == span) {
1531 continue;
1532 }
1533 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001534 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001535#if DEBUG_ANGLE
1536 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001537 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1538 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001539 wroteAfterHeader = true;
1540 }
1541#endif
caryclark54359292015-03-26 07:52:43 -07001542 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001543 baseAngle->insert(oAngle);
1544 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001545 }
caryclark54359292015-03-26 07:52:43 -07001546 if (!oSpan->final()) {
1547 oAngle = oSpan->upCast()->toAngle();
1548 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001549#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001550 if (!wroteAfterHeader) {
1551 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1552 span->t(), span->debugID());
1553 wroteAfterHeader = true;
1554 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001555#endif
caryclark54359292015-03-26 07:52:43 -07001556 if (!oAngle->loopContains(baseAngle)) {
1557 baseAngle->insert(oAngle);
1558 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001559 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001560 }
caryclark54359292015-03-26 07:52:43 -07001561 } while ((ptT = ptT->next()) != stopPtT);
1562 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001563 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001564 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001565 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001566 }
halcanary96fcdcc2015-08-27 07:41:13 -07001567 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001568 }
1569#if DEBUG_SORT
1570 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1571#endif
caryclark54359292015-03-26 07:52:43 -07001572 } while (!span->final() && (span = span->upCast()->next()));
caryclark@google.com570863f2013-09-16 15:55:01 +00001573}
1574
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001575// return true if midpoints were computed
caryclark54359292015-03-26 07:52:43 -07001576bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001577 SkOpCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001578 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001579 const SkOpPtT& startPtT = *start->ptT();
1580 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001581 SkDEBUGCODE(edge->fVerb = fVerb);
1582 edge->fPts[0] = startPtT.fPt;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001583 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001584 edge->fPts[points] = endPtT.fPt;
1585 edge->fWeight = 1;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001586 if (fVerb == SkPath::kLine_Verb) {
1587 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001588 }
caryclark54359292015-03-26 07:52:43 -07001589 double startT = startPtT.fT;
1590 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001591 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1592 // don't compute midpoints if we already have them
1593 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001594 edge->fPts[1] = fPts[1];
1595 return false;
1596 }
1597 if (fVerb == SkPath::kConic_Verb) {
1598 edge->fPts[1] = fPts[1];
1599 edge->fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001600 return false;
1601 }
1602 SkASSERT(fVerb == SkPath::kCubic_Verb);
1603 if (start < end) {
caryclark1049f122015-04-20 08:31:59 -07001604 edge->fPts[1] = fPts[1];
1605 edge->fPts[2] = fPts[2];
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001606 return false;
1607 }
caryclark1049f122015-04-20 08:31:59 -07001608 edge->fPts[1] = fPts[2];
1609 edge->fPts[2] = fPts[1];
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001610 return false;
1611 }
caryclark1049f122015-04-20 08:31:59 -07001612 const SkDPoint sub[2] = {{ edge->fPts[0].fX, edge->fPts[0].fY},
1613 {edge->fPts[points].fX, edge->fPts[points].fY }};
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001614 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001615 edge->fPts[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
1616 } else if (fVerb == SkPath::kConic_Verb) {
1617 edge->fPts[1] = SkDConic::SubDivide(fPts, fWeight, sub[0], sub[1],
1618 startT, endT, &edge->fWeight).asSkPoint();
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001619 } else {
1620 SkASSERT(fVerb == SkPath::kCubic_Verb);
1621 SkDPoint ctrl[2];
1622 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
caryclark1049f122015-04-20 08:31:59 -07001623 edge->fPts[1] = ctrl[0].asSkPoint();
1624 edge->fPts[2] = ctrl[1].asSkPoint();
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001625 }
1626 return true;
1627}
1628
caryclark54359292015-03-26 07:52:43 -07001629bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001630 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001631 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001632 const SkOpPtT& startPtT = *start->ptT();
1633 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001634 SkDEBUGCODE(edge->fVerb = fVerb);
1635 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001636 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001637 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001638 if (fVerb == SkPath::kLine_Verb) {
1639 return false;
1640 }
caryclark54359292015-03-26 07:52:43 -07001641 double startT = startPtT.fT;
1642 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001643 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1644 // don't compute midpoints if we already have them
1645 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001646 edge->fLine[1].set(fPts[1]);
1647 return false;
1648 }
1649 if (fVerb == SkPath::kConic_Verb) {
1650 edge->fConic[1].set(fPts[1]);
1651 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001652 return false;
1653 }
1654 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001655 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001656 edge->fCubic[1].set(fPts[1]);
1657 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001658 return false;
1659 }
caryclark1049f122015-04-20 08:31:59 -07001660 edge->fCubic[1].set(fPts[2]);
1661 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001662 return false;
1663 }
1664 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001665 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1666 } else if (fVerb == SkPath::kConic_Verb) {
1667 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1668 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001669 } else {
1670 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001671 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001672 }
1673 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001674}
1675
caryclark27c8eb82015-07-06 11:38:33 -07001676bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
1677 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp,
1678 SkScalar flatnessLimit) const {
1679 // average t, find mid pt
1680 double midT = (prior->t() + spanBase->t()) / 2;
1681 SkPoint midPt = this->ptAtT(midT);
1682 bool coincident = true;
1683 // if the mid pt is not near either end pt, project perpendicular through opp seg
1684 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1685 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
1686 coincident = false;
1687 SkIntersections i;
1688 SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->weight(), midT);
caryclarkb6693002015-12-16 12:28:35 -08001689 SkDLine ray = {{{midPt.fX, midPt.fY},
1690 {(double) midPt.fX + dxdy.fY, (double) midPt.fY - dxdy.fX}}};
caryclark27c8eb82015-07-06 11:38:33 -07001691 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), ray, &i);
1692 // measure distance and see if it's small enough to denote coincidence
1693 for (int index = 0; index < i.used(); ++index) {
1694 SkDPoint oppPt = i.pt(index);
1695 if (oppPt.approximatelyEqual(midPt)) {
1696 SkVector oppDxdy = (*CurveSlopeAtT[opp->verb()])(opp->pts(),
1697 opp->weight(), i[index][0]);
1698 oppDxdy.normalize();
1699 dxdy.normalize();
1700 SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy) / FLT_EPSILON);
1701 coincident |= flatness < flatnessLimit;
1702 }
1703 }
1704 }
1705 return coincident;
1706}
1707
caryclark54359292015-03-26 07:52:43 -07001708void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
1709 SkOpSpan* span = this->head();
1710 do {
1711 if (!span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001712 break;
1713 }
caryclark54359292015-03-26 07:52:43 -07001714 } while ((span = span->next()->upCastable()));
1715 SkASSERT(span);
1716 *start = span;
1717 *end = span->next();
reed0dc4dd62015-03-24 13:55:33 -07001718}
1719
caryclark54359292015-03-26 07:52:43 -07001720int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1721 const SkOpSpan* lesser = start->starter(end);
1722 int oppWinding = lesser->oppSum();
1723 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001724 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1725 && oppWinding != SK_MaxS32) {
1726 oppWinding -= oppSpanWinding;
1727 }
1728 return oppWinding;
1729}
1730
1731int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001732 const SkOpSpanBase* startSpan = angle->start();
1733 const SkOpSpanBase* endSpan = angle->end();
1734 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001735}
1736
1737int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001738 const SkOpSpanBase* startSpan = angle->start();
1739 const SkOpSpanBase* endSpan = angle->end();
1740 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001741}
1742
caryclark624637c2015-05-11 07:21:27 -07001743int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1744 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001745 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001746 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001747 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001748 }
1749 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001750 return winding;
1751 }
caryclark54359292015-03-26 07:52:43 -07001752 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001753 if (winding && UseInnerWinding(winding - spanWinding, winding)
1754 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001755 winding -= spanWinding;
1756 }
1757 return winding;
1758}
1759
caryclark624637c2015-05-11 07:21:27 -07001760int SkOpSegment::updateWinding(SkOpAngle* angle) {
1761 SkOpSpanBase* startSpan = angle->start();
1762 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001763 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001764}
1765
caryclark624637c2015-05-11 07:21:27 -07001766int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1767 SkOpSpanBase* startSpan = angle->start();
1768 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001769 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001770}
1771
1772// OPTIMIZATION: does the following also work, and is it any faster?
1773// return outerWinding * innerWinding > 0
1774// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1775bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1776 SkASSERT(outerWinding != SK_MaxS32);
1777 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001778 int absOut = SkTAbs(outerWinding);
1779 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001780 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1781 return result;
1782}
1783
caryclark@google.com07393ca2013-04-08 11:47:37 +00001784int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001785 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1786 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001787}