Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/pathops/SkOpCoincidence.cpp

Issue 2128633003: pathops coincidence and security rewrite (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: require resulting t to be between 0 and 1 Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 #include "SkOpCoincidence.h" 7 #include "SkOpCoincidence.h"
8 #include "SkOpSegment.h" 8 #include "SkOpSegment.h"
9 #include "SkPathOpsTSect.h" 9 #include "SkPathOpsTSect.h"
10 10
11 bool SkOpCoincidence::extend(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT * oppPtTStart, 11 #if DEBUG_COINCIDENCE
12 #define FAIL_IF(cond) SkASSERT(!(cond))
13 #else
14 #define FAIL_IF(cond) do { if (cond) return false; } while (false)
15 #endif
16
17 // returns true if coincident span's start and end are the same
18 bool SkCoincidentSpans::collapsed(const SkOpPtT* test) const {
19 return (fCoinPtTStart == test && fCoinPtTEnd->contains(test))
20 || (fCoinPtTEnd == test && fCoinPtTStart->contains(test))
21 || (fOppPtTStart == test && fOppPtTEnd->contains(test))
22 || (fOppPtTEnd == test && fOppPtTStart->contains(test));
23 }
24
25 // sets the span's end to the ptT referenced by the previous-next
26 void SkCoincidentSpans::correctOneEnd(
27 const SkOpPtT* (SkCoincidentSpans::* getEnd)() const,
28 void (SkCoincidentSpans::*setEnd)(const SkOpPtT* ptT) ) {
herb_g 2016/07/18 15:13:39 Do you need method pointers? Can this just use pla
caryclark 2016/07/18 15:55:49 It could be rewritten. I'm curious how that rewrit
29 const SkOpPtT* origPtT = (this->*getEnd)();
30 const SkOpSpanBase* origSpan = origPtT->span();
31 const SkOpSpan* prev = origSpan->prev();
32 const SkOpPtT* testPtT = prev ? prev->next()->ptT()
33 : origSpan->upCast()->next()->prev()->ptT();
34 if (origPtT != testPtT) {
35 (this->*setEnd)(testPtT);
36 }
37 }
38
39 // makes all span ends agree with the segment's spans that define them
40 void SkCoincidentSpans::correctEnds() {
41 this->correctOneEnd(&SkCoincidentSpans::coinPtTStart, &SkCoincidentSpans::se tCoinPtTStart);
42 this->correctOneEnd(&SkCoincidentSpans::coinPtTEnd, &SkCoincidentSpans::setC oinPtTEnd);
43 this->correctOneEnd(&SkCoincidentSpans::oppPtTStart, &SkCoincidentSpans::set OppPtTStart);
44 this->correctOneEnd(&SkCoincidentSpans::oppPtTEnd, &SkCoincidentSpans::setOp pPtTEnd);
45 }
46
47 /* Please keep this in sync with debugExpand */
48 // expand the range by checking adjacent spans for coincidence
49 bool SkCoincidentSpans::expand() {
50 bool expanded = false;
51 const SkOpSegment* segment = coinPtTStart()->segment();
52 const SkOpSegment* oppSegment = oppPtTStart()->segment();
53 do {
54 const SkOpSpan* start = coinPtTStart()->span()->upCast();
55 const SkOpSpan* prev = start->prev();
56 const SkOpPtT* oppPtT;
57 if (!prev || !(oppPtT = prev->contains(oppSegment))) {
58 break;
59 }
60 double midT = (prev->t() + start->t()) / 2;
61 if (!segment->isClose(midT, oppSegment)) {
62 break;
63 }
64 setStarts(prev->ptT(), oppPtT);
65 expanded = true;
66 } while (true);
67 do {
68 const SkOpSpanBase* end = coinPtTEnd()->span();
69 SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next();
70 const SkOpPtT* oppPtT;
71 if (!next || !(oppPtT = next->contains(oppSegment))) {
72 break;
73 }
74 double midT = (end->t() + next->t()) / 2;
75 if (!segment->isClose(midT, oppSegment)) {
76 break;
77 }
78 setEnds(next->ptT(), oppPtT);
79 expanded = true;
80 } while (true);
81 return expanded;
82 }
83
84 // increase the range of this span
85 bool SkCoincidentSpans::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinP tTEnd,
86 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
87 bool result = false;
88 if (fCoinPtTStart->fT > coinPtTStart->fT || (this->flipped()
89 ? fOppPtTStart->fT < oppPtTStart->fT : fOppPtTStart->fT > oppPtTStar t->fT)) {
90 this->setStarts(coinPtTStart, oppPtTStart);
91 result = true;
92 }
93 if (fCoinPtTEnd->fT < coinPtTEnd->fT || (this->flipped()
94 ? fOppPtTEnd->fT > oppPtTEnd->fT : fOppPtTEnd->fT < oppPtTEnd->fT)) {
95 this->setEnds(coinPtTEnd, oppPtTEnd);
96 result = true;
97 }
98 return result;
99 }
100
101 // set the range of this span
102 void SkCoincidentSpans::set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart ,
103 const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* op pPtTEnd
104 SkDEBUGPARAMS(int id)) {
105 SkASSERT(SkOpCoincidence::Ordered(coinPtTStart, oppPtTStart));
106 fNext = next;
107 this->setStarts(coinPtTStart, oppPtTStart);
108 this->setEnds(coinPtTEnd, oppPtTEnd);
109 SkDEBUGCODE(fID = id);
110 }
111
112 // returns true if both points are inside this
113 bool SkCoincidentSpans::contains(const SkOpPtT* s, const SkOpPtT* e) const {
114 if (s->fT > e->fT) {
115 SkTSwap(s, e);
116 }
117 if (s->segment() == fCoinPtTStart->segment()) {
118 return fCoinPtTStart->fT <= s->fT && e->fT <= fCoinPtTEnd->fT;
119 } else {
120 SkASSERT(s->segment() == fOppPtTStart->segment());
121 double oppTs = fOppPtTStart->fT;
122 double oppTe = fOppPtTEnd->fT;
123 if (oppTs > oppTe) {
124 SkTSwap(oppTs, oppTe);
125 }
126 return oppTs <= s->fT && e->fT <= oppTe;
127 }
128 }
129
130 // returns the number of segment span's contained by this, or -1 if inconsistent
131 int SkCoincidentSpans::spanCount() const {
132 // most commonly, concidence are one span long; check for that first
133 const SkOpSpanBase* start = coinPtTStart()->span();
134 const SkOpSpanBase* end = coinPtTEnd()->span();
135 int coinIntervals = 0;
136 while (start != end) {
137 coinIntervals++;
138 start = start->upCast()->next();
139 }
140 const SkOpSpanBase* oppStart = (flipped() ? oppPtTEnd() : oppPtTStart())->sp an();
141 const SkOpSpanBase* oppEnd = (flipped() ? oppPtTStart() : oppPtTEnd())->span ();
142 int oppIntervals = 0;
143 while (oppStart != oppEnd) {
144 oppIntervals++;
145 oppStart = oppStart->upCast()->next();
146 }
147 return coinIntervals == oppIntervals ? coinIntervals : -1;
148 }
149
150 // returns true if the point is on a coincident edge, and if it is the start of that edge
151 bool SkOpCoincidence::edge(const SkOpPtT* test, bool* start) const {
152 SkCoincidentSpans* coinRec = fHead;
153 if (!coinRec) {
154 return false;
155 }
156 do {
157 if (coinRec->coinPtTStart() == test) {
158 *start = true;
159 return true;
160 }
161 if (coinRec->coinPtTEnd() == test) {
162 *start = false;
163 return true;
164 }
165 if (coinRec->oppPtTStart() == test) {
166 *start = !coinRec->flipped();
167 return true;
168 }
169 if (coinRec->coinPtTEnd() == test) {
170 *start = coinRec->flipped();
171 return true;
172 }
173 } while ((coinRec = coinRec->next()));
174 return false;
175 }
176
177 // if there is an existing pair that overlaps the addition, extend it
178 bool SkOpCoincidence::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtT End,
179 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
180 SkCoincidentSpans* test = fHead;
181 if (!test) {
182 return false;
183 }
184 const SkOpSegment* coinSeg = coinPtTStart->segment();
185 const SkOpSegment* oppSeg = oppPtTStart->segment();
186 if (!Ordered(coinPtTStart, oppPtTStart)) {
187 SkTSwap(coinSeg, oppSeg);
188 SkTSwap(coinPtTStart, oppPtTStart);
189 SkTSwap(coinPtTEnd, oppPtTEnd);
190 if (coinPtTStart->fT > coinPtTEnd->fT) {
191 SkTSwap(coinPtTStart, coinPtTEnd);
192 SkTSwap(oppPtTStart, oppPtTEnd);
193 }
194 }
195 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
196 SkDEBUGCODE(double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT));
197 do {
198 if (coinSeg != test->coinPtTStart()->segment()) {
199 continue;
200 }
201 if (oppSeg != test->oppPtTStart()->segment()) {
202 continue;
203 }
204 double oTestMinT = SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT );
205 double oTestMaxT = SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT );
206 // if debug check triggers, caller failed to check if extended already e xists
207 SkASSERT(test->coinPtTStart()->fT > coinPtTStart->fT
208 || coinPtTEnd->fT > test->coinPtTEnd()->fT
209 || oTestMinT > oppMinT || oppMaxT > oTestMaxT);
210 if ((test->coinPtTStart()->fT <= coinPtTEnd->fT
211 && coinPtTStart->fT <= test->coinPtTEnd()->fT)
212 || (oTestMinT <= oTestMaxT && oppMinT <= oTestMaxT)) {
213 test->extend(coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
214 return true;
215 }
216 } while ((test = test->next()));
217 return false;
218 }
219
220 // verifies that the coincidence hasn't already been added
221 static void DebugCheckAdd(const SkCoincidentSpans* check, const SkOpPtT* coinPtT Start,
222 const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* op pPtTEnd) {
223 #if DEBUG_COINCIDENCE
224 while (check) {
225 SkASSERT(check->coinPtTStart() != coinPtTStart || check->coinPtTEnd() != coinPtTEnd
226 || check->oppPtTStart() != oppPtTStart || check->oppPtTEnd() != oppPtTEnd);
227 SkASSERT(check->coinPtTStart() != oppPtTStart || check->coinPtTEnd() != oppPtTEnd
228 || check->oppPtTStart() != coinPtTStart || check->oppPtTEnd() != coinPtTEnd);
229 check = check->next();
230 }
231 #endif
232 }
233
234 // adds a new coincident pair
235 void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* o ppPtTStart,
12 SkOpPtT* oppPtTEnd) { 236 SkOpPtT* oppPtTEnd) {
13 // if there is an existing pair that overlaps the addition, extend it 237 // FIXME: caller should have already sorted
herb_g 2016/07/18 15:13:39 Does this need an assert to check for sortedness?
caryclark 2016/07/18 15:55:49 If it is already sorted, the Ordered() function wi
14 SkCoincidentSpans* coinRec = fHead; 238 if (!Ordered(coinPtTStart, oppPtTStart)) {
15 if (coinRec) { 239 if (oppPtTStart->fT < oppPtTEnd->fT) {
16 do { 240 this->add(oppPtTStart, oppPtTEnd, coinPtTStart, coinPtTEnd);
17 if (coinRec->fCoinPtTStart->segment() != coinPtTStart->segment()) { 241 } else {
242 this->add(oppPtTEnd, oppPtTStart, coinPtTEnd, coinPtTStart);
243 }
244 return;
245 }
246 SkASSERT(Ordered(coinPtTStart, oppPtTStart));
247 // choose the ptT at the front of the list to track
248 coinPtTStart = coinPtTStart->span()->ptT();
249 coinPtTEnd = coinPtTEnd->span()->ptT();
250 oppPtTStart = oppPtTStart->span()->ptT();
251 oppPtTEnd = oppPtTEnd->span()->ptT();
252 SkASSERT(coinPtTStart->fT < coinPtTEnd->fT);
253 SkASSERT(oppPtTStart->fT != oppPtTEnd->fT);
254 SkASSERT(!coinPtTStart->deleted());
255 SkASSERT(!coinPtTEnd->deleted());
256 SkASSERT(!oppPtTStart->deleted());
257 SkASSERT(!oppPtTEnd->deleted());
258 DebugCheckAdd(fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
259 DebugCheckAdd(fTop, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
260 SkCoincidentSpans* coinRec = SkOpTAllocator<SkCoincidentSpans>::Allocate(
261 this->globalState()->allocator());
262 coinRec->init();
263 coinRec->set(this->fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd
264 SkDEBUGPARAMS(fGlobalState->nextCoinID()));
265 fHead = coinRec;
266 }
267
268 // description below
269 void SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan) {
270 const SkOpPtT* testPtT = testSpan->ptT();
271 const SkOpPtT* stopPtT = testPtT;
272 const SkOpSegment* baseSeg = base->segment();
273 while ((testPtT = testPtT->next()) != stopPtT) {
274 const SkOpSegment* testSeg = testPtT->segment();
275 if (testPtT->deleted()) {
276 continue;
277 }
278 if (testSeg == baseSeg) {
279 continue;
280 }
281 if (this->contains(baseSeg, testSeg, testPtT->fT)) {
282 continue;
283 }
284 // intersect perp with base->ptT() with testPtT->segment()
285 SkDVector dxdy = baseSeg->dSlopeAtT(base->t());
286 const SkPoint& pt = base->pt();
287 SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}};
288 SkIntersections i;
289 (*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i);
290 for (int index = 0; index < i.used(); ++index) {
291 double t = i[0][index];
292 if (!between(0, t, 1)) {
18 continue; 293 continue;
19 } 294 }
20 if (coinRec->fOppPtTStart->segment() != oppPtTStart->segment()) { 295 SkDPoint oppPt = i.pt(index);
296 if (!oppPt.approximatelyEqual(pt)) {
21 continue; 297 continue;
22 } 298 }
23 if (coinRec->fCoinPtTStart->fT > coinPtTEnd->fT) { 299 SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg);
300 SkOpPtT* oppStart = writableSeg->addT(t, SkOpSegment::kAllowAliasMat ch, nullptr);
301 SkOpSpan* writableBase = const_cast<SkOpSpan*>(base);
302 oppStart->span()->addOppAndMerge(writableBase);
303 if (oppStart->deleted()) {
24 continue; 304 continue;
25 } 305 }
26 if (coinRec->fCoinPtTEnd->fT < coinPtTStart->fT) { 306 SkOpSegment* coinSeg = base->segment();
27 continue; 307 SkOpSegment* oppSeg = oppStart->segment();
28 } 308 double coinTs, coinTe, oppTs, oppTe;
29 if (coinRec->fCoinPtTStart->fT > coinPtTStart->fT) { 309 if (coinSeg < oppSeg) {
30 coinRec->fCoinPtTStart = coinPtTStart; 310 coinTs = base->t();
31 coinRec->fOppPtTStart = oppPtTStart; 311 coinTe = testSpan->t();
32 } 312 oppTs = oppStart->fT;
33 if (coinRec->fCoinPtTEnd->fT < coinPtTEnd->fT) { 313 oppTe = testPtT->fT;
34 coinRec->fCoinPtTEnd = coinPtTEnd; 314 } else {
35 coinRec->fOppPtTEnd = oppPtTEnd; 315 SkTSwap(coinSeg, oppSeg);
36 } 316 coinTs = oppStart->fT;
37 return true; 317 coinTe = testPtT->fT;
38 } while ((coinRec = coinRec->fNext)); 318 oppTs = base->t();
39 } 319 oppTe = testSpan->t();
320 }
321 if (coinTs > coinTe) {
322 SkTSwap(coinTs, coinTe);
323 SkTSwap(oppTs, oppTe);
324 }
325 (void) this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, op pTe);
326 }
327 }
328 }
329
330 // description below
331 bool SkOpCoincidence::addEndMovedSpans(const SkOpPtT* ptT) {
332 const SkOpSpan* base = ptT->span()->upCast();
333 const SkOpSpan* prev = base->prev();
334 if (!prev) {
335 return false;
336 }
337 if (!prev->isCanceled()) {
338 this->addEndMovedSpans(base, base->prev());
339 }
340 if (!base->isCanceled()) {
341 this->addEndMovedSpans(base, base->next());
342 }
343 return true;
344 }
345
346 /* If A is coincident with B and B includes an endpoint, and A's matching point
347 is not the endpoint (i.e., there's an implied line connecting B-end and A)
348 then assume that the same implied line may intersect another curve close to B.
349 Since we only care about coincidence that was undetected, look at the
350 ptT list on B-segment adjacent to the B-end/A ptT loop (not in the loop, but
351 next door) and see if the A matching point is close enough to form another
352 coincident pair. If so, check for a new coincident span between B-end/A ptT loop
353 and the adjacent ptT loop.
354 */
355 bool SkOpCoincidence::addEndMovedSpans() {
356 SkCoincidentSpans* span = fHead;
357 if (!span) {
358 return true;
359 }
360 fTop = span;
361 fHead = nullptr;
362 do {
363 if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) {
364 if (1 == span->coinPtTStart()->fT) {
365 return false;
366 }
367 bool onEnd = span->coinPtTStart()->fT == 0;
368 bool oOnEnd = zero_or_one(span->oppPtTStart()->fT);
369 if (onEnd) {
370 if (!oOnEnd) { // if both are on end, any nearby intersect was already found
371 if (!this->addEndMovedSpans(span->oppPtTStart())) {
372 return false;
373 }
374 }
375 } else if (oOnEnd) {
376 if (!this->addEndMovedSpans(span->coinPtTStart())) {
377 return false;
378 }
379 }
380 }
381 if (span->coinPtTEnd()->fPt != span->oppPtTEnd()->fPt) {
382 bool onEnd = span->coinPtTEnd()->fT == 1;
383 bool oOnEnd = zero_or_one(span->oppPtTEnd()->fT);
384 if (onEnd) {
385 if (!oOnEnd) {
386 if (!this->addEndMovedSpans(span->oppPtTEnd())) {
387 return false;
388 }
389 }
390 } else if (oOnEnd) {
391 if (!this->addEndMovedSpans(span->coinPtTEnd())) {
392 return false;
393 }
394 }
395 }
396 } while ((span = span->next()));
397 this->restoreHead();
398 return true;
399 }
400
401 /* Please keep this in sync with debugAddExpanded */
402 // for each coincident pair, match the spans
403 // if the spans don't match, add the missing pt to the segment and loop it in th e opposite span
404 bool SkOpCoincidence::addExpanded() {
405 SkCoincidentSpans* coin = this->fHead;
406 if (!coin) {
407 return true;
408 }
409 do {
410 const SkOpPtT* startPtT = coin->coinPtTStart();
411 const SkOpPtT* oStartPtT = coin->oppPtTStart();
412 SkASSERT(startPtT->contains(oStartPtT));
413 SkASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd()));
414 const SkOpSpanBase* start = startPtT->span();
415 const SkOpSpanBase* oStart = oStartPtT->span();
416 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
417 const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span();
418 FAIL_IF(oEnd->deleted());
419 const SkOpSpanBase* test = start->upCast()->next();
420 const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->u pCast()->next();
421 if (!oTest) {
422 return false;
423 }
424 while (test != end || oTest != oEnd) {
425 if (!test->ptT()->contains(oStart->segment())
426 || !oTest->ptT()->contains(start->segment())) {
427 // use t ranges to guess which one is missing
428 double startRange = coin->coinPtTEnd()->fT - startPtT->fT;
429 FAIL_IF(!startRange);
430 double startPart = (test->t() - startPtT->fT) / startRange;
431 double oStartRange = coin->oppPtTEnd()->fT - oStartPtT->fT;
432 FAIL_IF(!oStartRange);
433 double oStartPart = (oTest->t() - oStartPtT->fT) / oStartRange;
434 FAIL_IF(startPart == oStartPart);
435 bool startOver = false;
436 bool success = startPart < oStartPart
437 ? oStart->segment()->addExpanded(
438 oStartPtT->fT + oStartRange * startPart, test, & startOver)
439 : start->segment()->addExpanded(
440 startPtT->fT + startRange * oStartPart, oTest, & startOver);
441 if (!success) {
442 SkASSERT(0);
443 return false;
444 }
445 if (startOver) {
446 test = start;
447 oTest = oStart;
448 }
449 }
450 if (test != end) {
451 test = test->upCast()->next();
452 }
453 if (oTest != oEnd) {
454 oTest = coin->flipped() ? oTest->prev() : oTest->upCast()->next( );
455 if (!oTest) {
456 return false;
457 }
458 }
459 }
460 } while ((coin = coin->next()));
461 return true;
462 }
463
464 // checks to see if coincidence has already been found
465 bool SkOpCoincidence::alreadyAdded(const SkCoincidentSpans* check, const SkCoinc identSpans* outer,
466 const SkOpPtT* over1s, const SkOpPtT* over1e) const {
467 do {
468 if (check->oppPtTStart() == outer->coinPtTStart() && check->coinPtTStart () == over1s
469 && check->oppPtTEnd() == outer->coinPtTEnd() && check->coinPtTEn d() == over1e) {
470 return true;
471 }
472 if (check->coinPtTStart() == outer->coinPtTStart() && check->oppPtTStart () == over1s
473 && check->coinPtTEnd() == outer->coinPtTEnd() && check->oppPtTEn d() == over1e) {
474 return true;
475 }
476 if (check->startEquals(outer->oppPtTStart()->span(), over1s->span())) {
477 SkDEBUGCODE(check->debugStartCheck(outer->oppPtTEnd()->span(), over1 e->span(),
478 fGlobalState));
479 return true;
480 }
481 if (check->startEquals(over1s->span(), outer->coinPtTStart()->span())) {
482 SkDEBUGCODE(check->debugStartCheck(over1e->span(), outer->oppPtTEnd( )->span(),
483 fGlobalState));
484 return true;
485 }
486 } while ((check = check->next()));
40 return false; 487 return false;
41 } 488 }
42 489
43 void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* o ppPtTStart, 490 /* Please keep this in sync with debugAddIfMissing() */
44 SkOpPtT* oppPtTEnd, SkChunkAlloc* allocator) { 491 bool SkOpCoincidence::addIfMissing(const SkCoincidentSpans* outer, SkOpPtT* over 1s,
45 SkASSERT(coinPtTStart->fT < coinPtTEnd->fT); 492 SkOpPtT* over1e) {
46 bool flipped = oppPtTStart->fT > oppPtTEnd->fT; 493 SkASSERT(fTop);
47 SkCoincidentSpans* coinRec = SkOpTAllocator<SkCoincidentSpans>::Allocate(all ocator); 494 if (this->alreadyAdded(fTop, outer, over1s, over1e)) {
48 coinRec->fNext = this->fHead; 495 return false;
49 coinRec->fCoinPtTStart = coinPtTStart; 496 }
50 coinRec->fCoinPtTEnd = coinPtTEnd; 497 if (fHead && this->alreadyAdded(fHead, outer, over1s, over1e)) {
51 coinRec->fOppPtTStart = oppPtTStart; 498 return false;
52 coinRec->fOppPtTEnd = oppPtTEnd; 499 }
53 coinRec->fFlipped = flipped; 500 this->add(outer->coinPtTStart(), outer->coinPtTEnd(), over1s, over1e);
54 SkDEBUGCODE(coinRec->fID = fDebugState->nextCoinID()); 501 this->debugValidate();
55 502 return true;
56 this->fHead = coinRec; 503 }
57 } 504
58 505 // given a t span, map the same range on the coincident span
59 static void t_range(const SkOpPtT* overS, const SkOpPtT* overE, double tStart, d ouble tEnd, 506 void SkOpCoincidence::TRange(const SkOpPtT* overS, const SkOpPtT* overE, double tStart,
60 const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, double* coinTs, double* coinTe) { 507 double tEnd, const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, dou ble* coinTs,
508 double* coinTe) {
61 double denom = overE->fT - overS->fT; 509 double denom = overE->fT - overS->fT;
62 double start = 0 < denom ? tStart : tEnd; 510 double start = 0 < denom ? tStart : tEnd;
63 double end = 0 < denom ? tEnd : tStart; 511 double end = 0 < denom ? tEnd : tStart;
64 double sRatio = (start - overS->fT) / denom; 512 double sRatio = (start - overS->fT) / denom;
65 double eRatio = (end - overS->fT) / denom; 513 double eRatio = (end - overS->fT) / denom;
66 *coinTs = coinPtTStart->fT + (coinPtTEnd->fT - coinPtTStart->fT) * sRatio; 514 *coinTs = coinPtTStart->fT + (coinPtTEnd->fT - coinPtTStart->fT) * sRatio;
67 *coinTe = coinPtTStart->fT + (coinPtTEnd->fT - coinPtTStart->fT) * eRatio; 515 *coinTe = coinPtTStart->fT + (coinPtTEnd->fT - coinPtTStart->fT) * eRatio;
68 } 516 }
69 517
70 bool SkOpCoincidence::addExpanded(SkChunkAlloc* allocator 518 // return true if span overlaps existing and needs to adjust the coincident list
71 PATH_OPS_DEBUG_VALIDATE_PARAMS(SkOpGlobalState* globalState)) { 519 bool SkOpCoincidence::checkOverlap(SkCoincidentSpans* check,
72 #if DEBUG_VALIDATE 520 const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
73 globalState->setPhase(SkOpGlobalState::kIntersecting); 521 double coinTs, double coinTe, double oppTs, double oppTe,
74 #endif 522 SkTDArray<SkCoincidentSpans*>* overlaps) const {
75 // for each coincident pair, match the spans 523 if (!Ordered(coinSeg, oppSeg)) {
76 // if the spans don't match, add the mssing pt to the segment and loop it in the opposite span 524 if (oppTs < oppTe) {
77 SkCoincidentSpans* coin = this->fHead; 525 return this->checkOverlap(check, oppSeg, coinSeg, oppTs, oppTe, coin Ts, coinTe,
78 SkASSERT(coin); 526 overlaps);
527 }
528 return this->checkOverlap(check, oppSeg, coinSeg, oppTe, oppTs, coinTe, coinTs, overlaps);
529 }
530 bool swapOpp = oppTs > oppTe;
531 if (swapOpp) {
532 SkTSwap(oppTs, oppTe);
533 }
79 do { 534 do {
80 SkOpPtT* startPtT = coin->fCoinPtTStart; 535 if (check->coinPtTStart()->segment() != coinSeg) {
81 SkOpPtT* oStartPtT = coin->fOppPtTStart; 536 continue;
82 SkASSERT(startPtT->contains(oStartPtT)); 537 }
83 SkASSERT(coin->fCoinPtTEnd->contains(coin->fOppPtTEnd)); 538 if (check->oppPtTStart()->segment() != oppSeg) {
84 SkOpSpanBase* start = startPtT->span(); 539 continue;
85 SkOpSpanBase* oStart = oStartPtT->span(); 540 }
86 const SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 541 double checkTs = check->coinPtTStart()->fT;
87 const SkOpSpanBase* oEnd = coin->fOppPtTEnd->span(); 542 double checkTe = check->coinPtTEnd()->fT;
88 if (oEnd->deleted()) { 543 bool coinOutside = coinTe < checkTs || coinTs > checkTe;
89 return false; 544 double oCheckTs = check->oppPtTStart()->fT;
90 } 545 double oCheckTe = check->oppPtTEnd()->fT;
91 SkOpSpanBase* test = start->upCast()->next(); 546 if (swapOpp) {
92 SkOpSpanBase* oTest = coin->fFlipped ? oStart->prev() : oStart->upCast() ->next(); 547 if (oCheckTs <= oCheckTe) {
93 if (!oTest) { 548 return false;
94 return false; 549 }
95 } 550 SkTSwap(oCheckTs, oCheckTe);
96 while (test != end || oTest != oEnd) { 551 }
97 if (!test->ptT()->contains(oTest->ptT())) { 552 bool oppOutside = oppTe < oCheckTs || oppTs > oCheckTe;
98 // use t ranges to guess which one is missing 553 if (coinOutside && oppOutside) {
99 double startRange = coin->fCoinPtTEnd->fT - startPtT->fT; 554 continue;
100 if (!startRange) { 555 }
101 return false; 556 bool coinInside = coinTe <= checkTe && coinTs >= checkTs;
102 } 557 bool oppInside = oppTe <= oCheckTe && oppTs >= oCheckTs;
103 double startPart = (test->t() - startPtT->fT) / startRange; 558 if (coinInside && oppInside) {
104 double oStartRange = coin->fOppPtTEnd->fT - oStartPtT->fT; 559 return false; // complete overlap, already included, do nothing
105 if (!oStartRange) { 560 }
106 return false; 561 *overlaps->append() = check; // partial overlap, extend existing entry
107 } 562 } while ((check = check->next()));
108 double oStartPart = (oTest->t() - oStartPtT->fT) / oStartRange;
109 if (startPart == oStartPart) {
110 return false;
111 }
112 SkOpPtT* newPt;
113 if (startPart < oStartPart) {
114 double newT = oStartPtT->fT + oStartRange * startPart;
115 newPt = oStart->segment()->addT(newT, SkOpSegment::kAllowAli as, allocator);
116 if (!newPt) {
117 return false;
118 }
119 newPt->fPt = test->pt();
120 test->ptT()->addOpp(newPt);
121 } else {
122 double newT = startPtT->fT + startRange * oStartPart;
123 newPt = start->segment()->addT(newT, SkOpSegment::kAllowAlia s, allocator);
124 if (!newPt) {
125 return false;
126 }
127 newPt->fPt = oTest->pt();
128 oTest->ptT()->addOpp(newPt);
129 }
130 // start over
131 test = start;
132 oTest = oStart;
133 }
134 if (test != end) {
135 test = test->upCast()->next();
136 }
137 if (oTest != oEnd) {
138 oTest = coin->fFlipped ? oTest->prev() : oTest->upCast()->next() ;
139 if (!oTest) {
140 return false;
141 }
142 }
143 }
144 } while ((coin = coin->fNext));
145 #if DEBUG_VALIDATE
146 globalState->setPhase(SkOpGlobalState::kWalking);
147 #endif
148 return true; 563 return true;
149 } 564 }
150 565
151 bool SkOpCoincidence::addIfMissing(const SkCoincidentSpans* outer, SkOpPtT* over 1s, 566 /* Please keep this in sync with debugAddIfMissing() */
152 SkOpPtT* over1e, SkChunkAlloc* allocator) {
153 SkCoincidentSpans* check = this->fTop;
154 do {
155 if (check->fCoinPtTStart->span() == over1s->span()
156 && check->fOppPtTStart->span() == outer->fOppPtTStart->span()) {
157 SkASSERT(check->fCoinPtTEnd->span() == over1e->span()
158 || !fDebugState->debugRunFail());
159 SkASSERT(check->fOppPtTEnd->span() == outer->fOppPtTEnd->span()
160 || !fDebugState->debugRunFail());
161 return false;
162 }
163 if (check->fCoinPtTStart->span() == outer->fCoinPtTStart->span()
164 && check->fOppPtTStart->span() == over1s->span()) {
165 SkASSERT(check->fCoinPtTEnd->span() == outer->fCoinPtTEnd->span()
166 || !fDebugState->debugRunFail());
167 SkASSERT(check->fOppPtTEnd->span() == over1e->span()
168 || !fDebugState->debugRunFail());
169 return false;
170 }
171 } while ((check = check->fNext));
172 this->add(outer->fCoinPtTStart, outer->fCoinPtTEnd, over1s, over1e, allocato r);
173 #if 0
174 // FIXME: up to four flavors could be added -- do we need only one?
175 #endif
176 return true;
177 }
178
179 bool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over1e, 567 bool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over1e,
180 const SkOpPtT* over2s, const SkOpPtT* over2e, double tStar t, double tEnd, 568 const SkOpPtT* over2s, const SkOpPtT* over2e, double tStart, double tEnd ,
181 SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, 569 SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
182 SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd, SkChunkAlloc* allocator) { 570 SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
183 double coinTs, coinTe, oppTs, oppTe; 571 double coinTs, coinTe, oppTs, oppTe;
184 t_range(over1s, over1e, tStart, tEnd, coinPtTStart, coinPtTEnd, &coinTs, &co inTe); 572 TRange(over1s, over1e, tStart, tEnd, coinPtTStart, coinPtTEnd, &coinTs, &coi nTe);
185 t_range(over2s, over2e, tStart, tEnd, oppPtTStart, oppPtTEnd, &oppTs, &oppTe ); 573 TRange(over2s, over2e, tStart, tEnd, oppPtTStart, oppPtTEnd, &oppTs, &oppTe) ;
574 bool swap = coinTs > coinTe;
575 if (swap) {
576 SkTSwap(coinTs, coinTe);
577 }
578 if ((over1s->fT < over1e->fT) != (over2s->fT < over2e->fT)) {
579 SkTSwap(oppTs, oppTe);
580 }
581 if (swap) {
582 SkTSwap(oppTs, oppTe);
583 }
186 SkOpSegment* coinSeg = coinPtTStart->segment(); 584 SkOpSegment* coinSeg = coinPtTStart->segment();
187 SkOpSegment* oppSeg = oppPtTStart->segment(); 585 SkOpSegment* oppSeg = oppPtTStart->segment();
188 SkASSERT(coinSeg != oppSeg); 586 if (coinSeg == oppSeg) {
189 SkCoincidentSpans* check = this->fTop; 587 return false;
190 do { 588 }
191 const SkOpSegment* checkCoinSeg = check->fCoinPtTStart->segment(); 589 return this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe);
192 if (checkCoinSeg != coinSeg && checkCoinSeg != oppSeg) { 590 }
193 continue; 591
194 } 592 /* Please keep this in sync with debugAddOrOverlap() */
195 const SkOpSegment* checkOppSeg = check->fOppPtTStart->segment(); 593 bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
196 if (checkOppSeg != coinSeg && checkOppSeg != oppSeg) { 594 double coinTs, double coinTe, double oppTs, double oppTe) {
197 continue; 595 SkTDArray<SkCoincidentSpans*> overlaps;
198 } 596 SkASSERT(fTop);
199 int cTs = coinTs; 597 if (!this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &overlaps)) {
200 int cTe = coinTe; 598 return false;
201 int oTs = oppTs; 599 }
202 int oTe = oppTe; 600 if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
203 if (checkCoinSeg != coinSeg) { 601 coinTe, oppTs, oppTe, &overlaps)) {
204 SkASSERT(checkOppSeg != oppSeg); 602 return false;
205 SkTSwap(cTs, oTs); 603 }
206 SkTSwap(cTe, oTe); 604 SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr;
207 } 605 for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing
208 int tweenCount = (int) between(check->fCoinPtTStart->fT, cTs, check->fCo inPtTEnd->fT) 606 SkCoincidentSpans* test = overlaps[index];
209 + (int) between(check->fCoinPtTStart->fT, cTe, check->fCo inPtTEnd->fT) 607 if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) {
210 + (int) between(check->fOppPtTStart->fT, oTs, check->fOpp PtTEnd->fT) 608 overlap->setCoinPtTStart(test->coinPtTStart());
211 + (int) between(check->fOppPtTStart->fT, oTe, check->fOpp PtTEnd->fT); 609 }
212 // SkASSERT(tweenCount == 0 || tweenCount == 4); 610 if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) {
213 if (tweenCount) { 611 overlap->setCoinPtTEnd(test->coinPtTEnd());
612 }
613 if (overlap->flipped()
614 ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT
615 : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) {
616 overlap->setOppPtTStart(test->oppPtTStart());
617 }
618 if (overlap->flipped()
619 ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT
620 : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) {
621 overlap->setOppPtTEnd(test->oppPtTEnd());
622 }
623 if (!fHead || !this->release(fHead, test)) {
624 SkAssertResult(this->release(fTop, test));
625 }
626 }
627 const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg);
628 const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg);
629 if (overlap && cs && ce && overlap->contains(cs, ce)) {
630 return false;
631 }
632 SkASSERT(cs != ce || !cs);
633 const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
634 const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
635 if (overlap && os && oe && overlap->contains(os, oe)) {
636 return false;
637 }
638 SkASSERT(!cs || !cs->deleted());
639 SkASSERT(!os || !os->deleted());
640 SkASSERT(!ce || !ce->deleted());
641 SkASSERT(!oe || !oe->deleted());
642 const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullp tr;
643 const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullp tr;
644 if (csExisting && csExisting == ceExisting) {
645 return false;
646 }
647 if (csExisting && (csExisting == ce || csExisting->contains(ceExisting ? ceE xisting : ce))) {
648 return false;
649 }
650 if (ceExisting && (ceExisting == cs || ceExisting->contains(csExisting ? csE xisting : cs))) {
651 return false;
652 }
653 const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr ;
654 const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr ;
655 if (osExisting && osExisting == oeExisting) {
656 return false;
657 }
658 if (osExisting && (osExisting == oe || osExisting->contains(oeExisting ? oeE xisting : oe))) {
659 return false;
660 }
661 if (oeExisting && (oeExisting == os || oeExisting->contains(osExisting ? osE xisting : os))) {
662 return false;
663 }
664 // extra line in debug code
665 this->debugValidate();
666 if (!cs || !os) {
667 SkOpPtT* csWritable = cs ? const_cast<SkOpPtT*>(cs)
668 : coinSeg->addT(coinTs, SkOpSegment::kNoAliasMatch, nullptr);
669 SkOpPtT* osWritable = os ? const_cast<SkOpPtT*>(os)
670 : oppSeg->addT(oppTs, SkOpSegment::kNoAliasMatch, nullptr);
671 csWritable->span()->addOppAndMerge(osWritable->span());
672 cs = csWritable;
673 os = osWritable;
674 if ((ce && ce->deleted()) || (oe && oe->deleted())) {
214 return false; 675 return false;
215 } 676 }
216 } while ((check = check->fNext)); 677 }
217 if ((over1s->fT < over1e->fT) != (over2s->fT < over2e->fT)) { 678 if (!ce || !oe) {
218 SkTSwap(oppTs, oppTe); 679 SkOpPtT* ceWritable = ce ? const_cast<SkOpPtT*>(ce)
219 } 680 : coinSeg->addT(coinTe, SkOpSegment::kNoAliasMatch, nullptr);
220 if (coinTs > coinTe) { 681 SkOpPtT* oeWritable = oe ? const_cast<SkOpPtT*>(oe)
221 SkTSwap(coinTs, coinTe); 682 : oppSeg->addT(oppTe, SkOpSegment::kNoAliasMatch, nullptr);
222 SkTSwap(oppTs, oppTe); 683 ceWritable->span()->addOppAndMerge(oeWritable->span());
223 } 684 ce = ceWritable;
224 SkOpPtT* cs = coinSeg->addMissing(coinTs, oppSeg, allocator); 685 oe = oeWritable;
225 SkOpPtT* ce = coinSeg->addMissing(coinTe, oppSeg, allocator); 686 }
226 SkASSERT(cs != ce); 687 this->debugValidate();
227 SkOpPtT* os = oppSeg->addMissing(oppTs, coinSeg, allocator); 688 if (cs->deleted() || os->deleted() || ce->deleted() || oe->deleted()) {
228 SkOpPtT* oe = oppSeg->addMissing(oppTe, coinSeg, allocator); 689 return false;
229 // SkASSERT(os != oe); 690 }
230 cs->addOpp(os); 691 if (cs->contains(ce) || os->contains(oe)) {
231 ce->addOpp(oe); 692 return false;
232 this->add(cs, ce, os, oe, allocator); 693 }
233 return true; 694 bool result = true;
234 } 695 if (overlap) {
235 696 if (overlap->coinPtTStart()->segment() == coinSeg) {
697 result = overlap->extend(cs, ce, os, oe);
698 } else {
699 if (os->fT > oe->fT) {
700 SkTSwap(cs, ce);
701 SkTSwap(os, oe);
702 }
703 result = overlap->extend(os, oe, cs, ce);
704 }
705 #if DEBUG_COINCIDENCE_VERBOSE
706 if (result) {
707 overlaps[0]->debugShow();
708 }
709 #endif
710 } else {
711 this->add(cs, ce, os, oe);
712 #if DEBUG_COINCIDENCE_VERBOSE
713 fHead->debugShow();
714 #endif
715 }
716 this->debugValidate();
717 return result;
718 }
719
720 // Please keep this in sync with debugAddMissing()
236 /* detects overlaps of different coincident runs on same segment */ 721 /* detects overlaps of different coincident runs on same segment */
237 /* does not detect overlaps for pairs without any segments in common */ 722 /* does not detect overlaps for pairs without any segments in common */
238 bool SkOpCoincidence::addMissing(SkChunkAlloc* allocator) { 723 // returns true if caller should loop again
724 bool SkOpCoincidence::addMissing() {
239 SkCoincidentSpans* outer = fHead; 725 SkCoincidentSpans* outer = fHead;
240 if (!outer) { 726 if (!outer) {
241 return true; 727 return false;
242 } 728 }
243 bool added = false; 729 bool added = false;
244 fTop = outer; 730 fTop = outer;
245 fHead = nullptr; 731 fHead = nullptr;
246 do { 732 do {
247 // addifmissing can modify the list that this is walking 733 // addifmissing can modify the list that this is walking
248 // save head so that walker can iterate over old data unperturbed 734 // save head so that walker can iterate over old data unperturbed
249 // addifmissing adds to head freely then add saved head in the end 735 // addifmissing adds to head freely then add saved head in the end
250 const SkOpSegment* outerCoin = outer->fCoinPtTStart->segment(); 736 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
251 SkASSERT(outerCoin == outer->fCoinPtTEnd->segment()); 737 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
252 const SkOpSegment* outerOpp = outer->fOppPtTStart->segment(); 738 if (outerCoin->done() || outerOpp->done()) {
253 SkASSERT(outerOpp == outer->fOppPtTEnd->segment()); 739 continue;
740 }
254 SkCoincidentSpans* inner = outer; 741 SkCoincidentSpans* inner = outer;
255 while ((inner = inner->fNext)) { 742 while ((inner = inner->next())) {
743 this->debugValidate();
256 double overS, overE; 744 double overS, overE;
257 const SkOpSegment* innerCoin = inner->fCoinPtTStart->segment(); 745 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
258 SkASSERT(innerCoin == inner->fCoinPtTEnd->segment()); 746 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
259 const SkOpSegment* innerOpp = inner->fOppPtTStart->segment(); 747 if (innerCoin->done() || innerOpp->done()) {
260 SkASSERT(innerOpp == inner->fOppPtTEnd->segment()); 748 continue;
261 if (outerCoin == innerCoin 749 }
262 && this->overlap(outer->fCoinPtTStart, outer->fCoinPtTEnd, 750 if (outerCoin == innerCoin) {
263 inner->fCoinPtTStart, inner->fCoinPtTEnd, &overS, &overE)) { 751 if (outerOpp != innerOpp
264 added |= this->addIfMissing(outer->fCoinPtTStart, outer->fCoinPt TEnd, 752 && this->overlap(outer->coinPtTStart(), outer->coinPtTEn d(),
265 inner->fCoinPtTStart, inner->fCoinPtTEnd, overS, overE, 753 inner->coinPtTStart(), inner->coinPtTEnd(), &overS, &ove rE)) {
266 outer->fOppPtTStart, outer->fOppPtTEnd, 754 added |= this->addIfMissing(outer->coinPtTStart(), outer->co inPtTEnd(),
267 inner->fOppPtTStart, inner->fOppPtTEnd, allocator); 755 inner->coinPtTStart(), inner->coinPtTEnd(), overS, o verE,
268 } else if (outerCoin == innerOpp 756 outer->oppPtTStart(), outer->oppPtTEnd(),
269 && this->overlap(outer->fCoinPtTStart, outer->fCoinPtTEnd, 757 inner->oppPtTStart(), inner->oppPtTEnd());
270 inner->fOppPtTStart, inner->fOppPtTEnd, &overS, &overE)) { 758 }
271 added |= this->addIfMissing(outer->fCoinPtTStart, outer->fCoinPt TEnd, 759 } else if (outerCoin == innerOpp) {
272 inner->fOppPtTStart, inner->fOppPtTEnd, overS, overE, 760 if (outerOpp != innerCoin
273 outer->fOppPtTStart, outer->fOppPtTEnd, 761 && this->overlap(outer->coinPtTStart(), outer->coinPtTEn d(),
274 inner->fCoinPtTStart, inner->fCoinPtTEnd, allocator); 762 inner->oppPtTStart(), inner->oppPtTEnd(), &overS, &overE )) {
275 } else if (outerOpp == innerCoin 763 added |= this->addIfMissing(outer->coinPtTStart(), outer->co inPtTEnd(),
276 && this->overlap(outer->fOppPtTStart, outer->fOppPtTEnd, 764 inner->oppPtTStart(), inner->oppPtTEnd(), overS, ove rE,
277 inner->fCoinPtTStart, inner->fCoinPtTEnd, &overS, &overE)) { 765 outer->oppPtTStart(), outer->oppPtTEnd(),
278 added |= this->addIfMissing(outer->fOppPtTStart, outer->fOppPtTE nd, 766 inner->coinPtTStart(), inner->coinPtTEnd());
279 inner->fCoinPtTStart, inner->fCoinPtTEnd, overS, overE, 767 }
280 outer->fCoinPtTStart, outer->fCoinPtTEnd, 768 } else if (outerOpp == innerCoin) {
281 inner->fOppPtTStart, inner->fOppPtTEnd, allocator); 769 SkASSERT(outerCoin != innerOpp);
282 } else if (outerOpp == innerOpp 770 if (this->overlap(outer->oppPtTStart(), outer->oppPtTEnd(),
283 && this->overlap(outer->fOppPtTStart, outer->fOppPtTEnd, 771 inner->coinPtTStart(), inner->coinPtTEnd(), &overS, &ove rE)) {
284 inner->fOppPtTStart, inner->fOppPtTEnd, &overS, &overE)) { 772 added |= this->addIfMissing(outer->oppPtTStart(), outer->opp PtTEnd(),
285 added |= this->addIfMissing(outer->fOppPtTStart, outer->fOppPtTE nd, 773 inner->coinPtTStart(), inner->coinPtTEnd(), overS, o verE,
286 inner->fOppPtTStart, inner->fOppPtTEnd, overS, overE, 774 outer->coinPtTStart(), outer->coinPtTEnd(),
287 outer->fCoinPtTStart, outer->fCoinPtTEnd, 775 inner->oppPtTStart(), inner->oppPtTEnd());
288 inner->fCoinPtTStart, inner->fCoinPtTEnd, allocator); 776 }
289 } else if (outerCoin != innerCoin) { 777 } else if (outerOpp == innerOpp) {
290 // check to see if outer span overlaps the inner span 778 SkASSERT(outerCoin != innerCoin);
291 // look for inner segment in pt-t list 779 if (this->overlap(outer->oppPtTStart(), outer->oppPtTEnd(),
292 // if present, and if t values are in coincident range 780 inner->oppPtTStart(), inner->oppPtTEnd(), &overS, &overE )) {
293 // add two pairs of new coincidence 781 added |= this->addIfMissing(outer->oppPtTStart(), outer->opp PtTEnd(),
294 SkOpPtT* testS = outer->fCoinPtTStart->contains(innerCoin); 782 inner->oppPtTStart(), inner->oppPtTEnd(), overS, ove rE,
295 SkOpPtT* testE = outer->fCoinPtTEnd->contains(innerCoin); 783 outer->coinPtTStart(), outer->coinPtTEnd(),
296 if (testS && testS->fT >= inner->fCoinPtTStart->fT 784 inner->coinPtTStart(), inner->coinPtTEnd());
297 && testE && testE->fT <= inner->fCoinPtTEnd->fT
298 && this->testForCoincidence(outer, testS, testE)) {
299 added |= this->addIfMissing(outer, testS, testE, allocator);
300 } else {
301 testS = inner->fCoinPtTStart->contains(outerCoin);
302 testE = inner->fCoinPtTEnd->contains(outerCoin);
303 if (testS && testS->fT >= outer->fCoinPtTStart->fT
304 && testE && testE->fT <= outer->fCoinPtTEnd->fT
305 && this->testForCoincidence(inner, testS, testE)) {
306 added |= this->addIfMissing(inner, testS, testE, allocat or);
307 }
308 } 785 }
309 } 786 }
310 #if 0 && DEBUG_COINCIDENCE 787 this->debugValidate();
311 SkString miss;
312 miss.printf("addMissing inner=%d outer=%d", inner->debugID(), outer- >debugID());
313 DEBUG_COINCIDENCE_HEALTH(fDebugState->contourHead(), miss.c_str());
314 #endif
315 } 788 }
316 } while ((outer = outer->fNext)); 789 } while ((outer = outer->next()));
317 SkCoincidentSpans** headPtr = &fHead; 790 this->restoreHead();
318 while (*headPtr) {
319 SkCoincidentSpans** headNext = &(*headPtr)->fNext;
320 if (*headNext) {
321 break;
322 }
323 headPtr = headNext;
324 }
325 *headPtr = fTop;
326 return added; 791 return added;
327 } 792 }
328 793
329 bool SkOpCoincidence::addOverlap(SkOpSegment* seg1, SkOpSegment* seg1o, SkOpSegm ent* seg2, 794 bool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg 1o,
330 SkOpSegment* seg2o, SkOpPtT* overS, SkOpPtT* overE, SkChunkAlloc* alloca tor) { 795 const SkOpSegment* seg2, const SkOpSegment* seg2o,
331 SkOpPtT* s1 = overS->find(seg1); 796 const SkOpPtT* overS, const SkOpPtT* overE) {
332 SkOpPtT* e1 = overE->find(seg1); 797 const SkOpPtT* s1, * e1, * s2, * e2;
798 if (!(s1 = overS->find(seg1))) {
799 return true;
800 }
801 if (!(e1 = overE->find(seg1))) {
802 return true;
803 }
804 if (s1 == e1) {
805 return true;
806 }
333 if (approximately_equal_half(s1->fT, e1->fT)) { 807 if (approximately_equal_half(s1->fT, e1->fT)) {
334 return false; 808 return false;
335 } 809 }
336 if (!s1->starter(e1)->span()->upCast()->windValue()) { 810 if (!s1->starter(e1)->span()->upCast()->windValue()) {
337 s1 = overS->find(seg1o); 811 if (!(s1 = overS->find(seg1o))) {
338 e1 = overE->find(seg1o); 812 return true;
813 }
814 if (!(e1 = overE->find(seg1o))) {
815 return true;
816 }
817 if (s1 == e1) {
818 return true;
819 }
339 if (!s1->starter(e1)->span()->upCast()->windValue()) { 820 if (!s1->starter(e1)->span()->upCast()->windValue()) {
340 return true; 821 return true;
341 } 822 }
342 } 823 }
343 SkOpPtT* s2 = overS->find(seg2); 824 if (!(s2 = overS->find(seg2))) {
344 SkOpPtT* e2 = overE->find(seg2); 825 return true;
826 }
827 if (!(e2 = overE->find(seg2))) {
828 return true;
829 }
830 if (s2 == e2) {
831 return true;
832 }
345 if (approximately_equal_half(s2->fT, e2->fT)) { 833 if (approximately_equal_half(s2->fT, e2->fT)) {
346 return false; 834 return false;
347 } 835 }
348 if (!s2->starter(e2)->span()->upCast()->windValue()) { 836 if (!s2->starter(e2)->span()->upCast()->windValue()) {
349 s2 = overS->find(seg2o); 837 if (!(s2 = overS->find(seg2o))) {
350 e2 = overE->find(seg2o); 838 return true;
839 }
840 if (!(e2 = overE->find(seg2o))) {
841 return true;
842 }
843 if (s2 == e2) {
844 return true;
845 }
351 if (!s2->starter(e2)->span()->upCast()->windValue()) { 846 if (!s2->starter(e2)->span()->upCast()->windValue()) {
352 return true; 847 return true;
353 } 848 }
354 } 849 }
355 if (s1->segment() == s2->segment()) { 850 if (s1->segment() == s2->segment()) {
356 return true; 851 return true;
357 } 852 }
358 if (s1->fT > e1->fT) { 853 if (s1->fT > e1->fT) {
359 SkTSwap(s1, e1); 854 SkTSwap(s1, e1);
360 SkTSwap(s2, e2); 855 SkTSwap(s2, e2);
361 } 856 }
362 this->add(s1, e1, s2, e2, allocator); 857 this->add(s1, e1, s2, e2);
363 return true; 858 return true;
364 } 859 }
365 860
366 bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinP tTEnd, 861 /* look for pairs of coincidence with no common segments
367 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd, bool flipped) cons t { 862 if there's no existing coincidence found that matches up the segments, and
368 const SkCoincidentSpans* coin = fHead; 863 if the pt-t list for one contains the other, create coincident pairs for what 's left */
864 bool SkOpCoincidence::addUncommon() {
865 SkCoincidentSpans* outer = fHead;
866 if (!outer) {
867 return false;
868 }
869 bool added = false;
870 fTop = outer;
871 fHead = nullptr;
872 do {
873 // addifmissing can modify the list that this is walking
874 // save head so that walker can iterate over old data unperturbed
875 // addifmissing adds to head freely then add saved head in the end
876 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
877 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
878 if (outerCoin->done() || outerOpp->done()) {
879 continue;
880 }
881 SkCoincidentSpans* inner = outer;
882 while ((inner = inner->next())) {
883 this->debugValidate();
884 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
885 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
886 if (innerCoin->done() || innerOpp->done()) {
887 continue;
888 }
889 // check to see if outer span overlaps the inner span
890 // look for inner segment in pt-t list
891 // if present, and if t values are in coincident range
892 // add two pairs of new coincidence
893 const SkOpPtT* testS = outer->coinPtTStart()->contains(innerCoin);
894 const SkOpPtT* testE = outer->coinPtTEnd()->contains(innerCoin);
895 if (testS && testS->fT >= inner->coinPtTStart()->fT
896 && testE && testE->fT <= inner->coinPtTEnd()->fT
897 && this->testForCoincidence(outer, testS, testE)) {
898 added |= this->addIfMissing(outer, testS, testE);
899 } else {
900 testS = inner->coinPtTStart()->contains(outerCoin);
901 testE = inner->coinPtTEnd()->contains(outerCoin);
902 if (testS && testS->fT >= outer->coinPtTStart()->fT
903 && testE && testE->fT <= outer->coinPtTEnd()->fT
904 && this->testForCoincidence(inner, testS, testE)) {
905 added |= this->addIfMissing(inner, testS, testE);
906 }
907 }
908 }
909 } while ((outer = outer->next()));
910 this->restoreHead();
911 return added;
912 }
913
914 bool SkOpCoincidence::contains(const SkOpSegment* seg, const SkOpSegment* opp, d ouble oppT) const {
915 if (this->contains(fHead, seg, opp, oppT)) {
916 return true;
917 }
918 if (this->contains(fTop, seg, opp, oppT)) {
919 return true;
920 }
921 return false;
922 }
923
924 bool SkOpCoincidence::contains(const SkCoincidentSpans* coin, const SkOpSegment* seg,
925 const SkOpSegment* opp, double oppT) const {
369 if (!coin) { 926 if (!coin) {
370 return false; 927 return false;
928 }
929 do {
930 if (coin->coinPtTStart()->segment() == seg && coin->oppPtTStart()->segme nt() == opp
931 && between(coin->oppPtTStart()->fT, oppT, coin->oppPtTEnd()->fT) ) {
932 return true;
933 }
934 if (coin->oppPtTStart()->segment() == seg && coin->coinPtTStart()->segme nt() == opp
935 && between(coin->coinPtTStart()->fT, oppT, coin->coinPtTEnd()->f T)) {
936 return true;
937 }
938 } while ((coin = coin->next()));
939 return false;
940 }
941
942 bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinP tTEnd,
943 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const {
944 const SkCoincidentSpans* test = fHead;
945 if (!test) {
946 return false;
947 }
948 const SkOpSegment* coinSeg = coinPtTStart->segment();
949 const SkOpSegment* oppSeg = oppPtTStart->segment();
950 if (!Ordered(coinPtTStart, oppPtTStart)) {
951 SkTSwap(coinSeg, oppSeg);
952 SkTSwap(coinPtTStart, oppPtTStart);
953 SkTSwap(coinPtTEnd, oppPtTEnd);
954 if (coinPtTStart->fT > coinPtTEnd->fT) {
955 SkTSwap(coinPtTStart, coinPtTEnd);
956 SkTSwap(oppPtTStart, oppPtTEnd);
957 }
958 }
959 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
960 double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT);
961 do {
962 if (coinSeg != test->coinPtTStart()->segment()) {
963 continue;
964 }
965 if (coinPtTStart->fT < test->coinPtTStart()->fT) {
966 continue;
967 }
968 if (coinPtTEnd->fT > test->coinPtTEnd()->fT) {
969 continue;
970 }
971 if (oppSeg != test->oppPtTStart()->segment()) {
972 continue;
973 }
974 if (oppMinT < SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
975 continue;
976 }
977 if (oppMaxT > SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
978 continue;
979 }
980 return true;
981 } while ((test = test->next()));
982 return false;
983 }
984
985 void SkOpCoincidence::correctEnds() {
986 SkCoincidentSpans* coin = fHead;
987 if (!coin) {
988 return;
371 } 989 }
372 do { 990 do {
373 if (coin->fCoinPtTStart == coinPtTStart && coin->fCoinPtTEnd == coinPtT End 991 coin->correctEnds();
374 && coin->fOppPtTStart == oppPtTStart && coin->fOppPtTEnd == oppP tTEnd 992 } while ((coin = coin->next()));
375 && coin->fFlipped == flipped) {
376 return true;
377 }
378 } while ((coin = coin->fNext));
379 return false;
380 } 993 }
381 994
382 // walk span sets in parallel, moving winding from one to the other 995 // walk span sets in parallel, moving winding from one to the other
383 bool SkOpCoincidence::apply() { 996 bool SkOpCoincidence::apply() {
384 SkCoincidentSpans* coin = fHead; 997 SkCoincidentSpans* coin = fHead;
385 if (!coin) { 998 if (!coin) {
386 return true; 999 return true;
387 } 1000 }
388 do { 1001 do {
389 SkOpSpan* start = coin->fCoinPtTStart->span()->upCast(); 1002 SkOpSpan* start = coin->coinPtTStartWritable()->span()->upCast();
390 if (start->deleted()) { 1003 if (start->deleted()) {
391 continue; 1004 continue;
392 } 1005 }
393 SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 1006 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
394 SkASSERT(start == start->starter(end)); 1007 SkASSERT(start == start->starter(end));
395 bool flipped = coin->fFlipped; 1008 bool flipped = coin->flipped();
396 SkOpSpan* oStart = (flipped ? coin->fOppPtTEnd : coin->fOppPtTStart)->sp an()->upCast(); 1009 SkOpSpan* oStart = (flipped ? coin->oppPtTEndWritable()
1010 : coin->oppPtTStartWritable())->span()->upCast();
397 if (oStart->deleted()) { 1011 if (oStart->deleted()) {
398 continue; 1012 continue;
399 } 1013 }
400 SkOpSpanBase* oEnd = (flipped ? coin->fOppPtTStart : coin->fOppPtTEnd)-> span(); 1014 const SkOpSpanBase* oEnd = (flipped ? coin->oppPtTStart() : coin->oppPtT End())->span();
401 SkASSERT(oStart == oStart->starter(oEnd)); 1015 SkASSERT(oStart == oStart->starter(oEnd));
402 SkOpSegment* segment = start->segment(); 1016 SkOpSegment* segment = start->segment();
403 SkOpSegment* oSegment = oStart->segment(); 1017 SkOpSegment* oSegment = oStart->segment();
404 bool operandSwap = segment->operand() != oSegment->operand(); 1018 bool operandSwap = segment->operand() != oSegment->operand();
405 if (flipped) { 1019 if (flipped) {
406 if (oEnd->deleted()) { 1020 if (oEnd->deleted()) {
407 continue; 1021 continue;
408 } 1022 }
409 do { 1023 do {
410 SkOpSpanBase* oNext = oStart->next(); 1024 SkOpSpanBase* oNext = oStart->next();
411 if (oNext == oEnd) { 1025 if (oNext == oEnd) {
412 break; 1026 break;
413 } 1027 }
414 oStart = oNext->upCast(); 1028 oStart = oNext->upCast();
415 } while (true); 1029 } while (true);
416 } 1030 }
417 do { 1031 do {
418 int windValue = start->windValue(); 1032 int windValue = start->windValue();
419 int oppValue = start->oppValue(); 1033 int oppValue = start->oppValue();
420 int oWindValue = oStart->windValue(); 1034 int oWindValue = oStart->windValue();
421 int oOppValue = oStart->oppValue(); 1035 int oOppValue = oStart->oppValue();
422 // winding values are added or subtracted depending on direction and wind type 1036 // winding values are added or subtracted depending on direction and wind type
423 // same or opposite values are summed depending on the operand value 1037 // same or opposite values are summed depending on the operand value
424 int windDiff = operandSwap ? oOppValue : oWindValue; 1038 int windDiff = operandSwap ? oOppValue : oWindValue;
425 int oWindDiff = operandSwap ? oppValue : windValue; 1039 int oWindDiff = operandSwap ? oppValue : windValue;
426 if (!flipped) { 1040 if (!flipped) {
427 windDiff = -windDiff; 1041 windDiff = -windDiff;
428 oWindDiff = -oWindDiff; 1042 oWindDiff = -oWindDiff;
429 } 1043 }
430 if (windValue && (windValue > windDiff || (windValue == windDiff 1044 bool addToStart = windValue && (windValue > windDiff || (windValue = = windDiff
431 && oWindValue <= oWindDiff))) { 1045 && oWindValue <= oWindDiff));
1046 if (addToStart ? start->done() : oStart->done()) {
1047 addToStart ^= true;
1048 }
1049 if (addToStart) {
432 if (operandSwap) { 1050 if (operandSwap) {
433 SkTSwap(oWindValue, oOppValue); 1051 SkTSwap(oWindValue, oOppValue);
434 } 1052 }
435 if (flipped) { 1053 if (flipped) {
436 windValue -= oWindValue; 1054 windValue -= oWindValue;
437 oppValue -= oOppValue; 1055 oppValue -= oOppValue;
438 } else { 1056 } else {
439 windValue += oWindValue; 1057 windValue += oWindValue;
440 oppValue += oOppValue; 1058 oppValue += oOppValue;
441 } 1059 }
(...skipping 16 matching lines...) Expand all
458 oOppValue += oppValue; 1076 oOppValue += oppValue;
459 } 1077 }
460 if (oSegment->isXor()) { 1078 if (oSegment->isXor()) {
461 oWindValue &= 1; 1079 oWindValue &= 1;
462 } 1080 }
463 if (oSegment->oppXor()) { 1081 if (oSegment->oppXor()) {
464 oOppValue &= 1; 1082 oOppValue &= 1;
465 } 1083 }
466 windValue = oppValue = 0; 1084 windValue = oppValue = 0;
467 } 1085 }
1086 #if DEBUG_COINCIDENCE
1087 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", segment->debug ID(),
1088 start->debugID(), windValue, oppValue);
1089 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", oSegment->debu gID(),
1090 oStart->debugID(), oWindValue, oOppValue);
1091 #endif
468 start->setWindValue(windValue); 1092 start->setWindValue(windValue);
469 start->setOppValue(oppValue); 1093 start->setOppValue(oppValue);
470 oStart->setWindValue(oWindValue); 1094 oStart->setWindValue(oWindValue);
471 oStart->setOppValue(oOppValue); 1095 oStart->setOppValue(oOppValue);
472 if (!windValue && !oppValue) { 1096 if (!windValue && !oppValue) {
473 segment->markDone(start); 1097 segment->markDone(start);
474 } 1098 }
475 if (!oWindValue && !oOppValue) { 1099 if (!oWindValue && !oOppValue) {
476 oSegment->markDone(oStart); 1100 oSegment->markDone(oStart);
477 } 1101 }
478 SkOpSpanBase* next = start->next(); 1102 SkOpSpanBase* next = start->next();
479 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next(); 1103 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next();
480 if (next == end) { 1104 if (next == end) {
481 break; 1105 break;
482 } 1106 }
483 if (!next->upCastable()) { 1107 if (!next->upCastable()) {
484 return false; 1108 return false;
485 } 1109 }
486 start = next->upCast(); 1110 start = next->upCast();
487 // if the opposite ran out too soon, just reuse the last span 1111 // if the opposite ran out too soon, just reuse the last span
488 if (!oNext || !oNext->upCastable()) { 1112 if (!oNext || !oNext->upCastable()) {
489 oNext = oStart; 1113 oNext = oStart;
490 } 1114 }
491 oStart = oNext->upCast(); 1115 oStart = oNext->upCast();
492 } while (true); 1116 } while (true);
493 } while ((coin = coin->fNext)); 1117 } while ((coin = coin->next()));
494 return true; 1118 return true;
495 } 1119 }
496 1120
497 void SkOpCoincidence::release(SkCoincidentSpans* remove) { 1121 // Please keep this in sync with debugRelease()
498 SkCoincidentSpans* coin = fHead; 1122 bool SkOpCoincidence::release(SkCoincidentSpans* coin, SkCoincidentSpans* remove ) {
1123 SkCoincidentSpans* head = coin;
499 SkCoincidentSpans* prev = nullptr; 1124 SkCoincidentSpans* prev = nullptr;
500 SkCoincidentSpans* next; 1125 SkCoincidentSpans* next;
501 do { 1126 do {
502 next = coin->fNext; 1127 next = coin->next();
503 if (coin == remove) { 1128 if (coin == remove) {
504 if (prev) { 1129 if (prev) {
505 prev->fNext = next; 1130 prev->setNext(next);
1131 } else if (head == fHead) {
1132 fHead = next;
506 } else { 1133 } else {
507 fHead = next; 1134 fTop = next;
508 } 1135 }
509 break; 1136 break;
510 } 1137 }
511 prev = coin; 1138 prev = coin;
512 } while ((coin = next)); 1139 } while ((coin = next));
513 SkASSERT(coin); 1140 return coin != nullptr;
514 } 1141 }
515 1142
1143 // Please keep this in sync with debugReorder()
1144 // iterate through all coincident pairs, looking for ranges greater than 1
1145 // if found, see if the opposite pair can match it -- which may require
1146 // reordering the ptT pairs
1147 bool SkOpCoincidence::reorder() {
1148 SkCoincidentSpans* coin = fHead;
1149 if (!coin) {
1150 return true;
1151 }
1152 do {
1153 // most commonly, concidence are one span long; check for that first
1154 int intervals = coin->spanCount();
1155 if (intervals <= 0) {
1156 return false;
1157 }
1158 if (1 == intervals) {
1159 #if DEBUG_COINCIDENCE_VERBOSE
1160 SkASSERT(!coin->debugExpand(nullptr, nullptr));
1161 #endif
1162 continue;
1163 }
1164 coin->expand(); // be all that you can be
1165 if (coin->spanCount() <= 0) {
1166 return false;
1167 }
1168 // check to see if every span in coin has a mate in opp
1169 const SkOpSpan* start = coin->coinPtTStart()->span()->upCast();
1170 bool flipped = coin->flipped();
1171 const SkOpSpanBase* oppStartBase = coin->oppPtTStart()->span();
1172 const SkOpSpan* oppStart = flipped ? oppStartBase->prev() : oppStartBase ->upCast();
1173 SkDebugf("", start, oppStart);
1174 } while ((coin = coin->next()));
1175 return true;
1176 }
1177
1178 void SkOpCoincidence::restoreHead() {
1179 SkCoincidentSpans** headPtr = &fHead;
1180 while (*headPtr) {
1181 headPtr = (*headPtr)->nextPtr();
1182 }
1183 *headPtr = fTop;
1184 fTop = nullptr;
1185 // segments may have collapsed in the meantime; remove empty referenced segm ents
1186 headPtr = &fHead;
1187 while (*headPtr) {
1188 SkCoincidentSpans* test = *headPtr;
1189 if (test->coinPtTStart()->segment()->done() || test->oppPtTStart()->segm ent()->done()) {
1190 *headPtr = test->next();
1191 continue;
1192 }
1193 headPtr = (*headPtr)->nextPtr();
1194 }
1195 }
1196
1197 // Please keep this in sync with debugExpand()
516 bool SkOpCoincidence::expand() { 1198 bool SkOpCoincidence::expand() {
517 SkCoincidentSpans* coin = fHead; 1199 SkCoincidentSpans* coin = fHead;
518 if (!coin) { 1200 if (!coin) {
519 return false; 1201 return false;
520 } 1202 }
521 bool expanded = false; 1203 bool expanded = false;
522 do { 1204 do {
523 SkOpSpan* start = coin->fCoinPtTStart->span()->upCast(); 1205 if (coin->expand()) {
524 SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 1206 // check to see if multiple spans expanded so they are now identical
525 SkOpSegment* segment = coin->fCoinPtTStart->segment(); 1207 SkCoincidentSpans* test = fHead;
526 SkOpSegment* oppSegment = coin->fOppPtTStart->segment(); 1208 do {
527 SkOpSpan* prev = start->prev(); 1209 if (coin == test) {
528 SkOpPtT* oppPtT; 1210 continue;
529 if (prev && (oppPtT = prev->contains(oppSegment))) { 1211 }
530 double midT = (prev->t() + start->t()) / 2; 1212 if (coin->coinPtTStart() == test->coinPtTStart()
531 if (segment->isClose(midT, oppSegment)) { 1213 && coin->oppPtTStart() == test->oppPtTStart()) {
532 coin->fCoinPtTStart = prev->ptT(); 1214 this->release(fHead, test);
533 coin->fOppPtTStart = oppPtT; 1215 break;
534 expanded = true; 1216 }
535 } 1217 } while ((test = test->next()));
1218 expanded = true;
536 } 1219 }
537 SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next(); 1220 } while ((coin = coin->next()));
538 if (next && (oppPtT = next->contains(oppSegment))) {
539 double midT = (end->t() + next->t()) / 2;
540 if (segment->isClose(midT, oppSegment)) {
541 coin->fCoinPtTEnd = next->ptT();
542 coin->fOppPtTEnd = oppPtT;
543 expanded = true;
544 }
545 }
546 } while ((coin = coin->fNext));
547 return expanded; 1221 return expanded;
548 } 1222 }
549 1223
550 bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps, SkChunkAlloc* allo cator) const { 1224 bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps) const {
551 overlaps->fHead = overlaps->fTop = nullptr; 1225 overlaps->fHead = overlaps->fTop = nullptr;
552 SkDEBUGCODE_(overlaps->debugSetGlobalState(fDebugState));
553 SkCoincidentSpans* outer = fHead; 1226 SkCoincidentSpans* outer = fHead;
554 while (outer) { 1227 while (outer) {
555 SkOpSegment* outerCoin = outer->fCoinPtTStart->segment(); 1228 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
556 SkOpSegment* outerOpp = outer->fOppPtTStart->segment(); 1229 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
557 SkCoincidentSpans* inner = outer; 1230 SkCoincidentSpans* inner = outer;
558 while ((inner = inner->fNext)) { 1231 while ((inner = inner->next())) {
559 SkOpSegment* innerCoin = inner->fCoinPtTStart->segment(); 1232 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
560 if (outerCoin == innerCoin) { 1233 if (outerCoin == innerCoin) {
561 continue; // both winners are the same segment, so there's no a dditional overlap 1234 continue; // both winners are the same segment, so there's no a dditional overlap
562 } 1235 }
563 SkOpSegment* innerOpp = inner->fOppPtTStart->segment(); 1236 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
564 SkOpPtT* overlapS, * overlapE; 1237 const SkOpPtT* overlapS;
565 if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->fOppPtTStart, outer->fOppPtTEnd, 1238 const SkOpPtT* overlapE;
566 inner->fCoinPtTStart, inner->fCoinPtTEnd, &overlapS, &overla pE)) 1239 if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->oppPtTStart() ,
567 || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->fCoinP tTStart, 1240 outer->oppPtTEnd(),inner->coinPtTStart(), inner->coinPtTEnd( ), &overlapS,
568 outer->fCoinPtTEnd, inner->fOppPtTStart, inner->fOppPtTEnd, 1241 &overlapE))
1242 || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->coinPt TStart(),
1243 outer->coinPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd( ),
569 &overlapS, &overlapE)) 1244 &overlapS, &overlapE))
570 || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->fOppPtT Start, 1245 || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTS tart(),
571 outer->fOppPtTEnd, inner->fOppPtTStart, inner->fOppPtTEnd, 1246 outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd() ,
572 &overlapS, &overlapE))) { 1247 &overlapS, &overlapE))) {
573 if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerO pp, 1248 if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerO pp,
574 overlapS, overlapE, allocator)) { 1249 overlapS, overlapE)) {
575 return false; 1250 return false;
576 } 1251 }
577 } 1252 }
578 } 1253 }
579 outer = outer->fNext; 1254 outer = outer->next();
580 } 1255 }
581 return true; 1256 return true;
582 } 1257 }
583 1258
584 bool SkOpCoincidence::fixAligned() { 1259 // Please keep this in sync with debugRemoveCollapsed()
1260 bool SkOpCoincidence::removeCollapsed() {
585 SkCoincidentSpans* coin = fHead; 1261 SkCoincidentSpans* coin = fHead;
586 if (!coin) { 1262 if (!coin) {
587 return true; 1263 return true;
588 } 1264 }
589 do {
590 if (coin->fCoinPtTStart->deleted()) {
591 coin->fCoinPtTStart = coin->fCoinPtTStart->doppelganger();
592 }
593 if (coin->fCoinPtTEnd->deleted()) {
594 coin->fCoinPtTEnd = coin->fCoinPtTEnd->doppelganger();
595 }
596 if (coin->fOppPtTStart->deleted()) {
597 coin->fOppPtTStart = coin->fOppPtTStart->doppelganger();
598 }
599 if (coin->fOppPtTEnd->deleted()) {
600 coin->fOppPtTEnd = coin->fOppPtTEnd->doppelganger();
601 }
602 } while ((coin = coin->fNext));
603 coin = fHead;
604 SkCoincidentSpans** priorPtr = &fHead; 1265 SkCoincidentSpans** priorPtr = &fHead;
605 do { 1266 do {
606 if (coin->fCoinPtTStart == coin->fCoinPtTEnd) { 1267 if (coin->coinPtTStart() == coin->coinPtTEnd()) {
607 return false; 1268 return false;
608 } 1269 }
609 if (coin->fOppPtTStart == coin->fOppPtTEnd) { 1270 if (coin->oppPtTStart() == coin->oppPtTEnd()) {
610 return false; 1271 return false;
611 } 1272 }
612 if (coin->fCoinPtTStart->collapsed(coin->fCoinPtTEnd) 1273 if (coin->coinPtTStart()->collapsed(coin->coinPtTEnd())) {
613 || coin->fOppPtTStart->collapsed(coin->fOppPtTEnd)) { 1274 *priorPtr = coin->next();
614 *priorPtr = coin->fNext;
615 continue; 1275 continue;
616 } 1276 }
617 priorPtr = &coin->fNext; 1277 if (coin->oppPtTStart()->collapsed(coin->oppPtTEnd())) {
618 } while ((coin = coin->fNext)); 1278 *priorPtr = coin->next();
1279 continue;
1280 }
1281 priorPtr = coin->nextPtr();
1282 } while ((coin = coin->next()));
619 return true; 1283 return true;
620 } 1284 }
621 1285
622 void SkOpCoincidence::fixUp(SkOpPtT* deleted, SkOpPtT* kept) { 1286 void SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) {
623 SkCoincidentSpans* coin = fHead; 1287 SkASSERT(deleted != kept);
624 if (!coin) { 1288 if (fHead) {
625 return; 1289 this->fixUp(fHead, deleted, kept);
626 } 1290 }
1291 if (fTop) {
1292 this->fixUp(fTop, deleted, kept);
1293 }
1294 }
1295
1296 void SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkO pPtT* kept) {
1297 SkCoincidentSpans* head = coin;
627 do { 1298 do {
628 if (coin->fCoinPtTStart == deleted) { 1299 if (coin->coinPtTStart() == deleted) {
629 if (coin->fCoinPtTEnd->span() == kept->span()) { 1300 if (coin->coinPtTEnd()->span() == kept->span()) {
630 this->release(coin); 1301 this->release(head, coin);
631 continue; 1302 continue;
632 } 1303 }
633 coin->fCoinPtTStart = kept; 1304 coin->setCoinPtTStart(kept);
634 } 1305 }
635 if (coin->fCoinPtTEnd == deleted) { 1306 if (coin->coinPtTEnd() == deleted) {
636 if (coin->fCoinPtTStart->span() == kept->span()) { 1307 if (coin->coinPtTStart()->span() == kept->span()) {
637 this->release(coin); 1308 this->release(head, coin);
638 continue; 1309 continue;
639 } 1310 }
640 coin->fCoinPtTEnd = kept; 1311 coin->setCoinPtTEnd(kept);
641 } 1312 }
642 if (coin->fOppPtTStart == deleted) { 1313 if (coin->oppPtTStart() == deleted) {
643 if (coin->fOppPtTEnd->span() == kept->span()) { 1314 if (coin->oppPtTEnd()->span() == kept->span()) {
644 this->release(coin); 1315 this->release(head, coin);
645 continue; 1316 continue;
646 } 1317 }
647 coin->fOppPtTStart = kept; 1318 coin->setOppPtTStart(kept);
648 } 1319 }
649 if (coin->fOppPtTEnd == deleted) { 1320 if (coin->oppPtTEnd() == deleted) {
650 if (coin->fOppPtTStart->span() == kept->span()) { 1321 if (coin->oppPtTStart()->span() == kept->span()) {
651 this->release(coin); 1322 this->release(head, coin);
652 continue; 1323 continue;
653 } 1324 }
654 coin->fOppPtTEnd = kept; 1325 coin->setOppPtTEnd(kept);
655 } 1326 }
656 } while ((coin = coin->fNext)); 1327 } while ((coin = coin->next()));
657 } 1328 }
658 1329
1330 // Please keep this in sync with debugMark()
659 /* this sets up the coincidence links in the segments when the coincidence cross es multiple spans */ 1331 /* this sets up the coincidence links in the segments when the coincidence cross es multiple spans */
660 bool SkOpCoincidence::mark() { 1332 bool SkOpCoincidence::mark() {
661 SkCoincidentSpans* coin = fHead; 1333 SkCoincidentSpans* coin = fHead;
662 if (!coin) { 1334 if (!coin) {
663 return true; 1335 return true;
664 } 1336 }
665 do { 1337 do {
666 SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 1338 SkOpSpan* start = coin->coinPtTStartWritable()->span()->upCast();
667 if (end->deleted()) { 1339 SkASSERT(!start->deleted());
668 return false; 1340 SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
669 } 1341 SkASSERT(!end->deleted());
670 SkOpSpanBase* oldEnd = end; 1342 SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
671 SkOpSpan* start = coin->fCoinPtTStart->span()->starter(&end); 1343 SkASSERT(!oStart->deleted());
672 SkOpSpanBase* oEnd = coin->fOppPtTEnd->span(); 1344 SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
673 if (oEnd->deleted()) { 1345 SkASSERT(!oEnd->deleted());
674 return false; 1346 bool flipped = coin->flipped();
675 }
676 SkOpSpanBase* oOldEnd = oEnd;
677 SkOpSpanBase* oStart = coin->fOppPtTStart->span()->starter(&oEnd);
678 bool flipped = (end == oldEnd) != (oEnd == oOldEnd);
679 if (flipped) { 1347 if (flipped) {
680 SkTSwap(oStart, oEnd); 1348 SkTSwap(oStart, oEnd);
681 } 1349 }
1350 /* coin and opp spans may not match up. Mark the ends, and then let the interior
1351 get marked as many times as the spans allow */
1352 start->insertCoincidence(oStart->upCast());
1353 end->insertCoinEnd(oEnd);
1354 const SkOpSegment* segment = start->segment();
1355 const SkOpSegment* oSegment = oStart->segment();
682 SkOpSpanBase* next = start; 1356 SkOpSpanBase* next = start;
683 SkOpSpanBase* oNext = oStart; 1357 SkOpSpanBase* oNext = oStart;
684 do { 1358 while ((next = next->upCast()->next()) != end) {
685 next = next->upCast()->next(); 1359 if (!next->upCast()->insertCoincidence(oSegment, flipped)) {
686 oNext = flipped ? oNext->prev() : oNext->upCast()->next(); 1360 return false;
687 if (next == end || oNext == oEnd) {
688 break;
689 } 1361 }
690 if (!next->containsCoinEnd(oNext)) { 1362 }
691 next->insertCoinEnd(oNext); 1363 while ((oNext = oNext->upCast()->next()) != oEnd) {
1364 if (!oNext->upCast()->insertCoincidence(segment, flipped)) {
1365 return false;
692 } 1366 }
693 SkOpSpan* nextSpan = next->upCast(); 1367 }
694 SkOpSpan* oNextSpan = oNext->upCast(); 1368 } while ((coin = coin->next()));
695 if (!nextSpan->containsCoincidence(oNextSpan)) {
696 nextSpan->insertCoincidence(oNextSpan);
697 }
698 } while (true);
699 } while ((coin = coin->fNext));
700 return true; 1369 return true;
701 } 1370 }
702 1371
703 bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e, 1372 // Please keep in sync with debugMarkCollapsed()
1373 void SkOpCoincidence::markCollapsed(SkCoincidentSpans* coin, SkOpPtT* test) {
1374 SkCoincidentSpans* head = coin;
1375 while (coin) {
1376 if (coin->collapsed(test)) {
1377 if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinP tTEnd()->fT)) {
1378 coin->coinPtTStartWritable()->segment()->markAllDone();
1379 }
1380 if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtT End()->fT)) {
1381 coin->oppPtTStartWritable()->segment()->markAllDone();
1382 }
1383 this->release(head, coin);
1384 }
1385 coin = coin->next();
1386 }
1387 }
1388
1389 // Please keep in sync with debugMarkCollapsed()
1390 void SkOpCoincidence::markCollapsed(SkOpPtT* test) {
1391 markCollapsed(fHead, test);
1392 markCollapsed(fTop, test);
1393 }
1394
1395 bool SkOpCoincidence::Ordered(const SkOpSegment* coinSeg, const SkOpSegment* opp Seg) {
1396 if (coinSeg->verb() < oppSeg->verb()) {
1397 return true;
1398 }
1399 if (coinSeg->verb() > oppSeg->verb()) {
1400 return false;
1401 }
1402 int count = (SkPathOpsVerbToPoints(coinSeg->verb()) + 1) * 2;
1403 const SkScalar* cPt = &coinSeg->pts()[0].fX;
1404 const SkScalar* oPt = &oppSeg->pts()[0].fX;
1405 for (int index = 0; index < count; ++index) {
1406 if (*cPt < *oPt) {
1407 return true;
1408 }
1409 if (*cPt > *oPt) {
1410 return false;
1411 }
1412 ++cPt;
1413 ++oPt;
1414 }
1415 return true;
1416 }
1417
1418 bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e,
704 const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* ove rE) const { 1419 const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* ove rE) const {
705 SkASSERT(coin1s->segment() == coin2s->segment()); 1420 SkASSERT(coin1s->segment() == coin2s->segment());
706 *overS = SkTMax(SkTMin(coin1s->fT, coin1e->fT), SkTMin(coin2s->fT, coin2e->f T)); 1421 *overS = SkTMax(SkTMin(coin1s->fT, coin1e->fT), SkTMin(coin2s->fT, coin2e->f T));
707 *overE = SkTMin(SkTMax(coin1s->fT, coin1e->fT), SkTMax(coin2s->fT, coin2e->f T)); 1422 *overE = SkTMin(SkTMax(coin1s->fT, coin1e->fT), SkTMax(coin2s->fT, coin2e->f T));
708 return *overS < *overE; 1423 return *overS < *overE;
709 } 1424 }
710 1425
1426 // Commented-out lines keep this in sync with debugRelease()
1427 void SkOpCoincidence::release(const SkOpSegment* deleted) {
1428 SkCoincidentSpans* coin = fHead;
1429 if (!coin) {
1430 return;
1431 }
1432 do {
1433 if (coin->coinPtTStart()->segment() == deleted
1434 || coin->coinPtTEnd()->segment() == deleted
1435 || coin->oppPtTStart()->segment() == deleted
1436 || coin->oppPtTEnd()->segment() == deleted) {
1437 this->release(fHead, coin);
1438 }
1439 } while ((coin = coin->next()));
1440 }
1441
711 bool SkOpCoincidence::testForCoincidence(const SkCoincidentSpans* outer, const S kOpPtT* testS, 1442 bool SkOpCoincidence::testForCoincidence(const SkCoincidentSpans* outer, const S kOpPtT* testS,
712 const SkOpPtT* testE) const { 1443 const SkOpPtT* testE) const {
713 return testS->segment()->testForCoincidence(testS, testE, testS->span(), 1444 return testS->segment()->testForCoincidence(testS, testE, testS->span(),
714 testE->span(), outer->fCoinPtTStart->segment(), 120000); // FIXME: replace with tuned 1445 testE->span(), outer->coinPtTStart()->segment());
715 } 1446 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698