OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 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 "SkOpContour.h" | 8 #include "SkOpContour.h" |
9 #include "SkOpSegment.h" | 9 #include "SkOpSegment.h" |
10 #include "SkPathWriter.h" | 10 #include "SkPathWriter.h" |
11 | 11 |
12 bool SkOpPtT::alias() const { | 12 bool SkOpPtT::alias() const { |
13 return this->span()->ptT() != this; | 13 return this->span()->ptT() != this; |
14 } | 14 } |
15 | 15 |
| 16 const SkOpPtT* SkOpPtT::active() const { |
| 17 if (!fDeleted) { |
| 18 return this; |
| 19 } |
| 20 const SkOpPtT* ptT = this; |
| 21 const SkOpPtT* stopPtT = ptT; |
| 22 while ((ptT = ptT->next()) != stopPtT) { |
| 23 if (ptT->fSpan == fSpan && !ptT->fDeleted) { |
| 24 return ptT; |
| 25 } |
| 26 } |
| 27 SkASSERT(0); // should never return deleted |
| 28 return this; |
| 29 } |
| 30 |
16 bool SkOpPtT::collapsed(const SkOpPtT* check) const { | 31 bool SkOpPtT::collapsed(const SkOpPtT* check) const { |
17 if (fPt != check->fPt) { | 32 if (fPt != check->fPt) { |
18 return false; | 33 return false; |
19 } | 34 } |
20 SkASSERT(this != check); | 35 SkASSERT(this != check); |
21 const SkOpSegment* segment = this->segment(); | 36 const SkOpSegment* segment = this->segment(); |
22 SkASSERT(segment == check->segment()); | 37 SkASSERT(segment == check->segment()); |
23 return segment->collapsed(); | 38 return segment->collapsed(); |
24 } | 39 } |
25 | 40 |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 SkOpSegment* SkOpPtT::segment() { | 185 SkOpSegment* SkOpPtT::segment() { |
171 return span()->segment(); | 186 return span()->segment(); |
172 } | 187 } |
173 | 188 |
174 void SkOpPtT::setDeleted() { | 189 void SkOpPtT::setDeleted() { |
175 SkASSERT(this->span()->debugDeleted() || this->span()->ptT() != this); | 190 SkASSERT(this->span()->debugDeleted() || this->span()->ptT() != this); |
176 SkOPASSERT(!fDeleted); | 191 SkOPASSERT(!fDeleted); |
177 fDeleted = true; | 192 fDeleted = true; |
178 } | 193 } |
179 | 194 |
180 // please keep this in sync with debugAddOppAndMerge | 195 void SkOpSpanBase::addOpp(SkOpSpanBase* opp) { |
181 // If the added points envelop adjacent spans, merge them in. | |
182 void SkOpSpanBase::addOppAndMerge(SkOpSpanBase* opp) { | |
183 SkOpPtT* oppPrev = this->ptT()->oppPrev(opp->ptT()); | 196 SkOpPtT* oppPrev = this->ptT()->oppPrev(opp->ptT()); |
184 if (oppPrev) { | 197 if (!oppPrev) { |
185 this->ptT()->addOpp(opp->ptT(), oppPrev); | |
186 this->checkForCollapsedCoincidence(); | |
187 } | |
188 // compute bounds of points in span | |
189 SkPathOpsBounds bounds; | |
190 bounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin); | |
191 const SkOpPtT* head = this->ptT(); | |
192 const SkOpPtT* nextPt = head; | |
193 do { | |
194 bounds.add(nextPt->fPt); | |
195 } while ((nextPt = nextPt->next()) != head); | |
196 if (!bounds.width() && !bounds.height()) { | |
197 return; | 198 return; |
198 } | 199 } |
199 this->mergeContained(bounds); | 200 this->mergeMatches(opp); |
200 opp->mergeContained(bounds); | 201 this->ptT()->addOpp(opp->ptT(), oppPrev); |
| 202 this->checkForCollapsedCoincidence(); |
201 } | 203 } |
202 | 204 |
203 // Please keep this in sync with debugMergeContained() | 205 // Please keep this in sync with debugMergeContained() |
204 void SkOpSpanBase::mergeContained(const SkPathOpsBounds& bounds) { | 206 void SkOpSpanBase::mergeContained(const SkPathOpsBounds& bounds) { |
205 // while adjacent spans' points are contained by the bounds, merge them | 207 // while adjacent spans' points are contained by the bounds, merge them |
206 SkOpSpanBase* prev = this; | 208 SkOpSpanBase* prev = this; |
207 SkOpSegment* seg = this->segment(); | 209 SkOpSegment* seg = this->segment(); |
208 while ((prev = prev->prev()) && bounds.contains(prev->pt()) && !seg->ptsDisj
oint(prev, this)) { | 210 while ((prev = prev->prev()) && bounds.contains(prev->pt()) && !seg->ptsDisj
oint(prev, this)) { |
209 if (prev->prev()) { | 211 this->mergeMatches(prev); |
210 this->merge(prev->upCast()); | 212 this->addOpp(prev); |
211 prev = this; | |
212 } else if (this->final()) { | |
213 seg->clearAll(); | |
214 return; | |
215 } else { | |
216 prev->merge(this->upCast()); | |
217 } | |
218 } | 213 } |
219 SkOpSpanBase* current = this; | |
220 SkOpSpanBase* next = this; | 214 SkOpSpanBase* next = this; |
221 while (next->upCastable() && (next = next->upCast()->next()) | 215 while (next->upCastable() && (next = next->upCast()->next()) |
222 && bounds.contains(next->pt()) && !seg->ptsDisjoint(this, next)) { | 216 && bounds.contains(next->pt()) && !seg->ptsDisjoint(this, next)) { |
223 if (!current->prev() && next->final()) { | 217 this->mergeMatches(next); |
224 seg->clearAll(); | 218 this->addOpp(next); |
225 return; | |
226 } | |
227 if (current->prev()) { | |
228 next->merge(current->upCast()); | |
229 current = next; | |
230 } else { | |
231 current->merge(next->upCast()); | |
232 // extra line in debug version | |
233 } | |
234 } | 219 } |
235 #if DEBUG_COINCIDENCE | 220 #if DEBUG_COINCIDENCE |
236 this->globalState()->coincidence()->debugValidate(); | 221 this->globalState()->coincidence()->debugValidate(); |
237 #endif | 222 #endif |
238 } | 223 } |
239 | 224 |
| 225 bool SkOpSpanBase::collapsed(double s, double e) const { |
| 226 const SkOpPtT* start = &fPtT; |
| 227 const SkOpPtT* walk = start; |
| 228 double min = walk->fT; |
| 229 double max = min; |
| 230 const SkOpSegment* segment = this->segment(); |
| 231 while ((walk = walk->next()) != start) { |
| 232 if (walk->segment() != segment) { |
| 233 continue; |
| 234 } |
| 235 min = SkTMin(min, walk->fT); |
| 236 max = SkTMax(max, walk->fT); |
| 237 if (between(min, s, max) && between(min, e, max)) { |
| 238 return true; |
| 239 } |
| 240 } |
| 241 return false; |
| 242 } |
| 243 |
240 bool SkOpSpanBase::contains(const SkOpSpanBase* span) const { | 244 bool SkOpSpanBase::contains(const SkOpSpanBase* span) const { |
241 const SkOpPtT* start = &fPtT; | 245 const SkOpPtT* start = &fPtT; |
242 const SkOpPtT* check = &span->fPtT; | 246 const SkOpPtT* check = &span->fPtT; |
243 SkOPASSERT(start != check); | 247 SkOPASSERT(start != check); |
244 const SkOpPtT* walk = start; | 248 const SkOpPtT* walk = start; |
245 while ((walk = walk->next()) != start) { | 249 while ((walk = walk->next()) != start) { |
246 if (walk == check) { | 250 if (walk == check) { |
247 return true; | 251 return true; |
248 } | 252 } |
249 } | 253 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 fSegment = segment; | 291 fSegment = segment; |
288 fPtT.init(this, t, pt, false); | 292 fPtT.init(this, t, pt, false); |
289 fCoinEnd = this; | 293 fCoinEnd = this; |
290 fFromAngle = nullptr; | 294 fFromAngle = nullptr; |
291 fPrev = prev; | 295 fPrev = prev; |
292 fSpanAdds = 0; | 296 fSpanAdds = 0; |
293 fAligned = true; | 297 fAligned = true; |
294 fChased = false; | 298 fChased = false; |
295 SkDEBUGCODE(fCount = 1); | 299 SkDEBUGCODE(fCount = 1); |
296 SkDEBUGCODE(fID = globalState()->nextSpanID()); | 300 SkDEBUGCODE(fID = globalState()->nextSpanID()); |
297 SkDEBUGCODE(fDeleted = false); | 301 SkDEBUGCODE(fDebugDeleted = false); |
298 } | 302 } |
299 | 303 |
300 // this pair of spans share a common t value or point; merge them and eliminate
duplicates | 304 // this pair of spans share a common t value or point; merge them and eliminate
duplicates |
301 // this does not compute the best t or pt value; this merely moves all data into
a single list | 305 // this does not compute the best t or pt value; this merely moves all data into
a single list |
302 void SkOpSpanBase::merge(SkOpSpan* span) { | 306 void SkOpSpanBase::merge(SkOpSpan* span) { |
303 SkOpPtT* spanPtT = span->ptT(); | 307 SkOpPtT* spanPtT = span->ptT(); |
304 SkASSERT(this->t() != spanPtT->fT); | 308 SkASSERT(this->t() != spanPtT->fT); |
305 SkASSERT(!zero_or_one(spanPtT->fT)); | 309 SkASSERT(!zero_or_one(spanPtT->fT)); |
306 span->release(this->ptT()); | 310 span->release(this->ptT()); |
307 if (this->contains(span)) { | 311 if (this->contains(span)) { |
| 312 SkOPASSERT(0); // check to see if this ever happens -- should have been
found earlier |
308 return; // merge is already in the ptT loop | 313 return; // merge is already in the ptT loop |
309 } | 314 } |
310 SkOpPtT* remainder = spanPtT->next(); | 315 SkOpPtT* remainder = spanPtT->next(); |
311 this->ptT()->insert(spanPtT); | 316 this->ptT()->insert(spanPtT); |
312 while (remainder != spanPtT) { | 317 while (remainder != spanPtT) { |
313 SkOpPtT* next = remainder->next(); | 318 SkOpPtT* next = remainder->next(); |
314 SkOpPtT* compare = spanPtT->next(); | 319 SkOpPtT* compare = spanPtT->next(); |
315 while (compare != spanPtT) { | 320 while (compare != spanPtT) { |
316 SkOpPtT* nextC = compare->next(); | 321 SkOpPtT* nextC = compare->next(); |
317 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT
) { | 322 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT
) { |
318 goto tryNextRemainder; | 323 goto tryNextRemainder; |
319 } | 324 } |
320 compare = nextC; | 325 compare = nextC; |
321 } | 326 } |
322 spanPtT->insert(remainder); | 327 spanPtT->insert(remainder); |
323 tryNextRemainder: | 328 tryNextRemainder: |
324 remainder = next; | 329 remainder = next; |
325 } | 330 } |
326 fSpanAdds += span->fSpanAdds; | 331 fSpanAdds += span->fSpanAdds; |
327 this->checkForCollapsedCoincidence(); | 332 } |
| 333 |
| 334 SkOpSpanBase* SkOpSpanBase::active() { |
| 335 SkOpSpanBase* result = fPrev ? fPrev->next() : upCast()->next()->prev(); |
| 336 SkASSERT(this == result || fDebugDeleted); |
| 337 return result; |
328 } | 338 } |
329 | 339 |
330 // please keep in sync with debugCheckForCollapsedCoincidence() | 340 // please keep in sync with debugCheckForCollapsedCoincidence() |
331 void SkOpSpanBase::checkForCollapsedCoincidence() { | 341 void SkOpSpanBase::checkForCollapsedCoincidence() { |
332 SkOpCoincidence* coins = this->globalState()->coincidence(); | 342 SkOpCoincidence* coins = this->globalState()->coincidence(); |
333 if (coins->isEmpty()) { | 343 if (coins->isEmpty()) { |
334 return; | 344 return; |
335 } | 345 } |
336 // the insert above may have put both ends of a coincident run in the same span | 346 // the insert above may have put both ends of a coincident run in the same span |
337 // for each coincident ptT in loop; see if its opposite in is also in the loop | 347 // for each coincident ptT in loop; see if its opposite in is also in the loop |
338 // this implementation is the motivation for marking that a ptT is referenced by
a coincident span | 348 // this implementation is the motivation for marking that a ptT is referenced by
a coincident span |
339 SkOpPtT* head = this->ptT(); | 349 SkOpPtT* head = this->ptT(); |
340 SkOpPtT* test = head; | 350 SkOpPtT* test = head; |
341 do { | 351 do { |
342 if (!test->coincident()) { | 352 if (!test->coincident()) { |
343 continue; | 353 continue; |
344 } | 354 } |
345 coins->markCollapsed(test); | 355 coins->markCollapsed(test); |
346 } while ((test = test->next()) != head); | 356 } while ((test = test->next()) != head); |
| 357 coins->releaseDeleted(); |
| 358 } |
| 359 |
| 360 // please keep in sync with debugMergeMatches() |
| 361 // Look to see if pt-t linked list contains same segment more than once |
| 362 // if so, and if each pt-t is directly pointed to by spans in that segment, |
| 363 // merge them |
| 364 // keep the points, but remove spans so that the segment doesn't have 2 or more |
| 365 // spans pointing to the same pt-t loop at different loop elements |
| 366 void SkOpSpanBase::mergeMatches(SkOpSpanBase* opp) { |
| 367 SkOpPtT* test = &fPtT; |
| 368 SkOpPtT* testNext; |
| 369 const SkOpPtT* stop = test; |
| 370 do { |
| 371 testNext = test->next(); |
| 372 if (test->deleted()) { |
| 373 continue; |
| 374 } |
| 375 SkOpSpanBase* testBase = test->span(); |
| 376 SkASSERT(testBase->ptT() == test); |
| 377 SkOpSegment* segment = test->segment(); |
| 378 if (segment->done()) { |
| 379 continue; |
| 380 } |
| 381 SkOpPtT* inner = opp->ptT(); |
| 382 const SkOpPtT* innerStop = inner; |
| 383 do { |
| 384 if (inner->segment() != segment) { |
| 385 continue; |
| 386 } |
| 387 if (inner->deleted()) { |
| 388 continue; |
| 389 } |
| 390 SkOpSpanBase* innerBase = inner->span(); |
| 391 SkASSERT(innerBase->ptT() == inner); |
| 392 // when the intersection is first detected, the span base is marked
if there are |
| 393 // more than one point in the intersection. |
| 394 if (!zero_or_one(inner->fT)) { |
| 395 innerBase->upCast()->release(test); |
| 396 } else { |
| 397 SkASSERT(inner->fT != test->fT); |
| 398 if (!zero_or_one(test->fT)) { |
| 399 testBase->upCast()->release(inner); |
| 400 } else { |
| 401 segment->markAllDone(); // mark segment as collapsed |
| 402 SkDEBUGCODE(testBase->debugSetDeleted()); |
| 403 test->setDeleted(); |
| 404 SkDEBUGCODE(innerBase->debugSetDeleted()); |
| 405 inner->setDeleted(); |
| 406 } |
| 407 } |
| 408 #ifdef SK_DEBUG // assert if another undeleted entry points to segment |
| 409 const SkOpPtT* debugInner = inner; |
| 410 while ((debugInner = debugInner->next()) != innerStop) { |
| 411 if (debugInner->segment() != segment) { |
| 412 continue; |
| 413 } |
| 414 if (debugInner->deleted()) { |
| 415 continue; |
| 416 } |
| 417 SkOPASSERT(0); |
| 418 } |
| 419 #endif |
| 420 break; |
| 421 } while ((inner = inner->next()) != innerStop); |
| 422 } while ((test = testNext) != stop); |
| 423 this->checkForCollapsedCoincidence(); |
347 } | 424 } |
348 | 425 |
349 int SkOpSpan::computeWindSum() { | 426 int SkOpSpan::computeWindSum() { |
350 SkOpGlobalState* globals = this->globalState(); | 427 SkOpGlobalState* globals = this->globalState(); |
351 SkOpContour* contourHead = globals->contourHead(); | 428 SkOpContour* contourHead = globals->contourHead(); |
352 int windTry = 0; | 429 int windTry = 0; |
353 while (!this->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxW
indingTries) { | 430 while (!this->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxW
indingTries) { |
354 ; | 431 ; |
355 } | 432 } |
356 return this->windSum(); | 433 return this->windSum(); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 return true; | 483 return true; |
407 } | 484 } |
408 } | 485 } |
409 #if DEBUG_COINCIDENCE | 486 #if DEBUG_COINCIDENCE |
410 SkASSERT(0); // FIXME? if we get here, the span is missing its opposite segm
ent... | 487 SkASSERT(0); // FIXME? if we get here, the span is missing its opposite segm
ent... |
411 #endif | 488 #endif |
412 return true; | 489 return true; |
413 } | 490 } |
414 | 491 |
415 void SkOpSpan::release(const SkOpPtT* kept) { | 492 void SkOpSpan::release(const SkOpPtT* kept) { |
416 SkDEBUGCODE(fDeleted = true); | 493 SkDEBUGCODE(fDebugDeleted = true); |
417 SkASSERT(kept->span() != this); | 494 SkASSERT(kept->span() != this); |
418 SkASSERT(!final()); | 495 SkASSERT(!final()); |
419 SkOpSpan* prev = this->prev(); | 496 SkOpSpan* prev = this->prev(); |
420 SkASSERT(prev); | 497 SkASSERT(prev); |
421 SkOpSpanBase* next = this->next(); | 498 SkOpSpanBase* next = this->next(); |
422 SkASSERT(next); | 499 SkASSERT(next); |
423 prev->setNext(next); | 500 prev->setNext(next); |
424 next->setPrev(prev); | 501 next->setPrev(prev); |
425 this->segment()->release(this); | 502 this->segment()->release(this); |
426 SkOpCoincidence* coincidence = this->globalState()->coincidence(); | 503 SkOpCoincidence* coincidence = this->globalState()->coincidence(); |
(...skipping 23 matching lines...) Expand all Loading... |
450 | 527 |
451 void SkOpSpan::setWindSum(int windSum) { | 528 void SkOpSpan::setWindSum(int windSum) { |
452 SkASSERT(!final()); | 529 SkASSERT(!final()); |
453 if (fWindSum != SK_MinS32 && fWindSum != windSum) { | 530 if (fWindSum != SK_MinS32 && fWindSum != windSum) { |
454 this->globalState()->setWindingFailed(); | 531 this->globalState()->setWindingFailed(); |
455 return; | 532 return; |
456 } | 533 } |
457 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(windSum) <= DEBUG_LIMIT_WIND_SUM); | 534 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(windSum) <= DEBUG_LIMIT_WIND_SUM); |
458 fWindSum = windSum; | 535 fWindSum = windSum; |
459 } | 536 } |
OLD | NEW |