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 bool SkOpCoincidence::extend(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart, 12 SkOpPtT* oppPtTEnd) { 13 // if there is an existing pair that overlaps the addition, extend it 14 SkCoincidentSpans* coinRec = fHead; 15 if (coinRec) { 16 do { 17 if (coinRec->fCoinPtTStart->segment() != coinPtTStart->segment()) { 18 continue; 19 } 20 if (coinRec->fOppPtTStart->segment() != oppPtTStart->segment()) { 21 continue; 22 } 23 if (coinRec->fCoinPtTStart->fT > coinPtTEnd->fT) { 24 continue; 25 } 26 if (coinRec->fCoinPtTEnd->fT < coinPtTStart->fT) { 27 continue; 28 } 29 if (coinRec->fCoinPtTStart->fT > coinPtTStart->fT) { 30 coinRec->fCoinPtTStart = coinPtTStart; 31 coinRec->fOppPtTStart = oppPtTStart; 32 } 33 if (coinRec->fCoinPtTEnd->fT < coinPtTEnd->fT) { 34 coinRec->fCoinPtTEnd = coinPtTEnd; 35 coinRec->fOppPtTEnd = oppPtTEnd; 36 } 37 return true; 38 } while ((coinRec = coinRec->fNext)); 39 } 40 return false; 41 } 42 43 void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart, 44 SkOpPtT* oppPtTEnd, SkChunkAlloc* allocator) { 45 SkASSERT(coinPtTStart->fT < coinPtTEnd->fT); 46 bool flipped = oppPtTStart->fT > oppPtTEnd->fT; 47 SkCoincidentSpans* coinRec = SkOpTAllocator<SkCoincidentSpans>::Allocate(allocator); 48 coinRec->fNext = this->fHead; 49 coinRec->fCoinPtTStart = coinPtTStart; 50 coinRec->fCoinPtTEnd = coinPtTEnd; 51 coinRec->fOppPtTStart = oppPtTStart; 52 coinRec->fOppPtTEnd = oppPtTEnd; 53 coinRec->fFlipped = flipped; 54 SkDEBUGCODE(coinRec->fID = fDebugState->nextCoinID()); 55 56 this->fHead = coinRec; 57 } 58 59 static void t_range(const SkOpPtT* overS, const SkOpPtT* overE, double tStart, double tEnd, 60 const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, double* coinTs, double* coinTe) { 61 double denom = overE->fT - overS->fT; 62 double start = 0 < denom ? tStart : tEnd; 63 double end = 0 < denom ? tEnd : tStart; 64 double sRatio = (start - overS->fT) / denom; 65 double eRatio = (end - overS->fT) / denom; 66 *coinTs = coinPtTStart->fT + (coinPtTEnd->fT - coinPtTStart->fT) * sRatio; 67 *coinTe = coinPtTStart->fT + (coinPtTEnd->fT - coinPtTStart->fT) * eRatio; 68 } 69 70 bool SkOpCoincidence::addExpanded(SkChunkAlloc* allocator 71 PATH_OPS_DEBUG_VALIDATE_PARAMS(SkOpGlobalState* globalState)) { 72 #if DEBUG_VALIDATE 73 globalState->setPhase(SkOpGlobalState::kIntersecting); 74 #endif 75 // for each coincident pair, match the spans 76 // if the spans don't match, add the mssing pt to the segment and loop it in the opposite span 77 SkCoincidentSpans* coin = this->fHead; 78 SkASSERT(coin); 79 do { 80 SkOpPtT* startPtT = coin->fCoinPtTStart; 81 SkOpPtT* oStartPtT = coin->fOppPtTStart; 82 SkASSERT(startPtT->contains(oStartPtT)); 83 SkASSERT(coin->fCoinPtTEnd->contains(coin->fOppPtTEnd)); 84 SkOpSpanBase* start = startPtT->span(); 85 SkOpSpanBase* oStart = oStartPtT->span(); 86 const SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 87 const SkOpSpanBase* oEnd = coin->fOppPtTEnd->span(); 88 if (oEnd->deleted()) { 89 return false; 90 } 91 SkOpSpanBase* test = start->upCast()->next(); 92 SkOpSpanBase* oTest = coin->fFlipped ? oStart->prev() : oStart->upCast()->next(); 93 while (test != end || oTest != oEnd) { 94 if (!test->ptT()->contains(oTest->ptT())) { 95 // use t ranges to guess which one is missing 96 double startRange = coin->fCoinPtTEnd->fT - startPtT->fT; 97 if (!startRange) { 98 return false; 99 } 100 double startPart = (test->t() - startPtT->fT) / startRange; 101 double oStartRange = coin->fOppPtTEnd->fT - oStartPtT->fT; 102 if (!oStartRange) { 103 return false; 104 } 105 double oStartPart = (oTest->t() - oStartPtT->fT) / oStartRange; 106 if (startPart == oStartPart) { 107 return false; 108 } 109 SkOpPtT* newPt; 110 if (startPart < oStartPart) { 111 double newT = oStartPtT->fT + oStartRange * startPart; 112 newPt = oStart->segment()->addT(newT, SkOpSegment::kAllowAlias, allocator); 113 if (!newPt) { 114 return false; 115 } 116 newPt->fPt = test->pt(); 117 test->ptT()->addOpp(newPt); 118 } else { 119 double newT = startPtT->fT + startRange * oStartPart; 120 newPt = start->segment()->addT(newT, SkOpSegment::kAllowAlias, allocator); 121 if (!newPt) { 122 return false; 123 } 124 newPt->fPt = oTest->pt(); 125 oTest->ptT()->addOpp(newPt); 126 } 127 // start over 128 test = start; 129 oTest = oStart; 130 } 131 if (test != end) { 132 test = test->upCast()->next(); 133 } 134 if (oTest != oEnd) { 135 oTest = coin->fFlipped ? oTest->prev() : oTest->upCast()->next(); 136 } 137 } 138 } while ((coin = coin->fNext)); 139 #if DEBUG_VALIDATE 140 globalState->setPhase(SkOpGlobalState::kWalking); 141 #endif 142 return true; 143 } 144 145 bool SkOpCoincidence::addIfMissing(const SkCoincidentSpans* outer, SkOpPtT* over1s, 146 SkOpPtT* over1e, SkChunkAlloc* allocator) { 147 SkCoincidentSpans* check = this->fTop; 148 do { 149 if (check->fCoinPtTStart->span() == over1s->span() 150 && check->fOppPtTStart->span() == outer->fOppPtTStart->span()) { 151 SkASSERT(check->fCoinPtTEnd->span() == over1e->span() 152 || !fDebugState->debugRunFail()); 153 SkASSERT(check->fOppPtTEnd->span() == outer->fOppPtTEnd->span() 154 || !fDebugState->debugRunFail()); 155 return false; 156 } 157 if (check->fCoinPtTStart->span() == outer->fCoinPtTStart->span() 158 && check->fOppPtTStart->span() == over1s->span()) { 159 SkASSERT(check->fCoinPtTEnd->span() == outer->fCoinPtTEnd->span() 160 || !fDebugState->debugRunFail()); 161 SkASSERT(check->fOppPtTEnd->span() == over1e->span() 162 || !fDebugState->debugRunFail()); 163 return false; 164 } 165 } while ((check = check->fNext)); 166 this->add(outer->fCoinPtTStart, outer->fCoinPtTEnd, over1s, over1e, allocator); 167 #if 0 168 // FIXME: up to four flavors could be added -- do we need only one? 169 #endif 170 return true; 171 } 172 173 bool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over1e, 174 const SkOpPtT* over2s, const SkOpPtT* over2e, double tStart, double tEnd, 175 SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, 176 SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd, SkChunkAlloc* allocator) { 177 double coinTs, coinTe, oppTs, oppTe; 178 t_range(over1s, over1e, tStart, tEnd, coinPtTStart, coinPtTEnd, &coinTs, &coinTe); 179 t_range(over2s, over2e, tStart, tEnd, oppPtTStart, oppPtTEnd, &oppTs, &oppTe); 180 SkOpSegment* coinSeg = coinPtTStart->segment(); 181 SkOpSegment* oppSeg = oppPtTStart->segment(); 182 SkASSERT(coinSeg != oppSeg); 183 SkCoincidentSpans* check = this->fTop; 184 do { 185 const SkOpSegment* checkCoinSeg = check->fCoinPtTStart->segment(); 186 if (checkCoinSeg != coinSeg && checkCoinSeg != oppSeg) { 187 continue; 188 } 189 const SkOpSegment* checkOppSeg = check->fOppPtTStart->segment(); 190 if (checkOppSeg != coinSeg && checkOppSeg != oppSeg) { 191 continue; 192 } 193 int cTs = coinTs; 194 int cTe = coinTe; 195 int oTs = oppTs; 196 int oTe = oppTe; 197 if (checkCoinSeg != coinSeg) { 198 SkASSERT(checkOppSeg != oppSeg); 199 SkTSwap(cTs, oTs); 200 SkTSwap(cTe, oTe); 201 } 202 int tweenCount = (int) between(check->fCoinPtTStart->fT, cTs, check->fCoinPtTEnd->fT) 203 + (int) between(check->fCoinPtTStart->fT, cTe, check->fCoinPtTEnd->fT) 204 + (int) between(check->fOppPtTStart->fT, oTs, check->fOppPtTEnd->fT) 205 + (int) between(check->fOppPtTStart->fT, oTe, check->fOppPtTEnd->fT); 206 // SkASSERT(tweenCount == 0 || tweenCount == 4); 207 if (tweenCount) { 208 return false; 209 } 210 } while ((check = check->fNext)); 211 if ((over1s->fT < over1e->fT) != (over2s->fT < over2e->fT)) { 212 SkTSwap(oppTs, oppTe); 213 } 214 if (coinTs > coinTe) { 215 SkTSwap(coinTs, coinTe); 216 SkTSwap(oppTs, oppTe); 217 } 218 SkOpPtT* cs = coinSeg->addMissing(coinTs, oppSeg, allocator); 219 SkOpPtT* ce = coinSeg->addMissing(coinTe, oppSeg, allocator); 220 SkASSERT(cs != ce); 221 SkOpPtT* os = oppSeg->addMissing(oppTs, coinSeg, allocator); 222 SkOpPtT* oe = oppSeg->addMissing(oppTe, coinSeg, allocator); 223 // SkASSERT(os != oe); 224 cs->addOpp(os); 225 ce->addOpp(oe); 226 this->add(cs, ce, os, oe, allocator); 227 return true; 228 } 229 230 /* detects overlaps of different coincident runs on same segment */ 231 /* does not detect overlaps for pairs without any segments in common */ 232 bool SkOpCoincidence::addMissing(SkChunkAlloc* allocator) { 233 SkCoincidentSpans* outer = fHead; 234 if (!outer) { 235 return true; 236 } 237 bool added = false; 238 fTop = outer; 239 fHead = nullptr; 240 do { 241 // addifmissing can modify the list that this is walking 242 // save head so that walker can iterate over old data unperturbed 243 // addifmissing adds to head freely then add saved head in the end 244 const SkOpSegment* outerCoin = outer->fCoinPtTStart->segment(); 245 SkASSERT(outerCoin == outer->fCoinPtTEnd->segment()); 246 const SkOpSegment* outerOpp = outer->fOppPtTStart->segment(); 247 SkASSERT(outerOpp == outer->fOppPtTEnd->segment()); 248 SkCoincidentSpans* inner = outer; 249 while ((inner = inner->fNext)) { 250 double overS, overE; 251 const SkOpSegment* innerCoin = inner->fCoinPtTStart->segment(); 252 SkASSERT(innerCoin == inner->fCoinPtTEnd->segment()); 253 const SkOpSegment* innerOpp = inner->fOppPtTStart->segment(); 254 SkASSERT(innerOpp == inner->fOppPtTEnd->segment()); 255 if (outerCoin == innerCoin 256 && this->overlap(outer->fCoinPtTStart, outer->fCoinPtTEnd, 257 inner->fCoinPtTStart, inner->fCoinPtTEnd, &overS, &overE)) { 258 added |= this->addIfMissing(outer->fCoinPtTStart, outer->fCoinPtTEnd, 259 inner->fCoinPtTStart, inner->fCoinPtTEnd, overS, overE, 260 outer->fOppPtTStart, outer->fOppPtTEnd, 261 inner->fOppPtTStart, inner->fOppPtTEnd, allocator); 262 } else if (outerCoin == innerOpp 263 && this->overlap(outer->fCoinPtTStart, outer->fCoinPtTEnd, 264 inner->fOppPtTStart, inner->fOppPtTEnd, &overS, &overE)) { 265 added |= this->addIfMissing(outer->fCoinPtTStart, outer->fCoinPtTEnd, 266 inner->fOppPtTStart, inner->fOppPtTEnd, overS, overE, 267 outer->fOppPtTStart, outer->fOppPtTEnd, 268 inner->fCoinPtTStart, inner->fCoinPtTEnd, allocator); 269 } else if (outerOpp == innerCoin 270 && this->overlap(outer->fOppPtTStart, outer->fOppPtTEnd, 271 inner->fCoinPtTStart, inner->fCoinPtTEnd, &overS, &overE)) { 272 added |= this->addIfMissing(outer->fOppPtTStart, outer->fOppPtTEnd, 273 inner->fCoinPtTStart, inner->fCoinPtTEnd, overS, overE, 274 outer->fCoinPtTStart, outer->fCoinPtTEnd, 275 inner->fOppPtTStart, inner->fOppPtTEnd, allocator); 276 } else if (outerOpp == innerOpp 277 && this->overlap(outer->fOppPtTStart, outer->fOppPtTEnd, 278 inner->fOppPtTStart, inner->fOppPtTEnd, &overS, &overE)) { 279 added |= this->addIfMissing(outer->fOppPtTStart, outer->fOppPtTEnd, 280 inner->fOppPtTStart, inner->fOppPtTEnd, overS, overE, 281 outer->fCoinPtTStart, outer->fCoinPtTEnd, 282 inner->fCoinPtTStart, inner->fCoinPtTEnd, allocator); 283 } else if (outerCoin != innerCoin) { 284 // check to see if outer span overlaps the inner span 285 // look for inner segment in pt-t list 286 // if present, and if t values are in coincident range 287 // add two pairs of new coincidence 288 SkOpPtT* testS = outer->fCoinPtTStart->contains(innerCoin); 289 SkOpPtT* testE = outer->fCoinPtTEnd->contains(innerCoin); 290 if (testS && testS->fT >= inner->fCoinPtTStart->fT 291 && testE && testE->fT <= inner->fCoinPtTEnd->fT 292 && this->testForCoincidence(outer, testS, testE)) { 293 added |= this->addIfMissing(outer, testS, testE, allocator); 294 } else { 295 testS = inner->fCoinPtTStart->contains(outerCoin); 296 testE = inner->fCoinPtTEnd->contains(outerCoin); 297 if (testS && testS->fT >= outer->fCoinPtTStart->fT 298 && testE && testE->fT <= outer->fCoinPtTEnd->fT 299 && this->testForCoincidence(inner, testS, testE)) { 300 added |= this->addIfMissing(inner, testS, testE, allocator); 301 } 302 } 303 } 304 #if 0 && DEBUG_COINCIDENCE 305 SkString miss; 306 miss.printf("addMissing inner=%d outer=%d", inner->debugID(), outer->debugID()); 307 DEBUG_COINCIDENCE_HEALTH(fDebugState->contourHead(), miss.c_str()); 308 #endif 309 } 310 } while ((outer = outer->fNext)); 311 SkCoincidentSpans** headPtr = &fHead; 312 while (*headPtr) { 313 SkCoincidentSpans** headNext = &(*headPtr)->fNext; 314 if (*headNext) { 315 break; 316 } 317 headPtr = headNext; 318 } 319 *headPtr = fTop; 320 return added; 321 } 322 323 void SkOpCoincidence::addOverlap(SkOpSegment* seg1, SkOpSegment* seg1o, SkOpSegment* seg2, 324 SkOpSegment* seg2o, SkOpPtT* overS, SkOpPtT* overE, SkChunkAlloc* allocator) { 325 SkOpPtT* s1 = overS->find(seg1); 326 SkOpPtT* e1 = overE->find(seg1); 327 if (!s1->starter(e1)->span()->upCast()->windValue()) { 328 s1 = overS->find(seg1o); 329 e1 = overE->find(seg1o); 330 if (!s1->starter(e1)->span()->upCast()->windValue()) { 331 return; 332 } 333 } 334 SkOpPtT* s2 = overS->find(seg2); 335 SkOpPtT* e2 = overE->find(seg2); 336 if (!s2->starter(e2)->span()->upCast()->windValue()) { 337 s2 = overS->find(seg2o); 338 e2 = overE->find(seg2o); 339 if (!s2->starter(e2)->span()->upCast()->windValue()) { 340 return; 341 } 342 } 343 if (s1->segment() == s2->segment()) { 344 return; 345 } 346 if (s1->fT > e1->fT) { 347 SkTSwap(s1, e1); 348 SkTSwap(s2, e2); 349 } 350 this->add(s1, e1, s2, e2, allocator); 351 } 352 353 bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, 354 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd, bool flipped) const { 355 const SkCoincidentSpans* coin = fHead; 356 if (!coin) { 357 return false; 358 } 359 do { 360 if (coin->fCoinPtTStart == coinPtTStart && coin->fCoinPtTEnd == coinPtTEnd 361 && coin->fOppPtTStart == oppPtTStart && coin->fOppPtTEnd == oppPtTEnd 362 && coin->fFlipped == flipped) { 363 return true; 364 } 365 } while ((coin = coin->fNext)); 366 return false; 367 } 368 369 // walk span sets in parallel, moving winding from one to the other 370 bool SkOpCoincidence::apply() { 371 SkCoincidentSpans* coin = fHead; 372 if (!coin) { 373 return true; 374 } 375 do { 376 SkOpSpan* start = coin->fCoinPtTStart->span()->upCast(); 377 if (start->deleted()) { 378 continue; 379 } 380 SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 381 SkASSERT(start == start->starter(end)); 382 bool flipped = coin->fFlipped; 383 SkOpSpan* oStart = (flipped ? coin->fOppPtTEnd : coin->fOppPtTStart)->span()->upCast(); 384 if (oStart->deleted()) { 385 continue; 386 } 387 SkOpSpanBase* oEnd = (flipped ? coin->fOppPtTStart : coin->fOppPtTEnd)->span(); 388 SkASSERT(oStart == oStart->starter(oEnd)); 389 SkOpSegment* segment = start->segment(); 390 SkOpSegment* oSegment = oStart->segment(); 391 bool operandSwap = segment->operand() != oSegment->operand(); 392 if (flipped) { 393 if (oEnd->deleted()) { 394 continue; 395 } 396 do { 397 SkOpSpanBase* oNext = oStart->next(); 398 if (oNext == oEnd) { 399 break; 400 } 401 oStart = oNext->upCast(); 402 } while (true); 403 } 404 do { 405 int windValue = start->windValue(); 406 int oppValue = start->oppValue(); 407 int oWindValue = oStart->windValue(); 408 int oOppValue = oStart->oppValue(); 409 // winding values are added or subtracted depending on direction and wind type 410 // same or opposite values are summed depending on the operand value 411 int windDiff = operandSwap ? oOppValue : oWindValue; 412 int oWindDiff = operandSwap ? oppValue : windValue; 413 if (!flipped) { 414 windDiff = -windDiff; 415 oWindDiff = -oWindDiff; 416 } 417 if (windValue && (windValue > windDiff || (windValue == windDiff 418 && oWindValue <= oWindDiff))) { 419 if (operandSwap) { 420 SkTSwap(oWindValue, oOppValue); 421 } 422 if (flipped) { 423 windValue -= oWindValue; 424 oppValue -= oOppValue; 425 } else { 426 windValue += oWindValue; 427 oppValue += oOppValue; 428 } 429 if (segment->isXor()) { 430 windValue &= 1; 431 } 432 if (segment->oppXor()) { 433 oppValue &= 1; 434 } 435 oWindValue = oOppValue = 0; 436 } else { 437 if (operandSwap) { 438 SkTSwap(windValue, oppValue); 439 } 440 if (flipped) { 441 oWindValue -= windValue; 442 oOppValue -= oppValue; 443 } else { 444 oWindValue += windValue; 445 oOppValue += oppValue; 446 } 447 if (oSegment->isXor()) { 448 oWindValue &= 1; 449 } 450 if (oSegment->oppXor()) { 451 oOppValue &= 1; 452 } 453 windValue = oppValue = 0; 454 } 455 start->setWindValue(windValue); 456 start->setOppValue(oppValue); 457 oStart->setWindValue(oWindValue); 458 oStart->setOppValue(oOppValue); 459 if (!windValue && !oppValue) { 460 segment->markDone(start); 461 } 462 if (!oWindValue && !oOppValue) { 463 oSegment->markDone(oStart); 464 } 465 SkOpSpanBase* next = start->next(); 466 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next(); 467 if (next == end) { 468 break; 469 } 470 if (!next->upCastable()) { 471 return false; 472 } 473 start = next->upCast(); 474 // if the opposite ran out too soon, just reuse the last span 475 if (!oNext || !oNext->upCastable()) { 476 oNext = oStart; 477 } 478 oStart = oNext->upCast(); 479 } while (true); 480 } while ((coin = coin->fNext)); 481 return true; 482 } 483 484 void SkOpCoincidence::detach(SkCoincidentSpans* remove) { 485 SkCoincidentSpans* coin = fHead; 486 SkCoincidentSpans* prev = nullptr; 487 SkCoincidentSpans* next; 488 do { 489 next = coin->fNext; 490 if (coin == remove) { 491 if (prev) { 492 prev->fNext = next; 493 } else { 494 fHead = next; 495 } 496 break; 497 } 498 prev = coin; 499 } while ((coin = next)); 500 SkASSERT(coin); 501 } 502 503 bool SkOpCoincidence::expand() { 504 SkCoincidentSpans* coin = fHead; 505 if (!coin) { 506 return false; 507 } 508 bool expanded = false; 509 do { 510 SkOpSpan* start = coin->fCoinPtTStart->span()->upCast(); 511 SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 512 SkOpSegment* segment = coin->fCoinPtTStart->segment(); 513 SkOpSegment* oppSegment = coin->fOppPtTStart->segment(); 514 SkOpSpan* prev = start->prev(); 515 SkOpPtT* oppPtT; 516 if (prev && (oppPtT = prev->contains(oppSegment))) { 517 double midT = (prev->t() + start->t()) / 2; 518 if (segment->isClose(midT, oppSegment)) { 519 coin->fCoinPtTStart = prev->ptT(); 520 coin->fOppPtTStart = oppPtT; 521 expanded = true; 522 } 523 } 524 SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next(); 525 if (next && (oppPtT = next->contains(oppSegment))) { 526 double midT = (end->t() + next->t()) / 2; 527 if (segment->isClose(midT, oppSegment)) { 528 coin->fCoinPtTEnd = next->ptT(); 529 coin->fOppPtTEnd = oppPtT; 530 expanded = true; 531 } 532 } 533 } while ((coin = coin->fNext)); 534 return expanded; 535 } 536 537 void SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps, SkChunkAlloc* allocator) const { 538 overlaps->fHead = overlaps->fTop = nullptr; 539 SkDEBUGCODE_(overlaps->debugSetGlobalState(fDebugState)); 540 SkCoincidentSpans* outer = fHead; 541 while (outer) { 542 SkOpSegment* outerCoin = outer->fCoinPtTStart->segment(); 543 SkOpSegment* outerOpp = outer->fOppPtTStart->segment(); 544 SkCoincidentSpans* inner = outer; 545 while ((inner = inner->fNext)) { 546 SkOpSegment* innerCoin = inner->fCoinPtTStart->segment(); 547 if (outerCoin == innerCoin) { 548 continue; // both winners are the same segment, so there's no additional overlap 549 } 550 SkOpSegment* innerOpp = inner->fOppPtTStart->segment(); 551 SkOpPtT* overlapS, * overlapE; 552 if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->fOppPtTStart, outer->fOppPtTEnd, 553 inner->fCoinPtTStart, inner->fCoinPtTEnd, &overlapS, &overlapE)) 554 || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->fCoinPtTStart, 555 outer->fCoinPtTEnd, inner->fOppPtTStart, inner->fOppPtTEnd, 556 &overlapS, &overlapE)) 557 || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->fOppPtTStart, 558 outer->fOppPtTEnd, inner->fOppPtTStart, inner->fOppPtTEnd, 559 &overlapS, &overlapE))) { 560 overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp, 561 overlapS, overlapE, allocator); 562 } 563 } 564 outer = outer->fNext; 565 } 566 } 567 568 void SkOpCoincidence::fixAligned() { 569 SkCoincidentSpans* coin = fHead; 570 if (!coin) { 571 return; 572 } 573 do { 574 if (coin->fCoinPtTStart->deleted()) { 575 coin->fCoinPtTStart = coin->fCoinPtTStart->doppelganger(); 576 } 577 if (coin->fCoinPtTEnd->deleted()) { 578 coin->fCoinPtTEnd = coin->fCoinPtTEnd->doppelganger(); 579 } 580 if (coin->fOppPtTStart->deleted()) { 581 coin->fOppPtTStart = coin->fOppPtTStart->doppelganger(); 582 } 583 if (coin->fOppPtTEnd->deleted()) { 584 coin->fOppPtTEnd = coin->fOppPtTEnd->doppelganger(); 585 } 586 } while ((coin = coin->fNext)); 587 coin = fHead; 588 SkCoincidentSpans** priorPtr = &fHead; 589 do { 590 if (coin->fCoinPtTStart->collapsed(coin->fCoinPtTEnd) 591 || coin->fOppPtTStart->collapsed(coin->fOppPtTEnd)) { 592 *priorPtr = coin->fNext; 593 continue; 594 } 595 priorPtr = &coin->fNext; 596 } while ((coin = coin->fNext)); 597 } 598 599 void SkOpCoincidence::fixUp(SkOpPtT* deleted, SkOpPtT* kept) { 600 SkCoincidentSpans* coin = fHead; 601 if (!coin) { 602 return; 603 } 604 do { 605 if (coin->fCoinPtTStart == deleted) { 606 if (coin->fCoinPtTEnd->span() == kept->span()) { 607 this->detach(coin); 608 continue; 609 } 610 coin->fCoinPtTStart = kept; 611 } 612 if (coin->fCoinPtTEnd == deleted) { 613 if (coin->fCoinPtTStart->span() == kept->span()) { 614 this->detach(coin); 615 continue; 616 } 617 coin->fCoinPtTEnd = kept; 618 } 619 if (coin->fOppPtTStart == deleted) { 620 if (coin->fOppPtTEnd->span() == kept->span()) { 621 this->detach(coin); 622 continue; 623 } 624 coin->fOppPtTStart = kept; 625 } 626 if (coin->fOppPtTEnd == deleted) { 627 if (coin->fOppPtTStart->span() == kept->span()) { 628 this->detach(coin); 629 continue; 630 } 631 coin->fOppPtTEnd = kept; 632 } 633 } while ((coin = coin->fNext)); 634 } 635 636 /* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */ 637 bool SkOpCoincidence::mark() { 638 SkCoincidentSpans* coin = fHead; 639 if (!coin) { 640 return true; 641 } 642 do { 643 SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 644 if (end->deleted()) { 645 return false; 646 } 647 SkOpSpanBase* oldEnd = end; 648 SkOpSpan* start = coin->fCoinPtTStart->span()->starter(&end); 649 SkOpSpanBase* oEnd = coin->fOppPtTEnd->span(); 650 if (oEnd->deleted()) { 651 return false; 652 } 653 SkOpSpanBase* oOldEnd = oEnd; 654 SkOpSpanBase* oStart = coin->fOppPtTStart->span()->starter(&oEnd); 655 bool flipped = (end == oldEnd) != (oEnd == oOldEnd); 656 if (flipped) { 657 SkTSwap(oStart, oEnd); 658 } 659 SkOpSpanBase* next = start; 660 SkOpSpanBase* oNext = oStart; 661 do { 662 next = next->upCast()->next(); 663 oNext = flipped ? oNext->prev() : oNext->upCast()->next(); 664 if (next == end || oNext == oEnd) { 665 break; 666 } 667 if (!next->containsCoinEnd(oNext)) { 668 next->insertCoinEnd(oNext); 669 } 670 SkOpSpan* nextSpan = next->upCast(); 671 SkOpSpan* oNextSpan = oNext->upCast(); 672 if (!nextSpan->containsCoincidence(oNextSpan)) { 673 nextSpan->insertCoincidence(oNextSpan); 674 } 675 } while (true); 676 } while ((coin = coin->fNext)); 677 return true; 678 } 679 680 bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e, 681 const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const { 682 SkASSERT(coin1s->segment() == coin2s->segment()); 683 *overS = SkTMax(SkTMin(coin1s->fT, coin1e->fT), SkTMin(coin2s->fT, coin2e->fT)); 684 *overE = SkTMin(SkTMax(coin1s->fT, coin1e->fT), SkTMax(coin2s->fT, coin2e->fT)); 685 return *overS < *overE; 686 } 687 688 bool SkOpCoincidence::testForCoincidence(const SkCoincidentSpans* outer, const SkOpPtT* testS, 689 const SkOpPtT* testE) const { 690 return testS->segment()->testForCoincidence(testS, testE, testS->span(), 691 testE->span(), outer->fCoinPtTStart->segment(), 120000); // FIXME: replace with tuned 692 } 693