OLD | NEW |
---|---|
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 Loading... | |
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 } |
OLD | NEW |