blob: d066794cee2a02c10eec5e9e9de42bd8c351925d [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
1300void SkOpSegment::moveMultiples() {
1301 debugValidate();
1302 SkOpSpanBase* test = &fHead;
1303 do {
1304 int addCount = test->spanAddsCount();
1305 SkASSERT(addCount >= 1);
1306 if (addCount == 1) {
1307 continue;
1308 }
1309 SkOpPtT* startPtT = test->ptT();
1310 SkOpPtT* testPtT = startPtT;
1311 do { // iterate through all spans associated with start
1312 SkOpSpanBase* oppSpan = testPtT->span();
1313 if (oppSpan->spanAddsCount() == addCount) {
1314 continue;
1315 }
1316 if (oppSpan->deleted()) {
1317 continue;
1318 }
1319 SkOpSegment* oppSegment = oppSpan->segment();
1320 if (oppSegment == this) {
1321 continue;
1322 }
1323 // find range of spans to consider merging
1324 SkOpSpanBase* oppPrev = oppSpan;
1325 SkOpSpanBase* oppFirst = oppSpan;
1326 while ((oppPrev = oppPrev->prev())) {
1327 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1328 break;
1329 }
1330 if (oppPrev->spanAddsCount() == addCount) {
1331 continue;
1332 }
1333 if (oppPrev->deleted()) {
1334 continue;
1335 }
1336 oppFirst = oppPrev;
1337 }
1338 SkOpSpanBase* oppNext = oppSpan;
1339 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001340 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001341 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1342 break;
1343 }
1344 if (oppNext->spanAddsCount() == addCount) {
1345 continue;
1346 }
1347 if (oppNext->deleted()) {
1348 continue;
1349 }
1350 oppLast = oppNext;
1351 }
1352 if (oppFirst == oppLast) {
1353 continue;
1354 }
1355 SkOpSpanBase* oppTest = oppFirst;
1356 do {
1357 if (oppTest == oppSpan) {
1358 continue;
1359 }
1360 // check to see if the candidate meets specific criteria:
1361 // it contains spans of segments in test's loop but not including 'this'
1362 SkOpPtT* oppStartPtT = oppTest->ptT();
1363 SkOpPtT* oppPtT = oppStartPtT;
1364 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1365 SkOpSegment* oppPtTSegment = oppPtT->segment();
1366 if (oppPtTSegment == this) {
1367 goto tryNextSpan;
1368 }
1369 SkOpPtT* matchPtT = startPtT;
1370 do {
1371 if (matchPtT->segment() == oppPtTSegment) {
1372 goto foundMatch;
1373 }
1374 } while ((matchPtT = matchPtT->next()) != startPtT);
1375 goto tryNextSpan;
1376 foundMatch: // merge oppTest and oppSpan
1377 oppSegment->debugValidate();
1378 if (oppTest == &oppSegment->fTail || oppTest == &oppSegment->fHead) {
1379 SkASSERT(oppSpan != &oppSegment->fHead); // don't expect collapse
1380 SkASSERT(oppSpan != &oppSegment->fTail);
1381 oppTest->merge(oppSpan->upCast());
1382 } else {
1383 oppSpan->merge(oppTest->upCast());
1384 }
1385 oppSegment->debugValidate();
1386 goto checkNextSpan;
1387 }
1388 tryNextSpan:
1389 ;
1390 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1391 } while ((testPtT = testPtT->next()) != startPtT);
1392checkNextSpan:
1393 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001394 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001395 debugValidate();
1396}
1397
caryclark54359292015-03-26 07:52:43 -07001398// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
caryclark08bc8482015-04-24 09:08:57 -07001399void SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001400 debugValidate();
1401 SkOpSpanBase* spanS = &fHead;
1402 do {
1403 SkOpSpanBase* test = spanS->upCast()->next();
1404 SkOpSpanBase* next;
1405 if (spanS->contains(test)) {
1406 if (!test->final()) {
1407 test->upCast()->detach(spanS->ptT());
1408 continue;
1409 } else if (spanS != &fHead) {
1410 spanS->upCast()->detach(test->ptT());
1411 spanS = test;
1412 continue;
1413 }
reed0dc4dd62015-03-24 13:55:33 -07001414 }
caryclark54359292015-03-26 07:52:43 -07001415 do { // iterate through all spans associated with start
1416 SkOpPtT* startBase = spanS->ptT();
halcanary96fcdcc2015-08-27 07:41:13 -07001417 next = test->final() ? nullptr : test->upCast()->next();
caryclark54359292015-03-26 07:52:43 -07001418 do {
1419 SkOpPtT* testBase = test->ptT();
1420 do {
1421 if (startBase == testBase) {
1422 goto checkNextSpan;
1423 }
1424 if (testBase->duplicate()) {
1425 continue;
1426 }
1427 if (this->match(startBase, testBase->segment(), testBase->fT, testBase->fPt)) {
1428 if (test == &this->fTail) {
1429 if (spanS == &fHead) {
1430 debugValidate();
caryclark08bc8482015-04-24 09:08:57 -07001431 return; // if this span has collapsed, remove it from parent
caryclark54359292015-03-26 07:52:43 -07001432 }
1433 this->fTail.merge(spanS->upCast());
1434 debugValidate();
caryclark08bc8482015-04-24 09:08:57 -07001435 return;
caryclark54359292015-03-26 07:52:43 -07001436 }
1437 spanS->merge(test->upCast());
caryclark54359292015-03-26 07:52:43 -07001438 goto checkNextSpan;
1439 }
1440 } while ((testBase = testBase->next()) != test->ptT());
1441 } while ((startBase = startBase->next()) != spanS->ptT());
1442 checkNextSpan:
1443 ;
1444 } while ((test = next));
1445 spanS = spanS->upCast()->next();
1446 } while (!spanS->final());
1447 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001448}
1449
caryclark54359292015-03-26 07:52:43 -07001450bool SkOpSegment::operand() const {
1451 return fContour->operand();
1452}
1453
1454bool SkOpSegment::oppXor() const {
1455 return fContour->oppXor();
1456}
1457
1458bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1459 if (fVerb == SkPath::kLine_Verb) {
1460 return false;
1461 }
1462 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1463 // hits in two places with very different t values.
1464 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1465 // 'controls contained by ends' could avoid this check for common curves
1466 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1467 // on the other hand, the below check is relatively inexpensive
1468 double midT = (t1 + t2) / 2;
1469 SkPoint midPt = this->ptAtT(midT);
1470 double seDistSq = SkTMax(pt1.distanceToSqd(pt2) * 2, FLT_EPSILON * 2);
1471 return midPt.distanceToSqd(pt1) > seDistSq || midPt.distanceToSqd(pt2) > seDistSq;
1472}
1473
1474void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1475 int* maxWinding, int* sumWinding) {
1476 int deltaSum = SpanSign(start, end);
1477 *maxWinding = *sumMiWinding;
1478 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001479 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001480}
1481
1482void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1483 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1484 int* oppSumWinding) {
1485 int deltaSum = SpanSign(start, end);
1486 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001487 if (operand()) {
1488 *maxWinding = *sumSuWinding;
1489 *sumWinding = *sumSuWinding -= deltaSum;
1490 *oppMaxWinding = *sumMiWinding;
1491 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1492 } else {
1493 *maxWinding = *sumMiWinding;
1494 *sumWinding = *sumMiWinding -= deltaSum;
1495 *oppMaxWinding = *sumSuWinding;
1496 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1497 }
bungeman60e0fee2015-08-26 05:15:46 -07001498 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1499 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001500}
1501
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001502void SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001503 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001504 do {
caryclark54359292015-03-26 07:52:43 -07001505 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001506 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001507 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001508 continue;
1509 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001510#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001511 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001512#endif
caryclark54359292015-03-26 07:52:43 -07001513 SkOpAngle* baseAngle = fromAngle;
1514 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001515#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001516 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1517 span->debugID());
1518 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001519#endif
caryclark54359292015-03-26 07:52:43 -07001520 fromAngle->insert(toAngle);
1521 } else if (!fromAngle) {
1522 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001523 }
caryclark54359292015-03-26 07:52:43 -07001524 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001525 do {
caryclark54359292015-03-26 07:52:43 -07001526 SkOpSpanBase* oSpan = ptT->span();
1527 if (oSpan == span) {
1528 continue;
1529 }
1530 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001531 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001532#if DEBUG_ANGLE
1533 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001534 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1535 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001536 wroteAfterHeader = true;
1537 }
1538#endif
caryclark54359292015-03-26 07:52:43 -07001539 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001540 baseAngle->insert(oAngle);
1541 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001542 }
caryclark54359292015-03-26 07:52:43 -07001543 if (!oSpan->final()) {
1544 oAngle = oSpan->upCast()->toAngle();
1545 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001546#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001547 if (!wroteAfterHeader) {
1548 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1549 span->t(), span->debugID());
1550 wroteAfterHeader = true;
1551 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001552#endif
caryclark54359292015-03-26 07:52:43 -07001553 if (!oAngle->loopContains(baseAngle)) {
1554 baseAngle->insert(oAngle);
1555 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001556 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001557 }
caryclark54359292015-03-26 07:52:43 -07001558 } while ((ptT = ptT->next()) != stopPtT);
1559 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001560 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001561 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001562 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001563 }
halcanary96fcdcc2015-08-27 07:41:13 -07001564 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001565 }
1566#if DEBUG_SORT
1567 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1568#endif
caryclark54359292015-03-26 07:52:43 -07001569 } while (!span->final() && (span = span->upCast()->next()));
caryclark@google.com570863f2013-09-16 15:55:01 +00001570}
1571
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001572// return true if midpoints were computed
caryclark54359292015-03-26 07:52:43 -07001573bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001574 SkOpCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001575 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001576 const SkOpPtT& startPtT = *start->ptT();
1577 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001578 SkDEBUGCODE(edge->fVerb = fVerb);
1579 edge->fPts[0] = startPtT.fPt;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001580 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001581 edge->fPts[points] = endPtT.fPt;
1582 edge->fWeight = 1;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001583 if (fVerb == SkPath::kLine_Verb) {
1584 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001585 }
caryclark54359292015-03-26 07:52:43 -07001586 double startT = startPtT.fT;
1587 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001588 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1589 // don't compute midpoints if we already have them
1590 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001591 edge->fPts[1] = fPts[1];
1592 return false;
1593 }
1594 if (fVerb == SkPath::kConic_Verb) {
1595 edge->fPts[1] = fPts[1];
1596 edge->fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001597 return false;
1598 }
1599 SkASSERT(fVerb == SkPath::kCubic_Verb);
1600 if (start < end) {
caryclark1049f122015-04-20 08:31:59 -07001601 edge->fPts[1] = fPts[1];
1602 edge->fPts[2] = fPts[2];
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001603 return false;
1604 }
caryclark1049f122015-04-20 08:31:59 -07001605 edge->fPts[1] = fPts[2];
1606 edge->fPts[2] = fPts[1];
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001607 return false;
1608 }
caryclark1049f122015-04-20 08:31:59 -07001609 const SkDPoint sub[2] = {{ edge->fPts[0].fX, edge->fPts[0].fY},
1610 {edge->fPts[points].fX, edge->fPts[points].fY }};
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001611 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001612 edge->fPts[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
1613 } else if (fVerb == SkPath::kConic_Verb) {
1614 edge->fPts[1] = SkDConic::SubDivide(fPts, fWeight, sub[0], sub[1],
1615 startT, endT, &edge->fWeight).asSkPoint();
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001616 } else {
1617 SkASSERT(fVerb == SkPath::kCubic_Verb);
1618 SkDPoint ctrl[2];
1619 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
caryclark1049f122015-04-20 08:31:59 -07001620 edge->fPts[1] = ctrl[0].asSkPoint();
1621 edge->fPts[2] = ctrl[1].asSkPoint();
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001622 }
1623 return true;
1624}
1625
caryclark54359292015-03-26 07:52:43 -07001626bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001627 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001628 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001629 const SkOpPtT& startPtT = *start->ptT();
1630 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001631 SkDEBUGCODE(edge->fVerb = fVerb);
1632 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001633 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001634 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001635 if (fVerb == SkPath::kLine_Verb) {
1636 return false;
1637 }
caryclark54359292015-03-26 07:52:43 -07001638 double startT = startPtT.fT;
1639 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001640 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1641 // don't compute midpoints if we already have them
1642 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001643 edge->fLine[1].set(fPts[1]);
1644 return false;
1645 }
1646 if (fVerb == SkPath::kConic_Verb) {
1647 edge->fConic[1].set(fPts[1]);
1648 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001649 return false;
1650 }
1651 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001652 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001653 edge->fCubic[1].set(fPts[1]);
1654 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001655 return false;
1656 }
caryclark1049f122015-04-20 08:31:59 -07001657 edge->fCubic[1].set(fPts[2]);
1658 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001659 return false;
1660 }
1661 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001662 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1663 } else if (fVerb == SkPath::kConic_Verb) {
1664 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1665 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001666 } else {
1667 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001668 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001669 }
1670 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001671}
1672
caryclark27c8eb82015-07-06 11:38:33 -07001673bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
1674 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp,
1675 SkScalar flatnessLimit) const {
1676 // average t, find mid pt
1677 double midT = (prior->t() + spanBase->t()) / 2;
1678 SkPoint midPt = this->ptAtT(midT);
1679 bool coincident = true;
1680 // if the mid pt is not near either end pt, project perpendicular through opp seg
1681 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1682 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
1683 coincident = false;
1684 SkIntersections i;
1685 SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->weight(), midT);
1686 SkDLine ray = {{{midPt.fX, midPt.fY}, {midPt.fX + dxdy.fY, midPt.fY - dxdy.fX}}};
1687 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), ray, &i);
1688 // measure distance and see if it's small enough to denote coincidence
1689 for (int index = 0; index < i.used(); ++index) {
1690 SkDPoint oppPt = i.pt(index);
1691 if (oppPt.approximatelyEqual(midPt)) {
1692 SkVector oppDxdy = (*CurveSlopeAtT[opp->verb()])(opp->pts(),
1693 opp->weight(), i[index][0]);
1694 oppDxdy.normalize();
1695 dxdy.normalize();
1696 SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy) / FLT_EPSILON);
1697 coincident |= flatness < flatnessLimit;
1698 }
1699 }
1700 }
1701 return coincident;
1702}
1703
caryclark54359292015-03-26 07:52:43 -07001704void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
1705 SkOpSpan* span = this->head();
1706 do {
1707 if (!span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001708 break;
1709 }
caryclark54359292015-03-26 07:52:43 -07001710 } while ((span = span->next()->upCastable()));
1711 SkASSERT(span);
1712 *start = span;
1713 *end = span->next();
reed0dc4dd62015-03-24 13:55:33 -07001714}
1715
caryclark54359292015-03-26 07:52:43 -07001716int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1717 const SkOpSpan* lesser = start->starter(end);
1718 int oppWinding = lesser->oppSum();
1719 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001720 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1721 && oppWinding != SK_MaxS32) {
1722 oppWinding -= oppSpanWinding;
1723 }
1724 return oppWinding;
1725}
1726
1727int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001728 const SkOpSpanBase* startSpan = angle->start();
1729 const SkOpSpanBase* endSpan = angle->end();
1730 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001731}
1732
1733int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001734 const SkOpSpanBase* startSpan = angle->start();
1735 const SkOpSpanBase* endSpan = angle->end();
1736 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001737}
1738
caryclark624637c2015-05-11 07:21:27 -07001739int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1740 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001741 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001742 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001743 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001744 }
1745 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001746 return winding;
1747 }
caryclark54359292015-03-26 07:52:43 -07001748 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001749 if (winding && UseInnerWinding(winding - spanWinding, winding)
1750 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001751 winding -= spanWinding;
1752 }
1753 return winding;
1754}
1755
caryclark624637c2015-05-11 07:21:27 -07001756int SkOpSegment::updateWinding(SkOpAngle* angle) {
1757 SkOpSpanBase* startSpan = angle->start();
1758 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001759 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001760}
1761
caryclark624637c2015-05-11 07:21:27 -07001762int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1763 SkOpSpanBase* startSpan = angle->start();
1764 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001765 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001766}
1767
1768// OPTIMIZATION: does the following also work, and is it any faster?
1769// return outerWinding * innerWinding > 0
1770// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1771bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1772 SkASSERT(outerWinding != SK_MaxS32);
1773 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001774 int absOut = SkTAbs(outerWinding);
1775 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001776 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1777 return result;
1778}
1779
caryclark@google.com07393ca2013-04-08 11:47:37 +00001780int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001781 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1782 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001783}