SkOpCoincidence.cpp revision 18fa6421e9cb7ac2ea6b1a97112a115d6643c0fc
1/* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7#include "SkOpCoincidence.h" 8#include "SkOpSegment.h" 9#include "SkPathOpsTSect.h" 10 11// returns true if coincident span's start and end are the same 12bool SkCoincidentSpans::collapsed(const SkOpPtT* test) const { 13 return (fCoinPtTStart == test && fCoinPtTEnd->contains(test)) 14 || (fCoinPtTEnd == test && fCoinPtTStart->contains(test)) 15 || (fOppPtTStart == test && fOppPtTEnd->contains(test)) 16 || (fOppPtTEnd == test && fOppPtTStart->contains(test)); 17} 18 19// sets the span's end to the ptT referenced by the previous-next 20void SkCoincidentSpans::correctOneEnd( 21 const SkOpPtT* (SkCoincidentSpans::* getEnd)() const, 22 void (SkCoincidentSpans::*setEnd)(const SkOpPtT* ptT) ) { 23 const SkOpPtT* origPtT = (this->*getEnd)(); 24 const SkOpSpanBase* origSpan = origPtT->span(); 25 const SkOpSpan* prev = origSpan->prev(); 26 const SkOpPtT* testPtT = prev ? prev->next()->ptT() 27 : origSpan->upCast()->next()->prev()->ptT(); 28 if (origPtT != testPtT) { 29 (this->*setEnd)(testPtT); 30 } 31} 32 33/* Please keep this in sync with debugCorrectEnds */ 34// FIXME: member pointers have fallen out of favor and can be replaced with 35// an alternative approach. 36// makes all span ends agree with the segment's spans that define them 37void SkCoincidentSpans::correctEnds() { 38 this->correctOneEnd(&SkCoincidentSpans::coinPtTStart, &SkCoincidentSpans::setCoinPtTStart); 39 this->correctOneEnd(&SkCoincidentSpans::coinPtTEnd, &SkCoincidentSpans::setCoinPtTEnd); 40 this->correctOneEnd(&SkCoincidentSpans::oppPtTStart, &SkCoincidentSpans::setOppPtTStart); 41 this->correctOneEnd(&SkCoincidentSpans::oppPtTEnd, &SkCoincidentSpans::setOppPtTEnd); 42} 43 44/* Please keep this in sync with debugExpand */ 45// expand the range by checking adjacent spans for coincidence 46bool SkCoincidentSpans::expand() { 47 bool expanded = false; 48 const SkOpSegment* segment = coinPtTStart()->segment(); 49 const SkOpSegment* oppSegment = oppPtTStart()->segment(); 50 do { 51 const SkOpSpan* start = coinPtTStart()->span()->upCast(); 52 const SkOpSpan* prev = start->prev(); 53 const SkOpPtT* oppPtT; 54 if (!prev || !(oppPtT = prev->contains(oppSegment))) { 55 break; 56 } 57 double midT = (prev->t() + start->t()) / 2; 58 if (!segment->isClose(midT, oppSegment)) { 59 break; 60 } 61 setStarts(prev->ptT(), oppPtT); 62 expanded = true; 63 } while (true); 64 do { 65 const SkOpSpanBase* end = coinPtTEnd()->span(); 66 SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next(); 67 if (next && next->deleted()) { 68 break; 69 } 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 85bool SkCoincidentSpans::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, 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 > oppPtTStart->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 102void SkCoincidentSpans::set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart, 103 const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) { 104 SkASSERT(SkOpCoincidence::Ordered(coinPtTStart, oppPtTStart)); 105 fNext = next; 106 this->setStarts(coinPtTStart, oppPtTStart); 107 this->setEnds(coinPtTEnd, oppPtTEnd); 108} 109 110// returns true if both points are inside this 111bool SkCoincidentSpans::contains(const SkOpPtT* s, const SkOpPtT* e) const { 112 if (s->fT > e->fT) { 113 SkTSwap(s, e); 114 } 115 if (s->segment() == fCoinPtTStart->segment()) { 116 return fCoinPtTStart->fT <= s->fT && e->fT <= fCoinPtTEnd->fT; 117 } else { 118 SkASSERT(s->segment() == fOppPtTStart->segment()); 119 double oppTs = fOppPtTStart->fT; 120 double oppTe = fOppPtTEnd->fT; 121 if (oppTs > oppTe) { 122 SkTSwap(oppTs, oppTe); 123 } 124 return oppTs <= s->fT && e->fT <= oppTe; 125 } 126} 127 128// A coincident span is unordered if the pairs of points in the main and opposite curves' 129// t values do not ascend or descend. For instance, if a tightly arced quadratic is 130// coincident with another curve, it may intersect it out of order. 131bool SkCoincidentSpans::ordered(bool* result) const { 132 const SkOpSpanBase* start = this->coinPtTStart()->span(); 133 const SkOpSpanBase* end = this->coinPtTEnd()->span(); 134 const SkOpSpanBase* next = start->upCast()->next(); 135 if (next == end) { 136 *result = true; 137 return true; 138 } 139 bool flipped = this->flipped(); 140 const SkOpSegment* oppSeg = this->oppPtTStart()->segment(); 141 double oppLastT = fOppPtTStart->fT; 142 do { 143 const SkOpPtT* opp = next->contains(oppSeg); 144 if (!opp) { 145 SkOPOBJASSERT(start, 0); // may assert if coincident span isn't fully processed 146 return false; 147 } 148 if ((oppLastT > opp->fT) != flipped) { 149 *result = false; 150 return true; 151 } 152 oppLastT = opp->fT; 153 if (next == end) { 154 break; 155 } 156 if (!next->upCastable()) { 157 *result = false; 158 return true; 159 } 160 next = next->upCast()->next(); 161 } while (true); 162 *result = true; 163 return true; 164} 165 166// if there is an existing pair that overlaps the addition, extend it 167bool SkOpCoincidence::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, 168 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) { 169 SkCoincidentSpans* test = fHead; 170 if (!test) { 171 return false; 172 } 173 const SkOpSegment* coinSeg = coinPtTStart->segment(); 174 const SkOpSegment* oppSeg = oppPtTStart->segment(); 175 if (!Ordered(coinPtTStart, oppPtTStart)) { 176 SkTSwap(coinSeg, oppSeg); 177 SkTSwap(coinPtTStart, oppPtTStart); 178 SkTSwap(coinPtTEnd, oppPtTEnd); 179 if (coinPtTStart->fT > coinPtTEnd->fT) { 180 SkTSwap(coinPtTStart, coinPtTEnd); 181 SkTSwap(oppPtTStart, oppPtTEnd); 182 } 183 } 184 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT); 185 SkDEBUGCODE(double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT)); 186 do { 187 if (coinSeg != test->coinPtTStart()->segment()) { 188 continue; 189 } 190 if (oppSeg != test->oppPtTStart()->segment()) { 191 continue; 192 } 193 double oTestMinT = SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT); 194 double oTestMaxT = SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT); 195 // if debug check triggers, caller failed to check if extended already exists 196 SkASSERT(test->coinPtTStart()->fT > coinPtTStart->fT 197 || coinPtTEnd->fT > test->coinPtTEnd()->fT 198 || oTestMinT > oppMinT || oppMaxT > oTestMaxT); 199 if ((test->coinPtTStart()->fT <= coinPtTEnd->fT 200 && coinPtTStart->fT <= test->coinPtTEnd()->fT) 201 || (oTestMinT <= oTestMaxT && oppMinT <= oTestMaxT)) { 202 test->extend(coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd); 203 return true; 204 } 205 } while ((test = test->next())); 206 return false; 207} 208 209// verifies that the coincidence hasn't already been added 210static void DebugCheckAdd(const SkCoincidentSpans* check, const SkOpPtT* coinPtTStart, 211 const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) { 212#if DEBUG_COINCIDENCE 213 while (check) { 214 SkASSERT(check->coinPtTStart() != coinPtTStart || check->coinPtTEnd() != coinPtTEnd 215 || check->oppPtTStart() != oppPtTStart || check->oppPtTEnd() != oppPtTEnd); 216 SkASSERT(check->coinPtTStart() != oppPtTStart || check->coinPtTEnd() != oppPtTEnd 217 || check->oppPtTStart() != coinPtTStart || check->oppPtTEnd() != coinPtTEnd); 218 check = check->next(); 219 } 220#endif 221} 222 223// adds a new coincident pair 224void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart, 225 SkOpPtT* oppPtTEnd) { 226 // OPTIMIZE: caller should have already sorted 227 if (!Ordered(coinPtTStart, oppPtTStart)) { 228 if (oppPtTStart->fT < oppPtTEnd->fT) { 229 this->add(oppPtTStart, oppPtTEnd, coinPtTStart, coinPtTEnd); 230 } else { 231 this->add(oppPtTEnd, oppPtTStart, coinPtTEnd, coinPtTStart); 232 } 233 return; 234 } 235 SkASSERT(Ordered(coinPtTStart, oppPtTStart)); 236 // choose the ptT at the front of the list to track 237 coinPtTStart = coinPtTStart->span()->ptT(); 238 coinPtTEnd = coinPtTEnd->span()->ptT(); 239 oppPtTStart = oppPtTStart->span()->ptT(); 240 oppPtTEnd = oppPtTEnd->span()->ptT(); 241 SkOPASSERT(coinPtTStart->fT < coinPtTEnd->fT); 242 SkOPASSERT(oppPtTStart->fT != oppPtTEnd->fT); 243 SkOPASSERT(!coinPtTStart->deleted()); 244 SkOPASSERT(!coinPtTEnd->deleted()); 245 SkOPASSERT(!oppPtTStart->deleted()); 246 SkOPASSERT(!oppPtTEnd->deleted()); 247 DebugCheckAdd(fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd); 248 DebugCheckAdd(fTop, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd); 249 SkCoincidentSpans* coinRec = SkOpTAllocator<SkCoincidentSpans>::Allocate( 250 this->globalState()->allocator()); 251 coinRec->init(SkDEBUGCODE(fGlobalState)); 252 coinRec->set(this->fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd); 253 fHead = coinRec; 254} 255 256// description below 257bool SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan) { 258 const SkOpPtT* testPtT = testSpan->ptT(); 259 const SkOpPtT* stopPtT = testPtT; 260 const SkOpSegment* baseSeg = base->segment(); 261 while ((testPtT = testPtT->next()) != stopPtT) { 262 const SkOpSegment* testSeg = testPtT->segment(); 263 if (testPtT->deleted()) { 264 continue; 265 } 266 if (testSeg == baseSeg) { 267 continue; 268 } 269 if (testPtT->span()->ptT() != testPtT) { 270 continue; 271 } 272 if (this->contains(baseSeg, testSeg, testPtT->fT)) { 273 continue; 274 } 275 // intersect perp with base->ptT() with testPtT->segment() 276 SkDVector dxdy = baseSeg->dSlopeAtT(base->t()); 277 const SkPoint& pt = base->pt(); 278 SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}}; 279 SkIntersections i; 280 (*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i); 281 for (int index = 0; index < i.used(); ++index) { 282 double t = i[0][index]; 283 if (!between(0, t, 1)) { 284 continue; 285 } 286 SkDPoint oppPt = i.pt(index); 287 if (!oppPt.approximatelyEqual(pt)) { 288 continue; 289 } 290 SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg); 291 SkOpPtT* oppStart = writableSeg->addT(t); 292 if (oppStart == testPtT) { 293 continue; 294 } 295 SkOpSpan* writableBase = const_cast<SkOpSpan*>(base); 296 oppStart->span()->addOpp(writableBase); 297 if (oppStart->deleted()) { 298 continue; 299 } 300 SkOpSegment* coinSeg = base->segment(); 301 SkOpSegment* oppSeg = oppStart->segment(); 302 double coinTs, coinTe, oppTs, oppTe; 303 if (Ordered(coinSeg, oppSeg)) { 304 coinTs = base->t(); 305 coinTe = testSpan->t(); 306 oppTs = oppStart->fT; 307 oppTe = testPtT->fT; 308 } else { 309 SkTSwap(coinSeg, oppSeg); 310 coinTs = oppStart->fT; 311 coinTe = testPtT->fT; 312 oppTs = base->t(); 313 oppTe = testSpan->t(); 314 } 315 if (coinTs > coinTe) { 316 SkTSwap(coinTs, coinTe); 317 SkTSwap(oppTs, oppTe); 318 } 319 bool added; 320 if (!this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added)) { 321 return false; 322 } 323 } 324 } 325 return true; 326} 327 328// description below 329bool SkOpCoincidence::addEndMovedSpans(const SkOpPtT* ptT) { 330 FAIL_IF(!ptT->span()->upCastable()); 331 const SkOpSpan* base = ptT->span()->upCast(); 332 const SkOpSpan* prev = base->prev(); 333 FAIL_IF(!prev); 334 if (!prev->isCanceled()) { 335 if (!this->addEndMovedSpans(base, base->prev())) { 336 return false; 337 } 338 } 339 if (!base->isCanceled()) { 340 if (!this->addEndMovedSpans(base, base->next())) { 341 return false; 342 } 343 } 344 return true; 345} 346 347/* If A is coincident with B and B includes an endpoint, and A's matching point 348 is not the endpoint (i.e., there's an implied line connecting B-end and A) 349 then assume that the same implied line may intersect another curve close to B. 350 Since we only care about coincidence that was undetected, look at the 351 ptT list on B-segment adjacent to the B-end/A ptT loop (not in the loop, but 352 next door) and see if the A matching point is close enough to form another 353 coincident pair. If so, check for a new coincident span between B-end/A ptT loop 354 and the adjacent ptT loop. 355*/ 356bool SkOpCoincidence::addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { 357 DEBUG_SET_PHASE(); 358 SkCoincidentSpans* span = fHead; 359 if (!span) { 360 return true; 361 } 362 fTop = span; 363 fHead = nullptr; 364 do { 365 if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) { 366 FAIL_IF(1 == span->coinPtTStart()->fT); 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 the opposite span 404bool SkOpCoincidence::addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { 405 DEBUG_SET_PHASE(); 406 SkCoincidentSpans* coin = this->fHead; 407 if (!coin) { 408 return true; 409 } 410 do { 411 const SkOpPtT* startPtT = coin->coinPtTStart(); 412 const SkOpPtT* oStartPtT = coin->oppPtTStart(); 413 double priorT = startPtT->fT; 414 double oPriorT = oStartPtT->fT; 415 FAIL_IF(!startPtT->contains(oStartPtT)); 416 SkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd())); 417 const SkOpSpanBase* start = startPtT->span(); 418 const SkOpSpanBase* oStart = oStartPtT->span(); 419 const SkOpSpanBase* end = coin->coinPtTEnd()->span(); 420 const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span(); 421 FAIL_IF(oEnd->deleted()); 422 FAIL_IF(!start->upCastable()); 423 const SkOpSpanBase* test = start->upCast()->next(); 424 FAIL_IF(!coin->flipped() && !oStart->upCastable()); 425 const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->upCast()->next(); 426 FAIL_IF(!oTest); 427 SkOpSegment* seg = start->segment(); 428 SkOpSegment* oSeg = oStart->segment(); 429 while (test != end || oTest != oEnd) { 430 const SkOpPtT* containedOpp = test->ptT()->contains(oSeg); 431 const SkOpPtT* containedThis = oTest->ptT()->contains(seg); 432 if (!containedOpp || !containedThis) { 433 // choose the ends, or the first common pt-t list shared by both 434 double nextT, oNextT; 435 if (containedOpp) { 436 nextT = test->t(); 437 oNextT = containedOpp->fT; 438 } else if (containedThis) { 439 nextT = containedThis->fT; 440 oNextT = oTest->t(); 441 } else { 442 // iterate through until a pt-t list found that contains the other 443 const SkOpSpanBase* walk = test; 444 const SkOpPtT* walkOpp; 445 do { 446 FAIL_IF(!walk->upCastable()); 447 walk = walk->upCast()->next(); 448 } while (!(walkOpp = walk->ptT()->contains(oSeg)) 449 && walk != coin->coinPtTEnd()->span()); 450 FAIL_IF(!walkOpp); 451 nextT = walk->t(); 452 oNextT = walkOpp->fT; 453 } 454 // use t ranges to guess which one is missing 455 double startRange = nextT - priorT; 456 FAIL_IF(!startRange); 457 double startPart = (test->t() - priorT) / startRange; 458 double oStartRange = oNextT - oPriorT; 459 FAIL_IF(!oStartRange); 460 double oStartPart = (oTest->t() - oPriorT) / oStartRange; 461 FAIL_IF(startPart == oStartPart); 462 bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart 463 : !!containedThis; 464 bool startOver = false; 465 bool success = addToOpp ? oSeg->addExpanded( 466 oPriorT + oStartRange * startPart, test, &startOver) 467 : seg->addExpanded( 468 priorT + startRange * oStartPart, oTest, &startOver); 469 FAIL_IF(!success); 470 if (startOver) { 471 test = start; 472 oTest = oStart; 473 } 474 end = coin->coinPtTEnd()->span(); 475 oEnd = coin->oppPtTEnd()->span(); 476 } 477 if (test != end) { 478 FAIL_IF(!test->upCastable()); 479 priorT = test->t(); 480 test = test->upCast()->next(); 481 } 482 if (oTest != oEnd) { 483 oPriorT = oTest->t(); 484 if (coin->flipped()) { 485 oTest = oTest->prev(); 486 } else { 487 FAIL_IF(!oTest->upCastable()); 488 oTest = oTest->upCast()->next(); 489 } 490 FAIL_IF(!oTest); 491 } 492 493 } 494 } while ((coin = coin->next())); 495 return true; 496} 497 498// given a t span, map the same range on the coincident span 499/* 500the curves may not scale linearly, so interpolation may only happen within known points 501remap over1s, over1e, cointPtTStart, coinPtTEnd to smallest range that captures over1s 502then repeat to capture over1e 503*/ 504double SkOpCoincidence::TRange(const SkOpPtT* overS, double t, 505 const SkOpSegment* coinSeg SkDEBUGPARAMS(const SkOpPtT* overE)) { 506 const SkOpSpanBase* work = overS->span(); 507 const SkOpPtT* foundStart = nullptr; 508 const SkOpPtT* foundEnd = nullptr; 509 const SkOpPtT* coinStart = nullptr; 510 const SkOpPtT* coinEnd = nullptr; 511 do { 512 const SkOpPtT* contained = work->contains(coinSeg); 513 if (!contained) { 514 if (work->final()) { 515 break; 516 } 517 continue; 518 } 519 if (work->t() <= t) { 520 coinStart = contained; 521 foundStart = work->ptT(); 522 } 523 if (work->t() >= t) { 524 coinEnd = contained; 525 foundEnd = work->ptT(); 526 break; 527 } 528 SkASSERT(work->ptT() != overE); 529 } while ((work = work->upCast()->next())); 530 if (!coinStart || !coinEnd) { 531 return 1; 532 } 533 // while overS->fT <=t and overS contains coinSeg 534 double denom = foundEnd->fT - foundStart->fT; 535 double sRatio = denom ? (t - foundStart->fT) / denom : 1; 536 return coinStart->fT + (coinEnd->fT - coinStart->fT) * sRatio; 537} 538 539// return true if span overlaps existing and needs to adjust the coincident list 540bool SkOpCoincidence::checkOverlap(SkCoincidentSpans* check, 541 const SkOpSegment* coinSeg, const SkOpSegment* oppSeg, 542 double coinTs, double coinTe, double oppTs, double oppTe, 543 SkTDArray<SkCoincidentSpans*>* overlaps) const { 544 if (!Ordered(coinSeg, oppSeg)) { 545 if (oppTs < oppTe) { 546 return this->checkOverlap(check, oppSeg, coinSeg, oppTs, oppTe, coinTs, coinTe, 547 overlaps); 548 } 549 return this->checkOverlap(check, oppSeg, coinSeg, oppTe, oppTs, coinTe, coinTs, overlaps); 550 } 551 bool swapOpp = oppTs > oppTe; 552 if (swapOpp) { 553 SkTSwap(oppTs, oppTe); 554 } 555 do { 556 if (check->coinPtTStart()->segment() != coinSeg) { 557 continue; 558 } 559 if (check->oppPtTStart()->segment() != oppSeg) { 560 continue; 561 } 562 double checkTs = check->coinPtTStart()->fT; 563 double checkTe = check->coinPtTEnd()->fT; 564 bool coinOutside = coinTe < checkTs || coinTs > checkTe; 565 double oCheckTs = check->oppPtTStart()->fT; 566 double oCheckTe = check->oppPtTEnd()->fT; 567 if (swapOpp) { 568 if (oCheckTs <= oCheckTe) { 569 return false; 570 } 571 SkTSwap(oCheckTs, oCheckTe); 572 } 573 bool oppOutside = oppTe < oCheckTs || oppTs > oCheckTe; 574 if (coinOutside && oppOutside) { 575 continue; 576 } 577 bool coinInside = coinTe <= checkTe && coinTs >= checkTs; 578 bool oppInside = oppTe <= oCheckTe && oppTs >= oCheckTs; 579 if (coinInside && oppInside) { // already included, do nothing 580 return false; 581 } 582 *overlaps->append() = check; // partial overlap, extend existing entry 583 } while ((check = check->next())); 584 return true; 585} 586 587/* Please keep this in sync with debugAddIfMissing() */ 588// note that over1s, over1e, over2s, over2e are ordered 589bool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over2s, 590 double tStart, double tEnd, SkOpSegment* coinSeg, SkOpSegment* oppSeg, bool* added 591 SkDEBUGPARAMS(const SkOpPtT* over1e) SkDEBUGPARAMS(const SkOpPtT* over2e)) { 592 SkASSERT(tStart < tEnd); 593 SkASSERT(over1s->fT < over1e->fT); 594 SkASSERT(between(over1s->fT, tStart, over1e->fT)); 595 SkASSERT(between(over1s->fT, tEnd, over1e->fT)); 596 SkASSERT(over2s->fT < over2e->fT); 597 SkASSERT(between(over2s->fT, tStart, over2e->fT)); 598 SkASSERT(between(over2s->fT, tEnd, over2e->fT)); 599 SkASSERT(over1s->segment() == over1e->segment()); 600 SkASSERT(over2s->segment() == over2e->segment()); 601 SkASSERT(over1s->segment() == over2s->segment()); 602 SkASSERT(over1s->segment() != coinSeg); 603 SkASSERT(over1s->segment() != oppSeg); 604 SkASSERT(coinSeg != oppSeg); 605 double coinTs, coinTe, oppTs, oppTe; 606 coinTs = TRange(over1s, tStart, coinSeg SkDEBUGPARAMS(over1e)); 607 coinTe = TRange(over1s, tEnd, coinSeg SkDEBUGPARAMS(over1e)); 608 if (coinSeg->collapsed(coinTs, coinTe)) { 609 return true; 610 } 611 oppTs = TRange(over2s, tStart, oppSeg SkDEBUGPARAMS(over2e)); 612 oppTe = TRange(over2s, tEnd, oppSeg SkDEBUGPARAMS(over2e)); 613 if (oppSeg->collapsed(oppTs, oppTe)) { 614 return true; 615 } 616 if (coinTs > coinTe) { 617 SkTSwap(coinTs, coinTe); 618 SkTSwap(oppTs, oppTe); 619 } 620 return this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added); 621} 622 623/* Please keep this in sync with debugAddOrOverlap() */ 624// If this is called by addEndMovedSpans(), a returned false propogates out to an abort. 625// If this is called by AddIfMissing(), a returned false indicates there was nothing to add 626bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg, 627 double coinTs, double coinTe, double oppTs, double oppTe, bool* added) { 628 SkTDArray<SkCoincidentSpans*> overlaps; 629 FAIL_IF(!fTop); 630 if (!this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &overlaps)) { 631 return true; 632 } 633 if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs, 634 coinTe, oppTs, oppTe, &overlaps)) { 635 return true; 636 } 637 SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr; 638 for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing 639 SkCoincidentSpans* test = overlaps[index]; 640 if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) { 641 overlap->setCoinPtTStart(test->coinPtTStart()); 642 } 643 if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) { 644 overlap->setCoinPtTEnd(test->coinPtTEnd()); 645 } 646 if (overlap->flipped() 647 ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT 648 : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) { 649 overlap->setOppPtTStart(test->oppPtTStart()); 650 } 651 if (overlap->flipped() 652 ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT 653 : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) { 654 overlap->setOppPtTEnd(test->oppPtTEnd()); 655 } 656 if (!fHead || !this->release(fHead, test)) { 657 SkAssertResult(this->release(fTop, test)); 658 } 659 } 660 const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg); 661 const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg); 662 if (overlap && cs && ce && overlap->contains(cs, ce)) { 663 return true; 664 } 665 FAIL_IF(cs == ce && cs); 666 const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg); 667 const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg); 668 if (overlap && os && oe && overlap->contains(os, oe)) { 669 return true; 670 } 671 SkASSERT(!cs || !cs->deleted()); 672 SkASSERT(!os || !os->deleted()); 673 SkASSERT(!ce || !ce->deleted()); 674 SkASSERT(!oe || !oe->deleted()); 675 const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr; 676 const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr; 677 FAIL_IF(csExisting && csExisting == ceExisting); 678// FAIL_IF(csExisting && (csExisting == ce || 679// csExisting->contains(ceExisting ? ceExisting : ce))); 680 FAIL_IF(ceExisting && (ceExisting == cs || 681 ceExisting->contains(csExisting ? csExisting : cs))); 682 const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr; 683 const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr; 684 FAIL_IF(osExisting && osExisting == oeExisting); 685 FAIL_IF(osExisting && (osExisting == oe || 686 osExisting->contains(oeExisting ? oeExisting : oe))); 687 FAIL_IF(oeExisting && (oeExisting == os || 688 oeExisting->contains(osExisting ? osExisting : os))); 689 // extra line in debug code 690 this->debugValidate(); 691 if (!cs || !os) { 692 SkOpPtT* csWritable = cs ? const_cast<SkOpPtT*>(cs) 693 : coinSeg->addT(coinTs); 694 if (csWritable == ce) { 695 return true; 696 } 697 SkOpPtT* osWritable = os ? const_cast<SkOpPtT*>(os) 698 : oppSeg->addT(oppTs); 699 FAIL_IF(!csWritable || !osWritable); 700 csWritable->span()->addOpp(osWritable->span()); 701 cs = csWritable; 702 os = osWritable->active(); 703 FAIL_IF((ce && ce->deleted()) || (oe && oe->deleted())); 704 } 705 if (!ce || !oe) { 706 SkOpPtT* ceWritable = ce ? const_cast<SkOpPtT*>(ce) 707 : coinSeg->addT(coinTe); 708 SkOpPtT* oeWritable = oe ? const_cast<SkOpPtT*>(oe) 709 : oppSeg->addT(oppTe); 710 ceWritable->span()->addOpp(oeWritable->span()); 711 ce = ceWritable; 712 oe = oeWritable; 713 } 714 this->debugValidate(); 715 FAIL_IF(cs->deleted()); 716 FAIL_IF(os->deleted()); 717 FAIL_IF(ce->deleted()); 718 FAIL_IF(oe->deleted()); 719 FAIL_IF(cs->contains(ce) || os->contains(oe)); 720 bool result = true; 721 if (overlap) { 722 if (overlap->coinPtTStart()->segment() == coinSeg) { 723 result = overlap->extend(cs, ce, os, oe); 724 } else { 725 if (os->fT > oe->fT) { 726 SkTSwap(cs, ce); 727 SkTSwap(os, oe); 728 } 729 result = overlap->extend(os, oe, cs, ce); 730 } 731#if DEBUG_COINCIDENCE_VERBOSE 732 if (result) { 733 overlaps[0]->debugShow(); 734 } 735#endif 736 } else { 737 this->add(cs, ce, os, oe); 738#if DEBUG_COINCIDENCE_VERBOSE 739 fHead->debugShow(); 740#endif 741 } 742 this->debugValidate(); 743 if (result) { 744 *added = true; 745 } 746 return true; 747} 748 749// Please keep this in sync with debugAddMissing() 750/* detects overlaps of different coincident runs on same segment */ 751/* does not detect overlaps for pairs without any segments in common */ 752// returns true if caller should loop again 753bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) { 754 SkCoincidentSpans* outer = fHead; 755 *added = false; 756 if (!outer) { 757 return true; 758 } 759 fTop = outer; 760 fHead = nullptr; 761 do { 762 // addifmissing can modify the list that this is walking 763 // save head so that walker can iterate over old data unperturbed 764 // addifmissing adds to head freely then add saved head in the end 765 const SkOpPtT* ocs = outer->coinPtTStart(); 766 FAIL_IF(ocs->deleted()); 767 const SkOpSegment* outerCoin = ocs->segment(); 768 SkASSERT(!outerCoin->done()); // if it's done, should have already been removed from list 769 const SkOpPtT* oos = outer->oppPtTStart(); 770 if (oos->deleted()) { 771 return true; 772 } 773 const SkOpSegment* outerOpp = oos->segment(); 774 SkASSERT(!outerOpp->done()); 775 SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin); 776 SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp); 777 SkCoincidentSpans* inner = outer; 778 while ((inner = inner->next())) { 779 this->debugValidate(); 780 double overS, overE; 781 const SkOpPtT* ics = inner->coinPtTStart(); 782 FAIL_IF(ics->deleted()); 783 const SkOpSegment* innerCoin = ics->segment(); 784 FAIL_IF(innerCoin->done()); 785 const SkOpPtT* ios = inner->oppPtTStart(); 786 FAIL_IF(ios->deleted()); 787 const SkOpSegment* innerOpp = ios->segment(); 788 SkASSERT(!innerOpp->done()); 789 SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin); 790 SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp); 791 if (outerCoin == innerCoin) { 792 const SkOpPtT* oce = outer->coinPtTEnd(); 793 if (oce->deleted()) { 794 return true; 795 } 796 const SkOpPtT* ice = inner->coinPtTEnd(); 797 FAIL_IF(ice->deleted()); 798 if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) { 799 (void) this->addIfMissing(ocs->starter(oce), ics->starter(ice), 800 overS, overE, outerOppWritable, innerOppWritable, added 801 SkDEBUGPARAMS(ocs->debugEnder(oce)) 802 SkDEBUGPARAMS(ics->debugEnder(ice))); 803 } 804 } else if (outerCoin == innerOpp) { 805 const SkOpPtT* oce = outer->coinPtTEnd(); 806 SkASSERT(!oce->deleted()); 807 const SkOpPtT* ioe = inner->oppPtTEnd(); 808 SkASSERT(!ioe->deleted()); 809 if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) { 810 (void) this->addIfMissing(ocs->starter(oce), ios->starter(ioe), 811 overS, overE, outerOppWritable, innerCoinWritable, added 812 SkDEBUGPARAMS(ocs->debugEnder(oce)) 813 SkDEBUGPARAMS(ios->debugEnder(ioe))); 814 } 815 } else if (outerOpp == innerCoin) { 816 const SkOpPtT* ooe = outer->oppPtTEnd(); 817 SkASSERT(!ooe->deleted()); 818 const SkOpPtT* ice = inner->coinPtTEnd(); 819 SkASSERT(!ice->deleted()); 820 SkASSERT(outerCoin != innerOpp); 821 if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) { 822 (void) this->addIfMissing(oos->starter(ooe), ics->starter(ice), 823 overS, overE, outerCoinWritable, innerOppWritable, added 824 SkDEBUGPARAMS(oos->debugEnder(ooe)) 825 SkDEBUGPARAMS(ics->debugEnder(ice))); 826 } 827 } else if (outerOpp == innerOpp) { 828 const SkOpPtT* ooe = outer->oppPtTEnd(); 829 SkASSERT(!ooe->deleted()); 830 const SkOpPtT* ioe = inner->oppPtTEnd(); 831 if (ioe->deleted()) { 832 return true; 833 } 834 SkASSERT(outerCoin != innerCoin); 835 if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) { 836 (void) this->addIfMissing(oos->starter(ooe), ios->starter(ioe), 837 overS, overE, outerCoinWritable, innerCoinWritable, added 838 SkDEBUGPARAMS(oos->debugEnder(ooe)) 839 SkDEBUGPARAMS(ios->debugEnder(ioe))); 840 } 841 } 842 this->debugValidate(); 843 } 844 } while ((outer = outer->next())); 845 this->restoreHead(); 846 return true; 847} 848 849bool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o, 850 const SkOpSegment* seg2, const SkOpSegment* seg2o, 851 const SkOpPtT* overS, const SkOpPtT* overE) { 852 const SkOpPtT* s1 = overS->find(seg1); 853 const SkOpPtT* e1 = overE->find(seg1); 854 FAIL_IF(!s1); 855 FAIL_IF(!e1); 856 if (!s1->starter(e1)->span()->upCast()->windValue()) { 857 s1 = overS->find(seg1o); 858 e1 = overE->find(seg1o); 859 FAIL_IF(!s1); 860 FAIL_IF(!e1); 861 if (!s1->starter(e1)->span()->upCast()->windValue()) { 862 return true; 863 } 864 } 865 const SkOpPtT* s2 = overS->find(seg2); 866 const SkOpPtT* e2 = overE->find(seg2); 867 FAIL_IF(!s2); 868 FAIL_IF(!e2); 869 if (!s2->starter(e2)->span()->upCast()->windValue()) { 870 s2 = overS->find(seg2o); 871 e2 = overE->find(seg2o); 872 FAIL_IF(!s2); 873 FAIL_IF(!e2); 874 if (!s2->starter(e2)->span()->upCast()->windValue()) { 875 return true; 876 } 877 } 878 if (s1->segment() == s2->segment()) { 879 return true; 880 } 881 if (s1->fT > e1->fT) { 882 SkTSwap(s1, e1); 883 SkTSwap(s2, e2); 884 } 885 this->add(s1, e1, s2, e2); 886 return true; 887} 888 889bool SkOpCoincidence::contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const { 890 if (this->contains(fHead, seg, opp, oppT)) { 891 return true; 892 } 893 if (this->contains(fTop, seg, opp, oppT)) { 894 return true; 895 } 896 return false; 897} 898 899bool SkOpCoincidence::contains(const SkCoincidentSpans* coin, const SkOpSegment* seg, 900 const SkOpSegment* opp, double oppT) const { 901 if (!coin) { 902 return false; 903 } 904 do { 905 if (coin->coinPtTStart()->segment() == seg && coin->oppPtTStart()->segment() == opp 906 && between(coin->oppPtTStart()->fT, oppT, coin->oppPtTEnd()->fT)) { 907 return true; 908 } 909 if (coin->oppPtTStart()->segment() == seg && coin->coinPtTStart()->segment() == opp 910 && between(coin->coinPtTStart()->fT, oppT, coin->coinPtTEnd()->fT)) { 911 return true; 912 } 913 } while ((coin = coin->next())); 914 return false; 915} 916 917bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, 918 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const { 919 const SkCoincidentSpans* test = fHead; 920 if (!test) { 921 return false; 922 } 923 const SkOpSegment* coinSeg = coinPtTStart->segment(); 924 const SkOpSegment* oppSeg = oppPtTStart->segment(); 925 if (!Ordered(coinPtTStart, oppPtTStart)) { 926 SkTSwap(coinSeg, oppSeg); 927 SkTSwap(coinPtTStart, oppPtTStart); 928 SkTSwap(coinPtTEnd, oppPtTEnd); 929 if (coinPtTStart->fT > coinPtTEnd->fT) { 930 SkTSwap(coinPtTStart, coinPtTEnd); 931 SkTSwap(oppPtTStart, oppPtTEnd); 932 } 933 } 934 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT); 935 double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT); 936 do { 937 if (coinSeg != test->coinPtTStart()->segment()) { 938 continue; 939 } 940 if (coinPtTStart->fT < test->coinPtTStart()->fT) { 941 continue; 942 } 943 if (coinPtTEnd->fT > test->coinPtTEnd()->fT) { 944 continue; 945 } 946 if (oppSeg != test->oppPtTStart()->segment()) { 947 continue; 948 } 949 if (oppMinT < SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) { 950 continue; 951 } 952 if (oppMaxT > SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) { 953 continue; 954 } 955 return true; 956 } while ((test = test->next())); 957 return false; 958} 959 960void SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { 961 DEBUG_SET_PHASE(); 962 SkCoincidentSpans* coin = fHead; 963 if (!coin) { 964 return; 965 } 966 do { 967 coin->correctEnds(); 968 } while ((coin = coin->next())); 969} 970 971// walk span sets in parallel, moving winding from one to the other 972bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { 973 DEBUG_SET_PHASE(); 974 SkCoincidentSpans* coin = fHead; 975 if (!coin) { 976 return true; 977 } 978 do { 979 SkOpSpan* start = coin->coinPtTStartWritable()->span()->upCast(); 980 if (start->deleted()) { 981 continue; 982 } 983 const SkOpSpanBase* end = coin->coinPtTEnd()->span(); 984 SkASSERT(start == start->starter(end)); 985 bool flipped = coin->flipped(); 986 SkOpSpanBase* oStartBase = (flipped ? coin->oppPtTEndWritable() 987 : coin->oppPtTStartWritable())->span(); 988 FAIL_IF(!oStartBase->upCastable()); 989 SkOpSpan* oStart = oStartBase->upCast(); 990 if (oStart->deleted()) { 991 continue; 992 } 993 const SkOpSpanBase* oEnd = (flipped ? coin->oppPtTStart() : coin->oppPtTEnd())->span(); 994 SkASSERT(oStart == oStart->starter(oEnd)); 995 SkOpSegment* segment = start->segment(); 996 SkOpSegment* oSegment = oStart->segment(); 997 bool operandSwap = segment->operand() != oSegment->operand(); 998 if (flipped) { 999 if (oEnd->deleted()) { 1000 continue; 1001 } 1002 do { 1003 SkOpSpanBase* oNext = oStart->next(); 1004 if (oNext == oEnd) { 1005 break; 1006 } 1007 oStart = oNext->upCast(); 1008 } while (true); 1009 } 1010 do { 1011 int windValue = start->windValue(); 1012 int oppValue = start->oppValue(); 1013 int oWindValue = oStart->windValue(); 1014 int oOppValue = oStart->oppValue(); 1015 // winding values are added or subtracted depending on direction and wind type 1016 // same or opposite values are summed depending on the operand value 1017 int windDiff = operandSwap ? oOppValue : oWindValue; 1018 int oWindDiff = operandSwap ? oppValue : windValue; 1019 if (!flipped) { 1020 windDiff = -windDiff; 1021 oWindDiff = -oWindDiff; 1022 } 1023 bool addToStart = windValue && (windValue > windDiff || (windValue == windDiff 1024 && oWindValue <= oWindDiff)); 1025 if (addToStart ? start->done() : oStart->done()) { 1026 addToStart ^= true; 1027 } 1028 if (addToStart) { 1029 if (operandSwap) { 1030 SkTSwap(oWindValue, oOppValue); 1031 } 1032 if (flipped) { 1033 windValue -= oWindValue; 1034 oppValue -= oOppValue; 1035 } else { 1036 windValue += oWindValue; 1037 oppValue += oOppValue; 1038 } 1039 if (segment->isXor()) { 1040 windValue &= 1; 1041 } 1042 if (segment->oppXor()) { 1043 oppValue &= 1; 1044 } 1045 oWindValue = oOppValue = 0; 1046 } else { 1047 if (operandSwap) { 1048 SkTSwap(windValue, oppValue); 1049 } 1050 if (flipped) { 1051 oWindValue -= windValue; 1052 oOppValue -= oppValue; 1053 } else { 1054 oWindValue += windValue; 1055 oOppValue += oppValue; 1056 } 1057 if (oSegment->isXor()) { 1058 oWindValue &= 1; 1059 } 1060 if (oSegment->oppXor()) { 1061 oOppValue &= 1; 1062 } 1063 windValue = oppValue = 0; 1064 } 1065#if 0 && DEBUG_COINCIDENCE 1066 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", segment->debugID(), 1067 start->debugID(), windValue, oppValue); 1068 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", oSegment->debugID(), 1069 oStart->debugID(), oWindValue, oOppValue); 1070#endif 1071 start->setWindValue(windValue); 1072 start->setOppValue(oppValue); 1073 FAIL_IF(oWindValue == -1); 1074 oStart->setWindValue(oWindValue); 1075 oStart->setOppValue(oOppValue); 1076 if (!windValue && !oppValue) { 1077 segment->markDone(start); 1078 } 1079 if (!oWindValue && !oOppValue) { 1080 oSegment->markDone(oStart); 1081 } 1082 SkOpSpanBase* next = start->next(); 1083 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next(); 1084 if (next == end) { 1085 break; 1086 } 1087 FAIL_IF(!next->upCastable()); 1088 start = next->upCast(); 1089 // if the opposite ran out too soon, just reuse the last span 1090 if (!oNext || !oNext->upCastable()) { 1091 oNext = oStart; 1092 } 1093 oStart = oNext->upCast(); 1094 } while (true); 1095 } while ((coin = coin->next())); 1096 return true; 1097} 1098 1099// Please keep this in sync with debugRelease() 1100bool SkOpCoincidence::release(SkCoincidentSpans* coin, SkCoincidentSpans* remove) { 1101 SkCoincidentSpans* head = coin; 1102 SkCoincidentSpans* prev = nullptr; 1103 SkCoincidentSpans* next; 1104 do { 1105 next = coin->next(); 1106 if (coin == remove) { 1107 if (prev) { 1108 prev->setNext(next); 1109 } else if (head == fHead) { 1110 fHead = next; 1111 } else { 1112 fTop = next; 1113 } 1114 break; 1115 } 1116 prev = coin; 1117 } while ((coin = next)); 1118 return coin != nullptr; 1119} 1120 1121void SkOpCoincidence::releaseDeleted(SkCoincidentSpans* coin) { 1122 if (!coin) { 1123 return; 1124 } 1125 SkCoincidentSpans* head = coin; 1126 SkCoincidentSpans* prev = nullptr; 1127 SkCoincidentSpans* next; 1128 do { 1129 next = coin->next(); 1130 if (coin->coinPtTStart()->deleted()) { 1131 SkOPASSERT(coin->flipped() ? coin->oppPtTEnd()->deleted() : 1132 coin->oppPtTStart()->deleted()); 1133 if (prev) { 1134 prev->setNext(next); 1135 } else if (head == fHead) { 1136 fHead = next; 1137 } else { 1138 fTop = next; 1139 } 1140 } else { 1141 SkOPASSERT(coin->flipped() ? !coin->oppPtTEnd()->deleted() : 1142 !coin->oppPtTStart()->deleted()); 1143 prev = coin; 1144 } 1145 } while ((coin = next)); 1146} 1147 1148void SkOpCoincidence::releaseDeleted() { 1149 this->releaseDeleted(fHead); 1150 this->releaseDeleted(fTop); 1151} 1152 1153void SkOpCoincidence::restoreHead() { 1154 SkCoincidentSpans** headPtr = &fHead; 1155 while (*headPtr) { 1156 headPtr = (*headPtr)->nextPtr(); 1157 } 1158 *headPtr = fTop; 1159 fTop = nullptr; 1160 // segments may have collapsed in the meantime; remove empty referenced segments 1161 headPtr = &fHead; 1162 while (*headPtr) { 1163 SkCoincidentSpans* test = *headPtr; 1164 if (test->coinPtTStart()->segment()->done() || test->oppPtTStart()->segment()->done()) { 1165 *headPtr = test->next(); 1166 continue; 1167 } 1168 headPtr = (*headPtr)->nextPtr(); 1169 } 1170} 1171 1172// Please keep this in sync with debugExpand() 1173// expand the range by checking adjacent spans for coincidence 1174bool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { 1175 DEBUG_SET_PHASE(); 1176 SkCoincidentSpans* coin = fHead; 1177 if (!coin) { 1178 return false; 1179 } 1180 bool expanded = false; 1181 do { 1182 if (coin->expand()) { 1183 // check to see if multiple spans expanded so they are now identical 1184 SkCoincidentSpans* test = fHead; 1185 do { 1186 if (coin == test) { 1187 continue; 1188 } 1189 if (coin->coinPtTStart() == test->coinPtTStart() 1190 && coin->oppPtTStart() == test->oppPtTStart()) { 1191 this->release(fHead, test); 1192 break; 1193 } 1194 } while ((test = test->next())); 1195 expanded = true; 1196 } 1197 } while ((coin = coin->next())); 1198 return expanded; 1199} 1200 1201bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const { 1202 DEBUG_SET_PHASE(); 1203 overlaps->fHead = overlaps->fTop = nullptr; 1204 SkCoincidentSpans* outer = fHead; 1205 while (outer) { 1206 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment(); 1207 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment(); 1208 SkCoincidentSpans* inner = outer; 1209 while ((inner = inner->next())) { 1210 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment(); 1211 if (outerCoin == innerCoin) { 1212 continue; // both winners are the same segment, so there's no additional overlap 1213 } 1214 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment(); 1215 const SkOpPtT* overlapS; 1216 const SkOpPtT* overlapE; 1217 if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->oppPtTStart(), 1218 outer->oppPtTEnd(),inner->coinPtTStart(), inner->coinPtTEnd(), &overlapS, 1219 &overlapE)) 1220 || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->coinPtTStart(), 1221 outer->coinPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(), 1222 &overlapS, &overlapE)) 1223 || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTStart(), 1224 outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(), 1225 &overlapS, &overlapE))) { 1226 if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp, 1227 overlapS, overlapE)) { 1228 return false; 1229 } 1230 } 1231 } 1232 outer = outer->next(); 1233 } 1234 return true; 1235} 1236 1237void SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) { 1238 SkOPASSERT(deleted != kept); 1239 if (fHead) { 1240 this->fixUp(fHead, deleted, kept); 1241 } 1242 if (fTop) { 1243 this->fixUp(fTop, deleted, kept); 1244 } 1245} 1246 1247void SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept) { 1248 SkCoincidentSpans* head = coin; 1249 do { 1250 if (coin->coinPtTStart() == deleted) { 1251 if (coin->coinPtTEnd()->span() == kept->span()) { 1252 this->release(head, coin); 1253 continue; 1254 } 1255 coin->setCoinPtTStart(kept); 1256 } 1257 if (coin->coinPtTEnd() == deleted) { 1258 if (coin->coinPtTStart()->span() == kept->span()) { 1259 this->release(head, coin); 1260 continue; 1261 } 1262 coin->setCoinPtTEnd(kept); 1263 } 1264 if (coin->oppPtTStart() == deleted) { 1265 if (coin->oppPtTEnd()->span() == kept->span()) { 1266 this->release(head, coin); 1267 continue; 1268 } 1269 coin->setOppPtTStart(kept); 1270 } 1271 if (coin->oppPtTEnd() == deleted) { 1272 if (coin->oppPtTStart()->span() == kept->span()) { 1273 this->release(head, coin); 1274 continue; 1275 } 1276 coin->setOppPtTEnd(kept); 1277 } 1278 } while ((coin = coin->next())); 1279} 1280 1281// Please keep this in sync with debugMark() 1282/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */ 1283bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { 1284 DEBUG_SET_PHASE(); 1285 SkCoincidentSpans* coin = fHead; 1286 if (!coin) { 1287 return true; 1288 } 1289 do { 1290 SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span(); 1291 FAIL_IF(!startBase->upCastable()); 1292 SkOpSpan* start = startBase->upCast(); 1293 FAIL_IF(start->deleted()); 1294 SkOpSpanBase* end = coin->coinPtTEndWritable()->span(); 1295 SkOPASSERT(!end->deleted()); 1296 SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span(); 1297 SkOPASSERT(!oStart->deleted()); 1298 SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span(); 1299 SkASSERT(!oEnd->deleted()); 1300 bool flipped = coin->flipped(); 1301 if (flipped) { 1302 SkTSwap(oStart, oEnd); 1303 } 1304 /* coin and opp spans may not match up. Mark the ends, and then let the interior 1305 get marked as many times as the spans allow */ 1306 start->insertCoincidence(oStart->upCast()); 1307 end->insertCoinEnd(oEnd); 1308 const SkOpSegment* segment = start->segment(); 1309 const SkOpSegment* oSegment = oStart->segment(); 1310 SkOpSpanBase* next = start; 1311 SkOpSpanBase* oNext = oStart; 1312 bool ordered; 1313 FAIL_IF(!coin->ordered(&ordered)); 1314 while ((next = next->upCast()->next()) != end) { 1315 FAIL_IF(!next->upCastable()); 1316 SkAssertResult(next->upCast()->insertCoincidence(oSegment, flipped, ordered)); 1317 } 1318 while ((oNext = oNext->upCast()->next()) != oEnd) { 1319 FAIL_IF(!oNext->upCastable()); 1320 FAIL_IF(!oNext->upCast()->insertCoincidence(segment, flipped, ordered)); 1321 } 1322 } while ((coin = coin->next())); 1323 return true; 1324} 1325 1326// Please keep in sync with debugMarkCollapsed() 1327void SkOpCoincidence::markCollapsed(SkCoincidentSpans* coin, SkOpPtT* test) { 1328 SkCoincidentSpans* head = coin; 1329 while (coin) { 1330 if (coin->collapsed(test)) { 1331 if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) { 1332 coin->coinPtTStartWritable()->segment()->markAllDone(); 1333 } 1334 if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) { 1335 coin->oppPtTStartWritable()->segment()->markAllDone(); 1336 } 1337 this->release(head, coin); 1338 } 1339 coin = coin->next(); 1340 } 1341} 1342 1343// Please keep in sync with debugMarkCollapsed() 1344void SkOpCoincidence::markCollapsed(SkOpPtT* test) { 1345 markCollapsed(fHead, test); 1346 markCollapsed(fTop, test); 1347} 1348 1349bool SkOpCoincidence::Ordered(const SkOpSegment* coinSeg, const SkOpSegment* oppSeg) { 1350 if (coinSeg->verb() < oppSeg->verb()) { 1351 return true; 1352 } 1353 if (coinSeg->verb() > oppSeg->verb()) { 1354 return false; 1355 } 1356 int count = (SkPathOpsVerbToPoints(coinSeg->verb()) + 1) * 2; 1357 const SkScalar* cPt = &coinSeg->pts()[0].fX; 1358 const SkScalar* oPt = &oppSeg->pts()[0].fX; 1359 for (int index = 0; index < count; ++index) { 1360 if (*cPt < *oPt) { 1361 return true; 1362 } 1363 if (*cPt > *oPt) { 1364 return false; 1365 } 1366 ++cPt; 1367 ++oPt; 1368 } 1369 return true; 1370} 1371 1372bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e, 1373 const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const { 1374 SkASSERT(coin1s->segment() == coin2s->segment()); 1375 *overS = SkTMax(SkTMin(coin1s->fT, coin1e->fT), SkTMin(coin2s->fT, coin2e->fT)); 1376 *overE = SkTMin(SkTMax(coin1s->fT, coin1e->fT), SkTMax(coin2s->fT, coin2e->fT)); 1377 return *overS < *overE; 1378} 1379 1380// Commented-out lines keep this in sync with debugRelease() 1381void SkOpCoincidence::release(const SkOpSegment* deleted) { 1382 SkCoincidentSpans* coin = fHead; 1383 if (!coin) { 1384 return; 1385 } 1386 do { 1387 if (coin->coinPtTStart()->segment() == deleted 1388 || coin->coinPtTEnd()->segment() == deleted 1389 || coin->oppPtTStart()->segment() == deleted 1390 || coin->oppPtTEnd()->segment() == deleted) { 1391 this->release(fHead, coin); 1392 } 1393 } while ((coin = coin->next())); 1394} 1395