blob: 161eb33765de35bec78cc85ba9dbb736ced84480 [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,
46 SkOpSpanBase** endPtr, bool* done, bool* sortable) {
47 if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done, sortable)) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000048 return result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000049 }
caryclark54359292015-03-26 07:52:43 -070050 if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done, sortable)) {
51 return result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000052 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000053 return NULL;
caryclark@google.com07393ca2013-04-08 11:47:37 +000054}
55
caryclark54359292015-03-26 07:52:43 -070056SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** startPtr,
57 SkOpSpanBase** endPtr, bool* done, bool* sortable) {
58 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 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000094 return NULL;
95}
96
caryclark54359292015-03-26 07:52:43 -070097SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** startPtr,
98 SkOpSpanBase** endPtr, bool* done, bool* sortable) {
99 SkOpPtT* oPtT = start->ptT()->next();
100 SkOpSegment* other = oPtT->segment();
101 SkOpSpanBase* oSpan = oPtT->span();
102 return other->activeAngleInner(oSpan, startPtr, endPtr, done, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000103}
104
caryclark54359292015-03-26 07:52:43 -0700105SkPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000106 SkASSERT(!done());
107 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
caryclark@google.com07393ca2013-04-08 11:47:37 +0000108 // see if either end is not done since we want smaller Y of the pair
109 bool lastDone = true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000110 double lastT = -1;
caryclark54359292015-03-26 07:52:43 -0700111 SkOpSpanBase* span = &fHead;
112 do {
113 if (lastDone && (span->final() || span->upCast()->done())) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000114 goto next;
115 }
116 {
caryclark54359292015-03-26 07:52:43 -0700117 const SkPoint& xy = span->pt();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000118 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
119 topPt = xy;
caryclark54359292015-03-26 07:52:43 -0700120 if (firstSpan) {
121 *firstSpan = span;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000122 }
123 }
124 if (fVerb != SkPath::kLine_Verb && !lastDone) {
caryclark1049f122015-04-20 08:31:59 -0700125 SkPoint curveTop = (*CurveTop[fVerb])(fPts, fWeight, lastT, span->t());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000126 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
127 && topPt.fX > curveTop.fX)) {
128 topPt = curveTop;
caryclark54359292015-03-26 07:52:43 -0700129 if (firstSpan) {
130 *firstSpan = span;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000131 }
132 }
133 }
caryclark54359292015-03-26 07:52:43 -0700134 lastT = span->t();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000135 }
136next:
caryclark54359292015-03-26 07:52:43 -0700137 if (span->final()) {
138 break;
139 }
140 lastDone = span->upCast()->done();
141 } while ((span = span->upCast()->next()));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000142 return topPt;
143}
144
caryclark54359292015-03-26 07:52:43 -0700145bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xorSuMask,
146 SkPathOp op) {
147 int sumMiWinding = this->updateWinding(end, start);
148 int sumSuWinding = this->updateOppWinding(end, start);
caryclark65f55312014-11-13 06:58:52 -0800149#if DEBUG_LIMIT_WIND_SUM
150 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM);
151 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM);
152#endif
caryclark54359292015-03-26 07:52:43 -0700153 if (this->operand()) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000154 SkTSwap<int>(sumMiWinding, sumSuWinding);
155 }
caryclark54359292015-03-26 07:52:43 -0700156 return this->activeOp(xorMiMask, xorSuMask, start, end, op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000157}
158
caryclark54359292015-03-26 07:52:43 -0700159bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end,
160 SkPathOp op, int* sumMiWinding, int* sumSuWinding) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000161 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
caryclark54359292015-03-26 07:52:43 -0700162 this->setUpWindings(start, end, sumMiWinding, sumSuWinding,
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000163 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000164 bool miFrom;
165 bool miTo;
166 bool suFrom;
167 bool suTo;
168 if (operand()) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000169 miFrom = (oppMaxWinding & xorMiMask) != 0;
170 miTo = (oppSumWinding & xorMiMask) != 0;
171 suFrom = (maxWinding & xorSuMask) != 0;
172 suTo = (sumWinding & xorSuMask) != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000173 } else {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000174 miFrom = (maxWinding & xorMiMask) != 0;
175 miTo = (sumWinding & xorMiMask) != 0;
176 suFrom = (oppMaxWinding & xorSuMask) != 0;
177 suTo = (oppSumWinding & xorSuMask) != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000178 }
179 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
180#if DEBUG_ACTIVE_OP
caryclarkdac1d172014-06-17 05:15:38 -0700181 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 -0700182 __FUNCTION__, debugID(), start->t(), end->t(),
caryclark@google.com570863f2013-09-16 15:55:01 +0000183 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000184#endif
185 return result;
186}
187
caryclark54359292015-03-26 07:52:43 -0700188bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
189 int sumWinding = updateWinding(end, start);
190 return activeWinding(start, end, &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000191}
192
caryclark54359292015-03-26 07:52:43 -0700193bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000194 int maxWinding;
caryclark54359292015-03-26 07:52:43 -0700195 setUpWinding(start, end, &maxWinding, sumWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000196 bool from = maxWinding != 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000197 bool to = *sumWinding != 0;
198 bool result = gUnaryActiveEdge[from][to];
199 return result;
200}
201
caryclark54359292015-03-26 07:52:43 -0700202void SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
203 SkPathWriter* path, bool active) const {
caryclark1049f122015-04-20 08:31:59 -0700204 SkOpCurve edge;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000205 const SkPoint* ePtr;
caryclark1049f122015-04-20 08:31:59 -0700206 SkScalar eWeight;
caryclark54359292015-03-26 07:52:43 -0700207 if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000208 ePtr = fPts;
caryclark1049f122015-04-20 08:31:59 -0700209 eWeight = fWeight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000210 } else {
211 // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
caryclark1049f122015-04-20 08:31:59 -0700212 subDivide(start, end, &edge);
213 ePtr = edge.fPts;
214 eWeight = edge.fWeight;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000215 }
216 if (active) {
caryclark54359292015-03-26 07:52:43 -0700217 bool reverse = ePtr == fPts && start != &fHead;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000218 if (reverse) {
reed@google.com277c3f82013-05-31 15:17:50 +0000219 path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000220 switch (fVerb) {
221 case SkPath::kLine_Verb:
222 path->deferredLine(ePtr[0]);
223 break;
224 case SkPath::kQuad_Verb:
225 path->quadTo(ePtr[1], ePtr[0]);
226 break;
caryclark1049f122015-04-20 08:31:59 -0700227 case SkPath::kConic_Verb:
228 path->conicTo(ePtr[1], ePtr[0], eWeight);
229 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000230 case SkPath::kCubic_Verb:
231 path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
232 break;
233 default:
234 SkASSERT(0);
235 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000236 } else {
237 path->deferredMoveLine(ePtr[0]);
238 switch (fVerb) {
239 case SkPath::kLine_Verb:
240 path->deferredLine(ePtr[1]);
241 break;
242 case SkPath::kQuad_Verb:
243 path->quadTo(ePtr[1], ePtr[2]);
244 break;
caryclark1049f122015-04-20 08:31:59 -0700245 case SkPath::kConic_Verb:
246 path->conicTo(ePtr[1], ePtr[2], eWeight);
247 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000248 case SkPath::kCubic_Verb:
249 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
250 break;
251 default:
252 SkASSERT(0);
253 }
254 }
255 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000256}
257
caryclark54359292015-03-26 07:52:43 -0700258SkOpPtT* SkOpSegment::addMissing(double t, SkOpSegment* opp, SkChunkAlloc* allocator) {
259 SkOpSpanBase* existing = NULL;
260 SkOpSpanBase* test = &fHead;
261 double testT;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000262 do {
caryclark54359292015-03-26 07:52:43 -0700263 if ((testT = test->ptT()->fT) >= t) {
264 if (testT == t) {
265 existing = test;
266 }
reed0dc4dd62015-03-24 13:55:33 -0700267 break;
268 }
caryclark54359292015-03-26 07:52:43 -0700269 } while ((test = test->upCast()->next()));
270 SkOpPtT* result;
271 if (existing && existing->contains(opp)) {
272 result = existing->ptT();
273 } else {
274 result = this->addT(t, SkOpSegment::kNoAlias, allocator);
275 }
276 SkASSERT(result);
277 return result;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000278}
279
caryclark54359292015-03-26 07:52:43 -0700280SkOpAngle* SkOpSegment::addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle** anglePtr,
281 SkChunkAlloc* allocator) {
282 SkOpSpan* startSpan = fTail.prev();
283 SkASSERT(startSpan);
284 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
285 *anglePtr = angle;
286 angle->set(&fTail, startSpan);
287 fTail.setFromAngle(angle);
288 SkOpSegment* other = NULL; // these initializations silence a release build warning
289 SkOpSpan* oStartSpan = NULL;
290 SkOpSpanBase* oEndSpan = NULL;
291 SkOpPtT* ptT = fTail.ptT(), * startPtT = ptT;
292 while ((ptT = ptT->next()) != startPtT) {
293 other = ptT->segment();
294 oStartSpan = ptT->span()->upCastable();
295 if (oStartSpan && oStartSpan->windValue()) {
296 oEndSpan = oStartSpan->next();
reed0dc4dd62015-03-24 13:55:33 -0700297 break;
298 }
caryclark54359292015-03-26 07:52:43 -0700299 oEndSpan = ptT->span();
300 oStartSpan = oEndSpan->prev();
301 if (oStartSpan && oStartSpan->windValue()) {
302 break;
303 }
304 }
caryclark1049f122015-04-20 08:31:59 -0700305 if (!oStartSpan) {
306 return NULL;
307 }
caryclark54359292015-03-26 07:52:43 -0700308 SkOpAngle* oAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
309 oAngle->set(oStartSpan, oEndSpan);
310 oStartSpan->setToAngle(oAngle);
reed0dc4dd62015-03-24 13:55:33 -0700311 *otherPtr = other;
caryclark54359292015-03-26 07:52:43 -0700312 return oAngle;
reed0dc4dd62015-03-24 13:55:33 -0700313}
314
caryclark54359292015-03-26 07:52:43 -0700315SkOpAngle* SkOpSegment::addSingletonAngles(int step, SkChunkAlloc* allocator) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000316 SkOpSegment* other;
caryclarkdac1d172014-06-17 05:15:38 -0700317 SkOpAngle* angle, * otherAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000318 if (step > 0) {
caryclark54359292015-03-26 07:52:43 -0700319 otherAngle = addSingletonAngleUp(&other, &angle, allocator);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000320 } else {
caryclark54359292015-03-26 07:52:43 -0700321 otherAngle = addSingletonAngleDown(&other, &angle, allocator);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000322 }
caryclark1049f122015-04-20 08:31:59 -0700323 if (!otherAngle) {
324 return NULL;
325 }
caryclarkdac1d172014-06-17 05:15:38 -0700326 angle->insert(otherAngle);
327 return angle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000328}
329
caryclark54359292015-03-26 07:52:43 -0700330SkOpAngle* SkOpSegment::addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** anglePtr,
331 SkChunkAlloc* allocator) {
332 SkOpSpanBase* endSpan = fHead.next();
333 SkASSERT(endSpan);
334 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
335 *anglePtr = angle;
336 angle->set(&fHead, endSpan);
337 fHead.setToAngle(angle);
338 SkOpSegment* other = NULL; // these initializations silence a release build warning
339 SkOpSpan* oStartSpan = NULL;
340 SkOpSpanBase* oEndSpan = NULL;
341 SkOpPtT* ptT = fHead.ptT(), * startPtT = ptT;
342 while ((ptT = ptT->next()) != startPtT) {
343 other = ptT->segment();
344 oEndSpan = ptT->span();
345 oStartSpan = oEndSpan->prev();
346 if (oStartSpan && oStartSpan->windValue()) {
caryclarkccec0f92015-03-24 07:28:17 -0700347 break;
348 }
caryclark54359292015-03-26 07:52:43 -0700349 oStartSpan = oEndSpan->upCastable();
350 if (oStartSpan && oStartSpan->windValue()) {
351 oEndSpan = oStartSpan->next();
reed0dc4dd62015-03-24 13:55:33 -0700352 break;
353 }
reed0dc4dd62015-03-24 13:55:33 -0700354 }
caryclark54359292015-03-26 07:52:43 -0700355 SkOpAngle* oAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
356 oAngle->set(oEndSpan, oStartSpan);
357 oEndSpan->setFromAngle(oAngle);
358 *otherPtr = other;
359 return oAngle;
reed0dc4dd62015-03-24 13:55:33 -0700360}
361
caryclark54359292015-03-26 07:52:43 -0700362SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* allocator) {
reed0dc4dd62015-03-24 13:55:33 -0700363 debugValidate();
caryclark54359292015-03-26 07:52:43 -0700364 SkPoint pt = this->ptAtT(t);
365 SkOpSpanBase* span = &fHead;
366 do {
367 SkOpPtT* result = span->ptT();
368 if (t == result->fT) {
369 return result;
reed0dc4dd62015-03-24 13:55:33 -0700370 }
caryclark54359292015-03-26 07:52:43 -0700371 if (this->match(result, this, t, pt)) {
372 // see if any existing alias matches segment, pt, and t
373 SkOpPtT* loop = result->next();
374 bool duplicatePt = false;
375 while (loop != result) {
376 bool ptMatch = loop->fPt == pt;
377 if (loop->segment() == this && loop->fT == t && ptMatch) {
378 return result;
reed0dc4dd62015-03-24 13:55:33 -0700379 }
caryclark54359292015-03-26 07:52:43 -0700380 duplicatePt |= ptMatch;
381 loop = loop->next();
reed0dc4dd62015-03-24 13:55:33 -0700382 }
caryclark54359292015-03-26 07:52:43 -0700383 if (kNoAlias == allowAlias) {
384 return result;
385 }
386 SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(allocator);
387 alias->init(result->span(), t, pt, duplicatePt);
388 result->insert(alias);
389 result->span()->unaligned();
390 this->debugValidate();
391#if DEBUG_ADD_T
392 SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
393 alias->segment()->debugID(), alias->span()->debugID());
394#endif
395 return alias;
reed0dc4dd62015-03-24 13:55:33 -0700396 }
caryclark54359292015-03-26 07:52:43 -0700397 if (t < result->fT) {
398 SkOpSpan* prev = result->span()->prev();
399 SkOpSpan* span = insert(prev, allocator);
400 span->init(this, prev, t, pt);
401 this->debugValidate();
402#if DEBUG_ADD_T
403 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
404 span->segment()->debugID(), span->debugID());
405#endif
406 return span->ptT();
407 }
408 SkASSERT(span != &fTail);
409 } while ((span = span->upCast()->next()));
410 SkASSERT(0);
411 return NULL;
412}
413
414// choose a solitary t and pt value; remove aliases; align the opposite ends
415void SkOpSegment::align() {
416 debugValidate();
417 SkOpSpanBase* span = &fHead;
418 if (!span->aligned()) {
419 span->alignEnd(0, fPts[0]);
420 }
421 while ((span = span->upCast()->next())) {
422 if (span == &fTail) {
423 break;
424 }
425 span->align();
426 }
427 if (!span->aligned()) {
428 span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]);
reed0dc4dd62015-03-24 13:55:33 -0700429 }
430 debugValidate();
431}
432
caryclark54359292015-03-26 07:52:43 -0700433bool SkOpSegment::BetweenTs(const SkOpSpanBase* lesser, double testT,
434 const SkOpSpanBase* greater) {
435 if (lesser->t() > greater->t()) {
436 SkTSwap<const SkOpSpanBase*>(lesser, greater);
reed0dc4dd62015-03-24 13:55:33 -0700437 }
caryclark54359292015-03-26 07:52:43 -0700438 return approximately_between(lesser->t(), testT, greater->t());
reed0dc4dd62015-03-24 13:55:33 -0700439}
440
caryclark54359292015-03-26 07:52:43 -0700441void SkOpSegment::calcAngles(SkChunkAlloc* allocator) {
442 bool activePrior = !fHead.isCanceled();
443 if (activePrior && !fHead.simple()) {
444 addStartSpan(allocator);
reed0dc4dd62015-03-24 13:55:33 -0700445 }
caryclark54359292015-03-26 07:52:43 -0700446 SkOpSpan* prior = &fHead;
447 SkOpSpanBase* spanBase = fHead.next();
448 while (spanBase != &fTail) {
449 if (activePrior) {
450 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
451 priorAngle->set(spanBase, prior);
452 spanBase->setFromAngle(priorAngle);
reed0dc4dd62015-03-24 13:55:33 -0700453 }
caryclark54359292015-03-26 07:52:43 -0700454 SkOpSpan* span = spanBase->upCast();
455 bool active = !span->isCanceled();
456 SkOpSpanBase* next = span->next();
457 if (active) {
458 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
459 angle->set(span, next);
460 span->setToAngle(angle);
reed0dc4dd62015-03-24 13:55:33 -0700461 }
reed0dc4dd62015-03-24 13:55:33 -0700462 activePrior = active;
caryclark54359292015-03-26 07:52:43 -0700463 prior = span;
464 spanBase = next;
reed0dc4dd62015-03-24 13:55:33 -0700465 }
caryclark54359292015-03-26 07:52:43 -0700466 if (activePrior && !fTail.simple()) {
467 addEndSpan(allocator);
reed0dc4dd62015-03-24 13:55:33 -0700468 }
reed0dc4dd62015-03-24 13:55:33 -0700469}
470
caryclark54359292015-03-26 07:52:43 -0700471void SkOpSegment::checkAngleCoin(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) {
472 SkOpSpanBase* base = &fHead;
473 SkOpSpan* span;
reed0dc4dd62015-03-24 13:55:33 -0700474 do {
caryclark54359292015-03-26 07:52:43 -0700475 SkOpAngle* angle = base->fromAngle();
476 if (angle && angle->fCheckCoincidence) {
477 angle->checkNearCoincidence();
reed0dc4dd62015-03-24 13:55:33 -0700478 }
caryclark54359292015-03-26 07:52:43 -0700479 if (base->final()) {
480 break;
reed0dc4dd62015-03-24 13:55:33 -0700481 }
caryclark54359292015-03-26 07:52:43 -0700482 span = base->upCast();
483 angle = span->toAngle();
484 if (angle && angle->fCheckCoincidence) {
485 angle->checkNearCoincidence();
reed0dc4dd62015-03-24 13:55:33 -0700486 }
caryclark54359292015-03-26 07:52:43 -0700487 } while ((base = span->next()));
488}
489
490// from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
491bool SkOpSegment::clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end, bool* swap) const {
492 SkASSERT(fVerb != SkPath::kLine_Verb);
caryclark1049f122015-04-20 08:31:59 -0700493 SkOpCurve edge;
caryclark54359292015-03-26 07:52:43 -0700494 if (fVerb == SkPath::kCubic_Verb) {
495 double startT = start->t();
496 double endT = end->t();
497 bool flip = startT > endT;
498 SkDCubic cubic;
499 cubic.set(fPts);
500 double inflectionTs[2];
501 int inflections = cubic.findInflections(inflectionTs);
502 for (int index = 0; index < inflections; ++index) {
503 double inflectionT = inflectionTs[index];
504 if (between(startT, inflectionT, endT)) {
505 if (flip) {
caryclark1049f122015-04-20 08:31:59 -0700506 if (!roughly_equal(inflectionT, endT)) {
507 startT = inflectionT;
caryclark54359292015-03-26 07:52:43 -0700508 }
509 } else {
caryclark1049f122015-04-20 08:31:59 -0700510 if (!roughly_equal(inflectionT, startT)) {
caryclark54359292015-03-26 07:52:43 -0700511 endT = inflectionT;
512 }
513 }
514 }
515 }
516 SkDCubic part = cubic.subDivide(startT, endT);
caryclark1049f122015-04-20 08:31:59 -0700517 edge.set(part);
caryclark54359292015-03-26 07:52:43 -0700518 } else {
caryclark1049f122015-04-20 08:31:59 -0700519 subDivide(start, end, &edge);
reed0dc4dd62015-03-24 13:55:33 -0700520 }
caryclark54359292015-03-26 07:52:43 -0700521 bool sumSet = false;
522 int points = SkPathOpsVerbToPoints(fVerb);
523 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY);
524 if (!sumSet) {
525 for (int idx = 0; idx < points; ++idx){
526 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
527 }
reed0dc4dd62015-03-24 13:55:33 -0700528 }
caryclark54359292015-03-26 07:52:43 -0700529 if (fVerb == SkPath::kCubic_Verb) {
530 SkDCubic cubic;
caryclark1049f122015-04-20 08:31:59 -0700531 cubic.set(edge.fPts);
caryclark54359292015-03-26 07:52:43 -0700532 *swap = sum > 0 && !cubic.monotonicInY();
533 } else {
534 SkDQuad quad;
caryclark1049f122015-04-20 08:31:59 -0700535 quad.set(edge.fPts);
caryclark54359292015-03-26 07:52:43 -0700536 *swap = sum > 0 && !quad.monotonicInY();
537 }
538 return sum <= 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000539}
540
caryclark@google.com570863f2013-09-16 15:55:01 +0000541void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
542 SkOpAngle::IncludeType includeType) {
543 const SkOpSegment* baseSegment = baseAngle->segment();
544 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
545 int sumSuWinding;
546 bool binary = includeType >= SkOpAngle::kBinarySingle;
547 if (binary) {
548 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
549 if (baseSegment->operand()) {
550 SkTSwap<int>(sumMiWinding, sumSuWinding);
551 }
552 }
553 SkOpSegment* nextSegment = nextAngle->segment();
554 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700555 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000556 if (binary) {
557 int oppMaxWinding, oppSumWinding;
558 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
559 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
560 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000561 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000562 } else {
563 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
564 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000565 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000566 }
567 nextAngle->setLastMarked(last);
568}
569
570void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
571 SkOpAngle::IncludeType includeType) {
572 const SkOpSegment* baseSegment = baseAngle->segment();
573 int sumMiWinding = baseSegment->updateWinding(baseAngle);
574 int sumSuWinding;
575 bool binary = includeType >= SkOpAngle::kBinarySingle;
576 if (binary) {
577 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
578 if (baseSegment->operand()) {
579 SkTSwap<int>(sumMiWinding, sumSuWinding);
580 }
581 }
582 SkOpSegment* nextSegment = nextAngle->segment();
583 int maxWinding, sumWinding;
caryclark54359292015-03-26 07:52:43 -0700584 SkOpSpanBase* last;
caryclark@google.com570863f2013-09-16 15:55:01 +0000585 if (binary) {
586 int oppMaxWinding, oppSumWinding;
587 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
588 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
589 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000590 nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000591 } else {
592 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
593 &maxWinding, &sumWinding);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000594 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
caryclark@google.com570863f2013-09-16 15:55:01 +0000595 }
596 nextAngle->setLastMarked(last);
597}
598
caryclark54359292015-03-26 07:52:43 -0700599// at this point, the span is already ordered, or unorderable
600int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
601 SkOpAngle::IncludeType includeType) {
602 SkASSERT(includeType != SkOpAngle::kUnaryXor);
603 SkOpAngle* firstAngle = this->spanToAngle(end, start);
604 if (NULL == firstAngle || NULL == firstAngle->next()) {
605 return SK_NaN32;
606 }
607 // if all angles have a computed winding,
608 // or if no adjacent angles are orderable,
609 // or if adjacent orderable angles have no computed winding,
610 // there's nothing to do
611 // if two orderable angles are adjacent, and both are next to orderable angles,
612 // and one has winding computed, transfer to the other
613 SkOpAngle* baseAngle = NULL;
614 bool tryReverse = false;
615 // look for counterclockwise transfers
616 SkOpAngle* angle = firstAngle->previous();
617 SkOpAngle* next = angle->next();
618 firstAngle = next;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000619 do {
caryclark54359292015-03-26 07:52:43 -0700620 SkOpAngle* prior = angle;
621 angle = next;
622 next = angle->next();
623 SkASSERT(prior->next() == angle);
624 SkASSERT(angle->next() == next);
625 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
626 baseAngle = NULL;
627 continue;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000628 }
caryclark54359292015-03-26 07:52:43 -0700629 int testWinding = angle->starter()->windSum();
630 if (SK_MinS32 != testWinding) {
631 baseAngle = angle;
632 tryReverse = true;
633 continue;
reed0dc4dd62015-03-24 13:55:33 -0700634 }
caryclark54359292015-03-26 07:52:43 -0700635 if (baseAngle) {
636 ComputeOneSum(baseAngle, angle, includeType);
637 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : NULL;
638 }
639 } while (next != firstAngle);
640 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
641 firstAngle = baseAngle;
642 tryReverse = true;
643 }
644 if (tryReverse) {
645 baseAngle = NULL;
646 SkOpAngle* prior = firstAngle;
647 do {
648 angle = prior;
649 prior = angle->previous();
650 SkASSERT(prior->next() == angle);
651 next = angle->next();
652 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
653 baseAngle = NULL;
reed0dc4dd62015-03-24 13:55:33 -0700654 continue;
655 }
caryclark54359292015-03-26 07:52:43 -0700656 int testWinding = angle->starter()->windSum();
657 if (SK_MinS32 != testWinding) {
658 baseAngle = angle;
659 continue;
reed0dc4dd62015-03-24 13:55:33 -0700660 }
caryclark54359292015-03-26 07:52:43 -0700661 if (baseAngle) {
662 ComputeOneSumReverse(baseAngle, angle, includeType);
663 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : NULL;
reed0dc4dd62015-03-24 13:55:33 -0700664 }
caryclark54359292015-03-26 07:52:43 -0700665 } while (prior != firstAngle);
reed0dc4dd62015-03-24 13:55:33 -0700666 }
caryclark54359292015-03-26 07:52:43 -0700667 return start->starter(end)->windSum();
reed0dc4dd62015-03-24 13:55:33 -0700668}
669
caryclark54359292015-03-26 07:52:43 -0700670SkOpSpan* SkOpSegment::crossedSpanY(const SkPoint& basePt, double mid, bool opp, bool current,
671 SkScalar* bestY, double* hitT, bool* hitSomething, bool* vertical) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000672 SkScalar bottom = fBounds.fBottom;
caryclark54359292015-03-26 07:52:43 -0700673 *vertical = false;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000674 if (bottom <= *bestY) {
caryclark54359292015-03-26 07:52:43 -0700675 return NULL;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000676 }
677 SkScalar top = fBounds.fTop;
678 if (top >= basePt.fY) {
caryclark54359292015-03-26 07:52:43 -0700679 return NULL;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000680 }
681 if (fBounds.fLeft > basePt.fX) {
caryclark54359292015-03-26 07:52:43 -0700682 return NULL;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000683 }
684 if (fBounds.fRight < basePt.fX) {
caryclark54359292015-03-26 07:52:43 -0700685 return NULL;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000686 }
687 if (fBounds.fLeft == fBounds.fRight) {
688 // if vertical, and directly above test point, wait for another one
caryclark54359292015-03-26 07:52:43 -0700689 *vertical = AlmostEqualUlps(basePt.fX, fBounds.fLeft);
690 return NULL;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000691 }
692 // intersect ray starting at basePt with edge
693 SkIntersections intersections;
694 // OPTIMIZE: use specialty function that intersects ray with curve,
695 // returning t values only for curve (we don't care about t on ray)
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000696 intersections.allowNear(false);
caryclark1049f122015-04-20 08:31:59 -0700697 int pts = (intersections.*CurveVertical[fVerb])(fPts, fWeight, top, bottom, basePt.fX, false);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000698 if (pts == 0 || (current && pts == 1)) {
caryclark54359292015-03-26 07:52:43 -0700699 return NULL;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000700 }
701 if (current) {
702 SkASSERT(pts > 1);
703 int closestIdx = 0;
704 double closest = fabs(intersections[0][0] - mid);
705 for (int idx = 1; idx < pts; ++idx) {
706 double test = fabs(intersections[0][idx] - mid);
707 if (closest > test) {
708 closestIdx = idx;
709 closest = test;
710 }
711 }
712 intersections.quickRemoveOne(closestIdx, --pts);
713 }
714 double bestT = -1;
715 for (int index = 0; index < pts; ++index) {
716 double foundT = intersections[0][index];
717 if (approximately_less_than_zero(foundT)
718 || approximately_greater_than_one(foundT)) {
719 continue;
720 }
caryclark1049f122015-04-20 08:31:59 -0700721 SkScalar testY = (*CurvePointAtT[fVerb])(fPts, fWeight, foundT).fY;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000722 if (approximately_negative(testY - *bestY)
723 || approximately_negative(basePt.fY - testY)) {
724 continue;
725 }
726 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
caryclark54359292015-03-26 07:52:43 -0700727 *vertical = true;
728 return NULL; // if the intersection is edge on, wait for another one
caryclark@google.com07393ca2013-04-08 11:47:37 +0000729 }
730 if (fVerb > SkPath::kLine_Verb) {
caryclark1049f122015-04-20 08:31:59 -0700731 SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, foundT).fX;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000732 if (approximately_zero(dx)) {
caryclark54359292015-03-26 07:52:43 -0700733 *vertical = true;
734 return NULL; // hit vertical, wait for another one
caryclark@google.com07393ca2013-04-08 11:47:37 +0000735 }
736 }
737 *bestY = testY;
738 bestT = foundT;
739 }
740 if (bestT < 0) {
caryclark54359292015-03-26 07:52:43 -0700741 return NULL;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000742 }
743 SkASSERT(bestT >= 0);
caryclark54359292015-03-26 07:52:43 -0700744 SkASSERT(bestT < 1);
745 SkOpSpanBase* testTSpanBase = &this->fHead;
746 SkOpSpanBase* nextTSpan;
747 double endT = 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000748 do {
caryclark54359292015-03-26 07:52:43 -0700749 nextTSpan = testTSpanBase->upCast()->next();
750 endT = nextTSpan->t();
751 if (endT >= bestT) {
752 break;
753 }
754 testTSpanBase = nextTSpan;
755 } while (testTSpanBase);
756 SkOpSpan* bestTSpan = NULL;
757 SkOpSpan* testTSpan = testTSpanBase->upCast();
758 if (!testTSpan->isCanceled()) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000759 *hitT = bestT;
caryclark54359292015-03-26 07:52:43 -0700760 bestTSpan = testTSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000761 *hitSomething = true;
762 }
caryclark54359292015-03-26 07:52:43 -0700763 return bestTSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000764}
765
caryclark54359292015-03-26 07:52:43 -0700766void SkOpSegment::detach(const SkOpSpan* span) {
767 if (span->done()) {
768 --this->fDoneCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000769 }
caryclark54359292015-03-26 07:52:43 -0700770 --this->fCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000771}
772
caryclark54359292015-03-26 07:52:43 -0700773double SkOpSegment::distSq(double t, SkOpAngle* oppAngle) {
774 SkDPoint testPt = this->dPtAtT(t);
775 SkDLine testPerp = {{ testPt, testPt }};
776 SkDVector slope = this->dSlopeAtT(t);
777 testPerp[1].fX += slope.fY;
778 testPerp[1].fY -= slope.fX;
779 SkIntersections i;
780 SkOpSegment* oppSegment = oppAngle->segment();
caryclark1049f122015-04-20 08:31:59 -0700781 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
caryclark54359292015-03-26 07:52:43 -0700782 double closestDistSq = SK_ScalarInfinity;
783 for (int index = 0; index < i.used(); ++index) {
784 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000785 continue;
786 }
caryclark54359292015-03-26 07:52:43 -0700787 double testDistSq = testPt.distanceSquared(i.pt(index));
788 if (closestDistSq > testDistSq) {
789 closestDistSq = testDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000790 }
791 }
caryclark54359292015-03-26 07:52:43 -0700792 return closestDistSq;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000793}
794
caryclark@google.com07393ca2013-04-08 11:47:37 +0000795/*
796 The M and S variable name parts stand for the operators.
797 Mi stands for Minuend (see wiki subtraction, analogous to difference)
798 Su stands for Subtrahend
799 The Opp variable name part designates that the value is for the Opposite operator.
800 Opposite values result from combining coincident spans.
801 */
caryclark54359292015-03-26 07:52:43 -0700802SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
803 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) {
804 SkOpSpanBase* start = *nextStart;
805 SkOpSpanBase* end = *nextEnd;
806 SkASSERT(start != end);
807 int step = start->step(end);
808 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
809 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000810 // mark the smaller of startIndex, endIndex done, and all adjacent
811 // spans with the same T value (but not 'other' spans)
812#if DEBUG_WINDING
813 SkDebugf("%s simple\n", __FUNCTION__);
814#endif
caryclark54359292015-03-26 07:52:43 -0700815 SkOpSpan* startSpan = start->starter(end);
816 if (startSpan->done()) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000817 return NULL;
818 }
caryclark54359292015-03-26 07:52:43 -0700819 markDone(startSpan);
820 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000821 return other;
822 }
caryclark54359292015-03-26 07:52:43 -0700823 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
824 SkASSERT(endNear == end); // is this ever not end?
825 SkASSERT(endNear);
826 SkASSERT(start != endNear);
827 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000828 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700829 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
caryclark@google.com570863f2013-09-16 15:55:01 +0000830 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000831 if (!sortable) {
832 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700833 markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000834 return NULL;
835 }
caryclark54359292015-03-26 07:52:43 -0700836 SkOpAngle* angle = this->spanToAngle(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000837 if (angle->unorderable()) {
838 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700839 markDone(start->starter(end));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000840 return NULL;
841 }
842#if DEBUG_SORT
843 SkDebugf("%s\n", __FUNCTION__);
844 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000845#endif
caryclark54359292015-03-26 07:52:43 -0700846 int sumMiWinding = updateWinding(end, start);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000847 if (sumMiWinding == SK_MinS32) {
848 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700849 markDone(start->starter(end));
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000850 return NULL;
851 }
caryclark54359292015-03-26 07:52:43 -0700852 int sumSuWinding = updateOppWinding(end, start);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000853 if (operand()) {
854 SkTSwap<int>(sumMiWinding, sumSuWinding);
855 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000856 SkOpAngle* nextAngle = angle->next();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000857 const SkOpAngle* foundAngle = NULL;
858 bool foundDone = false;
859 // iterate through the angle, and compute everyone's winding
860 SkOpSegment* nextSegment;
861 int activeCount = 0;
862 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000863 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000864 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000865 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000866 if (activeAngle) {
867 ++activeCount;
868 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000869 foundAngle = nextAngle;
caryclark@google.com570863f2013-09-16 15:55:01 +0000870 foundDone = nextSegment->done(nextAngle);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000871 }
872 }
873 if (nextSegment->done()) {
874 continue;
875 }
reed0dc4dd62015-03-24 13:55:33 -0700876 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700877 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700878 }
caryclark54359292015-03-26 07:52:43 -0700879 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000880 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000881 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000882 *chase->append() = last;
883#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700884 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
885 last->segment()->debugID(), last->debugID());
886 if (!last->final()) {
887 SkDebugf(" windSum=%d", last->upCast()->windSum());
888 }
889 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000890#endif
891 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000892 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700893 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000894 if (!foundAngle) {
895 return NULL;
896 }
897 *nextStart = foundAngle->start();
898 *nextEnd = foundAngle->end();
899 nextSegment = foundAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000900#if DEBUG_WINDING
901 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
902 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
903 #endif
904 return nextSegment;
905}
906
caryclark54359292015-03-26 07:52:43 -0700907SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
908 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
909 SkOpSpanBase* start = *nextStart;
910 SkOpSpanBase* end = *nextEnd;
911 SkASSERT(start != end);
912 int step = start->step(end);
913 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
914 if (other) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000915 // mark the smaller of startIndex, endIndex done, and all adjacent
916 // spans with the same T value (but not 'other' spans)
917#if DEBUG_WINDING
918 SkDebugf("%s simple\n", __FUNCTION__);
919#endif
caryclark54359292015-03-26 07:52:43 -0700920 SkOpSpan* startSpan = start->starter(end);
921 if (startSpan->done()) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000922 return NULL;
923 }
caryclark54359292015-03-26 07:52:43 -0700924 markDone(startSpan);
925 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000926 return other;
927 }
caryclark54359292015-03-26 07:52:43 -0700928 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
929 SkASSERT(endNear == end); // is this ever not end?
930 SkASSERT(endNear);
931 SkASSERT(start != endNear);
932 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000933 // more than one viable candidate -- measure angles to find best
caryclark54359292015-03-26 07:52:43 -0700934 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
caryclark@google.com570863f2013-09-16 15:55:01 +0000935 bool sortable = calcWinding != SK_NaN32;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000936 if (!sortable) {
937 *unsortable = true;
caryclark54359292015-03-26 07:52:43 -0700938 markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000939 return NULL;
940 }
caryclark54359292015-03-26 07:52:43 -0700941 SkOpAngle* angle = this->spanToAngle(end, start);
942 if (angle->unorderable()) {
943 *unsortable = true;
944 markDone(start->starter(end));
945 return NULL;
946 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000947#if DEBUG_SORT
948 SkDebugf("%s\n", __FUNCTION__);
949 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000950#endif
caryclark54359292015-03-26 07:52:43 -0700951 int sumWinding = updateWinding(end, start);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000952 SkOpAngle* nextAngle = angle->next();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000953 const SkOpAngle* foundAngle = NULL;
954 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -0700955 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +0000956 SkOpSegment* nextSegment;
957 int activeCount = 0;
958 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000959 nextSegment = nextAngle->segment();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000960 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000961 &sumWinding);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000962 if (activeAngle) {
963 ++activeCount;
964 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000965 foundAngle = nextAngle;
966 foundDone = nextSegment->done(nextAngle);
967 }
968 }
969 if (nextSegment->done()) {
970 continue;
971 }
reed0dc4dd62015-03-24 13:55:33 -0700972 if (!activeAngle) {
caryclark54359292015-03-26 07:52:43 -0700973 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
reed0dc4dd62015-03-24 13:55:33 -0700974 }
caryclark54359292015-03-26 07:52:43 -0700975 SkOpSpanBase* last = nextAngle->lastMarked();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000976 if (last) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000977 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000978 *chase->append() = last;
979#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -0700980 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
981 last->segment()->debugID(), last->debugID());
982 if (!last->final()) {
983 SkDebugf(" windSum=%d", last->upCast()->windSum());
984 }
985 SkDebugf("\n");
caryclark@google.com07393ca2013-04-08 11:47:37 +0000986#endif
987 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000988 } while ((nextAngle = nextAngle->next()) != angle);
caryclark54359292015-03-26 07:52:43 -0700989 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000990 if (!foundAngle) {
991 return NULL;
992 }
993 *nextStart = foundAngle->start();
994 *nextEnd = foundAngle->end();
995 nextSegment = foundAngle->segment();
996#if DEBUG_WINDING
997 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
998 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
999 #endif
1000 return nextSegment;
1001}
1002
caryclark54359292015-03-26 07:52:43 -07001003SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
1004 bool* unsortable) {
1005 SkOpSpanBase* start = *nextStart;
1006 SkOpSpanBase* end = *nextEnd;
1007 SkASSERT(start != end);
1008 int step = start->step(end);
1009 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
1010 if (other) {
1011 // mark the smaller of startIndex, endIndex done, and all adjacent
1012 // spans with the same T value (but not 'other' spans)
caryclark@google.com07393ca2013-04-08 11:47:37 +00001013#if DEBUG_WINDING
1014 SkDebugf("%s simple\n", __FUNCTION__);
1015#endif
caryclark54359292015-03-26 07:52:43 -07001016 SkOpSpan* startSpan = start->starter(end);
1017 if (startSpan->done()) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001018 return NULL;
1019 }
caryclark54359292015-03-26 07:52:43 -07001020 markDone(startSpan);
1021 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001022 return other;
1023 }
caryclark54359292015-03-26 07:52:43 -07001024 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
1025 : (*nextStart)->prev());
1026 SkASSERT(endNear == end); // is this ever not end?
1027 SkASSERT(endNear);
1028 SkASSERT(start != endNear);
1029 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
1030 SkOpAngle* angle = this->spanToAngle(end, start);
1031 if (angle->unorderable()) {
1032 *unsortable = true;
1033 markDone(start->starter(end));
1034 return NULL;
1035 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001036#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001037 SkDebugf("%s\n", __FUNCTION__);
1038 angle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001039#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001040 SkOpAngle* nextAngle = angle->next();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001041 const SkOpAngle* foundAngle = NULL;
1042 bool foundDone = false;
caryclark54359292015-03-26 07:52:43 -07001043 // iterate through the angle, and compute everyone's winding
caryclark@google.com07393ca2013-04-08 11:47:37 +00001044 SkOpSegment* nextSegment;
1045 int activeCount = 0;
1046 do {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001047 nextSegment = nextAngle->segment();
1048 ++activeCount;
1049 if (!foundAngle || (foundDone && activeCount & 1)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001050 foundAngle = nextAngle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001051 if (!(foundDone = nextSegment->done(nextAngle))) {
1052 break;
1053 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001054 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001055 nextAngle = nextAngle->next();
1056 } while (nextAngle != angle);
caryclark54359292015-03-26 07:52:43 -07001057 start->segment()->markDone(start->starter(end));
caryclark@google.com07393ca2013-04-08 11:47:37 +00001058 if (!foundAngle) {
1059 return NULL;
1060 }
1061 *nextStart = foundAngle->start();
1062 *nextEnd = foundAngle->end();
1063 nextSegment = foundAngle->segment();
1064#if DEBUG_WINDING
1065 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1066 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
1067 #endif
1068 return nextSegment;
1069}
1070
caryclark54359292015-03-26 07:52:43 -07001071SkOpSegment* SkOpSegment::findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpSpanBase** endPtr,
1072 bool* unsortable, SkChunkAlloc* allocator) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001073 // iterate through T intersections and return topmost
1074 // topmost tangent from y-min to first pt is closer to horizontal
1075 SkASSERT(!done());
caryclark54359292015-03-26 07:52:43 -07001076 SkOpSpanBase* firstT = NULL;
1077 (void) this->activeLeftTop(&firstT);
1078 if (!firstT) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001079 *unsortable = !firstPass;
caryclark54359292015-03-26 07:52:43 -07001080 firstT = &fHead;
1081 while (firstT->upCast()->done()) {
1082 firstT = firstT->upCast()->next();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001083 }
caryclark54359292015-03-26 07:52:43 -07001084 *startPtr = firstT;
1085 *endPtr = firstT->upCast()->next();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001086 return this;
1087 }
1088 // sort the edges to find the leftmost
1089 int step = 1;
caryclark54359292015-03-26 07:52:43 -07001090 SkOpSpanBase* end;
1091 if (firstT->final() || firstT->upCast()->done()) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001092 step = -1;
caryclark54359292015-03-26 07:52:43 -07001093 end = firstT->prev();
1094 SkASSERT(end);
1095 } else {
1096 end = firstT->upCast()->next();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001097 }
1098 // if the topmost T is not on end, or is three-way or more, find left
1099 // look for left-ness from tLeft to firstT (matching y of other)
caryclark54359292015-03-26 07:52:43 -07001100 SkASSERT(firstT != end);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001101 SkOpAngle* markAngle = spanToAngle(firstT, end);
1102 if (!markAngle) {
caryclark54359292015-03-26 07:52:43 -07001103 markAngle = addSingletonAngles(step, allocator);
caryclark@google.com570863f2013-09-16 15:55:01 +00001104 }
caryclark1049f122015-04-20 08:31:59 -07001105 if (!markAngle) {
1106 return NULL;
1107 }
1108 if (!markAngle->markStops()) {
1109 return NULL;
1110 }
caryclarke4097e32014-06-18 07:24:19 -07001111 const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical() ? markAngle
1112 : markAngle->findFirst();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001113 if (!baseAngle) {
1114 return NULL; // nothing to do
caryclark@google.com570863f2013-09-16 15:55:01 +00001115 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001116 SkScalar top = SK_ScalarMax;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001117 const SkOpAngle* firstAngle = NULL;
1118 const SkOpAngle* angle = baseAngle;
1119 do {
1120 if (!angle->unorderable()) {
caryclark54359292015-03-26 07:52:43 -07001121 const SkOpSegment* next = angle->segment();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001122 SkPathOpsBounds bounds;
1123 next->subDivideBounds(angle->end(), angle->start(), &bounds);
caryclark65f55312014-11-13 06:58:52 -08001124 bool nearSame = AlmostEqualUlps(top, bounds.top());
1125 bool lowerSector = !firstAngle || angle->sectorEnd() < firstAngle->sectorStart();
1126 bool lesserSector = top > bounds.fTop;
1127 if (lesserSector && (!nearSame || lowerSector)) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001128 top = bounds.fTop;
1129 firstAngle = angle;
1130 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001131 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001132 angle = angle->next();
1133 } while (angle != baseAngle);
caryclark65f55312014-11-13 06:58:52 -08001134 if (!firstAngle) {
1135 return NULL; // if all are unorderable, give up
1136 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001137#if DEBUG_SORT
1138 SkDebugf("%s\n", __FUNCTION__);
1139 firstAngle->debugLoop();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001140#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00001141 // skip edges that have already been processed
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001142 angle = firstAngle;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001143 SkOpSegment* leftSegment = NULL;
1144 bool looped = false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001145 do {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001146 *unsortable = angle->unorderable();
1147 if (firstPass || !*unsortable) {
1148 leftSegment = angle->segment();
caryclark54359292015-03-26 07:52:43 -07001149 *startPtr = angle->end();
1150 *endPtr = angle->start();
1151 const SkOpSpan* firstSpan = (*startPtr)->starter(*endPtr);
1152 if (!firstSpan->done()) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001153 break;
1154 }
1155 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001156 angle = angle->next();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001157 looped = true;
1158 } while (angle != firstAngle);
1159 if (angle == firstAngle && looped) {
1160 return NULL;
1161 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001162 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
caryclark54359292015-03-26 07:52:43 -07001163 SkOpSpanBase* start = *startPtr;
1164 SkOpSpanBase* end = *endPtr;
caryclarke4097e32014-06-18 07:24:19 -07001165 bool swap;
caryclark54359292015-03-26 07:52:43 -07001166 if (!leftSegment->clockwise(start, end, &swap)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001167 #if DEBUG_SWAP_TOP
caryclark54359292015-03-26 07:52:43 -07001168 SkDebugf("%s swap=%d inflections=%d monotonic=%d\n",
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001169 __FUNCTION__,
caryclark54359292015-03-26 07:52:43 -07001170 swap, leftSegment->debugInflections(start, end),
1171 leftSegment->monotonicInY(start, end));
caryclark@google.com07393ca2013-04-08 11:47:37 +00001172 #endif
1173 if (swap) {
1174 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first
1175 // sorted but merely the first not already processed (i.e., not done)
caryclark54359292015-03-26 07:52:43 -07001176 SkTSwap(*startPtr, *endPtr);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001177 }
1178 }
caryclark1049f122015-04-20 08:31:59 -07001179 // FIXME: clockwise isn't reliable -- try computing swap from tangent ?
caryclark@google.com07393ca2013-04-08 11:47:37 +00001180 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001181 return leftSegment;
1182}
1183
caryclark54359292015-03-26 07:52:43 -07001184SkOpGlobalState* SkOpSegment::globalState() const {
1185 return contour()->globalState();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001186}
1187
caryclark1049f122015-04-20 08:31:59 -07001188void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
caryclark54359292015-03-26 07:52:43 -07001189 fContour = contour;
1190 fNext = NULL;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001191 fPts = pts;
caryclark1049f122015-04-20 08:31:59 -07001192 fWeight = weight;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001193 fVerb = verb;
caryclark54359292015-03-26 07:52:43 -07001194 fCount = 0;
1195 fDoneCount = 0;
1196 fVisited = false;
1197 SkOpSpan* zeroSpan = &fHead;
1198 zeroSpan->init(this, NULL, 0, fPts[0]);
1199 SkOpSpanBase* oneSpan = &fTail;
1200 zeroSpan->setNext(oneSpan);
1201 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
caryclark1049f122015-04-20 08:31:59 -07001202 SkDEBUGCODE(fID = globalState()->nextSegmentID());
caryclark@google.com07393ca2013-04-08 11:47:37 +00001203}
1204
caryclark54359292015-03-26 07:52:43 -07001205void SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end,
1206 SkOpAngle::IncludeType angleIncludeType) {
1207 int local = SkOpSegment::SpanSign(start, end);
caryclark65f55312014-11-13 06:58:52 -08001208 SkDEBUGCODE(bool success);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001209 if (angleIncludeType == SkOpAngle::kBinarySingle) {
caryclark54359292015-03-26 07:52:43 -07001210 int oppLocal = SkOpSegment::OppSign(start, end);
caryclark65f55312014-11-13 06:58:52 -08001211 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, oppLocal, NULL);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001212 // OPTIMIZATION: the reverse mark and chase could skip the first marking
caryclark65f55312014-11-13 06:58:52 -08001213 SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, oppLocal, NULL);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001214 } else {
caryclark65f55312014-11-13 06:58:52 -08001215 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, NULL);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001216 // OPTIMIZATION: the reverse mark and chase could skip the first marking
caryclark65f55312014-11-13 06:58:52 -08001217 SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, NULL);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001218 }
caryclark65f55312014-11-13 06:58:52 -08001219 SkASSERT(success);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001220}
1221
1222/*
1223when we start with a vertical intersect, we try to use the dx to determine if the edge is to
1224the left or the right of vertical. This determines if we need to add the span's
1225sign or not. However, this isn't enough.
1226If the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed.
1227If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
1228from has the same x direction as this span, the winding should change. If the dx is opposite, then
1229the same winding is shared by both.
1230*/
caryclark54359292015-03-26 07:52:43 -07001231bool SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end, double tHit,
1232 int winding, SkScalar hitDx, int oppWind, SkScalar hitOppDx) {
1233 SkASSERT(this == start->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +00001234 SkASSERT(hitDx || !winding);
caryclark1049f122015-04-20 08:31:59 -07001235 SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, tHit).fX;
caryclark54359292015-03-26 07:52:43 -07001236// SkASSERT(dx);
1237 int windVal = start->starter(end)->windValue();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001238#if DEBUG_WINDING_AT_T
caryclarkdac1d172014-06-17 05:15:38 -07001239 SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, debugID(), winding,
caryclark@google.com07393ca2013-04-08 11:47:37 +00001240 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
1241#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001242 int sideWind = winding + (dx < 0 ? windVal : -windVal);
1243 if (abs(winding) < abs(sideWind)) {
1244 winding = sideWind;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001245 }
caryclark54359292015-03-26 07:52:43 -07001246 SkDEBUGCODE(int oppLocal = SkOpSegment::OppSign(start, end));
caryclark@google.com07393ca2013-04-08 11:47:37 +00001247 SkASSERT(hitOppDx || !oppWind || !oppLocal);
caryclark54359292015-03-26 07:52:43 -07001248 int oppWindVal = start->starter(end)->oppValue();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001249 if (!oppWind) {
1250 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
1251 } else if (hitOppDx * dx >= 0) {
1252 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
1253 if (abs(oppWind) < abs(oppSideWind)) {
1254 oppWind = oppSideWind;
1255 }
1256 }
caryclarkdac1d172014-06-17 05:15:38 -07001257#if DEBUG_WINDING_AT_T
1258 SkDebugf(" winding=%d oppWind=%d\n", winding, oppWind);
1259#endif
caryclark65f55312014-11-13 06:58:52 -08001260 // if this fails to mark (because the edges are too small) inform caller to try again
1261 bool success = markAndChaseWinding(start, end, winding, oppWind, NULL);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +00001262 // OPTIMIZATION: the reverse mark and chase could skip the first marking
caryclark65f55312014-11-13 06:58:52 -08001263 success |= markAndChaseWinding(end, start, winding, oppWind, NULL);
1264 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001265}
1266
caryclark54359292015-03-26 07:52:43 -07001267bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
1268 SkDPoint cPt = this->dPtAtT(t);
caryclark1049f122015-04-20 08:31:59 -07001269 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
caryclark54359292015-03-26 07:52:43 -07001270 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
1271 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -07001272 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
caryclark54359292015-03-26 07:52:43 -07001273 int used = i.used();
1274 for (int index = 0; index < used; ++index) {
1275 if (cPt.roughlyEqual(i.pt(index))) {
reed0dc4dd62015-03-24 13:55:33 -07001276 return true;
1277 }
caryclark54359292015-03-26 07:52:43 -07001278 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +00001279 return false;
1280}
1281
caryclark54359292015-03-26 07:52:43 -07001282bool SkOpSegment::isXor() const {
1283 return fContour->isXor();
1284}
caryclark@google.com07393ca2013-04-08 11:47:37 +00001285
caryclark54359292015-03-26 07:52:43 -07001286SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) {
1287 int step = start->step(end);
1288 SkOpSpan* minSpan = start->starter(end);
1289 markDone(minSpan);
1290 SkOpSpanBase* last = NULL;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001291 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -07001292 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001293 if (other->done()) {
caryclarkdac1d172014-06-17 05:15:38 -07001294 SkASSERT(!last);
1295 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001296 }
caryclark54359292015-03-26 07:52:43 -07001297 other->markDone(minSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001298 }
1299 return last;
1300}
1301
caryclark54359292015-03-26 07:52:43 -07001302bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
1303 SkOpSpanBase** lastPtr) {
1304 SkOpSpan* spanStart = start->starter(end);
1305 int step = start->step(end);
1306 bool success = markWinding(spanStart, winding);
1307 SkOpSpanBase* last = NULL;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001308 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -07001309 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
1310 if (spanStart->windSum() != SK_MinS32) {
1311 SkASSERT(spanStart->windSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -07001312 SkASSERT(!last);
1313 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001314 }
caryclark54359292015-03-26 07:52:43 -07001315 (void) other->markWinding(spanStart, winding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001316 }
caryclark65f55312014-11-13 06:58:52 -08001317 if (lastPtr) {
1318 *lastPtr = last;
1319 }
1320 return success;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001321}
1322
caryclark54359292015-03-26 07:52:43 -07001323bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
1324 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
1325 SkOpSpan* spanStart = start->starter(end);
1326 int step = start->step(end);
1327 bool success = markWinding(spanStart, winding, oppWinding);
1328 SkOpSpanBase* last = NULL;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001329 SkOpSegment* other = this;
caryclark54359292015-03-26 07:52:43 -07001330 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
1331 if (spanStart->windSum() != SK_MinS32) {
1332 if (this->operand() == other->operand()) {
1333 SkASSERT(spanStart->windSum() == winding);
1334 if (spanStart->oppSum() != oppWinding) {
1335 this->globalState()->setWindingFailed();
1336 return false;
caryclarkdac1d172014-06-17 05:15:38 -07001337 }
caryclark54359292015-03-26 07:52:43 -07001338 } else {
1339 SkASSERT(spanStart->windSum() == oppWinding);
1340 SkASSERT(spanStart->oppSum() == winding);
caryclarkdac1d172014-06-17 05:15:38 -07001341 }
1342 SkASSERT(!last);
caryclarkdac1d172014-06-17 05:15:38 -07001343 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001344 }
caryclark54359292015-03-26 07:52:43 -07001345 if (this->operand() == other->operand()) {
1346 (void) other->markWinding(spanStart, winding, oppWinding);
caryclarkdac1d172014-06-17 05:15:38 -07001347 } else {
caryclark54359292015-03-26 07:52:43 -07001348 (void) other->markWinding(spanStart, oppWinding, winding);
caryclarkdac1d172014-06-17 05:15:38 -07001349 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001350 }
caryclark65f55312014-11-13 06:58:52 -08001351 if (lastPtr) {
1352 *lastPtr = last;
1353 }
1354 return success;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001355}
1356
caryclark54359292015-03-26 07:52:43 -07001357SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001358 SkASSERT(angle->segment() == this);
1359 if (UseInnerWinding(maxWinding, sumWinding)) {
1360 maxWinding = sumWinding;
1361 }
caryclark54359292015-03-26 07:52:43 -07001362 SkOpSpanBase* last;
1363 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +00001364#if DEBUG_WINDING
1365 if (last) {
caryclark54359292015-03-26 07:52:43 -07001366 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
1367 last->segment()->debugID(), last->debugID());
1368 if (!last->final()) {
1369 SkDebugf(" windSum=");
1370 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
1371 }
1372 SkDebugf("\n");
caryclark@google.com570863f2013-09-16 15:55:01 +00001373 }
1374#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00001375 return last;
1376}
1377
caryclark54359292015-03-26 07:52:43 -07001378SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
1379 int oppSumWinding, const SkOpAngle* angle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001380 SkASSERT(angle->segment() == this);
1381 if (UseInnerWinding(maxWinding, sumWinding)) {
1382 maxWinding = sumWinding;
1383 }
1384 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
1385 oppMaxWinding = oppSumWinding;
1386 }
caryclark54359292015-03-26 07:52:43 -07001387 SkOpSpanBase* last = NULL;
caryclark65f55312014-11-13 06:58:52 -08001388 // caller doesn't require that this marks anything
caryclark54359292015-03-26 07:52:43 -07001389 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
caryclark@google.com570863f2013-09-16 15:55:01 +00001390#if DEBUG_WINDING
1391 if (last) {
caryclark54359292015-03-26 07:52:43 -07001392 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
1393 last->segment()->debugID(), last->debugID());
1394 if (!last->final()) {
1395 SkDebugf(" windSum=");
1396 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
1397 }
1398 SkDebugf(" \n");
caryclark@google.com570863f2013-09-16 15:55:01 +00001399 }
1400#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +00001401 return last;
1402}
1403
caryclark54359292015-03-26 07:52:43 -07001404void SkOpSegment::markDone(SkOpSpan* span) {
1405 SkASSERT(this == span->segment());
1406 if (span->done()) {
1407 return;
1408 }
1409#if DEBUG_MARK_DONE
1410 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
1411#endif
1412 span->setDone(true);
1413 ++fDoneCount;
1414 debugValidate();
1415}
1416
1417bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
1418 SkASSERT(this == span->segment());
reed0dc4dd62015-03-24 13:55:33 -07001419 SkASSERT(winding);
caryclark54359292015-03-26 07:52:43 -07001420 if (span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001421 return false;
1422 }
1423#if DEBUG_MARK_DONE
caryclark54359292015-03-26 07:52:43 -07001424 debugShowNewWinding(__FUNCTION__, span, winding);
reed0dc4dd62015-03-24 13:55:33 -07001425#endif
caryclark54359292015-03-26 07:52:43 -07001426 span->setWindSum(winding);
1427 debugValidate();
reed0dc4dd62015-03-24 13:55:33 -07001428 return true;
1429}
1430
caryclark54359292015-03-26 07:52:43 -07001431bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
1432 SkASSERT(this == span->segment());
caryclark@google.com07393ca2013-04-08 11:47:37 +00001433 SkASSERT(winding || oppWinding);
caryclark54359292015-03-26 07:52:43 -07001434 if (span->done()) {
1435 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001436 }
caryclark54359292015-03-26 07:52:43 -07001437#if DEBUG_MARK_DONE
1438 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1439#endif
1440 span->setWindSum(winding);
1441 span->setOppSum(oppWinding);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001442 debugValidate();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001443 return true;
1444}
1445
caryclark54359292015-03-26 07:52:43 -07001446bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
1447 const SkPoint& testPt) const {
1448 const SkOpSegment* baseParent = base->segment();
1449 if (this == baseParent && this == testParent && precisely_equal(base->fT, testT)) {
1450 return true;
1451 }
1452 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1453 return false;
1454 }
1455 return !ptsDisjoint(base->fT, base->fPt, testT, testPt);
1456}
1457
1458static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1459 if (last) {
1460 *last = endSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001461 }
1462 return NULL;
1463}
1464
caryclark54359292015-03-26 07:52:43 -07001465bool SkOpSegment::monotonicInY(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1466 SkASSERT(fVerb != SkPath::kLine_Verb);
1467 if (fVerb == SkPath::kQuad_Verb) {
1468 SkDQuad dst = SkDQuad::SubDivide(fPts, start->t(), end->t());
1469 return dst.monotonicInY();
1470 }
caryclark1049f122015-04-20 08:31:59 -07001471 if (fVerb == SkPath::kConic_Verb) {
1472 SkDConic dst = SkDConic::SubDivide(fPts, fWeight, start->t(), end->t());
1473 return dst.monotonicInY();
1474 }
caryclark54359292015-03-26 07:52:43 -07001475 SkASSERT(fVerb == SkPath::kCubic_Verb);
1476 SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t());
1477 return dst.monotonicInY();
1478}
1479
1480bool SkOpSegment::NextCandidate(SkOpSpanBase* span, SkOpSpanBase** start,
1481 SkOpSpanBase** end) {
1482 while (span->final() || span->upCast()->done()) {
1483 if (span->final()) {
1484 return false;
1485 }
1486 span = span->upCast()->next();
1487 }
1488 *start = span;
1489 *end = span->upCast()->next();
1490 return true;
1491}
1492
1493SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1494 SkOpSpanBase** last) const {
1495 SkOpSpanBase* origStart = *startPtr;
caryclarkdac1d172014-06-17 05:15:38 -07001496 int step = *stepPtr;
caryclark54359292015-03-26 07:52:43 -07001497 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1498 SkASSERT(endSpan);
1499 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1500 SkOpSpanBase* foundSpan;
1501 SkOpSpanBase* otherEnd;
caryclarkdac1d172014-06-17 05:15:38 -07001502 SkOpSegment* other;
1503 if (angle == NULL) {
caryclark54359292015-03-26 07:52:43 -07001504 if (endSpan->t() != 0 && endSpan->t() != 1) {
caryclarkdac1d172014-06-17 05:15:38 -07001505 return NULL;
1506 }
caryclark54359292015-03-26 07:52:43 -07001507 SkOpPtT* otherPtT = endSpan->ptT()->next();
1508 other = otherPtT->segment();
1509 foundSpan = otherPtT->span();
1510 otherEnd = step > 0 ? foundSpan->upCast()->next() : foundSpan->prev();
caryclarkdac1d172014-06-17 05:15:38 -07001511 } else {
1512 int loopCount = angle->loopCount();
1513 if (loopCount > 2) {
caryclark54359292015-03-26 07:52:43 -07001514 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001515 }
1516 const SkOpAngle* next = angle->next();
caryclark65b427c2014-09-18 10:32:57 -07001517 if (NULL == next) {
1518 return NULL;
1519 }
caryclarkdac1d172014-06-17 05:15:38 -07001520#if DEBUG_WINDING
caryclark54359292015-03-26 07:52:43 -07001521 if (angle->sign() != next->sign() && !angle->segment()->contour()->isXor()
1522 && !next->segment()->contour()->isXor()) {
caryclarkdac1d172014-06-17 05:15:38 -07001523 SkDebugf("%s mismatched signs\n", __FUNCTION__);
reed0dc4dd62015-03-24 13:55:33 -07001524 }
caryclark54359292015-03-26 07:52:43 -07001525#endif
caryclarkdac1d172014-06-17 05:15:38 -07001526 other = next->segment();
caryclark54359292015-03-26 07:52:43 -07001527 foundSpan = endSpan = next->start();
caryclarkdac1d172014-06-17 05:15:38 -07001528 otherEnd = next->end();
caryclark@google.com570863f2013-09-16 15:55:01 +00001529 }
caryclark54359292015-03-26 07:52:43 -07001530 int foundStep = foundSpan->step(otherEnd);
caryclarkdac1d172014-06-17 05:15:38 -07001531 if (*stepPtr != foundStep) {
caryclark54359292015-03-26 07:52:43 -07001532 return set_last(last, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001533 }
caryclark54359292015-03-26 07:52:43 -07001534 SkASSERT(*startPtr);
1535 if (!otherEnd) {
caryclark65b427c2014-09-18 10:32:57 -07001536 return NULL;
1537 }
1538// SkASSERT(otherEnd >= 0);
caryclark54359292015-03-26 07:52:43 -07001539 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1540 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1541 if (foundMin->windValue() != origMin->windValue()
1542 || foundMin->oppValue() != origMin->oppValue()) {
1543 return set_last(last, endSpan);
caryclarkdac1d172014-06-17 05:15:38 -07001544 }
caryclark54359292015-03-26 07:52:43 -07001545 *startPtr = foundSpan;
caryclarkdac1d172014-06-17 05:15:38 -07001546 *stepPtr = foundStep;
1547 if (minPtr) {
1548 *minPtr = foundMin;
caryclark@google.coma5e55922013-05-07 18:51:31 +00001549 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00001550 return other;
1551}
1552
caryclark54359292015-03-26 07:52:43 -07001553static void clear_visited(SkOpSpan* span) {
1554 // reset visited flag back to false
1555 do {
1556 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1557 while ((ptT = ptT->next()) != stopPtT) {
1558 SkOpSegment* opp = ptT->segment();
1559 opp->resetVisited();
caryclark@google.com07393ca2013-04-08 11:47:37 +00001560 }
caryclark54359292015-03-26 07:52:43 -07001561 } while ((span = span->next()->upCastable()));
reed0dc4dd62015-03-24 13:55:33 -07001562}
1563
caryclark54359292015-03-26 07:52:43 -07001564// look for pairs of undetected coincident curves
1565// assumes that segments going in have visited flag clear
1566// curve/curve intersection should now do a pretty good job of finding coincident runs so
1567// this may be only be necessary for line/curve pairs -- so skip unless this is a line and the
1568// the opp is not a line
1569void SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) {
1570 if (this->verb() != SkPath::kLine_Verb) {
1571 return;
1572 }
1573 SkOpSpan* prior = NULL;
1574 SkOpSpan* span = &fHead;
1575 do {
1576 SkOpPtT* ptT = span->ptT(), * spanStopPtT = ptT;
1577 SkASSERT(ptT->span() == span);
1578 while ((ptT = ptT->next()) != spanStopPtT) {
1579 SkOpSegment* opp = ptT->span()->segment();
1580 if (opp->setVisited()) {
caryclark@google.com570863f2013-09-16 15:55:01 +00001581 continue;
1582 }
caryclark54359292015-03-26 07:52:43 -07001583 if (opp->verb() == SkPath::kLine_Verb) {
caryclarkccec0f92015-03-24 07:28:17 -07001584 continue;
1585 }
caryclark54359292015-03-26 07:52:43 -07001586 if (span->containsCoincidence(opp)) { // FIXME: this assumes that if the opposite
1587 // segment is coincident then no more coincidence
1588 // needs to be detected. This may not be true.
1589 continue;
reed0dc4dd62015-03-24 13:55:33 -07001590 }
caryclark54359292015-03-26 07:52:43 -07001591 if (span->containsCoinEnd(opp)) {
1592 continue;
1593 }
1594 // if already visited and visited again, check for coin
1595 if (span == &fHead) {
1596 continue;
1597 }
1598 SkOpPtT* priorPtT = NULL, * priorStopPtT;
1599 // find prior span containing opp segment
1600 SkOpSegment* priorOpp = NULL;
1601 prior = span;
1602 while (!priorOpp && (prior = prior->prev())) {
1603 priorStopPtT = priorPtT = prior->ptT();
1604 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
1605 SkOpSegment* segment = priorPtT->span()->segment();
1606 if (segment == opp) {
1607 priorOpp = opp;
1608 break;
1609 }
1610 }
1611 }
1612 if (!priorOpp) {
1613 continue;
1614 }
1615 SkOpPtT* oppStart = prior->ptT();
1616 SkOpPtT* oppEnd = span->ptT();
1617 bool swapped = priorPtT->fT > ptT->fT;
1618 if (swapped) {
1619 SkTSwap(priorPtT, ptT);
1620 SkTSwap(oppStart, oppEnd);
1621 }
1622 bool flipped = oppStart->fT > oppEnd->fT;
1623 bool coincident;
1624 if (coincidences->contains(priorPtT, ptT, oppStart, oppEnd, flipped)) {
1625 goto swapBack;
1626 }
1627 {
1628 // average t, find mid pt
1629 double midT = (prior->t() + span->t()) / 2;
1630 SkPoint midPt = this->ptAtT(midT);
1631 coincident = true;
1632 // if the mid pt is not near either end pt, project perpendicular through opp seg
1633 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1634 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
1635 coincident = false;
1636 SkIntersections i;
caryclark1049f122015-04-20 08:31:59 -07001637 SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->weight(), midT);
caryclark54359292015-03-26 07:52:43 -07001638 SkDLine ray = {{{midPt.fX, midPt.fY},
1639 {midPt.fX + dxdy.fY, midPt.fY - dxdy.fX}}};
caryclark1049f122015-04-20 08:31:59 -07001640 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), ray, &i);
caryclark54359292015-03-26 07:52:43 -07001641 // measure distance and see if it's small enough to denote coincidence
1642 for (int index = 0; index < i.used(); ++index) {
1643 SkDPoint oppPt = i.pt(index);
1644 if (oppPt.approximatelyEqual(midPt)) {
caryclark1049f122015-04-20 08:31:59 -07001645 SkVector oppDxdy = (*CurveSlopeAtT[opp->verb()])(opp->pts(),
1646 opp->weight(), i[index][0]);
caryclark54359292015-03-26 07:52:43 -07001647 oppDxdy.normalize();
1648 dxdy.normalize();
1649 SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy) / FLT_EPSILON);
1650 coincident |= flatness < 5000; // FIXME: replace with tuned value
1651 }
1652 }
1653 }
1654 }
1655 if (coincident) {
1656 // mark coincidence
1657 coincidences->add(priorPtT, ptT, oppStart, oppEnd, allocator);
1658 clear_visited(&fHead);
1659 missingCoincidence(coincidences, allocator);
1660 return;
1661 }
1662 swapBack:
1663 if (swapped) {
1664 SkTSwap(priorPtT, ptT);
1665 }
reed0dc4dd62015-03-24 13:55:33 -07001666 }
caryclark54359292015-03-26 07:52:43 -07001667 } while ((span = span->next()->upCastable()));
1668 clear_visited(&fHead);
reed0dc4dd62015-03-24 13:55:33 -07001669}
1670
caryclark54359292015-03-26 07:52:43 -07001671// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
1672bool SkOpSegment::moveNearby() {
1673 debugValidate();
1674 SkOpSpanBase* spanS = &fHead;
1675 do {
1676 SkOpSpanBase* test = spanS->upCast()->next();
1677 SkOpSpanBase* next;
1678 if (spanS->contains(test)) {
1679 if (!test->final()) {
1680 test->upCast()->detach(spanS->ptT());
1681 continue;
1682 } else if (spanS != &fHead) {
1683 spanS->upCast()->detach(test->ptT());
1684 spanS = test;
1685 continue;
1686 }
reed0dc4dd62015-03-24 13:55:33 -07001687 }
caryclark54359292015-03-26 07:52:43 -07001688 do { // iterate through all spans associated with start
1689 SkOpPtT* startBase = spanS->ptT();
1690 next = test->final() ? NULL : test->upCast()->next();
1691 do {
1692 SkOpPtT* testBase = test->ptT();
1693 do {
1694 if (startBase == testBase) {
1695 goto checkNextSpan;
1696 }
1697 if (testBase->duplicate()) {
1698 continue;
1699 }
1700 if (this->match(startBase, testBase->segment(), testBase->fT, testBase->fPt)) {
1701 if (test == &this->fTail) {
1702 if (spanS == &fHead) {
1703 debugValidate();
1704 return true; // if this span has collapsed, remove it from parent
1705 }
1706 this->fTail.merge(spanS->upCast());
1707 debugValidate();
1708 return true;
1709 }
1710 spanS->merge(test->upCast());
1711 spanS->upCast()->setNext(next);
1712 goto checkNextSpan;
1713 }
1714 } while ((testBase = testBase->next()) != test->ptT());
1715 } while ((startBase = startBase->next()) != spanS->ptT());
1716 checkNextSpan:
1717 ;
1718 } while ((test = next));
1719 spanS = spanS->upCast()->next();
1720 } while (!spanS->final());
1721 debugValidate();
1722 return true;
reed0dc4dd62015-03-24 13:55:33 -07001723}
1724
caryclark54359292015-03-26 07:52:43 -07001725bool SkOpSegment::operand() const {
1726 return fContour->operand();
1727}
1728
1729bool SkOpSegment::oppXor() const {
1730 return fContour->oppXor();
1731}
1732
1733bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1734 if (fVerb == SkPath::kLine_Verb) {
1735 return false;
1736 }
1737 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1738 // hits in two places with very different t values.
1739 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1740 // 'controls contained by ends' could avoid this check for common curves
1741 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1742 // on the other hand, the below check is relatively inexpensive
1743 double midT = (t1 + t2) / 2;
1744 SkPoint midPt = this->ptAtT(midT);
1745 double seDistSq = SkTMax(pt1.distanceToSqd(pt2) * 2, FLT_EPSILON * 2);
1746 return midPt.distanceToSqd(pt1) > seDistSq || midPt.distanceToSqd(pt2) > seDistSq;
1747}
1748
1749void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1750 int* maxWinding, int* sumWinding) {
1751 int deltaSum = SpanSign(start, end);
1752 *maxWinding = *sumMiWinding;
1753 *sumWinding = *sumMiWinding -= deltaSum;
1754 SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1755}
1756
1757void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1758 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1759 int* oppSumWinding) {
1760 int deltaSum = SpanSign(start, end);
1761 int oppDeltaSum = OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001762 if (operand()) {
1763 *maxWinding = *sumSuWinding;
1764 *sumWinding = *sumSuWinding -= deltaSum;
1765 *oppMaxWinding = *sumMiWinding;
1766 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1767 } else {
1768 *maxWinding = *sumMiWinding;
1769 *sumWinding = *sumMiWinding -= deltaSum;
1770 *oppMaxWinding = *sumSuWinding;
1771 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1772 }
caryclark54359292015-03-26 07:52:43 -07001773 SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1774 SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001775}
1776
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001777void SkOpSegment::sortAngles() {
caryclark54359292015-03-26 07:52:43 -07001778 SkOpSpanBase* span = &this->fHead;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001779 do {
caryclark54359292015-03-26 07:52:43 -07001780 SkOpAngle* fromAngle = span->fromAngle();
1781 SkOpAngle* toAngle = span->final() ? NULL : span->upCast()->toAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001782 if (!fromAngle && !toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001783 continue;
1784 }
caryclark@google.com570863f2013-09-16 15:55:01 +00001785#if DEBUG_ANGLE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001786 bool wroteAfterHeader = false;
caryclark@google.com570863f2013-09-16 15:55:01 +00001787#endif
caryclark54359292015-03-26 07:52:43 -07001788 SkOpAngle* baseAngle = fromAngle;
1789 if (fromAngle && toAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001790#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001791 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1792 span->debugID());
1793 wroteAfterHeader = true;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001794#endif
caryclark54359292015-03-26 07:52:43 -07001795 fromAngle->insert(toAngle);
1796 } else if (!fromAngle) {
1797 baseAngle = toAngle;
reed0dc4dd62015-03-24 13:55:33 -07001798 }
caryclark54359292015-03-26 07:52:43 -07001799 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
reed0dc4dd62015-03-24 13:55:33 -07001800 do {
caryclark54359292015-03-26 07:52:43 -07001801 SkOpSpanBase* oSpan = ptT->span();
1802 if (oSpan == span) {
1803 continue;
1804 }
1805 SkOpAngle* oAngle = oSpan->fromAngle();
caryclarkdac1d172014-06-17 05:15:38 -07001806 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001807#if DEBUG_ANGLE
1808 if (!wroteAfterHeader) {
caryclark54359292015-03-26 07:52:43 -07001809 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1810 span->t(), span->debugID());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001811 wroteAfterHeader = true;
1812 }
1813#endif
caryclark54359292015-03-26 07:52:43 -07001814 if (!oAngle->loopContains(baseAngle)) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001815 baseAngle->insert(oAngle);
1816 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001817 }
caryclark54359292015-03-26 07:52:43 -07001818 if (!oSpan->final()) {
1819 oAngle = oSpan->upCast()->toAngle();
1820 if (oAngle) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001821#if DEBUG_ANGLE
caryclark54359292015-03-26 07:52:43 -07001822 if (!wroteAfterHeader) {
1823 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1824 span->t(), span->debugID());
1825 wroteAfterHeader = true;
1826 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001827#endif
caryclark54359292015-03-26 07:52:43 -07001828 if (!oAngle->loopContains(baseAngle)) {
1829 baseAngle->insert(oAngle);
1830 }
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001831 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001832 }
caryclark54359292015-03-26 07:52:43 -07001833 } while ((ptT = ptT->next()) != stopPtT);
1834 if (baseAngle->loopCount() == 1) {
1835 span->setFromAngle(NULL);
1836 if (toAngle) {
1837 span->upCast()->setToAngle(NULL);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001838 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +00001839 baseAngle = NULL;
1840 }
1841#if DEBUG_SORT
1842 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1843#endif
caryclark54359292015-03-26 07:52:43 -07001844 } while (!span->final() && (span = span->upCast()->next()));
caryclark@google.com570863f2013-09-16 15:55:01 +00001845}
1846
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001847// return true if midpoints were computed
caryclark54359292015-03-26 07:52:43 -07001848bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001849 SkOpCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001850 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001851 const SkOpPtT& startPtT = *start->ptT();
1852 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001853 SkDEBUGCODE(edge->fVerb = fVerb);
1854 edge->fPts[0] = startPtT.fPt;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001855 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001856 edge->fPts[points] = endPtT.fPt;
1857 edge->fWeight = 1;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001858 if (fVerb == SkPath::kLine_Verb) {
1859 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001860 }
caryclark54359292015-03-26 07:52:43 -07001861 double startT = startPtT.fT;
1862 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001863 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1864 // don't compute midpoints if we already have them
1865 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001866 edge->fPts[1] = fPts[1];
1867 return false;
1868 }
1869 if (fVerb == SkPath::kConic_Verb) {
1870 edge->fPts[1] = fPts[1];
1871 edge->fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001872 return false;
1873 }
1874 SkASSERT(fVerb == SkPath::kCubic_Verb);
1875 if (start < end) {
caryclark1049f122015-04-20 08:31:59 -07001876 edge->fPts[1] = fPts[1];
1877 edge->fPts[2] = fPts[2];
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001878 return false;
1879 }
caryclark1049f122015-04-20 08:31:59 -07001880 edge->fPts[1] = fPts[2];
1881 edge->fPts[2] = fPts[1];
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001882 return false;
1883 }
caryclark1049f122015-04-20 08:31:59 -07001884 const SkDPoint sub[2] = {{ edge->fPts[0].fX, edge->fPts[0].fY},
1885 {edge->fPts[points].fX, edge->fPts[points].fY }};
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001886 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001887 edge->fPts[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
1888 } else if (fVerb == SkPath::kConic_Verb) {
1889 edge->fPts[1] = SkDConic::SubDivide(fPts, fWeight, sub[0], sub[1],
1890 startT, endT, &edge->fWeight).asSkPoint();
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001891 } else {
1892 SkASSERT(fVerb == SkPath::kCubic_Verb);
1893 SkDPoint ctrl[2];
1894 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
caryclark1049f122015-04-20 08:31:59 -07001895 edge->fPts[1] = ctrl[0].asSkPoint();
1896 edge->fPts[2] = ctrl[1].asSkPoint();
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001897 }
1898 return true;
1899}
1900
caryclark54359292015-03-26 07:52:43 -07001901bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
caryclark1049f122015-04-20 08:31:59 -07001902 SkDCurve* edge) const {
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001903 SkASSERT(start != end);
caryclark54359292015-03-26 07:52:43 -07001904 const SkOpPtT& startPtT = *start->ptT();
1905 const SkOpPtT& endPtT = *end->ptT();
caryclark1049f122015-04-20 08:31:59 -07001906 SkDEBUGCODE(edge->fVerb = fVerb);
1907 edge->fCubic[0].set(startPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001908 int points = SkPathOpsVerbToPoints(fVerb);
caryclark1049f122015-04-20 08:31:59 -07001909 edge->fCubic[points].set(endPtT.fPt);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001910 if (fVerb == SkPath::kLine_Verb) {
1911 return false;
1912 }
caryclark54359292015-03-26 07:52:43 -07001913 double startT = startPtT.fT;
1914 double endT = endPtT.fT;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001915 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1916 // don't compute midpoints if we already have them
1917 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001918 edge->fLine[1].set(fPts[1]);
1919 return false;
1920 }
1921 if (fVerb == SkPath::kConic_Verb) {
1922 edge->fConic[1].set(fPts[1]);
1923 edge->fConic.fWeight = fWeight;
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001924 return false;
1925 }
1926 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark54359292015-03-26 07:52:43 -07001927 if (startT == 0) {
caryclark1049f122015-04-20 08:31:59 -07001928 edge->fCubic[1].set(fPts[1]);
1929 edge->fCubic[2].set(fPts[2]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001930 return false;
1931 }
caryclark1049f122015-04-20 08:31:59 -07001932 edge->fCubic[1].set(fPts[2]);
1933 edge->fCubic[2].set(fPts[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001934 return false;
1935 }
1936 if (fVerb == SkPath::kQuad_Verb) {
caryclark1049f122015-04-20 08:31:59 -07001937 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1938 } else if (fVerb == SkPath::kConic_Verb) {
1939 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1940 startT, endT, &edge->fConic.fWeight);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001941 } else {
1942 SkASSERT(fVerb == SkPath::kCubic_Verb);
caryclark1049f122015-04-20 08:31:59 -07001943 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
caryclark@google.comcffbcc32013-06-04 17:59:42 +00001944 }
1945 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +00001946}
1947
caryclark54359292015-03-26 07:52:43 -07001948void SkOpSegment::subDivideBounds(const SkOpSpanBase* start, const SkOpSpanBase* end,
1949 SkPathOpsBounds* bounds) const {
caryclark1049f122015-04-20 08:31:59 -07001950 SkOpCurve edge;
1951 subDivide(start, end, &edge);
1952 (bounds->*SetCurveBounds[fVerb])(edge.fPts, edge.fWeight);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001953}
1954
caryclark54359292015-03-26 07:52:43 -07001955void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
1956 SkOpSpan* span = this->head();
1957 do {
1958 if (!span->done()) {
reed0dc4dd62015-03-24 13:55:33 -07001959 break;
1960 }
caryclark54359292015-03-26 07:52:43 -07001961 } while ((span = span->next()->upCastable()));
1962 SkASSERT(span);
1963 *start = span;
1964 *end = span->next();
reed0dc4dd62015-03-24 13:55:33 -07001965}
1966
caryclark54359292015-03-26 07:52:43 -07001967int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1968 const SkOpSpan* lesser = start->starter(end);
1969 int oppWinding = lesser->oppSum();
1970 int oppSpanWinding = SkOpSegment::OppSign(start, end);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001971 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1972 && oppWinding != SK_MaxS32) {
1973 oppWinding -= oppSpanWinding;
1974 }
1975 return oppWinding;
1976}
1977
1978int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001979 const SkOpSpanBase* startSpan = angle->start();
1980 const SkOpSpanBase* endSpan = angle->end();
1981 return updateOppWinding(endSpan, startSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001982}
1983
1984int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07001985 const SkOpSpanBase* startSpan = angle->start();
1986 const SkOpSpanBase* endSpan = angle->end();
1987 return updateOppWinding(startSpan, endSpan);
caryclark@google.com07393ca2013-04-08 11:47:37 +00001988}
1989
caryclark54359292015-03-26 07:52:43 -07001990int SkOpSegment::updateWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1991 const SkOpSpan* lesser = start->starter(end);
1992 int winding = lesser->windSum();
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +00001993 if (winding == SK_MinS32) {
1994 return winding;
1995 }
caryclark54359292015-03-26 07:52:43 -07001996 int spanWinding = SkOpSegment::SpanSign(start, end);
caryclark@google.com570863f2013-09-16 15:55:01 +00001997 if (winding && UseInnerWinding(winding - spanWinding, winding)
1998 && winding != SK_MaxS32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +00001999 winding -= spanWinding;
2000 }
2001 return winding;
2002}
2003
2004int SkOpSegment::updateWinding(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07002005 const SkOpSpanBase* startSpan = angle->start();
2006 const SkOpSpanBase* endSpan = angle->end();
2007 return updateWinding(endSpan, startSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00002008}
2009
caryclark@google.com07393ca2013-04-08 11:47:37 +00002010int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07002011 const SkOpSpanBase* startSpan = angle->start();
2012 const SkOpSpanBase* endSpan = angle->end();
2013 return updateWinding(startSpan, endSpan);
caryclark@google.com570863f2013-09-16 15:55:01 +00002014}
2015
2016// OPTIMIZATION: does the following also work, and is it any faster?
2017// return outerWinding * innerWinding > 0
2018// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
2019bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
2020 SkASSERT(outerWinding != SK_MaxS32);
2021 SkASSERT(innerWinding != SK_MaxS32);
2022 int absOut = abs(outerWinding);
2023 int absIn = abs(innerWinding);
2024 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
2025 return result;
2026}
2027
caryclark54359292015-03-26 07:52:43 -07002028int SkOpSegment::windingAtT(double tHit, const SkOpSpan* span, bool crossOpp,
2029 SkScalar* dx) const {
2030 if (approximately_zero(tHit - span->t())) { // if we hit the end of a span, disregard
caryclark@google.com07393ca2013-04-08 11:47:37 +00002031 return SK_MinS32;
2032 }
caryclark54359292015-03-26 07:52:43 -07002033 int winding = crossOpp ? span->oppSum() : span->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00002034 SkASSERT(winding != SK_MinS32);
caryclark54359292015-03-26 07:52:43 -07002035 int windVal = crossOpp ? span->oppValue() : span->windValue();
caryclark@google.com07393ca2013-04-08 11:47:37 +00002036#if DEBUG_WINDING_AT_T
caryclarkdac1d172014-06-17 05:15:38 -07002037 SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __FUNCTION__,
caryclark54359292015-03-26 07:52:43 -07002038 debugID(), crossOpp, tHit, span->t(), winding, windVal);
caryclark@google.com07393ca2013-04-08 11:47:37 +00002039#endif
2040 // see if a + change in T results in a +/- change in X (compute x'(T))
caryclark1049f122015-04-20 08:31:59 -07002041 *dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, tHit).fX;
caryclark@google.com07393ca2013-04-08 11:47:37 +00002042 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
2043 *dx = fPts[2].fX - fPts[1].fX - *dx;
2044 }
2045 if (*dx == 0) {
2046#if DEBUG_WINDING_AT_T
2047 SkDebugf(" dx=0 winding=SK_MinS32\n");
2048#endif
2049 return SK_MinS32;
2050 }
skia.committer@gmail.coma4aced42013-07-09 07:00:56 +00002051 if (windVal < 0) { // reverse sign if opp contour traveled in reverse
caryclark@google.com07e97fc2013-07-08 17:17:02 +00002052 *dx = -*dx;
2053 }
caryclark@google.com07393ca2013-04-08 11:47:37 +00002054 if (winding * *dx > 0) { // if same signs, result is negative
2055 winding += *dx > 0 ? -windVal : windVal;
2056 }
2057#if DEBUG_WINDING_AT_T
2058 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding);
2059#endif
2060 return winding;
2061}
2062
2063int SkOpSegment::windSum(const SkOpAngle* angle) const {
caryclark54359292015-03-26 07:52:43 -07002064 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
2065 return minSpan->windSum();
caryclark@google.com07393ca2013-04-08 11:47:37 +00002066}