blob: 3b81cf2eed1384fc64f71190a66d96b04bed8aae [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();
365 SkOpSpan* span = insert(prev, allocator);
366 span->init(this, prev, t, pt);
367 this->debugValidate();
368#if DEBUG_ADD_T
369 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
370 span->segment()->debugID(), span->debugID());
371#endif
caryclark08bc8482015-04-24 09:08:57 -0700372 span->bumpSpanAdds();
caryclark54359292015-03-26 07:52:43 -0700373 return span->ptT();
374 }
375 SkASSERT(span != &fTail);
376 } while ((span = span->upCast()->next()));
377 SkASSERT(0);
halcanary96fcdcc2015-08-27 07:41:13 -0700378 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700379}
380
381// choose a solitary t and pt value; remove aliases; align the opposite ends
382void SkOpSegment::align() {
383 debugValidate();
384 SkOpSpanBase* span = &fHead;
385 if (!span->aligned()) {
386 span->alignEnd(0, fPts[0]);
387 }
388 while ((span = span->upCast()->next())) {
389 if (span == &fTail) {
390 break;
391 }
392 span->align();
393 }
394 if (!span->aligned()) {
395 span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]);
reed0dc4dd62015-03-24 13:55:33 -0700396 }
caryclarkbca19f72015-05-13 08:23:48 -0700397 if (this->collapsed()) {
398 SkOpSpan* span = &fHead;
399 do {
400 span->setWindValue(0);
401 span->setOppValue(0);
402 this->markDone(span);
403 } while ((span = span->next()->upCastable()));
404 }
reed0dc4dd62015-03-24 13:55:33 -0700405 debugValidate();
406}
407
caryclark54359292015-03-26 07:52:43 -0700408void SkOpSegment::calcAngles(SkChunkAlloc* allocator) {
409 bool activePrior = !fHead.isCanceled();
410 if (activePrior && !fHead.simple()) {
411 addStartSpan(allocator);
reed0dc4dd62015-03-24 13:55:33 -0700412 }
caryclark54359292015-03-26 07:52:43 -0700413 SkOpSpan* prior = &fHead;
414 SkOpSpanBase* spanBase = fHead.next();
415 while (spanBase != &fTail) {
416 if (activePrior) {
417 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
418 priorAngle->set(spanBase, prior);
419 spanBase->setFromAngle(priorAngle);
reed0dc4dd62015-03-24 13:55:33 -0700420 }
caryclark54359292015-03-26 07:52:43 -0700421 SkOpSpan* span = spanBase->upCast();
422 bool active = !span->isCanceled();
423 SkOpSpanBase* next = span->next();
424 if (active) {
425 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
426 angle->set(span, next);
427 span->setToAngle(angle);
reed0dc4dd62015-03-24 13:55:33 -0700428 }
reed0dc4dd62015-03-24 13:55:33 -0700429 activePrior = active;
caryclark54359292015-03-26 07:52:43 -0700430 prior = span;
431 spanBase = next;
reed0dc4dd62015-03-24 13:55:33 -0700432 }
caryclark54359292015-03-26 07:52:43 -0700433 if (activePrior && !fTail.simple()) {
434 addEndSpan(allocator);
reed0dc4dd62015-03-24 13:55:33 -0700435 }
reed0dc4dd62015-03-24 13:55:33 -0700436}
437
caryclarkbca19f72015-05-13 08:23:48 -0700438bool SkOpSegment::collapsed() const {
439 return fVerb == SkPath::kLine_Verb && fHead.pt() == fTail.pt();
440}
441
caryclark@google.com570863f2013-09-16 15:55:01 +0000442void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
443 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700444 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000445 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
446 int sumSuWinding;
447 bool binary = includeType >= SkOpAngle::kBinarySingle;
448 if (binary) {
449 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
450 if (baseSegment->operand()) {
451 SkTSwap<int>(sumMiWinding, sumSuWinding);
452 }
453 }
454 SkOpSegment* nextSegment = nextAngle->segment();
455 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700456 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000457 if (binary) {
458 int oppMaxWinding, oppSumWinding;
459 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
460 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
461 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000462 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000463 } else {
464 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
465 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000466 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000467 }
468 nextAngle->setLastMarked(last);
469}
470
caryclark624637c2015-05-11 07:21:27 -0700471void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
caryclark@google.com570863f2013-09-16 15:55:01 +0000472 SkOpAngle::IncludeType includeType) {
caryclark624637c2015-05-11 07:21:27 -0700473 SkOpSegment* baseSegment = baseAngle->segment();
caryclark@google.com570863f2013-09-16 15:55:01 +0000474 int sumMiWinding = baseSegment->updateWinding(baseAngle);
475 int sumSuWinding;
476 bool binary = includeType >= SkOpAngle::kBinarySingle;
477 if (binary) {
478 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
479 if (baseSegment->operand()) {
480 SkTSwap<int>(sumMiWinding, sumSuWinding);
481 }
482 }
483 SkOpSegment* nextSegment = nextAngle->segment();
484 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700485 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000486 if (binary) {
487 int oppMaxWinding, oppSumWinding;
488 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
489 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
490 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000491 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000492 } else {
493 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
494 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000495 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000496 }
497 nextAngle->setLastMarked(last);
498}
499
caryclark54359292015-03-26 07:52:43 -0700500// at this point, the span is already ordered, or unorderable
501int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
502 SkOpAngle::IncludeType includeType) {
503 SkASSERT(includeType != SkOpAngle::kUnaryXor);
504 SkOpAngle* firstAngle = this->spanToAngle(end, start);
halcanary96fcdcc2015-08-27 07:41:13 -0700505 if (nullptr == firstAngle || nullptr == firstAngle->next()) {
caryclark54359292015-03-26 07:52:43 -0700506 return SK_NaN32;
507 }
508 // if all angles have a computed winding,
509 // or if no adjacent angles are orderable,
510 // or if adjacent orderable angles have no computed winding,
511 // there's nothing to do
512 // if two orderable angles are adjacent, and both are next to orderable angles,
513 // and one has winding computed, transfer to the other
halcanary96fcdcc2015-08-27 07:41:13 -0700514 SkOpAngle* baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700515 bool tryReverse = false;
516 // look for counterclockwise transfers
517 SkOpAngle* angle = firstAngle->previous();
518 SkOpAngle* next = angle->next();
519 firstAngle = next;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000520 do {
caryclark54359292015-03-26 07:52:43 -0700521 SkOpAngle* prior = angle;
522 angle = next;
523 next = angle->next();
524 SkASSERT(prior->next() == angle);
525 SkASSERT(angle->next() == next);
526 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700527 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700528 continue;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000529 }
caryclark54359292015-03-26 07:52:43 -0700530 int testWinding = angle->starter()->windSum();
531 if (SK_MinS32 != testWinding) {
532 baseAngle = angle;
533 tryReverse = true;
534 continue;
reed0dc4dd62015-03-24 13:55:33 -0700535 }
caryclark54359292015-03-26 07:52:43 -0700536 if (baseAngle) {
537 ComputeOneSum(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700538 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
caryclark54359292015-03-26 07:52:43 -0700539 }
540 } while (next != firstAngle);
541 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
542 firstAngle = baseAngle;
543 tryReverse = true;
544 }
545 if (tryReverse) {
halcanary96fcdcc2015-08-27 07:41:13 -0700546 baseAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700547 SkOpAngle* prior = firstAngle;
548 do {
549 angle = prior;
550 prior = angle->previous();
551 SkASSERT(prior->next() == angle);
552 next = angle->next();
553 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700554 baseAngle = nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700555 continue;
556 }
caryclark54359292015-03-26 07:52:43 -0700557 int testWinding = angle->starter()->windSum();
558 if (SK_MinS32 != testWinding) {
559 baseAngle = angle;
560 continue;
reed0dc4dd62015-03-24 13:55:33 -0700561 }
caryclark54359292015-03-26 07:52:43 -0700562 if (baseAngle) {
563 ComputeOneSumReverse(baseAngle, angle, includeType);
halcanary96fcdcc2015-08-27 07:41:13 -0700564 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
reed0dc4dd62015-03-24 13:55:33 -0700565 }
caryclark54359292015-03-26 07:52:43 -0700566 } while (prior != firstAngle);
reed0dc4dd62015-03-24 13:55:33 -0700567 }
caryclark54359292015-03-26 07:52:43 -0700568 return start->starter(end)->windSum();
reed0dc4dd62015-03-24 13:55:33 -0700569}
570
caryclark54359292015-03-26 07:52:43 -0700571void SkOpSegment::detach(const SkOpSpan* span) {
572 if (span->done()) {
caryclark08bc8482015-04-24 09:08:57 -0700573 --fDoneCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000574 }
caryclark08bc8482015-04-24 09:08:57 -0700575 --fCount;
576 SkASSERT(fCount >= fDoneCount);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000577}
578
caryclark26ad22a2015-10-16 09:03:38 -0700579double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
caryclark54359292015-03-26 07:52:43 -0700580 SkDPoint testPt = this->dPtAtT(t);
581 SkDLine testPerp = {{ testPt, testPt }};
582 SkDVector slope = this->dSlopeAtT(t);
583 testPerp[1].fX += slope.fY;
584 testPerp[1].fY -= slope.fX;
585 SkIntersections i;
caryclark26ad22a2015-10-16 09:03:38 -0700586 const SkOpSegment* oppSegment = oppAngle->segment();
caryclark1049f122015-04-20 08:31:59 -0700587 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
caryclark54359292015-03-26 07:52:43 -0700588 double closestDistSq = SK_ScalarInfinity;
589 for (int index = 0; index < i.used(); ++index) {
590 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000591 continue;
592 }
caryclark54359292015-03-26 07:52:43 -0700593 double testDistSq = testPt.distanceSquared(i.pt(index));
594 if (closestDistSq > testDistSq) {
595 closestDistSq = testDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000596 }
597 }
caryclark54359292015-03-26 07:52:43 -0700598 return closestDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000599}
600
caryclarkd4349722015-07-23 12:40:22 -0700601void SkOpSegment::findCollapsed() {
602 if (fHead.contains(&fTail)) {
603 markAllDone();
604 // move start and end to the same point
605 fHead.alignEnd(0, fHead.pt());
606 fTail.setAligned();
607 }
608}
609
caryclark@google.com07393ca2013-04-08 11:47:37 +0000610/*
611 The M and S variable name parts stand for the operators.
612 Mi stands for Minuend (see wiki subtraction, analogous to difference)
613 Su stands for Subtrahend
614 The Opp variable name part designates that the value is for the Opposite operator.
615 Opposite values result from combining coincident spans.
616 */
caryclark54359292015-03-26 07:52:43 -0700617SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
618 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) {
619 SkOpSpanBase* start = *nextStart;
620 SkOpSpanBase* end = *nextEnd;
621 SkASSERT(start != end);
622 int step = start->step(end);
623 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
624 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000625 // mark the smaller of startIndex, endIndex done, and all adjacent
626 // spans with the same T value (but not 'other' spans)
627#if DEBUG_WINDING
628 SkDebugf("%s simple\n", __FUNCTION__);
629#endif
caryclark54359292015-03-26 07:52:43 -0700630 SkOpSpan* startSpan = start->starter(end);
631 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700632 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000633 }
caryclark54359292015-03-26 07:52:43 -0700634 markDone(startSpan);
635 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000636 return other;
637 }
caryclark54359292015-03-26 07:52:43 -0700638 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
639 SkASSERT(endNear == end); // is this ever not end?
640 SkASSERT(endNear);
641 SkASSERT(start != endNear);
642 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000643 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700644 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
caryclark@google.com570863f2013-09-16 15:55:01 +0000645 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000646 if (!sortable) {
647 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700648 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700649 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000650 }
caryclark54359292015-03-26 07:52:43 -0700651 SkOpAngle* angle = this->spanToAngle(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000652 if (angle->unorderable()) {
653 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700654 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700655 return nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000656 }
657#if DEBUG_SORT
658 SkDebugf("%s\n", __FUNCTION__);
659 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000660#endif
caryclark54359292015-03-26 07:52:43 -0700661 int sumMiWinding = updateWinding(end, start);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000662 if (sumMiWinding == SK_MinS32) {
663 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700664 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700665 return nullptr;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000666 }
caryclark54359292015-03-26 07:52:43 -0700667 int sumSuWinding = updateOppWinding(end, start);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000668 if (operand()) {
669 SkTSwap<int>(sumMiWinding, sumSuWinding);
670 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000671 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700672 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000673 bool foundDone = false;
674 // iterate through the angle, and compute everyone's winding
675 SkOpSegment* nextSegment;
676 int activeCount = 0;
677 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000678 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000679 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000680 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000681 if (activeAngle) {
682 ++activeCount;
683 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000684 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +0000685 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000686 }
687 }
688 if (nextSegment->done()) {
689 continue;
690 }
reed0dc4dd62015-03-24 13:55:33 -0700691 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700692 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700693 }
caryclark54359292015-03-26 07:52:43 -0700694 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000695 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000696 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000697 *chase->append() = last;
698#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700699 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
700 last->segment()->debugID(), last->debugID());
701 if (!last->final()) {
702 SkDebugf(" windSum=%d", last->upCast()->windSum());
703 }
704 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000705#endif
706 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000707 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700708 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000709 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700710 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000711 }
712 *nextStart = foundAngle->start();
713 *nextEnd = foundAngle->end();
714 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000715#if DEBUG_WINDING
716 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
717 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
718 #endif
719 return nextSegment;
720}
721
caryclark54359292015-03-26 07:52:43 -0700722SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
723 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
724 SkOpSpanBase* start = *nextStart;
725 SkOpSpanBase* end = *nextEnd;
726 SkASSERT(start != end);
727 int step = start->step(end);
728 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
729 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000730 // mark the smaller of startIndex, endIndex done, and all adjacent
731 // spans with the same T value (but not 'other' spans)
732#if DEBUG_WINDING
733 SkDebugf("%s simple\n", __FUNCTION__);
734#endif
caryclark54359292015-03-26 07:52:43 -0700735 SkOpSpan* startSpan = start->starter(end);
736 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700737 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000738 }
caryclark54359292015-03-26 07:52:43 -0700739 markDone(startSpan);
740 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000741 return other;
742 }
caryclark54359292015-03-26 07:52:43 -0700743 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
744 SkASSERT(endNear == end); // is this ever not end?
745 SkASSERT(endNear);
746 SkASSERT(start != endNear);
747 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000748 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700749 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000750 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000751 if (!sortable) {
752 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700753 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700754 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000755 }
caryclark54359292015-03-26 07:52:43 -0700756 SkOpAngle* angle = this->spanToAngle(end, start);
757 if (angle->unorderable()) {
758 *unsortable = true;
759 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700760 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700761 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000762#if DEBUG_SORT
763 SkDebugf("%s\n", __FUNCTION__);
764 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000765#endif
caryclark54359292015-03-26 07:52:43 -0700766 int sumWinding = updateWinding(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000767 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700768 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000769 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700770 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000771 SkOpSegment* nextSegment;
772 int activeCount = 0;
773 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000774 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000775 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000776 &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000777 if (activeAngle) {
778 ++activeCount;
779 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000780 foundAngle = nextAngle;
781 foundDone = nextSegment->done(nextAngle);
782 }
783 }
784 if (nextSegment->done()) {
785 continue;
786 }
reed0dc4dd62015-03-24 13:55:33 -0700787 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700788 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700789 }
caryclark54359292015-03-26 07:52:43 -0700790 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000791 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000792 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000793 *chase->append() = last;
794#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700795 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
796 last->segment()->debugID(), last->debugID());
797 if (!last->final()) {
798 SkDebugf(" windSum=%d", last->upCast()->windSum());
799 }
800 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000801#endif
802 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000803 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700804 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000805 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700806 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000807 }
808 *nextStart = foundAngle->start();
809 *nextEnd = foundAngle->end();
810 nextSegment = foundAngle->segment();
811#if DEBUG_WINDING
812 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
813 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
814 #endif
815 return nextSegment;
816}
817
caryclark54359292015-03-26 07:52:43 -0700818SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
819 bool* unsortable) {
820 SkOpSpanBase* start = *nextStart;
821 SkOpSpanBase* end = *nextEnd;
822 SkASSERT(start != end);
823 int step = start->step(end);
824 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
825 if (other) {
826 // mark the smaller of startIndex, endIndex done, and all adjacent
827 // spans with the same T value (but not 'other' spans)
caryclark@google.com07393ca2013-04-08 11:47:37 +0000828#if DEBUG_WINDING
829 SkDebugf("%s simple\n", __FUNCTION__);
830#endif
caryclark54359292015-03-26 07:52:43 -0700831 SkOpSpan* startSpan = start->starter(end);
832 if (startSpan->done()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700833 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000834 }
caryclark54359292015-03-26 07:52:43 -0700835 markDone(startSpan);
836 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000837 return other;
838 }
caryclark54359292015-03-26 07:52:43 -0700839 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
840 : (*nextStart)->prev());
841 SkASSERT(endNear == end); // is this ever not end?
842 SkASSERT(endNear);
843 SkASSERT(start != endNear);
844 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
845 SkOpAngle* angle = this->spanToAngle(end, start);
caryclark27c8eb82015-07-06 11:38:33 -0700846 if (!angle || angle->unorderable()) {
caryclark54359292015-03-26 07:52:43 -0700847 *unsortable = true;
848 markDone(start->starter(end));
halcanary96fcdcc2015-08-27 07:41:13 -0700849 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700850 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000851#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000852 SkDebugf("%s\n", __FUNCTION__);
853 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000854#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000855 SkOpAngle* nextAngle = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -0700856 const SkOpAngle* foundAngle = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000857 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700858 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000859 SkOpSegment* nextSegment;
860 int activeCount = 0;
861 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000862 nextSegment = nextAngle->segment();
863 ++activeCount;
864 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000865 foundAngle = nextAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000866 if (!(foundDone = nextSegment->done(nextAngle))) {
867 break;
868 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000869 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000870 nextAngle = nextAngle->next();
871 } while (nextAngle != angle);
caryclark54359292015-03-26 07:52:43 -0700872 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000873 if (!foundAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -0700874 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000875 }
876 *nextStart = foundAngle->start();
877 *nextEnd = foundAngle->end();
878 nextSegment = foundAngle->segment();
879#if DEBUG_WINDING
880 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
881 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
882 #endif
883 return nextSegment;
884}
885
caryclark54359292015-03-26 07:52:43 -0700886SkOpGlobalState* SkOpSegment::globalState() const {
887 return contour()->globalState();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000888}
889
caryclark1049f122015-04-20 08:31:59 -0700890void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
caryclark54359292015-03-26 07:52:43 -0700891 fContour = contour;
halcanary96fcdcc2015-08-27 07:41:13 -0700892 fNext = nullptr;
caryclark27c8eb82015-07-06 11:38:33 -0700893 fOriginal[0] = pts[0];
894 fOriginal[1] = pts[SkPathOpsVerbToPoints(verb)];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000895 fPts = pts;
caryclark1049f122015-04-20 08:31:59 -0700896 fWeight = weight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000897 fVerb = verb;
caryclark54359292015-03-26 07:52:43 -0700898 fCount = 0;
899 fDoneCount = 0;
900 fVisited = false;
901 SkOpSpan* zeroSpan = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700902 zeroSpan->init(this, nullptr, 0, fPts[0]);
caryclark54359292015-03-26 07:52:43 -0700903 SkOpSpanBase* oneSpan = &fTail;
904 zeroSpan->setNext(oneSpan);
905 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
caryclark1049f122015-04-20 08:31:59 -0700906 SkDEBUGCODE(fID = globalState()->nextSegmentID());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000907}
908
caryclark54359292015-03-26 07:52:43 -0700909bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
910 SkDPoint cPt = this->dPtAtT(t);
caryclark1049f122015-04-20 08:31:59 -0700911 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
caryclark54359292015-03-26 07:52:43 -0700912 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
913 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -0700914 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
caryclark54359292015-03-26 07:52:43 -0700915 int used = i.used();
916 for (int index = 0; index < used; ++index) {
917 if (cPt.roughlyEqual(i.pt(index))) {
reed0dc4dd62015-03-24 13:55:33 -0700918 return true;
919 }
caryclark54359292015-03-26 07:52:43 -0700920 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000921 return false;
922}
923
caryclark54359292015-03-26 07:52:43 -0700924bool SkOpSegment::isXor() const {
925 return fContour->isXor();
926}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000927
caryclark5b5ddd72015-05-18 05:12:56 -0700928void SkOpSegment::markAllDone() {
929 SkOpSpan* span = this->head();
930 do {
931 this->markDone(span);
932 } while ((span = span->next()->upCastable()));
933}
934
caryclark54359292015-03-26 07:52:43 -0700935SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) {
936 int step = start->step(end);
937 SkOpSpan* minSpan = start->starter(end);
938 markDone(minSpan);
halcanary96fcdcc2015-08-27 07:41:13 -0700939 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000940 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700941 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000942 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -0700943 SkASSERT(!last);
944 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000945 }
caryclark54359292015-03-26 07:52:43 -0700946 other->markDone(minSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000947 }
948 return last;
949}
950
caryclark54359292015-03-26 07:52:43 -0700951bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
952 SkOpSpanBase** lastPtr) {
953 SkOpSpan* spanStart = start->starter(end);
954 int step = start->step(end);
955 bool success = markWinding(spanStart, winding);
halcanary96fcdcc2015-08-27 07:41:13 -0700956 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000957 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700958 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
959 if (spanStart->windSum() != SK_MinS32) {
960 SkASSERT(spanStart->windSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700961 SkASSERT(!last);
962 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000963 }
caryclark54359292015-03-26 07:52:43 -0700964 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000965 }
caryclark65f55312014-11-13 06:58:52 -0800966 if (lastPtr) {
967 *lastPtr = last;
968 }
969 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000970}
971
caryclark54359292015-03-26 07:52:43 -0700972bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
973 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
974 SkOpSpan* spanStart = start->starter(end);
975 int step = start->step(end);
976 bool success = markWinding(spanStart, winding, oppWinding);
halcanary96fcdcc2015-08-27 07:41:13 -0700977 SkOpSpanBase* last = nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000978 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -0700979 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
980 if (spanStart->windSum() != SK_MinS32) {
981 if (this->operand() == other->operand()) {
caryclark624637c2015-05-11 07:21:27 -0700982 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
caryclark54359292015-03-26 07:52:43 -0700983 this->globalState()->setWindingFailed();
984 return false;
caryclarkdac1d172014-06-17 05:15:38 -0700985 }
caryclark54359292015-03-26 07:52:43 -0700986 } else {
987 SkASSERT(spanStart->windSum() == oppWinding);
988 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -0700989 }
990 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -0700991 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000992 }
caryclark54359292015-03-26 07:52:43 -0700993 if (this->operand() == other->operand()) {
994 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -0700995 } else {
caryclark54359292015-03-26 07:52:43 -0700996 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -0700997 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000998 }
caryclark65f55312014-11-13 06:58:52 -0800999 if (lastPtr) {
1000 *lastPtr = last;
1001 }
1002 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001003}
1004
caryclark54359292015-03-26 07:52:43 -07001005SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001006 SkASSERT(angle->segment() == this);
1007 if (UseInnerWinding(maxWinding, sumWinding)) {
1008 maxWinding = sumWinding;
1009 }
caryclark54359292015-03-26 07:52:43 -07001010 SkOpSpanBase* last;
1011 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +00001012#if DEBUG_WINDING
1013 if (last) {
caryclark54359292015-03-26 07:52:43 -07001014 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
1015 last->segment()->debugID(), last->debugID());
1016 if (!last->final()) {
1017 SkDebugf(" windSum=");
1018 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
1019 }
1020 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +00001021 }
1022#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00001023 return last;
1024}
1025
caryclark54359292015-03-26 07:52:43 -07001026SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
1027 int oppSumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001028 SkASSERT(angle->segment() == this);
1029 if (UseInnerWinding(maxWinding, sumWinding)) {
1030 maxWinding = sumWinding;
1031 }
1032 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
1033 oppMaxWinding = oppSumWinding;
1034 }
halcanary96fcdcc2015-08-27 07:41:13 -07001035 SkOpSpanBase* last = nullptr;
caryclark65f55312014-11-13 06:58:52 -08001036 // caller doesn't require that this marks anything
caryclark54359292015-03-26 07:52:43 -07001037 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +00001038#if DEBUG_WINDING
1039 if (last) {
caryclark54359292015-03-26 07:52:43 -07001040 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
1041 last->segment()->debugID(), last->debugID());
1042 if (!last->final()) {
1043 SkDebugf(" windSum=");
1044 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
1045 }
1046 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +00001047 }
1048#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00001049 return last;
1050}
1051
caryclark54359292015-03-26 07:52:43 -07001052void SkOpSegment::markDone(SkOpSpan* span) {
1053 SkASSERT(this == span->segment());
1054 if (span->done()) {
1055 return;
1056 }
1057#if DEBUG_MARK_DONE
1058 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
1059#endif
1060 span->setDone(true);
1061 ++fDoneCount;
1062 debugValidate();
1063}
1064
1065bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
1066 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -07001067 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -07001068 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001069 return false;
1070 }
1071#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -07001072 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -07001073#endif
caryclark54359292015-03-26 07:52:43 -07001074 span->setWindSum(winding);
1075 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001076 return true;
1077}
1078
caryclark54359292015-03-26 07:52:43 -07001079bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
1080 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +00001081 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -07001082 if (span->done()) {
1083 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001084 }
caryclark54359292015-03-26 07:52:43 -07001085#if DEBUG_MARK_DONE
1086 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1087#endif
1088 span->setWindSum(winding);
1089 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001090 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001091 return true;
1092}
1093
caryclark54359292015-03-26 07:52:43 -07001094bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
1095 const SkPoint& testPt) const {
1096 const SkOpSegment* baseParent = base->segment();
1097 if (this == baseParent && this == testParent && precisely_equal(base->fT, testT)) {
1098 return true;
1099 }
1100 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1101 return false;
1102 }
caryclark08bc8482015-04-24 09:08:57 -07001103 return !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
caryclark54359292015-03-26 07:52:43 -07001104}
1105
1106static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1107 if (last) {
1108 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001109 }
halcanary96fcdcc2015-08-27 07:41:13 -07001110 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001111}
1112
caryclark54359292015-03-26 07:52:43 -07001113SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1114 SkOpSpanBase** last) const {
1115 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001116 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001117 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1118 SkASSERT(endSpan);
1119 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1120 SkOpSpanBase* foundSpan;
1121 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001122 SkOpSegment* other;
halcanary96fcdcc2015-08-27 07:41:13 -07001123 if (angle == nullptr) {
caryclark54359292015-03-26 07:52:43 -07001124 if (endSpan->t() != 0 && endSpan->t() != 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001125 return nullptr;
caryclarkdac1d172014-06-17 05:15:38 -07001126 }
caryclark54359292015-03-26 07:52:43 -07001127 SkOpPtT* otherPtT = endSpan->ptT()->next();
1128 other = otherPtT->segment();
1129 foundSpan = otherPtT->span();
1130 otherEnd = step > 0 ? foundSpan->upCast()->next() : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001131 } else {
1132 int loopCount = angle->loopCount();
1133 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001134 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001135 }
1136 const SkOpAngle* next = angle->next();
halcanary96fcdcc2015-08-27 07:41:13 -07001137 if (nullptr == next) {
1138 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001139 }
caryclarkdac1d172014-06-17 05:15:38 -07001140#if DEBUG_WINDING
caryclark624637c2015-05-11 07:21:27 -07001141 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
caryclark54359292015-03-26 07:52:43 -07001142 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001143 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001144 }
caryclark54359292015-03-26 07:52:43 -07001145#endif
caryclarkdac1d172014-06-17 05:15:38 -07001146 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001147 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001148 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001149 }
caryclark54359292015-03-26 07:52:43 -07001150 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001151 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001152 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001153 }
caryclark54359292015-03-26 07:52:43 -07001154 SkASSERT(*startPtr);
1155 if (!otherEnd) {
halcanary96fcdcc2015-08-27 07:41:13 -07001156 return nullptr;
caryclark65b427c2014-09-18 10:32:57 -07001157 }
1158// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001159 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1160 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1161 if (foundMin->windValue() != origMin->windValue()
1162 || foundMin->oppValue() != origMin->oppValue()) {
1163 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001164 }
caryclark54359292015-03-26 07:52:43 -07001165 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001166 *stepPtr = foundStep;
1167 if (minPtr) {
1168 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001169 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001170 return other;
1171}
1172
caryclarkbca19f72015-05-13 08:23:48 -07001173static void clear_visited(SkOpSpanBase* span) {
caryclark54359292015-03-26 07:52:43 -07001174 // reset visited flag back to false
1175 do {
1176 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1177 while ((ptT = ptT->next()) != stopPtT) {
1178 SkOpSegment* opp = ptT->segment();
1179 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001180 }
caryclarkbca19f72015-05-13 08:23:48 -07001181 } while (!span->final() && (span = span->upCast()->next()));
reed0dc4dd62015-03-24 13:55:33 -07001182}
1183
caryclark54359292015-03-26 07:52:43 -07001184// look for pairs of undetected coincident curves
1185// assumes that segments going in have visited flag clear
1186// curve/curve intersection should now do a pretty good job of finding coincident runs so
1187// this may be only be necessary for line/curve pairs -- so skip unless this is a line and the
1188// the opp is not a line
caryclark27c8eb82015-07-06 11:38:33 -07001189bool SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) {
caryclark54359292015-03-26 07:52:43 -07001190 if (this->verb() != SkPath::kLine_Verb) {
caryclark27c8eb82015-07-06 11:38:33 -07001191 return false;
caryclark54359292015-03-26 07:52:43 -07001192 }
caryclarkbca19f72015-05-13 08:23:48 -07001193 if (this->done()) {
caryclark27c8eb82015-07-06 11:38:33 -07001194 return false;
caryclarkbca19f72015-05-13 08:23:48 -07001195 }
halcanary96fcdcc2015-08-27 07:41:13 -07001196 SkOpSpan* prior = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001197 SkOpSpanBase* spanBase = &fHead;
caryclark54359292015-03-26 07:52:43 -07001198 do {
caryclarkbca19f72015-05-13 08:23:48 -07001199 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
1200 SkASSERT(ptT->span() == spanBase);
caryclark54359292015-03-26 07:52:43 -07001201 while ((ptT = ptT->next()) != spanStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001202 if (ptT->deleted()) {
1203 continue;
1204 }
caryclark54359292015-03-26 07:52:43 -07001205 SkOpSegment* opp = ptT->span()->segment();
caryclark26ad22a2015-10-16 09:03:38 -07001206// if (opp->verb() == SkPath::kLine_Verb) {
1207// continue;
1208// }
caryclarkbca19f72015-05-13 08:23:48 -07001209 if (opp->done()) {
caryclark54359292015-03-26 07:52:43 -07001210 continue;
reed0dc4dd62015-03-24 13:55:33 -07001211 }
caryclarkbca19f72015-05-13 08:23:48 -07001212 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1213 if (!opp->visited()) {
1214 continue;
1215 }
1216 if (spanBase == &fHead) {
1217 continue;
1218 }
1219 SkOpSpan* span = spanBase->upCastable();
1220 // FIXME?: this assumes that if the opposite segment is coincident then no more
1221 // coincidence needs to be detected. This may not be true.
1222 if (span && span->containsCoincidence(opp)) {
1223 continue;
1224 }
caryclark26ad22a2015-10-16 09:03:38 -07001225 if (spanBase->segment() == opp) {
1226 continue;
1227 }
caryclarkbca19f72015-05-13 08:23:48 -07001228 if (spanBase->containsCoinEnd(opp)) {
caryclark54359292015-03-26 07:52:43 -07001229 continue;
1230 }
halcanary96fcdcc2015-08-27 07:41:13 -07001231 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
caryclark54359292015-03-26 07:52:43 -07001232 // find prior span containing opp segment
halcanary96fcdcc2015-08-27 07:41:13 -07001233 SkOpSegment* priorOpp = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -07001234 SkOpSpan* priorTest = spanBase->prev();
1235 while (!priorOpp && priorTest) {
1236 priorStopPtT = priorPtT = priorTest->ptT();
caryclark54359292015-03-26 07:52:43 -07001237 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
caryclark182b4992015-05-14 05:45:54 -07001238 if (priorPtT->deleted()) {
1239 continue;
1240 }
caryclark54359292015-03-26 07:52:43 -07001241 SkOpSegment* segment = priorPtT->span()->segment();
1242 if (segment == opp) {
caryclarkbca19f72015-05-13 08:23:48 -07001243 prior = priorTest;
caryclark54359292015-03-26 07:52:43 -07001244 priorOpp = opp;
1245 break;
1246 }
1247 }
caryclarkbca19f72015-05-13 08:23:48 -07001248 priorTest = priorTest->prev();
caryclark54359292015-03-26 07:52:43 -07001249 }
1250 if (!priorOpp) {
1251 continue;
1252 }
caryclark26ad22a2015-10-16 09:03:38 -07001253 if (priorPtT == ptT) {
1254 continue;
1255 }
caryclark54359292015-03-26 07:52:43 -07001256 SkOpPtT* oppStart = prior->ptT();
caryclarkbca19f72015-05-13 08:23:48 -07001257 SkOpPtT* oppEnd = spanBase->ptT();
caryclark54359292015-03-26 07:52:43 -07001258 bool swapped = priorPtT->fT > ptT->fT;
1259 if (swapped) {
1260 SkTSwap(priorPtT, ptT);
1261 SkTSwap(oppStart, oppEnd);
1262 }
1263 bool flipped = oppStart->fT > oppEnd->fT;
caryclark26ad22a2015-10-16 09:03:38 -07001264 bool coincident = false;
caryclark54359292015-03-26 07:52:43 -07001265 if (coincidences->contains(priorPtT, ptT, oppStart, oppEnd, flipped)) {
1266 goto swapBack;
1267 }
caryclark26ad22a2015-10-16 09:03:38 -07001268 if (opp->verb() == SkPath::kLine_Verb) {
1269 coincident = (SkDPoint::ApproximatelyEqual(priorPtT->fPt, oppStart->fPt) ||
1270 SkDPoint::ApproximatelyEqual(priorPtT->fPt, oppEnd->fPt)) &&
1271 (SkDPoint::ApproximatelyEqual(ptT->fPt, oppStart->fPt) ||
1272 SkDPoint::ApproximatelyEqual(ptT->fPt, oppEnd->fPt));
1273 }
1274 if (!coincident) {
1275 coincident = testForCoincidence(priorPtT, ptT, prior, spanBase, opp, 5000);
1276 }
caryclark54359292015-03-26 07:52:43 -07001277 if (coincident) {
1278 // mark coincidence
caryclark182b4992015-05-14 05:45:54 -07001279 if (!coincidences->extend(priorPtT, ptT, oppStart, oppEnd)
1280 && !coincidences->extend(oppStart, oppEnd, priorPtT, ptT)) {
caryclarkbca19f72015-05-13 08:23:48 -07001281 coincidences->add(priorPtT, ptT, oppStart, oppEnd, allocator);
1282 }
caryclark54359292015-03-26 07:52:43 -07001283 clear_visited(&fHead);
caryclark27c8eb82015-07-06 11:38:33 -07001284 return true;
caryclark54359292015-03-26 07:52:43 -07001285 }
1286 swapBack:
1287 if (swapped) {
1288 SkTSwap(priorPtT, ptT);
1289 }
reed0dc4dd62015-03-24 13:55:33 -07001290 }
halcanary96fcdcc2015-08-27 07:41:13 -07001291 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
caryclark54359292015-03-26 07:52:43 -07001292 clear_visited(&fHead);
caryclark27c8eb82015-07-06 11:38:33 -07001293 return false;
reed0dc4dd62015-03-24 13:55:33 -07001294}
1295
caryclark08bc8482015-04-24 09:08:57 -07001296// if a span has more than one intersection, merge the other segments' span as needed
1297void SkOpSegment::moveMultiples() {
1298 debugValidate();
1299 SkOpSpanBase* test = &fHead;
1300 do {
1301 int addCount = test->spanAddsCount();
1302 SkASSERT(addCount >= 1);
1303 if (addCount == 1) {
1304 continue;
1305 }
1306 SkOpPtT* startPtT = test->ptT();
1307 SkOpPtT* testPtT = startPtT;
1308 do { // iterate through all spans associated with start
1309 SkOpSpanBase* oppSpan = testPtT->span();
1310 if (oppSpan->spanAddsCount() == addCount) {
1311 continue;
1312 }
1313 if (oppSpan->deleted()) {
1314 continue;
1315 }
1316 SkOpSegment* oppSegment = oppSpan->segment();
1317 if (oppSegment == this) {
1318 continue;
1319 }
1320 // find range of spans to consider merging
1321 SkOpSpanBase* oppPrev = oppSpan;
1322 SkOpSpanBase* oppFirst = oppSpan;
1323 while ((oppPrev = oppPrev->prev())) {
1324 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1325 break;
1326 }
1327 if (oppPrev->spanAddsCount() == addCount) {
1328 continue;
1329 }
1330 if (oppPrev->deleted()) {
1331 continue;
1332 }
1333 oppFirst = oppPrev;
1334 }
1335 SkOpSpanBase* oppNext = oppSpan;
1336 SkOpSpanBase* oppLast = oppSpan;
halcanary96fcdcc2015-08-27 07:41:13 -07001337 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
caryclark08bc8482015-04-24 09:08:57 -07001338 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1339 break;
1340 }
1341 if (oppNext->spanAddsCount() == addCount) {
1342 continue;
1343 }
1344 if (oppNext->deleted()) {
1345 continue;
1346 }
1347 oppLast = oppNext;
1348 }
1349 if (oppFirst == oppLast) {
1350 continue;
1351 }
1352 SkOpSpanBase* oppTest = oppFirst;
1353 do {
1354 if (oppTest == oppSpan) {
1355 continue;
1356 }
1357 // check to see if the candidate meets specific criteria:
1358 // it contains spans of segments in test's loop but not including 'this'
1359 SkOpPtT* oppStartPtT = oppTest->ptT();
1360 SkOpPtT* oppPtT = oppStartPtT;
1361 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1362 SkOpSegment* oppPtTSegment = oppPtT->segment();
1363 if (oppPtTSegment == this) {
1364 goto tryNextSpan;
1365 }
1366 SkOpPtT* matchPtT = startPtT;
1367 do {
1368 if (matchPtT->segment() == oppPtTSegment) {
1369 goto foundMatch;
1370 }
1371 } while ((matchPtT = matchPtT->next()) != startPtT);
1372 goto tryNextSpan;
1373 foundMatch: // merge oppTest and oppSpan
1374 oppSegment->debugValidate();
1375 if (oppTest == &oppSegment->fTail || oppTest == &oppSegment->fHead) {
1376 SkASSERT(oppSpan != &oppSegment->fHead); // don't expect collapse
1377 SkASSERT(oppSpan != &oppSegment->fTail);
1378 oppTest->merge(oppSpan->upCast());
1379 } else {
1380 oppSpan->merge(oppTest->upCast());
1381 }
1382 oppSegment->debugValidate();
1383 goto checkNextSpan;
1384 }
1385 tryNextSpan:
1386 ;
1387 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1388 } while ((testPtT = testPtT->next()) != startPtT);
1389checkNextSpan:
1390 ;
halcanary96fcdcc2015-08-27 07:41:13 -07001391 } while ((test = test->final() ? nullptr : test->upCast()->next()));
caryclark08bc8482015-04-24 09:08:57 -07001392 debugValidate();
1393}
1394
caryclark54359292015-03-26 07:52:43 -07001395// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
caryclark08bc8482015-04-24 09:08:57 -07001396void SkOpSegment::moveNearby() {
caryclark54359292015-03-26 07:52:43 -07001397 debugValidate();
1398 SkOpSpanBase* spanS = &fHead;
1399 do {
1400 SkOpSpanBase* test = spanS->upCast()->next();
1401 SkOpSpanBase* next;
1402 if (spanS->contains(test)) {
1403 if (!test->final()) {
1404 test->upCast()->detach(spanS->ptT());
1405 continue;
1406 } else if (spanS != &fHead) {
1407 spanS->upCast()->detach(test->ptT());
1408 spanS = test;
1409 continue;
1410 }
reed0dc4dd62015-03-24 13:55:33 -07001411 }
caryclark54359292015-03-26 07:52:43 -07001412 do { // iterate through all spans associated with start
1413 SkOpPtT* startBase = spanS->ptT();
halcanary96fcdcc2015-08-27 07:41:13 -07001414 next = test->final() ? nullptr : test->upCast()->next();
caryclark54359292015-03-26 07:52:43 -07001415 do {
1416 SkOpPtT* testBase = test->ptT();
1417 do {
1418 if (startBase == testBase) {
1419 goto checkNextSpan;
1420 }
1421 if (testBase->duplicate()) {
1422 continue;
1423 }
1424 if (this->match(startBase, testBase->segment(), testBase->fT, testBase->fPt)) {
1425 if (test == &this->fTail) {
1426 if (spanS == &fHead) {
1427 debugValidate();
caryclark08bc8482015-04-24 09:08:57 -07001428 return; // if this span has collapsed, remove it from parent
caryclark54359292015-03-26 07:52:43 -07001429 }
1430 this->fTail.merge(spanS->upCast());
1431 debugValidate();
caryclark08bc8482015-04-24 09:08:57 -07001432 return;
caryclark54359292015-03-26 07:52:43 -07001433 }
1434 spanS->merge(test->upCast());
caryclark54359292015-03-26 07:52:43 -07001435 goto checkNextSpan;
1436 }
1437 } while ((testBase = testBase->next()) != test->ptT());
1438 } while ((startBase = startBase->next()) != spanS->ptT());
1439 checkNextSpan:
1440 ;
1441 } while ((test = next));
1442 spanS = spanS->upCast()->next();
1443 } while (!spanS->final());
1444 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001445}
1446
caryclark54359292015-03-26 07:52:43 -07001447bool SkOpSegment::operand() const {
1448 return fContour->operand();
1449}
1450
1451bool SkOpSegment::oppXor() const {
1452 return fContour->oppXor();
1453}
1454
1455bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1456 if (fVerb == SkPath::kLine_Verb) {
1457 return false;
1458 }
1459 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1460 // hits in two places with very different t values.
1461 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1462 // 'controls contained by ends' could avoid this check for common curves
1463 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1464 // on the other hand, the below check is relatively inexpensive
1465 double midT = (t1 + t2) / 2;
1466 SkPoint midPt = this->ptAtT(midT);
1467 double seDistSq = SkTMax(pt1.distanceToSqd(pt2) * 2, FLT_EPSILON * 2);
1468 return midPt.distanceToSqd(pt1) > seDistSq || midPt.distanceToSqd(pt2) > seDistSq;
1469}
1470
1471void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1472 int* maxWinding, int* sumWinding) {
1473 int deltaSum = SpanSign(start, end);
1474 *maxWinding = *sumMiWinding;
1475 *sumWinding = *sumMiWinding -= deltaSum;
bungeman60e0fee2015-08-26 05:15:46 -07001476 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -07001477}
1478
1479void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1480 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1481 int* oppSumWinding) {
1482 int deltaSum = SpanSign(start, end);
1483 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001484 if (operand()) {
1485 *maxWinding = *sumSuWinding;
1486 *sumWinding = *sumSuWinding -= deltaSum;
1487 *oppMaxWinding = *sumMiWinding;
1488 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1489 } else {
1490 *maxWinding = *sumMiWinding;
1491 *sumWinding = *sumMiWinding -= deltaSum;
1492 *oppMaxWinding = *sumSuWinding;
1493 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1494 }
bungeman60e0fee2015-08-26 05:15:46 -07001495 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1496 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001497}
1498
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001499void SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001500 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001501 do {
caryclark54359292015-03-26 07:52:43 -07001502 SkOpAngle* fromAngle = span->fromAngle();
halcanary96fcdcc2015-08-27 07:41:13 -07001503 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001504 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001505 continue;
1506 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001507#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001508 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001509#endif
caryclark54359292015-03-26 07:52:43 -07001510 SkOpAngle* baseAngle = fromAngle;
1511 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001512#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001513 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1514 span->debugID());
1515 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001516#endif
caryclark54359292015-03-26 07:52:43 -07001517 fromAngle->insert(toAngle);
1518 } else if (!fromAngle) {
1519 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001520 }
caryclark54359292015-03-26 07:52:43 -07001521 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001522 do {
caryclark54359292015-03-26 07:52:43 -07001523 SkOpSpanBase* oSpan = ptT->span();
1524 if (oSpan == span) {
1525 continue;
1526 }
1527 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001528 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001529#if DEBUG_ANGLE
1530 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001531 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1532 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001533 wroteAfterHeader = true;
1534 }
1535#endif
caryclark54359292015-03-26 07:52:43 -07001536 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001537 baseAngle->insert(oAngle);
1538 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001539 }
caryclark54359292015-03-26 07:52:43 -07001540 if (!oSpan->final()) {
1541 oAngle = oSpan->upCast()->toAngle();
1542 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001543#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001544 if (!wroteAfterHeader) {
1545 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1546 span->t(), span->debugID());
1547 wroteAfterHeader = true;
1548 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001549#endif
caryclark54359292015-03-26 07:52:43 -07001550 if (!oAngle->loopContains(baseAngle)) {
1551 baseAngle->insert(oAngle);
1552 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001553 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001554 }
caryclark54359292015-03-26 07:52:43 -07001555 } while ((ptT = ptT->next()) != stopPtT);
1556 if (baseAngle->loopCount() == 1) {
halcanary96fcdcc2015-08-27 07:41:13 -07001557 span->setFromAngle(nullptr);
caryclark54359292015-03-26 07:52:43 -07001558 if (toAngle) {
halcanary96fcdcc2015-08-27 07:41:13 -07001559 span->upCast()->setToAngle(nullptr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001560 }
halcanary96fcdcc2015-08-27 07:41:13 -07001561 baseAngle = nullptr;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001562 }
1563#if DEBUG_SORT
1564 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1565#endif
caryclark54359292015-03-26 07:52:43 -07001566 } while (!span->final() && (span = span->upCast()->next()));
caryclark@google.com570863f2013-09-16 15:55:01 +00001567}
1568
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001569// return true if midpoints were computed
caryclark54359292015-03-26 07:52:43 -07001570bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001571 SkOpCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001572 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001573 const SkOpPtT& startPtT = *start->ptT();
1574 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001575 SkDEBUGCODE(edge->fVerb = fVerb);
1576 edge->fPts[0] = startPtT.fPt;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001577 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001578 edge->fPts[points] = endPtT.fPt;
1579 edge->fWeight = 1;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001580 if (fVerb == SkPath::kLine_Verb) {
1581 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001582 }
caryclark54359292015-03-26 07:52:43 -07001583 double startT = startPtT.fT;
1584 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001585 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1586 // don't compute midpoints if we already have them
1587 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001588 edge->fPts[1] = fPts[1];
1589 return false;
1590 }
1591 if (fVerb == SkPath::kConic_Verb) {
1592 edge->fPts[1] = fPts[1];
1593 edge->fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001594 return false;
1595 }
1596 SkASSERT(fVerb == SkPath::kCubic_Verb);
1597 if (start < end) {
caryclark1049f122015-04-20 08:31:59 -07001598 edge->fPts[1] = fPts[1];
1599 edge->fPts[2] = fPts[2];
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001600 return false;
1601 }
caryclark1049f122015-04-20 08:31:59 -07001602 edge->fPts[1] = fPts[2];
1603 edge->fPts[2] = fPts[1];
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001604 return false;
1605 }
caryclark1049f122015-04-20 08:31:59 -07001606 const SkDPoint sub[2] = {{ edge->fPts[0].fX, edge->fPts[0].fY},
1607 {edge->fPts[points].fX, edge->fPts[points].fY }};
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001608 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001609 edge->fPts[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
1610 } else if (fVerb == SkPath::kConic_Verb) {
1611 edge->fPts[1] = SkDConic::SubDivide(fPts, fWeight, sub[0], sub[1],
1612 startT, endT, &edge->fWeight).asSkPoint();
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001613 } else {
1614 SkASSERT(fVerb == SkPath::kCubic_Verb);
1615 SkDPoint ctrl[2];
1616 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
caryclark1049f122015-04-20 08:31:59 -07001617 edge->fPts[1] = ctrl[0].asSkPoint();
1618 edge->fPts[2] = ctrl[1].asSkPoint();
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001619 }
1620 return true;
1621}
1622
caryclark54359292015-03-26 07:52:43 -07001623bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001624 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001625 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001626 const SkOpPtT& startPtT = *start->ptT();
1627 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001628 SkDEBUGCODE(edge->fVerb = fVerb);
1629 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001630 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001631 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001632 if (fVerb == SkPath::kLine_Verb) {
1633 return false;
1634 }
caryclark54359292015-03-26 07:52:43 -07001635 double startT = startPtT.fT;
1636 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001637 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1638 // don't compute midpoints if we already have them
1639 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001640 edge->fLine[1].set(fPts[1]);
1641 return false;
1642 }
1643 if (fVerb == SkPath::kConic_Verb) {
1644 edge->fConic[1].set(fPts[1]);
1645 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001646 return false;
1647 }
1648 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001649 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001650 edge->fCubic[1].set(fPts[1]);
1651 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001652 return false;
1653 }
caryclark1049f122015-04-20 08:31:59 -07001654 edge->fCubic[1].set(fPts[2]);
1655 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001656 return false;
1657 }
1658 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001659 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1660 } else if (fVerb == SkPath::kConic_Verb) {
1661 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1662 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001663 } else {
1664 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001665 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001666 }
1667 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001668}
1669
caryclark27c8eb82015-07-06 11:38:33 -07001670bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
1671 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp,
1672 SkScalar flatnessLimit) const {
1673 // average t, find mid pt
1674 double midT = (prior->t() + spanBase->t()) / 2;
1675 SkPoint midPt = this->ptAtT(midT);
1676 bool coincident = true;
1677 // if the mid pt is not near either end pt, project perpendicular through opp seg
1678 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1679 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
1680 coincident = false;
1681 SkIntersections i;
1682 SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->weight(), midT);
1683 SkDLine ray = {{{midPt.fX, midPt.fY}, {midPt.fX + dxdy.fY, midPt.fY - dxdy.fX}}};
1684 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), ray, &i);
1685 // measure distance and see if it's small enough to denote coincidence
1686 for (int index = 0; index < i.used(); ++index) {
1687 SkDPoint oppPt = i.pt(index);
1688 if (oppPt.approximatelyEqual(midPt)) {
1689 SkVector oppDxdy = (*CurveSlopeAtT[opp->verb()])(opp->pts(),
1690 opp->weight(), i[index][0]);
1691 oppDxdy.normalize();
1692 dxdy.normalize();
1693 SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy) / FLT_EPSILON);
1694 coincident |= flatness < flatnessLimit;
1695 }
1696 }
1697 }
1698 return coincident;
1699}
1700
caryclark54359292015-03-26 07:52:43 -07001701void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
1702 SkOpSpan* span = this->head();
1703 do {
1704 if (!span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001705 break;
1706 }
caryclark54359292015-03-26 07:52:43 -07001707 } while ((span = span->next()->upCastable()));
1708 SkASSERT(span);
1709 *start = span;
1710 *end = span->next();
reed0dc4dd62015-03-24 13:55:33 -07001711}
1712
caryclark54359292015-03-26 07:52:43 -07001713int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1714 const SkOpSpan* lesser = start->starter(end);
1715 int oppWinding = lesser->oppSum();
1716 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001717 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1718 && oppWinding != SK_MaxS32) {
1719 oppWinding -= oppSpanWinding;
1720 }
1721 return oppWinding;
1722}
1723
1724int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001725 const SkOpSpanBase* startSpan = angle->start();
1726 const SkOpSpanBase* endSpan = angle->end();
1727 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001728}
1729
1730int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001731 const SkOpSpanBase* startSpan = angle->start();
1732 const SkOpSpanBase* endSpan = angle->end();
1733 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001734}
1735
caryclark624637c2015-05-11 07:21:27 -07001736int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1737 SkOpSpan* lesser = start->starter(end);
caryclark54359292015-03-26 07:52:43 -07001738 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001739 if (winding == SK_MinS32) {
caryclarkbca19f72015-05-13 08:23:48 -07001740 winding = lesser->computeWindSum();
caryclark624637c2015-05-11 07:21:27 -07001741 }
1742 if (winding == SK_MinS32) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001743 return winding;
1744 }
caryclark54359292015-03-26 07:52:43 -07001745 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001746 if (winding && UseInnerWinding(winding - spanWinding, winding)
1747 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001748 winding -= spanWinding;
1749 }
1750 return winding;
1751}
1752
caryclark624637c2015-05-11 07:21:27 -07001753int SkOpSegment::updateWinding(SkOpAngle* angle) {
1754 SkOpSpanBase* startSpan = angle->start();
1755 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001756 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001757}
1758
caryclark624637c2015-05-11 07:21:27 -07001759int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1760 SkOpSpanBase* startSpan = angle->start();
1761 SkOpSpanBase* endSpan = angle->end();
caryclark54359292015-03-26 07:52:43 -07001762 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00001763}
1764
1765// OPTIMIZATION: does the following also work, and is it any faster?
1766// return outerWinding * innerWinding > 0
1767// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1768bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1769 SkASSERT(outerWinding != SK_MaxS32);
1770 SkASSERT(innerWinding != SK_MaxS32);
bungeman60e0fee2015-08-26 05:15:46 -07001771 int absOut = SkTAbs(outerWinding);
1772 int absIn = SkTAbs(innerWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +00001773 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1774 return result;
1775}
1776
caryclark@google.com07393ca2013-04-08 11:47:37 +00001777int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001778 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1779 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001780}