1 /* 2 * Copyright 2012 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 "SkOpContour.h" 9 #include "SkOpSegment.h" 10 #include "SkPathWriter.h" 11 12 /* 13 After computing raw intersections, post process all segments to: 14 - find small collections of points that can be collapsed to a single point 15 - find missing intersections to resolve differences caused by different algorithms 16 17 Consider segments containing tiny or small intervals. Consider coincident segments 18 because coincidence finds intersections through distance measurement that non-coincident 19 intersection tests cannot. 20 */ 21 22 #define F (false) // discard the edge 23 #define T (true) // keep the edge 24 25 static const bool gUnaryActiveEdge[2][2] = { 26 // from=0 from=1 27 // to=0,1 to=0,1 28 {F, T}, {T, F}, 29 }; 30 31 static const bool gActiveEdge[kXOR_SkPathOp + 1][2][2][2][2] = { 32 // miFrom=0 miFrom=1 33 // miTo=0 miTo=1 miTo=0 miTo=1 34 // suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1 35 // suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 36 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su 37 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su 38 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su 39 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su 40 }; 41 42 #undef F 43 #undef T 44 45 SkOpAngle* SkOpSegment::activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr, 46 SkOpSpanBase** endPtr, bool* done) { 47 if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done)) { 48 return result; 49 } 50 if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done)) { 51 return result; 52 } 53 return nullptr; 54 } 55 56 SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** startPtr, 57 SkOpSpanBase** endPtr, bool* done) { 58 SkOpSpan* upSpan = start->upCastable(); 59 if (upSpan) { 60 if (upSpan->windValue() || upSpan->oppValue()) { 61 SkOpSpanBase* next = upSpan->next(); 62 if (!*endPtr) { 63 *startPtr = start; 64 *endPtr = next; 65 } 66 if (!upSpan->done()) { 67 if (upSpan->windSum() != SK_MinS32) { 68 return spanToAngle(start, next); 69 } 70 *done = false; 71 } 72 } else { 73 SkASSERT(upSpan->done()); 74 } 75 } 76 SkOpSpan* downSpan = start->prev(); 77 // edge leading into junction 78 if (downSpan) { 79 if (downSpan->windValue() || downSpan->oppValue()) { 80 if (!*endPtr) { 81 *startPtr = start; 82 *endPtr = downSpan; 83 } 84 if (!downSpan->done()) { 85 if (downSpan->windSum() != SK_MinS32) { 86 return spanToAngle(start, downSpan); 87 } 88 *done = false; 89 } 90 } else { 91 SkASSERT(downSpan->done()); 92 } 93 } 94 return nullptr; 95 } 96 97 SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** startPtr, 98 SkOpSpanBase** endPtr, bool* done) { 99 SkOpPtT* oPtT = start->ptT()->next(); 100 SkOpSegment* other = oPtT->segment(); 101 SkOpSpanBase* oSpan = oPtT->span(); 102 return other->activeAngleInner(oSpan, startPtr, endPtr, done); 103 } 104 105 bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xorSuMask, 106 SkPathOp op) { 107 int sumMiWinding = this->updateWinding(end, start); 108 int sumSuWinding = this->updateOppWinding(end, start); 109 #if DEBUG_LIMIT_WIND_SUM 110 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM); 111 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM); 112 #endif 113 if (this->operand()) { 114 SkTSwap<int>(sumMiWinding, sumSuWinding); 115 } 116 return this->activeOp(xorMiMask, xorSuMask, start, end, op, &sumMiWinding, &sumSuWinding); 117 } 118 119 bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end, 120 SkPathOp op, int* sumMiWinding, int* sumSuWinding) { 121 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; 122 this->setUpWindings(start, end, sumMiWinding, sumSuWinding, 123 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); 124 bool miFrom; 125 bool miTo; 126 bool suFrom; 127 bool suTo; 128 if (operand()) { 129 miFrom = (oppMaxWinding & xorMiMask) != 0; 130 miTo = (oppSumWinding & xorMiMask) != 0; 131 suFrom = (maxWinding & xorSuMask) != 0; 132 suTo = (sumWinding & xorSuMask) != 0; 133 } else { 134 miFrom = (maxWinding & xorMiMask) != 0; 135 miTo = (sumWinding & xorMiMask) != 0; 136 suFrom = (oppMaxWinding & xorSuMask) != 0; 137 suTo = (oppSumWinding & xorSuMask) != 0; 138 } 139 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo]; 140 #if DEBUG_ACTIVE_OP 141 SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", 142 __FUNCTION__, debugID(), start->t(), end->t(), 143 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result); 144 #endif 145 return result; 146 } 147 148 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end) { 149 int sumWinding = updateWinding(end, start); 150 return activeWinding(start, end, &sumWinding); 151 } 152 153 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding) { 154 int maxWinding; 155 setUpWinding(start, end, &maxWinding, sumWinding); 156 bool from = maxWinding != 0; 157 bool to = *sumWinding != 0; 158 bool result = gUnaryActiveEdge[from][to]; 159 return result; 160 } 161 162 bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end, 163 SkPathWriter* path) const { 164 FAIL_IF(start->starter(end)->alreadyAdded()); 165 SkDCurveSweep curvePart; 166 start->segment()->subDivide(start, end, &curvePart.fCurve); 167 curvePart.setCurveHullSweep(fVerb); 168 SkPath::Verb verb = curvePart.isCurve() ? fVerb : SkPath::kLine_Verb; 169 path->deferredMove(start->ptT()); 170 switch (verb) { 171 case SkPath::kLine_Verb: 172 FAIL_IF(!path->deferredLine(end->ptT())); 173 break; 174 case SkPath::kQuad_Verb: 175 path->quadTo(curvePart.fCurve.fQuad[1].asSkPoint(), end->ptT()); 176 break; 177 case SkPath::kConic_Verb: 178 path->conicTo(curvePart.fCurve.fConic[1].asSkPoint(), end->ptT(), 179 curvePart.fCurve.fConic.fWeight); 180 break; 181 case SkPath::kCubic_Verb: 182 path->cubicTo(curvePart.fCurve.fCubic[1].asSkPoint(), 183 curvePart.fCurve.fCubic[2].asSkPoint(), end->ptT()); 184 break; 185 default: 186 SkASSERT(0); 187 } 188 return true; 189 } 190 191 const SkOpPtT* SkOpSegment::existing(double t, const SkOpSegment* opp) const { 192 const SkOpSpanBase* test = &fHead; 193 const SkOpPtT* testPtT; 194 SkPoint pt = this->ptAtT(t); 195 do { 196 testPtT = test->ptT(); 197 if (testPtT->fT == t) { 198 break; 199 } 200 if (!this->match(testPtT, this, t, pt)) { 201 if (t < testPtT->fT) { 202 return nullptr; 203 } 204 continue; 205 } 206 if (!opp) { 207 return testPtT; 208 } 209 const SkOpPtT* loop = testPtT->next(); 210 while (loop != testPtT) { 211 if (loop->segment() == this && loop->fT == t && loop->fPt == pt) { 212 goto foundMatch; 213 } 214 loop = loop->next(); 215 } 216 return nullptr; 217 } while ((test = test->upCast()->next())); 218 foundMatch: 219 return opp && !test->contains(opp) ? nullptr : testPtT; 220 } 221 222 // break the span so that the coincident part does not change the angle of the remainder 223 bool SkOpSegment::addExpanded(double newT, const SkOpSpanBase* test, bool* startOver) { 224 if (this->contains(newT)) { 225 return true; 226 } 227 this->globalState()->resetAllocatedOpSpan(); 228 FAIL_IF(!between(0, newT, 1)); 229 SkOpPtT* newPtT = this->addT(newT); 230 *startOver |= this->globalState()->allocatedOpSpan(); 231 if (!newPtT) { 232 return false; 233 } 234 newPtT->fPt = this->ptAtT(newT); 235 SkOpPtT* oppPrev = test->ptT()->oppPrev(newPtT); 236 if (oppPrev) { 237 // const cast away to change linked list; pt/t values stays unchanged 238 SkOpSpanBase* writableTest = const_cast<SkOpSpanBase*>(test); 239 writableTest->mergeMatches(newPtT->span()); 240 writableTest->ptT()->addOpp(newPtT, oppPrev); 241 writableTest->checkForCollapsedCoincidence(); 242 } 243 return true; 244 } 245 246 // Please keep this in sync with debugAddT() 247 SkOpPtT* SkOpSegment::addT(double t, const SkPoint& pt) { 248 debugValidate(); 249 SkOpSpanBase* spanBase = &fHead; 250 do { 251 SkOpPtT* result = spanBase->ptT(); 252 if (t == result->fT || (!zero_or_one(t) && this->match(result, this, t, pt))) { 253 spanBase->bumpSpanAdds(); 254 return result; 255 } 256 if (t < result->fT) { 257 SkOpSpan* prev = result->span()->prev(); 258 FAIL_WITH_NULL_IF(!prev); 259 // marks in global state that new op span has been allocated 260 SkOpSpan* span = this->insert(prev); 261 span->init(this, prev, t, pt); 262 this->debugValidate(); 263 #if DEBUG_ADD_T 264 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, 265 span->segment()->debugID(), span->debugID()); 266 #endif 267 span->bumpSpanAdds(); 268 return span->ptT(); 269 } 270 FAIL_WITH_NULL_IF(spanBase == &fTail); 271 } while ((spanBase = spanBase->upCast()->next())); 272 SkASSERT(0); 273 return nullptr; // we never get here, but need this to satisfy compiler 274 } 275 276 SkOpPtT* SkOpSegment::addT(double t) { 277 return addT(t, this->ptAtT(t)); 278 } 279 280 void SkOpSegment::calcAngles() { 281 bool activePrior = !fHead.isCanceled(); 282 if (activePrior && !fHead.simple()) { 283 addStartSpan(); 284 } 285 SkOpSpan* prior = &fHead; 286 SkOpSpanBase* spanBase = fHead.next(); 287 while (spanBase != &fTail) { 288 if (activePrior) { 289 SkOpAngle* priorAngle = this->globalState()->allocator()->make<SkOpAngle>(); 290 priorAngle->set(spanBase, prior); 291 spanBase->setFromAngle(priorAngle); 292 } 293 SkOpSpan* span = spanBase->upCast(); 294 bool active = !span->isCanceled(); 295 SkOpSpanBase* next = span->next(); 296 if (active) { 297 SkOpAngle* angle = this->globalState()->allocator()->make<SkOpAngle>(); 298 angle->set(span, next); 299 span->setToAngle(angle); 300 } 301 activePrior = active; 302 prior = span; 303 spanBase = next; 304 } 305 if (activePrior && !fTail.simple()) { 306 addEndSpan(); 307 } 308 } 309 310 // Please keep this in sync with debugClearAll() 311 void SkOpSegment::clearAll() { 312 SkOpSpan* span = &fHead; 313 do { 314 this->clearOne(span); 315 } while ((span = span->next()->upCastable())); 316 this->globalState()->coincidence()->release(this); 317 } 318 319 // Please keep this in sync with debugClearOne() 320 void SkOpSegment::clearOne(SkOpSpan* span) { 321 span->setWindValue(0); 322 span->setOppValue(0); 323 this->markDone(span); 324 } 325 326 bool SkOpSegment::collapsed(double s, double e) const { 327 const SkOpSpanBase* span = &fHead; 328 do { 329 if (span->collapsed(s, e)) { 330 return true; 331 } 332 } while (span->upCastable() && (span = span->upCast()->next())); 333 return false; 334 } 335 336 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, 337 SkOpAngle::IncludeType includeType) { 338 SkOpSegment* baseSegment = baseAngle->segment(); 339 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); 340 int sumSuWinding; 341 bool binary = includeType >= SkOpAngle::kBinarySingle; 342 if (binary) { 343 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); 344 if (baseSegment->operand()) { 345 SkTSwap<int>(sumMiWinding, sumSuWinding); 346 } 347 } 348 SkOpSegment* nextSegment = nextAngle->segment(); 349 int maxWinding, sumWinding; 350 SkOpSpanBase* last; 351 if (binary) { 352 int oppMaxWinding, oppSumWinding; 353 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding, 354 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); 355 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding, 356 nextAngle); 357 } else { 358 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding, 359 &maxWinding, &sumWinding); 360 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); 361 } 362 nextAngle->setLastMarked(last); 363 } 364 365 void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle, 366 SkOpAngle::IncludeType includeType) { 367 SkOpSegment* baseSegment = baseAngle->segment(); 368 int sumMiWinding = baseSegment->updateWinding(baseAngle); 369 int sumSuWinding; 370 bool binary = includeType >= SkOpAngle::kBinarySingle; 371 if (binary) { 372 sumSuWinding = baseSegment->updateOppWinding(baseAngle); 373 if (baseSegment->operand()) { 374 SkTSwap<int>(sumMiWinding, sumSuWinding); 375 } 376 } 377 SkOpSegment* nextSegment = nextAngle->segment(); 378 int maxWinding, sumWinding; 379 SkOpSpanBase* last; 380 if (binary) { 381 int oppMaxWinding, oppSumWinding; 382 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding, 383 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); 384 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding, 385 nextAngle); 386 } else { 387 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding, 388 &maxWinding, &sumWinding); 389 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); 390 } 391 nextAngle->setLastMarked(last); 392 } 393 394 // at this point, the span is already ordered, or unorderable 395 int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end, 396 SkOpAngle::IncludeType includeType) { 397 SkASSERT(includeType != SkOpAngle::kUnaryXor); 398 SkOpAngle* firstAngle = this->spanToAngle(end, start); 399 if (nullptr == firstAngle || nullptr == firstAngle->next()) { 400 return SK_NaN32; 401 } 402 // if all angles have a computed winding, 403 // or if no adjacent angles are orderable, 404 // or if adjacent orderable angles have no computed winding, 405 // there's nothing to do 406 // if two orderable angles are adjacent, and both are next to orderable angles, 407 // and one has winding computed, transfer to the other 408 SkOpAngle* baseAngle = nullptr; 409 bool tryReverse = false; 410 // look for counterclockwise transfers 411 SkOpAngle* angle = firstAngle->previous(); 412 SkOpAngle* next = angle->next(); 413 firstAngle = next; 414 do { 415 SkOpAngle* prior = angle; 416 angle = next; 417 next = angle->next(); 418 SkASSERT(prior->next() == angle); 419 SkASSERT(angle->next() == next); 420 if (prior->unorderable() || angle->unorderable() || next->unorderable()) { 421 baseAngle = nullptr; 422 continue; 423 } 424 int testWinding = angle->starter()->windSum(); 425 if (SK_MinS32 != testWinding) { 426 baseAngle = angle; 427 tryReverse = true; 428 continue; 429 } 430 if (baseAngle) { 431 ComputeOneSum(baseAngle, angle, includeType); 432 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr; 433 } 434 } while (next != firstAngle); 435 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) { 436 firstAngle = baseAngle; 437 tryReverse = true; 438 } 439 if (tryReverse) { 440 baseAngle = nullptr; 441 SkOpAngle* prior = firstAngle; 442 do { 443 angle = prior; 444 prior = angle->previous(); 445 SkASSERT(prior->next() == angle); 446 next = angle->next(); 447 if (prior->unorderable() || angle->unorderable() || next->unorderable()) { 448 baseAngle = nullptr; 449 continue; 450 } 451 int testWinding = angle->starter()->windSum(); 452 if (SK_MinS32 != testWinding) { 453 baseAngle = angle; 454 continue; 455 } 456 if (baseAngle) { 457 ComputeOneSumReverse(baseAngle, angle, includeType); 458 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr; 459 } 460 } while (prior != firstAngle); 461 } 462 return start->starter(end)->windSum(); 463 } 464 465 bool SkOpSegment::contains(double newT) const { 466 const SkOpSpanBase* spanBase = &fHead; 467 do { 468 if (spanBase->ptT()->contains(this, newT)) { 469 return true; 470 } 471 if (spanBase == &fTail) { 472 break; 473 } 474 spanBase = spanBase->upCast()->next(); 475 } while (true); 476 return false; 477 } 478 479 void SkOpSegment::release(const SkOpSpan* span) { 480 if (span->done()) { 481 --fDoneCount; 482 } 483 --fCount; 484 SkOPASSERT(fCount >= fDoneCount); 485 } 486 487 #if DEBUG_ANGLE 488 // called only by debugCheckNearCoincidence 489 double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const { 490 SkDPoint testPt = this->dPtAtT(t); 491 SkDLine testPerp = {{ testPt, testPt }}; 492 SkDVector slope = this->dSlopeAtT(t); 493 testPerp[1].fX += slope.fY; 494 testPerp[1].fY -= slope.fX; 495 SkIntersections i; 496 const SkOpSegment* oppSegment = oppAngle->segment(); 497 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i); 498 double closestDistSq = SK_ScalarInfinity; 499 for (int index = 0; index < i.used(); ++index) { 500 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) { 501 continue; 502 } 503 double testDistSq = testPt.distanceSquared(i.pt(index)); 504 if (closestDistSq > testDistSq) { 505 closestDistSq = testDistSq; 506 } 507 } 508 return closestDistSq; 509 } 510 #endif 511 512 /* 513 The M and S variable name parts stand for the operators. 514 Mi stands for Minuend (see wiki subtraction, analogous to difference) 515 Su stands for Subtrahend 516 The Opp variable name part designates that the value is for the Opposite operator. 517 Opposite values result from combining coincident spans. 518 */ 519 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart, 520 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) { 521 SkOpSpanBase* start = *nextStart; 522 SkOpSpanBase* end = *nextEnd; 523 SkASSERT(start != end); 524 int step = start->step(end); 525 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart 526 if (other) { 527 // mark the smaller of startIndex, endIndex done, and all adjacent 528 // spans with the same T value (but not 'other' spans) 529 #if DEBUG_WINDING 530 SkDebugf("%s simple\n", __FUNCTION__); 531 #endif 532 SkOpSpan* startSpan = start->starter(end); 533 if (startSpan->done()) { 534 return nullptr; 535 } 536 markDone(startSpan); 537 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev(); 538 return other; 539 } 540 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev(); 541 SkASSERT(endNear == end); // is this ever not end? 542 SkASSERT(endNear); 543 SkASSERT(start != endNear); 544 SkASSERT((start->t() < endNear->t()) ^ (step < 0)); 545 // more than one viable candidate -- measure angles to find best 546 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp); 547 bool sortable = calcWinding != SK_NaN32; 548 if (!sortable) { 549 *unsortable = true; 550 markDone(start->starter(end)); 551 return nullptr; 552 } 553 SkOpAngle* angle = this->spanToAngle(end, start); 554 if (angle->unorderable()) { 555 *unsortable = true; 556 markDone(start->starter(end)); 557 return nullptr; 558 } 559 #if DEBUG_SORT 560 SkDebugf("%s\n", __FUNCTION__); 561 angle->debugLoop(); 562 #endif 563 int sumMiWinding = updateWinding(end, start); 564 if (sumMiWinding == SK_MinS32) { 565 *unsortable = true; 566 markDone(start->starter(end)); 567 return nullptr; 568 } 569 int sumSuWinding = updateOppWinding(end, start); 570 if (operand()) { 571 SkTSwap<int>(sumMiWinding, sumSuWinding); 572 } 573 SkOpAngle* nextAngle = angle->next(); 574 const SkOpAngle* foundAngle = nullptr; 575 bool foundDone = false; 576 // iterate through the angle, and compute everyone's winding 577 SkOpSegment* nextSegment; 578 int activeCount = 0; 579 do { 580 nextSegment = nextAngle->segment(); 581 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(), 582 nextAngle->end(), op, &sumMiWinding, &sumSuWinding); 583 if (activeAngle) { 584 ++activeCount; 585 if (!foundAngle || (foundDone && activeCount & 1)) { 586 foundAngle = nextAngle; 587 foundDone = nextSegment->done(nextAngle); 588 } 589 } 590 if (nextSegment->done()) { 591 continue; 592 } 593 if (!activeAngle) { 594 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end()); 595 } 596 SkOpSpanBase* last = nextAngle->lastMarked(); 597 if (last) { 598 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); 599 *chase->append() = last; 600 #if DEBUG_WINDING 601 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__, 602 last->segment()->debugID(), last->debugID()); 603 if (!last->final()) { 604 SkDebugf(" windSum=%d", last->upCast()->windSum()); 605 } 606 SkDebugf("\n"); 607 #endif 608 } 609 } while ((nextAngle = nextAngle->next()) != angle); 610 start->segment()->markDone(start->starter(end)); 611 if (!foundAngle) { 612 return nullptr; 613 } 614 *nextStart = foundAngle->start(); 615 *nextEnd = foundAngle->end(); 616 nextSegment = foundAngle->segment(); 617 #if DEBUG_WINDING 618 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 619 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd); 620 #endif 621 return nextSegment; 622 } 623 624 SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase, 625 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) { 626 SkOpSpanBase* start = *nextStart; 627 SkOpSpanBase* end = *nextEnd; 628 SkASSERT(start != end); 629 int step = start->step(end); 630 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart 631 if (other) { 632 // mark the smaller of startIndex, endIndex done, and all adjacent 633 // spans with the same T value (but not 'other' spans) 634 #if DEBUG_WINDING 635 SkDebugf("%s simple\n", __FUNCTION__); 636 #endif 637 SkOpSpan* startSpan = start->starter(end); 638 if (startSpan->done()) { 639 return nullptr; 640 } 641 markDone(startSpan); 642 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev(); 643 return other; 644 } 645 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev(); 646 SkASSERT(endNear == end); // is this ever not end? 647 SkASSERT(endNear); 648 SkASSERT(start != endNear); 649 SkASSERT((start->t() < endNear->t()) ^ (step < 0)); 650 // more than one viable candidate -- measure angles to find best 651 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding); 652 bool sortable = calcWinding != SK_NaN32; 653 if (!sortable) { 654 *unsortable = true; 655 markDone(start->starter(end)); 656 return nullptr; 657 } 658 SkOpAngle* angle = this->spanToAngle(end, start); 659 if (angle->unorderable()) { 660 *unsortable = true; 661 markDone(start->starter(end)); 662 return nullptr; 663 } 664 #if DEBUG_SORT 665 SkDebugf("%s\n", __FUNCTION__); 666 angle->debugLoop(); 667 #endif 668 int sumWinding = updateWinding(end, start); 669 SkOpAngle* nextAngle = angle->next(); 670 const SkOpAngle* foundAngle = nullptr; 671 bool foundDone = false; 672 // iterate through the angle, and compute everyone's winding 673 SkOpSegment* nextSegment; 674 int activeCount = 0; 675 do { 676 nextSegment = nextAngle->segment(); 677 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(), 678 &sumWinding); 679 if (activeAngle) { 680 ++activeCount; 681 if (!foundAngle || (foundDone && activeCount & 1)) { 682 foundAngle = nextAngle; 683 foundDone = nextSegment->done(nextAngle); 684 } 685 } 686 if (nextSegment->done()) { 687 continue; 688 } 689 if (!activeAngle) { 690 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end()); 691 } 692 SkOpSpanBase* last = nextAngle->lastMarked(); 693 if (last) { 694 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); 695 *chase->append() = last; 696 #if DEBUG_WINDING 697 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__, 698 last->segment()->debugID(), last->debugID()); 699 if (!last->final()) { 700 SkDebugf(" windSum=%d", last->upCast()->windSum()); 701 } 702 SkDebugf("\n"); 703 #endif 704 } 705 } while ((nextAngle = nextAngle->next()) != angle); 706 start->segment()->markDone(start->starter(end)); 707 if (!foundAngle) { 708 return nullptr; 709 } 710 *nextStart = foundAngle->start(); 711 *nextEnd = foundAngle->end(); 712 nextSegment = foundAngle->segment(); 713 #if DEBUG_WINDING 714 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 715 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd); 716 #endif 717 return nextSegment; 718 } 719 720 SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, 721 bool* unsortable) { 722 SkOpSpanBase* start = *nextStart; 723 SkOpSpanBase* end = *nextEnd; 724 SkASSERT(start != end); 725 int step = start->step(end); 726 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart 727 if (other) { 728 // mark the smaller of startIndex, endIndex done, and all adjacent 729 // spans with the same T value (but not 'other' spans) 730 #if DEBUG_WINDING 731 SkDebugf("%s simple\n", __FUNCTION__); 732 #endif 733 SkOpSpan* startSpan = start->starter(end); 734 if (startSpan->done()) { 735 return nullptr; 736 } 737 markDone(startSpan); 738 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev(); 739 return other; 740 } 741 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \ 742 : (*nextStart)->prev()); 743 SkASSERT(endNear == end); // is this ever not end? 744 SkASSERT(endNear); 745 SkASSERT(start != endNear); 746 SkASSERT((start->t() < endNear->t()) ^ (step < 0)); 747 SkOpAngle* angle = this->spanToAngle(end, start); 748 if (!angle || angle->unorderable()) { 749 *unsortable = true; 750 markDone(start->starter(end)); 751 return nullptr; 752 } 753 #if DEBUG_SORT 754 SkDebugf("%s\n", __FUNCTION__); 755 angle->debugLoop(); 756 #endif 757 SkOpAngle* nextAngle = angle->next(); 758 const SkOpAngle* foundAngle = nullptr; 759 bool foundDone = false; 760 // iterate through the angle, and compute everyone's winding 761 SkOpSegment* nextSegment; 762 int activeCount = 0; 763 do { 764 nextSegment = nextAngle->segment(); 765 ++activeCount; 766 if (!foundAngle || (foundDone && activeCount & 1)) { 767 foundAngle = nextAngle; 768 if (!(foundDone = nextSegment->done(nextAngle))) { 769 break; 770 } 771 } 772 nextAngle = nextAngle->next(); 773 } while (nextAngle != angle); 774 start->segment()->markDone(start->starter(end)); 775 if (!foundAngle) { 776 return nullptr; 777 } 778 *nextStart = foundAngle->start(); 779 *nextEnd = foundAngle->end(); 780 nextSegment = foundAngle->segment(); 781 #if DEBUG_WINDING 782 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 783 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd); 784 #endif 785 return nextSegment; 786 } 787 788 SkOpGlobalState* SkOpSegment::globalState() const { 789 return contour()->globalState(); 790 } 791 792 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) { 793 fContour = contour; 794 fNext = nullptr; 795 fPts = pts; 796 fWeight = weight; 797 fVerb = verb; 798 fCount = 0; 799 fDoneCount = 0; 800 fVisited = false; 801 SkOpSpan* zeroSpan = &fHead; 802 zeroSpan->init(this, nullptr, 0, fPts[0]); 803 SkOpSpanBase* oneSpan = &fTail; 804 zeroSpan->setNext(oneSpan); 805 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]); 806 SkDEBUGCODE(fID = globalState()->nextSegmentID()); 807 } 808 809 bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const { 810 SkDPoint cPt = this->dPtAtT(t); 811 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t); 812 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; 813 SkIntersections i; 814 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i); 815 int used = i.used(); 816 for (int index = 0; index < used; ++index) { 817 if (cPt.roughlyEqual(i.pt(index))) { 818 return true; 819 } 820 } 821 return false; 822 } 823 824 bool SkOpSegment::isXor() const { 825 return fContour->isXor(); 826 } 827 828 void SkOpSegment::markAllDone() { 829 SkOpSpan* span = this->head(); 830 do { 831 this->markDone(span); 832 } while ((span = span->next()->upCastable())); 833 } 834 835 SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) { 836 int step = start->step(end); 837 SkOpSpan* minSpan = start->starter(end); 838 markDone(minSpan); 839 SkOpSpanBase* last = nullptr; 840 SkOpSegment* other = this; 841 SkOpSpan* priorDone = nullptr; 842 SkOpSpan* lastDone = nullptr; 843 while ((other = other->nextChase(&start, &step, &minSpan, &last))) { 844 if (other->done()) { 845 SkASSERT(!last); 846 break; 847 } 848 if (lastDone == minSpan || priorDone == minSpan) { 849 return nullptr; 850 } 851 other->markDone(minSpan); 852 priorDone = lastDone; 853 lastDone = minSpan; 854 } 855 return last; 856 } 857 858 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding, 859 SkOpSpanBase** lastPtr) { 860 SkOpSpan* spanStart = start->starter(end); 861 int step = start->step(end); 862 bool success = markWinding(spanStart, winding); 863 SkOpSpanBase* last = nullptr; 864 SkOpSegment* other = this; 865 while ((other = other->nextChase(&start, &step, &spanStart, &last))) { 866 if (spanStart->windSum() != SK_MinS32) { 867 // SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive? 868 SkASSERT(!last); 869 break; 870 } 871 (void) other->markWinding(spanStart, winding); 872 } 873 if (lastPtr) { 874 *lastPtr = last; 875 } 876 return success; 877 } 878 879 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, 880 int winding, int oppWinding, SkOpSpanBase** lastPtr) { 881 SkOpSpan* spanStart = start->starter(end); 882 int step = start->step(end); 883 bool success = markWinding(spanStart, winding, oppWinding); 884 SkOpSpanBase* last = nullptr; 885 SkOpSegment* other = this; 886 while ((other = other->nextChase(&start, &step, &spanStart, &last))) { 887 if (spanStart->windSum() != SK_MinS32) { 888 if (this->operand() == other->operand()) { 889 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) { 890 this->globalState()->setWindingFailed(); 891 return false; 892 } 893 } else { 894 SkASSERT(spanStart->windSum() == oppWinding); 895 SkASSERT(spanStart->oppSum() == winding); 896 } 897 SkASSERT(!last); 898 break; 899 } 900 if (this->operand() == other->operand()) { 901 (void) other->markWinding(spanStart, winding, oppWinding); 902 } else { 903 (void) other->markWinding(spanStart, oppWinding, winding); 904 } 905 } 906 if (lastPtr) { 907 *lastPtr = last; 908 } 909 return success; 910 } 911 912 SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) { 913 SkASSERT(angle->segment() == this); 914 if (UseInnerWinding(maxWinding, sumWinding)) { 915 maxWinding = sumWinding; 916 } 917 SkOpSpanBase* last; 918 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last); 919 #if DEBUG_WINDING 920 if (last) { 921 SkDebugf("%s last seg=%d span=%d", __FUNCTION__, 922 last->segment()->debugID(), last->debugID()); 923 if (!last->final()) { 924 SkDebugf(" windSum="); 925 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum()); 926 } 927 SkDebugf("\n"); 928 } 929 #endif 930 return last; 931 } 932 933 SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding, 934 int oppSumWinding, const SkOpAngle* angle) { 935 SkASSERT(angle->segment() == this); 936 if (UseInnerWinding(maxWinding, sumWinding)) { 937 maxWinding = sumWinding; 938 } 939 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) { 940 oppMaxWinding = oppSumWinding; 941 } 942 SkOpSpanBase* last = nullptr; 943 // caller doesn't require that this marks anything 944 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last); 945 #if DEBUG_WINDING 946 if (last) { 947 SkDebugf("%s last segment=%d span=%d", __FUNCTION__, 948 last->segment()->debugID(), last->debugID()); 949 if (!last->final()) { 950 SkDebugf(" windSum="); 951 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum()); 952 } 953 SkDebugf(" \n"); 954 } 955 #endif 956 return last; 957 } 958 959 void SkOpSegment::markDone(SkOpSpan* span) { 960 SkASSERT(this == span->segment()); 961 if (span->done()) { 962 return; 963 } 964 #if DEBUG_MARK_DONE 965 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum()); 966 #endif 967 span->setDone(true); 968 ++fDoneCount; 969 debugValidate(); 970 } 971 972 bool SkOpSegment::markWinding(SkOpSpan* span, int winding) { 973 SkASSERT(this == span->segment()); 974 SkASSERT(winding); 975 if (span->done()) { 976 return false; 977 } 978 #if DEBUG_MARK_DONE 979 debugShowNewWinding(__FUNCTION__, span, winding); 980 #endif 981 span->setWindSum(winding); 982 debugValidate(); 983 return true; 984 } 985 986 bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) { 987 SkASSERT(this == span->segment()); 988 SkASSERT(winding || oppWinding); 989 if (span->done()) { 990 return false; 991 } 992 #if DEBUG_MARK_DONE 993 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding); 994 #endif 995 span->setWindSum(winding); 996 span->setOppSum(oppWinding); 997 debugValidate(); 998 return true; 999 } 1000 1001 bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT, 1002 const SkPoint& testPt) const { 1003 SkASSERT(this == base->segment()); 1004 if (this == testParent) { 1005 if (precisely_equal(base->fT, testT)) { 1006 return true; 1007 } 1008 } 1009 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) { 1010 return false; 1011 } 1012 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt); 1013 } 1014 1015 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) { 1016 if (last) { 1017 *last = endSpan; 1018 } 1019 return nullptr; 1020 } 1021 1022 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr, 1023 SkOpSpanBase** last) const { 1024 SkOpSpanBase* origStart = *startPtr; 1025 int step = *stepPtr; 1026 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev(); 1027 SkASSERT(endSpan); 1028 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle(); 1029 SkOpSpanBase* foundSpan; 1030 SkOpSpanBase* otherEnd; 1031 SkOpSegment* other; 1032 if (angle == nullptr) { 1033 if (endSpan->t() != 0 && endSpan->t() != 1) { 1034 return nullptr; 1035 } 1036 SkOpPtT* otherPtT = endSpan->ptT()->next(); 1037 other = otherPtT->segment(); 1038 foundSpan = otherPtT->span(); 1039 otherEnd = step > 0 1040 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr 1041 : foundSpan->prev(); 1042 } else { 1043 int loopCount = angle->loopCount(); 1044 if (loopCount > 2) { 1045 return set_last(last, endSpan); 1046 } 1047 const SkOpAngle* next = angle->next(); 1048 if (nullptr == next) { 1049 return nullptr; 1050 } 1051 #if DEBUG_WINDING 1052 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor() 1053 && !next->segment()->contour()->isXor()) { 1054 SkDebugf("%s mismatched signs\n", __FUNCTION__); 1055 } 1056 #endif 1057 other = next->segment(); 1058 foundSpan = endSpan = next->start(); 1059 otherEnd = next->end(); 1060 } 1061 if (!otherEnd) { 1062 return nullptr; 1063 } 1064 int foundStep = foundSpan->step(otherEnd); 1065 if (*stepPtr != foundStep) { 1066 return set_last(last, endSpan); 1067 } 1068 SkASSERT(*startPtr); 1069 // SkASSERT(otherEnd >= 0); 1070 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast(); 1071 SkOpSpan* foundMin = foundSpan->starter(otherEnd); 1072 if (foundMin->windValue() != origMin->windValue() 1073 || foundMin->oppValue() != origMin->oppValue()) { 1074 return set_last(last, endSpan); 1075 } 1076 *startPtr = foundSpan; 1077 *stepPtr = foundStep; 1078 if (minPtr) { 1079 *minPtr = foundMin; 1080 } 1081 return other; 1082 } 1083 1084 // Please keep this in sync with DebugClearVisited() 1085 void SkOpSegment::ClearVisited(SkOpSpanBase* span) { 1086 // reset visited flag back to false 1087 do { 1088 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT; 1089 while ((ptT = ptT->next()) != stopPtT) { 1090 SkOpSegment* opp = ptT->segment(); 1091 opp->resetVisited(); 1092 } 1093 } while (!span->final() && (span = span->upCast()->next())); 1094 } 1095 1096 // Please keep this in sync with debugMissingCoincidence() 1097 // look for pairs of undetected coincident curves 1098 // assumes that segments going in have visited flag clear 1099 // Even though pairs of curves correct detect coincident runs, a run may be missed 1100 // if the coincidence is a product of multiple intersections. For instance, given 1101 // curves A, B, and C: 1102 // A-B intersect at a point 1; A-C and B-C intersect at point 2, so near 1103 // the end of C that the intersection is replaced with the end of C. 1104 // Even though A-B correctly do not detect an intersection at point 2, 1105 // the resulting run from point 1 to point 2 is coincident on A and B. 1106 bool SkOpSegment::missingCoincidence() { 1107 if (this->done()) { 1108 return false; 1109 } 1110 SkOpSpan* prior = nullptr; 1111 SkOpSpanBase* spanBase = &fHead; 1112 bool result = false; 1113 do { 1114 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT; 1115 SkOPASSERT(ptT->span() == spanBase); 1116 while ((ptT = ptT->next()) != spanStopPtT) { 1117 if (ptT->deleted()) { 1118 continue; 1119 } 1120 SkOpSegment* opp = ptT->span()->segment(); 1121 if (opp->done()) { 1122 continue; 1123 } 1124 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence 1125 if (!opp->visited()) { 1126 continue; 1127 } 1128 if (spanBase == &fHead) { 1129 continue; 1130 } 1131 if (ptT->segment() == this) { 1132 continue; 1133 } 1134 SkOpSpan* span = spanBase->upCastable(); 1135 // FIXME?: this assumes that if the opposite segment is coincident then no more 1136 // coincidence needs to be detected. This may not be true. 1137 if (span && span->containsCoincidence(opp)) { 1138 continue; 1139 } 1140 if (spanBase->containsCoinEnd(opp)) { 1141 continue; 1142 } 1143 SkOpPtT* priorPtT = nullptr, * priorStopPtT; 1144 // find prior span containing opp segment 1145 SkOpSegment* priorOpp = nullptr; 1146 SkOpSpan* priorTest = spanBase->prev(); 1147 while (!priorOpp && priorTest) { 1148 priorStopPtT = priorPtT = priorTest->ptT(); 1149 while ((priorPtT = priorPtT->next()) != priorStopPtT) { 1150 if (priorPtT->deleted()) { 1151 continue; 1152 } 1153 SkOpSegment* segment = priorPtT->span()->segment(); 1154 if (segment == opp) { 1155 prior = priorTest; 1156 priorOpp = opp; 1157 break; 1158 } 1159 } 1160 priorTest = priorTest->prev(); 1161 } 1162 if (!priorOpp) { 1163 continue; 1164 } 1165 if (priorPtT == ptT) { 1166 continue; 1167 } 1168 SkOpPtT* oppStart = prior->ptT(); 1169 SkOpPtT* oppEnd = spanBase->ptT(); 1170 bool swapped = priorPtT->fT > ptT->fT; 1171 if (swapped) { 1172 SkTSwap(priorPtT, ptT); 1173 SkTSwap(oppStart, oppEnd); 1174 } 1175 SkOpCoincidence* coincidences = this->globalState()->coincidence(); 1176 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT(); 1177 SkOpPtT* rootPtT = ptT->span()->ptT(); 1178 SkOpPtT* rootOppStart = oppStart->span()->ptT(); 1179 SkOpPtT* rootOppEnd = oppEnd->span()->ptT(); 1180 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) { 1181 goto swapBack; 1182 } 1183 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) { 1184 // mark coincidence 1185 #if DEBUG_COINCIDENCE_VERBOSE 1186 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__, 1187 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(), 1188 rootOppEnd->debugID()); 1189 #endif 1190 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) { 1191 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd); 1192 } 1193 #if DEBUG_COINCIDENCE 1194 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)); 1195 #endif 1196 result = true; 1197 } 1198 swapBack: 1199 if (swapped) { 1200 SkTSwap(priorPtT, ptT); 1201 } 1202 } 1203 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next())); 1204 ClearVisited(&fHead); 1205 return result; 1206 } 1207 1208 // please keep this in sync with debugMoveMultiples() 1209 // if a span has more than one intersection, merge the other segments' span as needed 1210 bool SkOpSegment::moveMultiples() { 1211 debugValidate(); 1212 SkOpSpanBase* test = &fHead; 1213 do { 1214 int addCount = test->spanAddsCount(); 1215 // FAIL_IF(addCount < 1); 1216 if (addCount <= 1) { 1217 continue; 1218 } 1219 SkOpPtT* startPtT = test->ptT(); 1220 SkOpPtT* testPtT = startPtT; 1221 do { // iterate through all spans associated with start 1222 SkOpSpanBase* oppSpan = testPtT->span(); 1223 if (oppSpan->spanAddsCount() == addCount) { 1224 continue; 1225 } 1226 if (oppSpan->deleted()) { 1227 continue; 1228 } 1229 SkOpSegment* oppSegment = oppSpan->segment(); 1230 if (oppSegment == this) { 1231 continue; 1232 } 1233 // find range of spans to consider merging 1234 SkOpSpanBase* oppPrev = oppSpan; 1235 SkOpSpanBase* oppFirst = oppSpan; 1236 while ((oppPrev = oppPrev->prev())) { 1237 if (!roughly_equal(oppPrev->t(), oppSpan->t())) { 1238 break; 1239 } 1240 if (oppPrev->spanAddsCount() == addCount) { 1241 continue; 1242 } 1243 if (oppPrev->deleted()) { 1244 continue; 1245 } 1246 oppFirst = oppPrev; 1247 } 1248 SkOpSpanBase* oppNext = oppSpan; 1249 SkOpSpanBase* oppLast = oppSpan; 1250 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) { 1251 if (!roughly_equal(oppNext->t(), oppSpan->t())) { 1252 break; 1253 } 1254 if (oppNext->spanAddsCount() == addCount) { 1255 continue; 1256 } 1257 if (oppNext->deleted()) { 1258 continue; 1259 } 1260 oppLast = oppNext; 1261 } 1262 if (oppFirst == oppLast) { 1263 continue; 1264 } 1265 SkOpSpanBase* oppTest = oppFirst; 1266 do { 1267 if (oppTest == oppSpan) { 1268 continue; 1269 } 1270 // check to see if the candidate meets specific criteria: 1271 // it contains spans of segments in test's loop but not including 'this' 1272 SkOpPtT* oppStartPtT = oppTest->ptT(); 1273 SkOpPtT* oppPtT = oppStartPtT; 1274 while ((oppPtT = oppPtT->next()) != oppStartPtT) { 1275 SkOpSegment* oppPtTSegment = oppPtT->segment(); 1276 if (oppPtTSegment == this) { 1277 goto tryNextSpan; 1278 } 1279 SkOpPtT* matchPtT = startPtT; 1280 do { 1281 if (matchPtT->segment() == oppPtTSegment) { 1282 goto foundMatch; 1283 } 1284 } while ((matchPtT = matchPtT->next()) != startPtT); 1285 goto tryNextSpan; 1286 foundMatch: // merge oppTest and oppSpan 1287 oppSegment->debugValidate(); 1288 oppTest->mergeMatches(oppSpan); 1289 oppTest->addOpp(oppSpan); 1290 oppSegment->debugValidate(); 1291 goto checkNextSpan; 1292 } 1293 tryNextSpan: 1294 ; 1295 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next())); 1296 } while ((testPtT = testPtT->next()) != startPtT); 1297 checkNextSpan: 1298 ; 1299 } while ((test = test->final() ? nullptr : test->upCast()->next())); 1300 debugValidate(); 1301 return true; 1302 } 1303 1304 // adjacent spans may have points close by 1305 bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan, 1306 bool* found) const { 1307 const SkOpPtT* refHead = refSpan->ptT(); 1308 const SkOpPtT* checkHead = checkSpan->ptT(); 1309 // if the first pt pair from adjacent spans are far apart, assume that all are far enough apart 1310 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) { 1311 #if DEBUG_COINCIDENCE 1312 // verify that no combination of points are close 1313 const SkOpPtT* dBugRef = refHead; 1314 do { 1315 const SkOpPtT* dBugCheck = checkHead; 1316 do { 1317 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt)); 1318 dBugCheck = dBugCheck->next(); 1319 } while (dBugCheck != checkHead); 1320 dBugRef = dBugRef->next(); 1321 } while (dBugRef != refHead); 1322 #endif 1323 *found = false; 1324 return true; 1325 } 1326 // check only unique points 1327 SkScalar distSqBest = SK_ScalarMax; 1328 const SkOpPtT* refBest = nullptr; 1329 const SkOpPtT* checkBest = nullptr; 1330 const SkOpPtT* ref = refHead; 1331 do { 1332 if (ref->deleted()) { 1333 continue; 1334 } 1335 while (ref->ptAlreadySeen(refHead)) { 1336 ref = ref->next(); 1337 if (ref == refHead) { 1338 goto doneCheckingDistance; 1339 } 1340 } 1341 const SkOpPtT* check = checkHead; 1342 const SkOpSegment* refSeg = ref->segment(); 1343 int escapeHatch = 100000; // defend against infinite loops 1344 do { 1345 if (check->deleted()) { 1346 continue; 1347 } 1348 while (check->ptAlreadySeen(checkHead)) { 1349 check = check->next(); 1350 if (check == checkHead) { 1351 goto nextRef; 1352 } 1353 } 1354 SkScalar distSq = ref->fPt.distanceToSqd(check->fPt); 1355 if (distSqBest > distSq && (refSeg != check->segment() 1356 || !refSeg->ptsDisjoint(*ref, *check))) { 1357 distSqBest = distSq; 1358 refBest = ref; 1359 checkBest = check; 1360 } 1361 if (--escapeHatch <= 0) { 1362 return false; 1363 } 1364 } while ((check = check->next()) != checkHead); 1365 nextRef: 1366 ; 1367 } while ((ref = ref->next()) != refHead); 1368 doneCheckingDistance: 1369 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT, 1370 checkBest->fPt); 1371 return true; 1372 } 1373 1374 // Please keep this function in sync with debugMoveNearby() 1375 // Move nearby t values and pts so they all hang off the same span. Alignment happens later. 1376 bool SkOpSegment::moveNearby() { 1377 debugValidate(); 1378 // release undeleted spans pointing to this seg that are linked to the primary span 1379 SkOpSpanBase* spanBase = &fHead; 1380 do { 1381 SkOpPtT* ptT = spanBase->ptT(); 1382 const SkOpPtT* headPtT = ptT; 1383 while ((ptT = ptT->next()) != headPtT) { 1384 SkOpSpanBase* test = ptT->span(); 1385 if (ptT->segment() == this && !ptT->deleted() && test != spanBase 1386 && test->ptT() == ptT) { 1387 if (test->final()) { 1388 if (spanBase == &fHead) { 1389 this->clearAll(); 1390 return true; 1391 } 1392 spanBase->upCast()->release(ptT); 1393 } else if (test->prev()) { 1394 test->upCast()->release(headPtT); 1395 } 1396 break; 1397 } 1398 } 1399 spanBase = spanBase->upCast()->next(); 1400 } while (!spanBase->final()); 1401 1402 // This loop looks for adjacent spans which are near by 1403 spanBase = &fHead; 1404 do { // iterate through all spans associated with start 1405 SkOpSpanBase* test = spanBase->upCast()->next(); 1406 bool found; 1407 if (!this->spansNearby(spanBase, test, &found)) { 1408 return false; 1409 } 1410 if (found) { 1411 if (test->final()) { 1412 if (spanBase->prev()) { 1413 test->merge(spanBase->upCast()); 1414 } else { 1415 this->clearAll(); 1416 return true; 1417 } 1418 } else { 1419 spanBase->merge(test->upCast()); 1420 } 1421 } 1422 spanBase = test; 1423 } while (!spanBase->final()); 1424 debugValidate(); 1425 return true; 1426 } 1427 1428 bool SkOpSegment::operand() const { 1429 return fContour->operand(); 1430 } 1431 1432 bool SkOpSegment::oppXor() const { 1433 return fContour->oppXor(); 1434 } 1435 1436 bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const { 1437 if (fVerb == SkPath::kLine_Verb) { 1438 return false; 1439 } 1440 // quads (and cubics) can loop back to nearly a line so that an opposite curve 1441 // hits in two places with very different t values. 1442 // OPTIMIZATION: curves could be preflighted so that, for example, something like 1443 // 'controls contained by ends' could avoid this check for common curves 1444 // 'ends are extremes in x or y' is cheaper to compute and real-world common 1445 // on the other hand, the below check is relatively inexpensive 1446 double midT = (t1 + t2) / 2; 1447 SkPoint midPt = this->ptAtT(midT); 1448 double seDistSq = SkTMax(pt1.distanceToSqd(pt2) * 2, FLT_EPSILON * 2); 1449 return midPt.distanceToSqd(pt1) > seDistSq || midPt.distanceToSqd(pt2) > seDistSq; 1450 } 1451 1452 void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding, 1453 int* maxWinding, int* sumWinding) { 1454 int deltaSum = SpanSign(start, end); 1455 *maxWinding = *sumMiWinding; 1456 *sumWinding = *sumMiWinding -= deltaSum; 1457 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM); 1458 } 1459 1460 void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding, 1461 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding, 1462 int* oppSumWinding) { 1463 int deltaSum = SpanSign(start, end); 1464 int oppDeltaSum = OppSign(start, end); 1465 if (operand()) { 1466 *maxWinding = *sumSuWinding; 1467 *sumWinding = *sumSuWinding -= deltaSum; 1468 *oppMaxWinding = *sumMiWinding; 1469 *oppSumWinding = *sumMiWinding -= oppDeltaSum; 1470 } else { 1471 *maxWinding = *sumMiWinding; 1472 *sumWinding = *sumMiWinding -= deltaSum; 1473 *oppMaxWinding = *sumSuWinding; 1474 *oppSumWinding = *sumSuWinding -= oppDeltaSum; 1475 } 1476 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM); 1477 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM); 1478 } 1479 1480 bool SkOpSegment::sortAngles() { 1481 SkOpSpanBase* span = &this->fHead; 1482 do { 1483 SkOpAngle* fromAngle = span->fromAngle(); 1484 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle(); 1485 if (!fromAngle && !toAngle) { 1486 continue; 1487 } 1488 #if DEBUG_ANGLE 1489 bool wroteAfterHeader = false; 1490 #endif 1491 SkOpAngle* baseAngle = fromAngle; 1492 if (fromAngle && toAngle) { 1493 #if DEBUG_ANGLE 1494 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(), 1495 span->debugID()); 1496 wroteAfterHeader = true; 1497 #endif 1498 FAIL_IF(!fromAngle->insert(toAngle)); 1499 } else if (!fromAngle) { 1500 baseAngle = toAngle; 1501 } 1502 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT; 1503 do { 1504 SkOpSpanBase* oSpan = ptT->span(); 1505 if (oSpan == span) { 1506 continue; 1507 } 1508 SkOpAngle* oAngle = oSpan->fromAngle(); 1509 if (oAngle) { 1510 #if DEBUG_ANGLE 1511 if (!wroteAfterHeader) { 1512 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), 1513 span->t(), span->debugID()); 1514 wroteAfterHeader = true; 1515 } 1516 #endif 1517 if (!oAngle->loopContains(baseAngle)) { 1518 baseAngle->insert(oAngle); 1519 } 1520 } 1521 if (!oSpan->final()) { 1522 oAngle = oSpan->upCast()->toAngle(); 1523 if (oAngle) { 1524 #if DEBUG_ANGLE 1525 if (!wroteAfterHeader) { 1526 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), 1527 span->t(), span->debugID()); 1528 wroteAfterHeader = true; 1529 } 1530 #endif 1531 if (!oAngle->loopContains(baseAngle)) { 1532 baseAngle->insert(oAngle); 1533 } 1534 } 1535 } 1536 } while ((ptT = ptT->next()) != stopPtT); 1537 if (baseAngle->loopCount() == 1) { 1538 span->setFromAngle(nullptr); 1539 if (toAngle) { 1540 span->upCast()->setToAngle(nullptr); 1541 } 1542 baseAngle = nullptr; 1543 } 1544 #if DEBUG_SORT 1545 SkASSERT(!baseAngle || baseAngle->loopCount() > 1); 1546 #endif 1547 } while (!span->final() && (span = span->upCast()->next())); 1548 return true; 1549 } 1550 1551 bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, 1552 SkDCurve* edge) const { 1553 SkASSERT(start != end); 1554 const SkOpPtT& startPtT = *start->ptT(); 1555 const SkOpPtT& endPtT = *end->ptT(); 1556 SkDEBUGCODE(edge->fVerb = fVerb); 1557 edge->fCubic[0].set(startPtT.fPt); 1558 int points = SkPathOpsVerbToPoints(fVerb); 1559 edge->fCubic[points].set(endPtT.fPt); 1560 if (fVerb == SkPath::kLine_Verb) { 1561 return false; 1562 } 1563 double startT = startPtT.fT; 1564 double endT = endPtT.fT; 1565 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { 1566 // don't compute midpoints if we already have them 1567 if (fVerb == SkPath::kQuad_Verb) { 1568 edge->fLine[1].set(fPts[1]); 1569 return false; 1570 } 1571 if (fVerb == SkPath::kConic_Verb) { 1572 edge->fConic[1].set(fPts[1]); 1573 edge->fConic.fWeight = fWeight; 1574 return false; 1575 } 1576 SkASSERT(fVerb == SkPath::kCubic_Verb); 1577 if (startT == 0) { 1578 edge->fCubic[1].set(fPts[1]); 1579 edge->fCubic[2].set(fPts[2]); 1580 return false; 1581 } 1582 edge->fCubic[1].set(fPts[2]); 1583 edge->fCubic[2].set(fPts[1]); 1584 return false; 1585 } 1586 if (fVerb == SkPath::kQuad_Verb) { 1587 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT); 1588 } else if (fVerb == SkPath::kConic_Verb) { 1589 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2], 1590 startT, endT, &edge->fConic.fWeight); 1591 } else { 1592 SkASSERT(fVerb == SkPath::kCubic_Verb); 1593 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]); 1594 } 1595 return true; 1596 } 1597 1598 bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT, 1599 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const { 1600 // average t, find mid pt 1601 double midT = (prior->t() + spanBase->t()) / 2; 1602 SkPoint midPt = this->ptAtT(midT); 1603 bool coincident = true; 1604 // if the mid pt is not near either end pt, project perpendicular through opp seg 1605 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt) 1606 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) { 1607 if (priorPtT->span() == ptT->span()) { 1608 return false; 1609 } 1610 coincident = false; 1611 SkIntersections i; 1612 SkDCurve curvePart; 1613 this->subDivide(prior, spanBase, &curvePart); 1614 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f); 1615 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f); 1616 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}}; 1617 SkDCurve oppPart; 1618 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart); 1619 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i); 1620 // measure distance and see if it's small enough to denote coincidence 1621 for (int index = 0; index < i.used(); ++index) { 1622 if (!between(0, i[0][index], 1)) { 1623 continue; 1624 } 1625 SkDPoint oppPt = i.pt(index); 1626 if (oppPt.approximatelyDEqual(midPt)) { 1627 // the coincidence can occur at almost any angle 1628 coincident = true; 1629 } 1630 } 1631 } 1632 return coincident; 1633 } 1634 1635 SkOpSpan* SkOpSegment::undoneSpan() { 1636 SkOpSpan* span = &fHead; 1637 SkOpSpanBase* next; 1638 do { 1639 next = span->next(); 1640 if (!span->done()) { 1641 return span; 1642 } 1643 } while (!next->final() && (span = next->upCast())); 1644 return nullptr; 1645 } 1646 1647 int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const { 1648 const SkOpSpan* lesser = start->starter(end); 1649 int oppWinding = lesser->oppSum(); 1650 int oppSpanWinding = SkOpSegment::OppSign(start, end); 1651 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding) 1652 && oppWinding != SK_MaxS32) { 1653 oppWinding -= oppSpanWinding; 1654 } 1655 return oppWinding; 1656 } 1657 1658 int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const { 1659 const SkOpSpanBase* startSpan = angle->start(); 1660 const SkOpSpanBase* endSpan = angle->end(); 1661 return updateOppWinding(endSpan, startSpan); 1662 } 1663 1664 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const { 1665 const SkOpSpanBase* startSpan = angle->start(); 1666 const SkOpSpanBase* endSpan = angle->end(); 1667 return updateOppWinding(startSpan, endSpan); 1668 } 1669 1670 int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) { 1671 SkOpSpan* lesser = start->starter(end); 1672 int winding = lesser->windSum(); 1673 if (winding == SK_MinS32) { 1674 winding = lesser->computeWindSum(); 1675 } 1676 if (winding == SK_MinS32) { 1677 return winding; 1678 } 1679 int spanWinding = SkOpSegment::SpanSign(start, end); 1680 if (winding && UseInnerWinding(winding - spanWinding, winding) 1681 && winding != SK_MaxS32) { 1682 winding -= spanWinding; 1683 } 1684 return winding; 1685 } 1686 1687 int SkOpSegment::updateWinding(SkOpAngle* angle) { 1688 SkOpSpanBase* startSpan = angle->start(); 1689 SkOpSpanBase* endSpan = angle->end(); 1690 return updateWinding(endSpan, startSpan); 1691 } 1692 1693 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) { 1694 SkOpSpanBase* startSpan = angle->start(); 1695 SkOpSpanBase* endSpan = angle->end(); 1696 return updateWinding(startSpan, endSpan); 1697 } 1698 1699 // OPTIMIZATION: does the following also work, and is it any faster? 1700 // return outerWinding * innerWinding > 0 1701 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0))) 1702 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) { 1703 SkASSERT(outerWinding != SK_MaxS32); 1704 SkASSERT(innerWinding != SK_MaxS32); 1705 int absOut = SkTAbs(outerWinding); 1706 int absIn = SkTAbs(innerWinding); 1707 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; 1708 return result; 1709 } 1710 1711 int SkOpSegment::windSum(const SkOpAngle* angle) const { 1712 const SkOpSpan* minSpan = angle->start()->starter(angle->end()); 1713 return minSpan->windSum(); 1714 } 1715