| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 #include "SkOpCoincidence.h" | 7 #include "SkOpCoincidence.h" |
| 8 #include "SkOpContour.h" | 8 #include "SkOpContour.h" |
| 9 #include "SkOpSegment.h" | 9 #include "SkOpSegment.h" |
| 10 #include "SkPathWriter.h" | 10 #include "SkPathWriter.h" |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 } | 95 } |
| 96 | 96 |
| 97 SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** sta
rtPtr, | 97 SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** sta
rtPtr, |
| 98 SkOpSpanBase** endPtr, bool* done, bool* sortable) { | 98 SkOpSpanBase** endPtr, bool* done, bool* sortable) { |
| 99 SkOpPtT* oPtT = start->ptT()->next(); | 99 SkOpPtT* oPtT = start->ptT()->next(); |
| 100 SkOpSegment* other = oPtT->segment(); | 100 SkOpSegment* other = oPtT->segment(); |
| 101 SkOpSpanBase* oSpan = oPtT->span(); | 101 SkOpSpanBase* oSpan = oPtT->span(); |
| 102 return other->activeAngleInner(oSpan, startPtr, endPtr, done, sortable); | 102 return other->activeAngleInner(oSpan, startPtr, endPtr, done, sortable); |
| 103 } | 103 } |
| 104 | 104 |
| 105 SkDPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) { | |
| 106 SkASSERT(!done()); | |
| 107 SkDPoint topPt = {SK_ScalarMax, SK_ScalarMax}; | |
| 108 // see if either end is not done since we want smaller Y of the pair | |
| 109 bool lastDone = true; | |
| 110 SkOpSpanBase* span = &fHead; | |
| 111 SkOpSpanBase* lastSpan = NULL; | |
| 112 do { | |
| 113 if (!lastDone || (!span->final() && !span->upCast()->done())) { | |
| 114 const SkPoint& xy = span->pt(); | |
| 115 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) { | |
| 116 topPt = xy; | |
| 117 if (firstSpan) { | |
| 118 *firstSpan = span; | |
| 119 } | |
| 120 } | |
| 121 if (fVerb != SkPath::kLine_Verb && !lastDone) { | |
| 122 double curveTopT; | |
| 123 SkDCurve curve; | |
| 124 this->subDivide(lastSpan, span, &curve); | |
| 125 SkDPoint curveTop = (curve.*Top[fVerb])(fPts, fWeight, lastSpan-
>t(), span->t(), | |
| 126 &curveTopT); | |
| 127 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY && topPt.
fX > curveTop.fX)) { | |
| 128 topPt = curveTop; | |
| 129 if (firstSpan) { | |
| 130 const SkPoint& lastXY = lastSpan->pt(); | |
| 131 *firstSpan = lastXY.fY > xy.fY || (lastXY.fY == xy.fY &&
lastXY.fX > xy.fX) | |
| 132 ? span : lastSpan; | |
| 133 } | |
| 134 } | |
| 135 } | |
| 136 lastSpan = span; | |
| 137 } | |
| 138 if (span->final()) { | |
| 139 break; | |
| 140 } | |
| 141 lastDone = span->upCast()->done(); | |
| 142 } while ((span = span->upCast()->next())); | |
| 143 return topPt; | |
| 144 } | |
| 145 | |
| 146 bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask
, int xorSuMask, | 105 bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask
, int xorSuMask, |
| 147 SkPathOp op) { | 106 SkPathOp op) { |
| 148 int sumMiWinding = this->updateWinding(end, start); | 107 int sumMiWinding = this->updateWinding(end, start); |
| 149 int sumSuWinding = this->updateOppWinding(end, start); | 108 int sumSuWinding = this->updateOppWinding(end, start); |
| 150 #if DEBUG_LIMIT_WIND_SUM | 109 #if DEBUG_LIMIT_WIND_SUM |
| 151 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM); | 110 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM); |
| 152 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM); | 111 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM); |
| 153 #endif | 112 #endif |
| 154 if (this->operand()) { | 113 if (this->operand()) { |
| 155 SkTSwap<int>(sumMiWinding, sumSuWinding); | 114 SkTSwap<int>(sumMiWinding, sumSuWinding); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 SkOpPtT* result; | 230 SkOpPtT* result; |
| 272 if (existing && existing->contains(opp)) { | 231 if (existing && existing->contains(opp)) { |
| 273 result = existing->ptT(); | 232 result = existing->ptT(); |
| 274 } else { | 233 } else { |
| 275 result = this->addT(t, SkOpSegment::kNoAlias, allocator); | 234 result = this->addT(t, SkOpSegment::kNoAlias, allocator); |
| 276 } | 235 } |
| 277 SkASSERT(result); | 236 SkASSERT(result); |
| 278 return result; | 237 return result; |
| 279 } | 238 } |
| 280 | 239 |
| 281 SkOpAngle* SkOpSegment::addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle*
* anglePtr, | |
| 282 SkChunkAlloc* allocator) { | |
| 283 SkOpSpan* startSpan = fTail.prev(); | |
| 284 SkASSERT(startSpan); | |
| 285 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); | |
| 286 *anglePtr = angle; | |
| 287 angle->set(&fTail, startSpan); | |
| 288 fTail.setFromAngle(angle); | |
| 289 SkOpSegment* other = NULL; // these initializations silence a release build
warning | |
| 290 SkOpSpan* oStartSpan = NULL; | |
| 291 SkOpSpanBase* oEndSpan = NULL; | |
| 292 SkOpPtT* ptT = fTail.ptT(), * startPtT = ptT; | |
| 293 while ((ptT = ptT->next()) != startPtT) { | |
| 294 other = ptT->segment(); | |
| 295 oStartSpan = ptT->span()->upCastable(); | |
| 296 if (oStartSpan && oStartSpan->windValue()) { | |
| 297 oEndSpan = oStartSpan->next(); | |
| 298 break; | |
| 299 } | |
| 300 oEndSpan = ptT->span(); | |
| 301 oStartSpan = oEndSpan->prev(); | |
| 302 if (oStartSpan && oStartSpan->windValue()) { | |
| 303 break; | |
| 304 } | |
| 305 } | |
| 306 if (!oStartSpan) { | |
| 307 return NULL; | |
| 308 } | |
| 309 SkOpAngle* oAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); | |
| 310 oAngle->set(oStartSpan, oEndSpan); | |
| 311 oStartSpan->setToAngle(oAngle); | |
| 312 *otherPtr = other; | |
| 313 return oAngle; | |
| 314 } | |
| 315 | |
| 316 SkOpAngle* SkOpSegment::addSingletonAngles(int step, SkChunkAlloc* allocator) { | |
| 317 SkOpSegment* other; | |
| 318 SkOpAngle* angle, * otherAngle; | |
| 319 if (step > 0) { | |
| 320 otherAngle = addSingletonAngleUp(&other, &angle, allocator); | |
| 321 } else { | |
| 322 otherAngle = addSingletonAngleDown(&other, &angle, allocator); | |
| 323 } | |
| 324 if (!otherAngle) { | |
| 325 return NULL; | |
| 326 } | |
| 327 angle->insert(otherAngle); | |
| 328 return angle; | |
| 329 } | |
| 330 | |
| 331 SkOpAngle* SkOpSegment::addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle**
anglePtr, | |
| 332 SkChunkAlloc* allocator) { | |
| 333 SkOpSpanBase* endSpan = fHead.next(); | |
| 334 SkASSERT(endSpan); | |
| 335 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); | |
| 336 *anglePtr = angle; | |
| 337 angle->set(&fHead, endSpan); | |
| 338 fHead.setToAngle(angle); | |
| 339 SkOpSegment* other = NULL; // these initializations silence a release build
warning | |
| 340 SkOpSpan* oStartSpan = NULL; | |
| 341 SkOpSpanBase* oEndSpan = NULL; | |
| 342 SkOpPtT* ptT = fHead.ptT(), * startPtT = ptT; | |
| 343 while ((ptT = ptT->next()) != startPtT) { | |
| 344 other = ptT->segment(); | |
| 345 oEndSpan = ptT->span(); | |
| 346 oStartSpan = oEndSpan->prev(); | |
| 347 if (oStartSpan && oStartSpan->windValue()) { | |
| 348 break; | |
| 349 } | |
| 350 oStartSpan = oEndSpan->upCastable(); | |
| 351 if (oStartSpan && oStartSpan->windValue()) { | |
| 352 oEndSpan = oStartSpan->next(); | |
| 353 break; | |
| 354 } | |
| 355 } | |
| 356 SkOpAngle* oAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); | |
| 357 oAngle->set(oEndSpan, oStartSpan); | |
| 358 oEndSpan->setFromAngle(oAngle); | |
| 359 *otherPtr = other; | |
| 360 return oAngle; | |
| 361 } | |
| 362 | |
| 363 SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* alloca
tor) { | 240 SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* alloca
tor) { |
| 364 debugValidate(); | 241 debugValidate(); |
| 365 SkPoint pt = this->ptAtT(t); | 242 SkPoint pt = this->ptAtT(t); |
| 366 SkOpSpanBase* span = &fHead; | 243 SkOpSpanBase* span = &fHead; |
| 367 do { | 244 do { |
| 368 SkOpPtT* result = span->ptT(); | 245 SkOpPtT* result = span->ptT(); |
| 369 SkOpPtT* loop; | 246 SkOpPtT* loop; |
| 370 bool duplicatePt; | 247 bool duplicatePt; |
| 371 if (t == result->fT) { | 248 if (t == result->fT) { |
| 372 goto bumpSpan; | 249 goto bumpSpan; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 break; | 307 break; |
| 431 } | 308 } |
| 432 span->align(); | 309 span->align(); |
| 433 } | 310 } |
| 434 if (!span->aligned()) { | 311 if (!span->aligned()) { |
| 435 span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]); | 312 span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]); |
| 436 } | 313 } |
| 437 debugValidate(); | 314 debugValidate(); |
| 438 } | 315 } |
| 439 | 316 |
| 440 bool SkOpSegment::BetweenTs(const SkOpSpanBase* lesser, double testT, | |
| 441 const SkOpSpanBase* greater) { | |
| 442 if (lesser->t() > greater->t()) { | |
| 443 SkTSwap<const SkOpSpanBase*>(lesser, greater); | |
| 444 } | |
| 445 return approximately_between(lesser->t(), testT, greater->t()); | |
| 446 } | |
| 447 | |
| 448 void SkOpSegment::calcAngles(SkChunkAlloc* allocator) { | 317 void SkOpSegment::calcAngles(SkChunkAlloc* allocator) { |
| 449 bool activePrior = !fHead.isCanceled(); | 318 bool activePrior = !fHead.isCanceled(); |
| 450 if (activePrior && !fHead.simple()) { | 319 if (activePrior && !fHead.simple()) { |
| 451 addStartSpan(allocator); | 320 addStartSpan(allocator); |
| 452 } | 321 } |
| 453 SkOpSpan* prior = &fHead; | 322 SkOpSpan* prior = &fHead; |
| 454 SkOpSpanBase* spanBase = fHead.next(); | 323 SkOpSpanBase* spanBase = fHead.next(); |
| 455 while (spanBase != &fTail) { | 324 while (spanBase != &fTail) { |
| 456 if (activePrior) { | 325 if (activePrior) { |
| 457 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocato
r); | 326 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocato
r); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 487 break; | 356 break; |
| 488 } | 357 } |
| 489 span = base->upCast(); | 358 span = base->upCast(); |
| 490 angle = span->toAngle(); | 359 angle = span->toAngle(); |
| 491 if (angle && angle->fCheckCoincidence) { | 360 if (angle && angle->fCheckCoincidence) { |
| 492 angle->checkNearCoincidence(); | 361 angle->checkNearCoincidence(); |
| 493 } | 362 } |
| 494 } while ((base = span->next())); | 363 } while ((base = span->next())); |
| 495 } | 364 } |
| 496 | 365 |
| 497 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order | |
| 498 bool SkOpSegment::clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end,
bool* swap) const { | |
| 499 SkASSERT(fVerb != SkPath::kLine_Verb); | |
| 500 if (fVerb != SkPath::kCubic_Verb) { | |
| 501 SkOpCurve edge; | |
| 502 this->subDivide(start, end, &edge); | |
| 503 return SkDQuad::Clockwise(edge, swap); | |
| 504 } | |
| 505 return SkDCubic::Clockwise(fPts, start->t(), end->t(), swap); | |
| 506 } | |
| 507 | |
| 508 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
, | 366 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
, |
| 509 SkOpAngle::IncludeType includeType) { | 367 SkOpAngle::IncludeType includeType) { |
| 510 const SkOpSegment* baseSegment = baseAngle->segment(); | 368 SkOpSegment* baseSegment = baseAngle->segment(); |
| 511 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); | 369 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); |
| 512 int sumSuWinding; | 370 int sumSuWinding; |
| 513 bool binary = includeType >= SkOpAngle::kBinarySingle; | 371 bool binary = includeType >= SkOpAngle::kBinarySingle; |
| 514 if (binary) { | 372 if (binary) { |
| 515 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); | 373 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); |
| 516 if (baseSegment->operand()) { | 374 if (baseSegment->operand()) { |
| 517 SkTSwap<int>(sumMiWinding, sumSuWinding); | 375 SkTSwap<int>(sumMiWinding, sumSuWinding); |
| 518 } | 376 } |
| 519 } | 377 } |
| 520 SkOpSegment* nextSegment = nextAngle->segment(); | 378 SkOpSegment* nextSegment = nextAngle->segment(); |
| 521 int maxWinding, sumWinding; | 379 int maxWinding, sumWinding; |
| 522 SkOpSpanBase* last; | 380 SkOpSpanBase* last; |
| 523 if (binary) { | 381 if (binary) { |
| 524 int oppMaxWinding, oppSumWinding; | 382 int oppMaxWinding, oppSumWinding; |
| 525 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW
inding, | 383 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW
inding, |
| 526 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSum
Winding); | 384 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSum
Winding); |
| 527 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp
SumWinding, | 385 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp
SumWinding, |
| 528 nextAngle); | 386 nextAngle); |
| 529 } else { | 387 } else { |
| 530 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW
inding, | 388 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW
inding, |
| 531 &maxWinding, &sumWinding); | 389 &maxWinding, &sumWinding); |
| 532 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); | 390 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); |
| 533 } | 391 } |
| 534 nextAngle->setLastMarked(last); | 392 nextAngle->setLastMarked(last); |
| 535 } | 393 } |
| 536 | 394 |
| 537 void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* ne
xtAngle, | 395 void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngl
e, |
| 538 SkOpAngle::IncludeType includeType) { | 396 SkOpAngle::IncludeType includeType) { |
| 539 const SkOpSegment* baseSegment = baseAngle->segment(); | 397 SkOpSegment* baseSegment = baseAngle->segment(); |
| 540 int sumMiWinding = baseSegment->updateWinding(baseAngle); | 398 int sumMiWinding = baseSegment->updateWinding(baseAngle); |
| 541 int sumSuWinding; | 399 int sumSuWinding; |
| 542 bool binary = includeType >= SkOpAngle::kBinarySingle; | 400 bool binary = includeType >= SkOpAngle::kBinarySingle; |
| 543 if (binary) { | 401 if (binary) { |
| 544 sumSuWinding = baseSegment->updateOppWinding(baseAngle); | 402 sumSuWinding = baseSegment->updateOppWinding(baseAngle); |
| 545 if (baseSegment->operand()) { | 403 if (baseSegment->operand()) { |
| 546 SkTSwap<int>(sumMiWinding, sumSuWinding); | 404 SkTSwap<int>(sumMiWinding, sumSuWinding); |
| 547 } | 405 } |
| 548 } | 406 } |
| 549 SkOpSegment* nextSegment = nextAngle->segment(); | 407 SkOpSegment* nextSegment = nextAngle->segment(); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 627 } | 485 } |
| 628 if (baseAngle) { | 486 if (baseAngle) { |
| 629 ComputeOneSumReverse(baseAngle, angle, includeType); | 487 ComputeOneSumReverse(baseAngle, angle, includeType); |
| 630 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : N
ULL; | 488 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : N
ULL; |
| 631 } | 489 } |
| 632 } while (prior != firstAngle); | 490 } while (prior != firstAngle); |
| 633 } | 491 } |
| 634 return start->starter(end)->windSum(); | 492 return start->starter(end)->windSum(); |
| 635 } | 493 } |
| 636 | 494 |
| 637 SkOpSpan* SkOpSegment::crossedSpanY(const SkPoint& basePt, double mid, bool opp,
bool current, | |
| 638 SkScalar* bestY, double* hitT, bool* hitSomething, bool* vertical) { | |
| 639 SkScalar bottom = fBounds.fBottom; | |
| 640 *vertical = false; | |
| 641 if (bottom <= *bestY) { | |
| 642 return NULL; | |
| 643 } | |
| 644 SkScalar top = fBounds.fTop; | |
| 645 if (top >= basePt.fY) { | |
| 646 return NULL; | |
| 647 } | |
| 648 if (fBounds.fLeft > basePt.fX) { | |
| 649 return NULL; | |
| 650 } | |
| 651 if (fBounds.fRight < basePt.fX) { | |
| 652 return NULL; | |
| 653 } | |
| 654 if (fBounds.fLeft == fBounds.fRight) { | |
| 655 // if vertical, and directly above test point, wait for another one | |
| 656 *vertical = AlmostEqualUlps(basePt.fX, fBounds.fLeft); | |
| 657 return NULL; | |
| 658 } | |
| 659 // intersect ray starting at basePt with edge | |
| 660 SkIntersections intersections; | |
| 661 // OPTIMIZE: use specialty function that intersects ray with curve, | |
| 662 // returning t values only for curve (we don't care about t on ray) | |
| 663 intersections.allowNear(false); | |
| 664 int pts = (intersections.*CurveVertical[fVerb])(fPts, fWeight, top, bottom,
basePt.fX, false); | |
| 665 if (pts == 0 || (current && pts == 1)) { | |
| 666 return NULL; | |
| 667 } | |
| 668 if (current) { | |
| 669 SkASSERT(pts > 1); | |
| 670 int closestIdx = 0; | |
| 671 double closest = fabs(intersections[0][0] - mid); | |
| 672 for (int idx = 1; idx < pts; ++idx) { | |
| 673 double test = fabs(intersections[0][idx] - mid); | |
| 674 if (closest > test) { | |
| 675 closestIdx = idx; | |
| 676 closest = test; | |
| 677 } | |
| 678 } | |
| 679 intersections.quickRemoveOne(closestIdx, --pts); | |
| 680 } | |
| 681 double bestT = -1; | |
| 682 for (int index = 0; index < pts; ++index) { | |
| 683 double foundT = intersections[0][index]; | |
| 684 if (approximately_less_than_zero(foundT) | |
| 685 || approximately_greater_than_one(foundT)) { | |
| 686 continue; | |
| 687 } | |
| 688 SkScalar testY = (*CurvePointAtT[fVerb])(fPts, fWeight, foundT).fY; | |
| 689 if (approximately_negative(testY - *bestY) | |
| 690 || approximately_negative(basePt.fY - testY)) { | |
| 691 continue; | |
| 692 } | |
| 693 if (pts > 1 && fVerb == SkPath::kLine_Verb) { | |
| 694 *vertical = true; | |
| 695 return NULL; // if the intersection is edge on, wait for another on
e | |
| 696 } | |
| 697 if (fVerb > SkPath::kLine_Verb) { | |
| 698 SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, foundT).fX; | |
| 699 if (approximately_zero(dx)) { | |
| 700 *vertical = true; | |
| 701 return NULL; // hit vertical, wait for another one | |
| 702 } | |
| 703 } | |
| 704 *bestY = testY; | |
| 705 bestT = foundT; | |
| 706 } | |
| 707 if (bestT < 0) { | |
| 708 return NULL; | |
| 709 } | |
| 710 SkASSERT(bestT >= 0); | |
| 711 SkASSERT(bestT < 1); | |
| 712 SkOpSpanBase* testTSpanBase = &this->fHead; | |
| 713 SkOpSpanBase* nextTSpan; | |
| 714 double endT = 0; | |
| 715 do { | |
| 716 nextTSpan = testTSpanBase->upCast()->next(); | |
| 717 endT = nextTSpan->t(); | |
| 718 if (endT >= bestT) { | |
| 719 break; | |
| 720 } | |
| 721 testTSpanBase = nextTSpan; | |
| 722 } while (testTSpanBase); | |
| 723 SkOpSpan* bestTSpan = NULL; | |
| 724 SkOpSpan* testTSpan = testTSpanBase->upCast(); | |
| 725 if (!testTSpan->isCanceled()) { | |
| 726 *hitT = bestT; | |
| 727 bestTSpan = testTSpan; | |
| 728 *hitSomething = true; | |
| 729 } | |
| 730 return bestTSpan; | |
| 731 } | |
| 732 | |
| 733 void SkOpSegment::detach(const SkOpSpan* span) { | 495 void SkOpSegment::detach(const SkOpSpan* span) { |
| 734 if (span->done()) { | 496 if (span->done()) { |
| 735 --fDoneCount; | 497 --fDoneCount; |
| 736 } | 498 } |
| 737 --fCount; | 499 --fCount; |
| 738 SkASSERT(fCount >= fDoneCount); | 500 SkASSERT(fCount >= fDoneCount); |
| 739 } | 501 } |
| 740 | 502 |
| 741 double SkOpSegment::distSq(double t, SkOpAngle* oppAngle) { | 503 double SkOpSegment::distSq(double t, SkOpAngle* oppAngle) { |
| 742 SkDPoint testPt = this->dPtAtT(t); | 504 SkDPoint testPt = this->dPtAtT(t); |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1029 *nextStart = foundAngle->start(); | 791 *nextStart = foundAngle->start(); |
| 1030 *nextEnd = foundAngle->end(); | 792 *nextEnd = foundAngle->end(); |
| 1031 nextSegment = foundAngle->segment(); | 793 nextSegment = foundAngle->segment(); |
| 1032 #if DEBUG_WINDING | 794 #if DEBUG_WINDING |
| 1033 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", | 795 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", |
| 1034 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); | 796 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); |
| 1035 #endif | 797 #endif |
| 1036 return nextSegment; | 798 return nextSegment; |
| 1037 } | 799 } |
| 1038 | 800 |
| 1039 SkOpSegment* SkOpSegment::findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpS
panBase** endPtr, | |
| 1040 bool* unsortable, SkChunkAlloc* allocator) { | |
| 1041 // iterate through T intersections and return topmost | |
| 1042 // topmost tangent from y-min to first pt is closer to horizontal | |
| 1043 SkASSERT(!done()); | |
| 1044 SkOpSpanBase* firstT = NULL; | |
| 1045 (void) this->activeLeftTop(&firstT); | |
| 1046 if (!firstT) { | |
| 1047 *unsortable = !firstPass; | |
| 1048 firstT = &fHead; | |
| 1049 while (firstT->upCast()->done()) { | |
| 1050 firstT = firstT->upCast()->next(); | |
| 1051 } | |
| 1052 *startPtr = firstT; | |
| 1053 *endPtr = firstT->upCast()->next(); | |
| 1054 return this; | |
| 1055 } | |
| 1056 // sort the edges to find the leftmost | |
| 1057 int step = 1; | |
| 1058 SkOpSpanBase* end; | |
| 1059 if (firstT->final() || firstT->upCast()->done()) { | |
| 1060 step = -1; | |
| 1061 end = firstT->prev(); | |
| 1062 SkASSERT(end); | |
| 1063 } else { | |
| 1064 end = firstT->upCast()->next(); | |
| 1065 } | |
| 1066 // if the topmost T is not on end, or is three-way or more, find left | |
| 1067 // look for left-ness from tLeft to firstT (matching y of other) | |
| 1068 SkASSERT(firstT != end); | |
| 1069 SkOpAngle* markAngle = spanToAngle(firstT, end); | |
| 1070 if (!markAngle) { | |
| 1071 markAngle = addSingletonAngles(step, allocator); | |
| 1072 } | |
| 1073 if (!markAngle) { | |
| 1074 return NULL; | |
| 1075 } | |
| 1076 if (!markAngle->markStops()) { | |
| 1077 return NULL; | |
| 1078 } | |
| 1079 const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical()
? markAngle | |
| 1080 : markAngle->findFirst(); | |
| 1081 if (!baseAngle) { | |
| 1082 return NULL; // nothing to do | |
| 1083 } | |
| 1084 SkScalar top = SK_ScalarMax; | |
| 1085 const SkOpAngle* firstAngle = NULL; | |
| 1086 const SkOpAngle* angle = baseAngle; | |
| 1087 #if DEBUG_SWAP_TOP | |
| 1088 SkDebugf("-%s- baseAngle\n", __FUNCTION__); | |
| 1089 baseAngle->debugLoop(); | |
| 1090 #endif | |
| 1091 do { | |
| 1092 if (!angle->unorderable()) { | |
| 1093 const SkOpSegment* next = angle->segment(); | |
| 1094 SkPathOpsBounds bounds; | |
| 1095 next->subDivideBounds(angle->end(), angle->start(), &bounds); | |
| 1096 if (top > bounds.fTop) { | |
| 1097 top = bounds.fTop; | |
| 1098 firstAngle = angle; | |
| 1099 } | |
| 1100 } | |
| 1101 angle = angle->next(); | |
| 1102 } while (angle != baseAngle); | |
| 1103 if (!firstAngle) { | |
| 1104 return NULL; // if all are unorderable, give up | |
| 1105 } | |
| 1106 #if DEBUG_SWAP_TOP | |
| 1107 SkDebugf("-%s- firstAngle\n", __FUNCTION__); | |
| 1108 firstAngle->debugLoop(); | |
| 1109 #endif | |
| 1110 // skip edges that have already been processed | |
| 1111 angle = firstAngle; | |
| 1112 SkOpSegment* leftSegment = NULL; | |
| 1113 bool looped = false; | |
| 1114 do { | |
| 1115 *unsortable = angle->unorderable(); | |
| 1116 if (firstPass || !*unsortable) { | |
| 1117 leftSegment = angle->segment(); | |
| 1118 *startPtr = angle->end(); | |
| 1119 *endPtr = angle->start(); | |
| 1120 const SkOpSpan* firstSpan = (*startPtr)->starter(*endPtr); | |
| 1121 if (!firstSpan->done()) { | |
| 1122 break; | |
| 1123 } | |
| 1124 } | |
| 1125 angle = angle->next(); | |
| 1126 looped = true; | |
| 1127 } while (angle != firstAngle); | |
| 1128 if (angle == firstAngle && looped) { | |
| 1129 return NULL; | |
| 1130 } | |
| 1131 if (leftSegment->verb() >= SkPath::kQuad_Verb) { | |
| 1132 SkOpSpanBase* start = *startPtr; | |
| 1133 SkOpSpanBase* end = *endPtr; | |
| 1134 bool swap; | |
| 1135 bool cw = leftSegment->clockwise(start, end, &swap); | |
| 1136 #if DEBUG_SWAP_TOP | |
| 1137 SkDebugf("%s id=%d s=%1.9g e=%1.9g (%c) cw=%d swap=%d inflections=%d mon
otonic=%d\n", | |
| 1138 __FUNCTION__, leftSegment->debugID(), start->t(), end->t(), | |
| 1139 start->t() < end->t() ? '-' : '+', cw, | |
| 1140 swap, leftSegment->debugInflections(start, end), | |
| 1141 leftSegment->monotonicInY(start, end)); | |
| 1142 #endif | |
| 1143 if (!cw && swap) { | |
| 1144 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not t
he first | |
| 1145 // sorted but merely the first not already processed (i.e., not done) | |
| 1146 SkTSwap(*startPtr, *endPtr); | |
| 1147 } | |
| 1148 // FIXME: clockwise isn't reliable -- try computing swap from tangent ? | |
| 1149 } else { | |
| 1150 #if DEBUG_SWAP_TOP | |
| 1151 SkDebugf("%s id=%d s=%1.9g e=%1.9g (%c) cw=%d swap=%d inflections=%d mon
otonic=%d\n", | |
| 1152 __FUNCTION__, leftSegment->debugID(), (*startPtr)->t(), (*endPtr
)->t(), | |
| 1153 (*startPtr)->t() < (*endPtr)->t() ? '-' : '+', -1, -1, -1, 1); | |
| 1154 #endif | |
| 1155 } | |
| 1156 return leftSegment; | |
| 1157 } | |
| 1158 | |
| 1159 SkOpGlobalState* SkOpSegment::globalState() const { | 801 SkOpGlobalState* SkOpSegment::globalState() const { |
| 1160 return contour()->globalState(); | 802 return contour()->globalState(); |
| 1161 } | 803 } |
| 1162 | 804 |
| 1163 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP
ath::Verb verb) { | 805 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP
ath::Verb verb) { |
| 1164 fContour = contour; | 806 fContour = contour; |
| 1165 fNext = NULL; | 807 fNext = NULL; |
| 1166 fPts = pts; | 808 fPts = pts; |
| 1167 fWeight = weight; | 809 fWeight = weight; |
| 1168 fVerb = verb; | 810 fVerb = verb; |
| 1169 fCubicType = SkDCubic::kUnsplit_SkDCubicType; | 811 fCubicType = SkDCubic::kUnsplit_SkDCubicType; |
| 1170 fCount = 0; | 812 fCount = 0; |
| 1171 fDoneCount = 0; | 813 fDoneCount = 0; |
| 814 fTopsFound = false; |
| 1172 fVisited = false; | 815 fVisited = false; |
| 1173 SkOpSpan* zeroSpan = &fHead; | 816 SkOpSpan* zeroSpan = &fHead; |
| 1174 zeroSpan->init(this, NULL, 0, fPts[0]); | 817 zeroSpan->init(this, NULL, 0, fPts[0]); |
| 1175 SkOpSpanBase* oneSpan = &fTail; | 818 SkOpSpanBase* oneSpan = &fTail; |
| 1176 zeroSpan->setNext(oneSpan); | 819 zeroSpan->setNext(oneSpan); |
| 1177 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]); | 820 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]); |
| 1178 SkDEBUGCODE(fID = globalState()->nextSegmentID()); | 821 SkDEBUGCODE(fID = globalState()->nextSegmentID()); |
| 1179 } | 822 } |
| 1180 | 823 |
| 1181 void SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end, | |
| 1182 SkOpAngle::IncludeType angleIncludeType) { | |
| 1183 int local = SkOpSegment::SpanSign(start, end); | |
| 1184 SkDEBUGCODE(bool success); | |
| 1185 if (angleIncludeType == SkOpAngle::kBinarySingle) { | |
| 1186 int oppLocal = SkOpSegment::OppSign(start, end); | |
| 1187 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, oppLocal,
NULL); | |
| 1188 // OPTIMIZATION: the reverse mark and chase could skip the first marking | |
| 1189 SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, oppLocal,
NULL); | |
| 1190 } else { | |
| 1191 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, NULL); | |
| 1192 // OPTIMIZATION: the reverse mark and chase could skip the first marking | |
| 1193 SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, NULL); | |
| 1194 } | |
| 1195 SkASSERT(success); | |
| 1196 } | |
| 1197 | |
| 1198 /* | |
| 1199 when we start with a vertical intersect, we try to use the dx to determine if th
e edge is to | |
| 1200 the left or the right of vertical. This determines if we need to add the span's | |
| 1201 sign or not. However, this isn't enough. | |
| 1202 If the supplied sign (winding) is zero, then we didn't hit another vertical span
, so dx is needed. | |
| 1203 If there was a winding, then it may or may not need adjusting. If the span the w
inding was borrowed | |
| 1204 from has the same x direction as this span, the winding should change. If the dx
is opposite, then | |
| 1205 the same winding is shared by both. | |
| 1206 */ | |
| 1207 bool SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end, double tHi
t, | |
| 1208 int winding, SkScalar hitDx, int oppWind, SkScalar hitOppDx) { | |
| 1209 SkASSERT(this == start->segment()); | |
| 1210 SkASSERT(hitDx || !winding); | |
| 1211 SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, tHit).fX; | |
| 1212 // SkASSERT(dx); | |
| 1213 int windVal = start->starter(end)->windValue(); | |
| 1214 #if DEBUG_WINDING_AT_T | |
| 1215 SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, d
ebugID(), winding, | |
| 1216 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal); | |
| 1217 #endif | |
| 1218 int sideWind = winding + (dx < 0 ? windVal : -windVal); | |
| 1219 if (abs(winding) < abs(sideWind)) { | |
| 1220 winding = sideWind; | |
| 1221 } | |
| 1222 SkDEBUGCODE(int oppLocal = SkOpSegment::OppSign(start, end)); | |
| 1223 SkASSERT(hitOppDx || !oppWind || !oppLocal); | |
| 1224 int oppWindVal = start->starter(end)->oppValue(); | |
| 1225 if (!oppWind) { | |
| 1226 oppWind = dx < 0 ? oppWindVal : -oppWindVal; | |
| 1227 } else if (hitOppDx * dx >= 0) { | |
| 1228 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal); | |
| 1229 if (abs(oppWind) < abs(oppSideWind)) { | |
| 1230 oppWind = oppSideWind; | |
| 1231 } | |
| 1232 } | |
| 1233 #if DEBUG_WINDING_AT_T | |
| 1234 SkDebugf(" winding=%d oppWind=%d\n", winding, oppWind); | |
| 1235 #endif | |
| 1236 // if this fails to mark (because the edges are too small) inform caller to
try again | |
| 1237 bool success = markAndChaseWinding(start, end, winding, oppWind, NULL); | |
| 1238 // OPTIMIZATION: the reverse mark and chase could skip the first marking | |
| 1239 success |= markAndChaseWinding(end, start, winding, oppWind, NULL); | |
| 1240 return success; | |
| 1241 } | |
| 1242 | |
| 1243 bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const { | 824 bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const { |
| 1244 SkDPoint cPt = this->dPtAtT(t); | 825 SkDPoint cPt = this->dPtAtT(t); |
| 1245 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight()
, t); | 826 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight()
, t); |
| 1246 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; | 827 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; |
| 1247 SkIntersections i; | 828 SkIntersections i; |
| 1248 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i); | 829 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i); |
| 1249 int used = i.used(); | 830 int used = i.used(); |
| 1250 for (int index = 0; index < used; ++index) { | 831 for (int index = 0; index < used; ++index) { |
| 1251 if (cPt.roughlyEqual(i.pt(index))) { | 832 if (cPt.roughlyEqual(i.pt(index))) { |
| 1252 return true; | 833 return true; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1299 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, | 880 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, |
| 1300 int winding, int oppWinding, SkOpSpanBase** lastPtr) { | 881 int winding, int oppWinding, SkOpSpanBase** lastPtr) { |
| 1301 SkOpSpan* spanStart = start->starter(end); | 882 SkOpSpan* spanStart = start->starter(end); |
| 1302 int step = start->step(end); | 883 int step = start->step(end); |
| 1303 bool success = markWinding(spanStart, winding, oppWinding); | 884 bool success = markWinding(spanStart, winding, oppWinding); |
| 1304 SkOpSpanBase* last = NULL; | 885 SkOpSpanBase* last = NULL; |
| 1305 SkOpSegment* other = this; | 886 SkOpSegment* other = this; |
| 1306 while ((other = other->nextChase(&start, &step, &spanStart, &last))) { | 887 while ((other = other->nextChase(&start, &step, &spanStart, &last))) { |
| 1307 if (spanStart->windSum() != SK_MinS32) { | 888 if (spanStart->windSum() != SK_MinS32) { |
| 1308 if (this->operand() == other->operand()) { | 889 if (this->operand() == other->operand()) { |
| 1309 SkASSERT(spanStart->windSum() == winding); | 890 if (spanStart->windSum() != winding || spanStart->oppSum() != op
pWinding) { |
| 1310 if (spanStart->oppSum() != oppWinding) { | |
| 1311 this->globalState()->setWindingFailed(); | 891 this->globalState()->setWindingFailed(); |
| 1312 return false; | 892 return false; |
| 1313 } | 893 } |
| 1314 } else { | 894 } else { |
| 1315 SkASSERT(spanStart->windSum() == oppWinding); | 895 SkASSERT(spanStart->windSum() == oppWinding); |
| 1316 SkASSERT(spanStart->oppSum() == winding); | 896 SkASSERT(spanStart->oppSum() == winding); |
| 1317 } | 897 } |
| 1318 SkASSERT(!last); | 898 SkASSERT(!last); |
| 1319 break; | 899 break; |
| 1320 } | 900 } |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1431 return !this->ptsDisjoint(base->fT, base->fPt, testT, testPt); | 1011 return !this->ptsDisjoint(base->fT, base->fPt, testT, testPt); |
| 1432 } | 1012 } |
| 1433 | 1013 |
| 1434 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) { | 1014 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) { |
| 1435 if (last) { | 1015 if (last) { |
| 1436 *last = endSpan; | 1016 *last = endSpan; |
| 1437 } | 1017 } |
| 1438 return NULL; | 1018 return NULL; |
| 1439 } | 1019 } |
| 1440 | 1020 |
| 1441 bool SkOpSegment::monotonicInY(const SkOpSpanBase* start, const SkOpSpanBase* en
d) const { | |
| 1442 SkASSERT(fVerb != SkPath::kLine_Verb); | |
| 1443 if (fVerb == SkPath::kQuad_Verb) { | |
| 1444 SkDQuad dst = SkDQuad::SubDivide(fPts, start->t(), end->t()); | |
| 1445 return dst.monotonicInY(); | |
| 1446 } | |
| 1447 if (fVerb == SkPath::kConic_Verb) { | |
| 1448 SkDConic dst = SkDConic::SubDivide(fPts, fWeight, start->t(), end->t()); | |
| 1449 return dst.monotonicInY(); | |
| 1450 } | |
| 1451 SkASSERT(fVerb == SkPath::kCubic_Verb); | |
| 1452 SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t()); | |
| 1453 if (dst.monotonicInY()) { | |
| 1454 return true; | |
| 1455 } | |
| 1456 SkDCubic whole; | |
| 1457 whole.set(fPts); | |
| 1458 return whole.monotonicInY(); | |
| 1459 } | |
| 1460 | |
| 1461 bool SkOpSegment::NextCandidate(SkOpSpanBase* span, SkOpSpanBase** start, | |
| 1462 SkOpSpanBase** end) { | |
| 1463 while (span->final() || span->upCast()->done()) { | |
| 1464 if (span->final()) { | |
| 1465 return false; | |
| 1466 } | |
| 1467 span = span->upCast()->next(); | |
| 1468 } | |
| 1469 *start = span; | |
| 1470 *end = span->upCast()->next(); | |
| 1471 return true; | |
| 1472 } | |
| 1473 | |
| 1474 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS
pan** minPtr, | 1021 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS
pan** minPtr, |
| 1475 SkOpSpanBase** last) const { | 1022 SkOpSpanBase** last) const { |
| 1476 SkOpSpanBase* origStart = *startPtr; | 1023 SkOpSpanBase* origStart = *startPtr; |
| 1477 int step = *stepPtr; | 1024 int step = *stepPtr; |
| 1478 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->
prev(); | 1025 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->
prev(); |
| 1479 SkASSERT(endSpan); | 1026 SkASSERT(endSpan); |
| 1480 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAn
gle(); | 1027 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAn
gle(); |
| 1481 SkOpSpanBase* foundSpan; | 1028 SkOpSpanBase* foundSpan; |
| 1482 SkOpSpanBase* otherEnd; | 1029 SkOpSpanBase* otherEnd; |
| 1483 SkOpSegment* other; | 1030 SkOpSegment* other; |
| 1484 if (angle == NULL) { | 1031 if (angle == NULL) { |
| 1485 if (endSpan->t() != 0 && endSpan->t() != 1) { | 1032 if (endSpan->t() != 0 && endSpan->t() != 1) { |
| 1486 return NULL; | 1033 return NULL; |
| 1487 } | 1034 } |
| 1488 SkOpPtT* otherPtT = endSpan->ptT()->next(); | 1035 SkOpPtT* otherPtT = endSpan->ptT()->next(); |
| 1489 other = otherPtT->segment(); | 1036 other = otherPtT->segment(); |
| 1490 foundSpan = otherPtT->span(); | 1037 foundSpan = otherPtT->span(); |
| 1491 otherEnd = step > 0 ? foundSpan->upCast()->next() : foundSpan->prev(); | 1038 otherEnd = step > 0 ? foundSpan->upCast()->next() : foundSpan->prev(); |
| 1492 } else { | 1039 } else { |
| 1493 int loopCount = angle->loopCount(); | 1040 int loopCount = angle->loopCount(); |
| 1494 if (loopCount > 2) { | 1041 if (loopCount > 2) { |
| 1495 return set_last(last, endSpan); | 1042 return set_last(last, endSpan); |
| 1496 } | 1043 } |
| 1497 const SkOpAngle* next = angle->next(); | 1044 const SkOpAngle* next = angle->next(); |
| 1498 if (NULL == next) { | 1045 if (NULL == next) { |
| 1499 return NULL; | 1046 return NULL; |
| 1500 } | 1047 } |
| 1501 #if DEBUG_WINDING | 1048 #if DEBUG_WINDING |
| 1502 if (angle->sign() != next->sign() && !angle->segment()->contour()->isXor
() | 1049 if (angle->debugSign() != next->debugSign() && !angle->segment()->contou
r()->isXor() |
| 1503 && !next->segment()->contour()->isXor()) { | 1050 && !next->segment()->contour()->isXor()) { |
| 1504 SkDebugf("%s mismatched signs\n", __FUNCTION__); | 1051 SkDebugf("%s mismatched signs\n", __FUNCTION__); |
| 1505 } | 1052 } |
| 1506 #endif | 1053 #endif |
| 1507 other = next->segment(); | 1054 other = next->segment(); |
| 1508 foundSpan = endSpan = next->start(); | 1055 foundSpan = endSpan = next->start(); |
| 1509 otherEnd = next->end(); | 1056 otherEnd = next->end(); |
| 1510 } | 1057 } |
| 1511 int foundStep = foundSpan->step(otherEnd); | 1058 int foundStep = foundSpan->step(otherEnd); |
| 1512 if (*stepPtr != foundStep) { | 1059 if (*stepPtr != foundStep) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1551 if (this->verb() != SkPath::kLine_Verb) { | 1098 if (this->verb() != SkPath::kLine_Verb) { |
| 1552 return; | 1099 return; |
| 1553 } | 1100 } |
| 1554 SkOpSpan* prior = NULL; | 1101 SkOpSpan* prior = NULL; |
| 1555 SkOpSpan* span = &fHead; | 1102 SkOpSpan* span = &fHead; |
| 1556 do { | 1103 do { |
| 1557 SkOpPtT* ptT = span->ptT(), * spanStopPtT = ptT; | 1104 SkOpPtT* ptT = span->ptT(), * spanStopPtT = ptT; |
| 1558 SkASSERT(ptT->span() == span); | 1105 SkASSERT(ptT->span() == span); |
| 1559 while ((ptT = ptT->next()) != spanStopPtT) { | 1106 while ((ptT = ptT->next()) != spanStopPtT) { |
| 1560 SkOpSegment* opp = ptT->span()->segment(); | 1107 SkOpSegment* opp = ptT->span()->segment(); |
| 1561 if (opp->setVisited()) { | 1108 if (!opp->setVisited()) { |
| 1562 continue; | 1109 continue; |
| 1563 } | 1110 } |
| 1564 if (opp->verb() == SkPath::kLine_Verb) { | 1111 if (opp->verb() == SkPath::kLine_Verb) { |
| 1565 continue; | 1112 continue; |
| 1566 } | 1113 } |
| 1567 if (span->containsCoincidence(opp)) { // FIXME: this assumes that if
the opposite | 1114 if (span->containsCoincidence(opp)) { // FIXME: this assumes that if
the opposite |
| 1568 // segment is coincident then
no more coincidence | 1115 // segment is coincident then
no more coincidence |
| 1569 // needs to be detected. This
may not be true. | 1116 // needs to be detected. This
may not be true. |
| 1570 continue; | 1117 continue; |
| 1571 } | 1118 } |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2017 } else if (fVerb == SkPath::kConic_Verb) { | 1564 } else if (fVerb == SkPath::kConic_Verb) { |
| 2018 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edg
e->fQuad[2], | 1565 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edg
e->fQuad[2], |
| 2019 startT, endT, &edge->fConic.fWeight); | 1566 startT, endT, &edge->fConic.fWeight); |
| 2020 } else { | 1567 } else { |
| 2021 SkASSERT(fVerb == SkPath::kCubic_Verb); | 1568 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 2022 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT
, &edge->fCubic[1]); | 1569 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT
, &edge->fCubic[1]); |
| 2023 } | 1570 } |
| 2024 return true; | 1571 return true; |
| 2025 } | 1572 } |
| 2026 | 1573 |
| 2027 void SkOpSegment::subDivideBounds(const SkOpSpanBase* start, const SkOpSpanBase*
end, | |
| 2028 SkPathOpsBounds* bounds) const { | |
| 2029 SkDCurve edge; | |
| 2030 subDivide(start, end, &edge); | |
| 2031 (edge.*SetBounds[fVerb])(fPts, fWeight, start->t(), end->t(), bounds); | |
| 2032 } | |
| 2033 | |
| 2034 SkDPoint SkOpSegment::top(const SkOpSpanBase* start, const SkOpSpanBase* end, do
uble* topT) const { | |
| 2035 SkDCurve edge; | |
| 2036 subDivide(start, end, &edge); | |
| 2037 return (edge.*Top[fVerb])(fPts, fWeight, start->t(), end->t(), topT); | |
| 2038 } | |
| 2039 | |
| 2040 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) { | 1574 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) { |
| 2041 SkOpSpan* span = this->head(); | 1575 SkOpSpan* span = this->head(); |
| 2042 do { | 1576 do { |
| 2043 if (!span->done()) { | 1577 if (!span->done()) { |
| 2044 break; | 1578 break; |
| 2045 } | 1579 } |
| 2046 } while ((span = span->next()->upCastable())); | 1580 } while ((span = span->next()->upCastable())); |
| 2047 SkASSERT(span); | 1581 SkASSERT(span); |
| 2048 *start = span; | 1582 *start = span; |
| 2049 *end = span->next(); | 1583 *end = span->next(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2065 const SkOpSpanBase* endSpan = angle->end(); | 1599 const SkOpSpanBase* endSpan = angle->end(); |
| 2066 return updateOppWinding(endSpan, startSpan); | 1600 return updateOppWinding(endSpan, startSpan); |
| 2067 } | 1601 } |
| 2068 | 1602 |
| 2069 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const { | 1603 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const { |
| 2070 const SkOpSpanBase* startSpan = angle->start(); | 1604 const SkOpSpanBase* startSpan = angle->start(); |
| 2071 const SkOpSpanBase* endSpan = angle->end(); | 1605 const SkOpSpanBase* endSpan = angle->end(); |
| 2072 return updateOppWinding(startSpan, endSpan); | 1606 return updateOppWinding(startSpan, endSpan); |
| 2073 } | 1607 } |
| 2074 | 1608 |
| 2075 int SkOpSegment::updateWinding(const SkOpSpanBase* start, const SkOpSpanBase* en
d) const { | 1609 int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) { |
| 2076 const SkOpSpan* lesser = start->starter(end); | 1610 SkOpSpan* lesser = start->starter(end); |
| 2077 int winding = lesser->windSum(); | 1611 int winding = lesser->windSum(); |
| 2078 if (winding == SK_MinS32) { | 1612 if (winding == SK_MinS32) { |
| 1613 SkOpGlobalState* globals = this->globalState(); |
| 1614 SkOpContour* contourHead = globals->contourHead(); |
| 1615 int windTry = 0; |
| 1616 while (!lesser->sortableTop(contourHead) && ++windTry < SkOpGlobalState:
:kMaxWindingTries) { |
| 1617 ; |
| 1618 } |
| 1619 winding = lesser->windSum(); |
| 1620 } |
| 1621 if (winding == SK_MinS32) { |
| 2079 return winding; | 1622 return winding; |
| 2080 } | 1623 } |
| 2081 int spanWinding = SkOpSegment::SpanSign(start, end); | 1624 int spanWinding = SkOpSegment::SpanSign(start, end); |
| 2082 if (winding && UseInnerWinding(winding - spanWinding, winding) | 1625 if (winding && UseInnerWinding(winding - spanWinding, winding) |
| 2083 && winding != SK_MaxS32) { | 1626 && winding != SK_MaxS32) { |
| 2084 winding -= spanWinding; | 1627 winding -= spanWinding; |
| 2085 } | 1628 } |
| 2086 return winding; | 1629 return winding; |
| 2087 } | 1630 } |
| 2088 | 1631 |
| 2089 int SkOpSegment::updateWinding(const SkOpAngle* angle) const { | 1632 int SkOpSegment::updateWinding(SkOpAngle* angle) { |
| 2090 const SkOpSpanBase* startSpan = angle->start(); | 1633 SkOpSpanBase* startSpan = angle->start(); |
| 2091 const SkOpSpanBase* endSpan = angle->end(); | 1634 SkOpSpanBase* endSpan = angle->end(); |
| 2092 return updateWinding(endSpan, startSpan); | 1635 return updateWinding(endSpan, startSpan); |
| 2093 } | 1636 } |
| 2094 | 1637 |
| 2095 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const { | 1638 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) { |
| 2096 const SkOpSpanBase* startSpan = angle->start(); | 1639 SkOpSpanBase* startSpan = angle->start(); |
| 2097 const SkOpSpanBase* endSpan = angle->end(); | 1640 SkOpSpanBase* endSpan = angle->end(); |
| 2098 return updateWinding(startSpan, endSpan); | 1641 return updateWinding(startSpan, endSpan); |
| 2099 } | 1642 } |
| 2100 | 1643 |
| 2101 // OPTIMIZATION: does the following also work, and is it any faster? | 1644 // OPTIMIZATION: does the following also work, and is it any faster? |
| 2102 // return outerWinding * innerWinding > 0 | 1645 // return outerWinding * innerWinding > 0 |
| 2103 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) <
0))) | 1646 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) <
0))) |
| 2104 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) { | 1647 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) { |
| 2105 SkASSERT(outerWinding != SK_MaxS32); | 1648 SkASSERT(outerWinding != SK_MaxS32); |
| 2106 SkASSERT(innerWinding != SK_MaxS32); | 1649 SkASSERT(innerWinding != SK_MaxS32); |
| 2107 int absOut = abs(outerWinding); | 1650 int absOut = abs(outerWinding); |
| 2108 int absIn = abs(innerWinding); | 1651 int absIn = abs(innerWinding); |
| 2109 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; | 1652 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; |
| 2110 return result; | 1653 return result; |
| 2111 } | 1654 } |
| 2112 | 1655 |
| 2113 int SkOpSegment::windingAtT(double tHit, const SkOpSpan* span, bool crossOpp, | |
| 2114 SkScalar* dx) const { | |
| 2115 if (approximately_zero(tHit - span->t())) { // if we hit the end of a span,
disregard | |
| 2116 return SK_MinS32; | |
| 2117 } | |
| 2118 int winding = crossOpp ? span->oppSum() : span->windSum(); | |
| 2119 SkASSERT(winding != SK_MinS32); | |
| 2120 int windVal = crossOpp ? span->oppValue() : span->windValue(); | |
| 2121 #if DEBUG_WINDING_AT_T | |
| 2122 SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __
FUNCTION__, | |
| 2123 debugID(), crossOpp, tHit, span->t(), winding, windVal); | |
| 2124 #endif | |
| 2125 // see if a + change in T results in a +/- change in X (compute x'(T)) | |
| 2126 *dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, tHit).fX; | |
| 2127 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) { | |
| 2128 *dx = fPts[2].fX - fPts[1].fX - *dx; | |
| 2129 } | |
| 2130 if (*dx == 0) { | |
| 2131 #if DEBUG_WINDING_AT_T | |
| 2132 SkDebugf(" dx=0 winding=SK_MinS32\n"); | |
| 2133 #endif | |
| 2134 return SK_MinS32; | |
| 2135 } | |
| 2136 if (windVal < 0) { // reverse sign if opp contour traveled in reverse | |
| 2137 *dx = -*dx; | |
| 2138 } | |
| 2139 if (winding * *dx > 0) { // if same signs, result is negative | |
| 2140 winding += *dx > 0 ? -windVal : windVal; | |
| 2141 } | |
| 2142 #if DEBUG_WINDING_AT_T | |
| 2143 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding); | |
| 2144 #endif | |
| 2145 return winding; | |
| 2146 } | |
| 2147 | |
| 2148 int SkOpSegment::windSum(const SkOpAngle* angle) const { | 1656 int SkOpSegment::windSum(const SkOpAngle* angle) const { |
| 2149 const SkOpSpan* minSpan = angle->start()->starter(angle->end()); | 1657 const SkOpSpan* minSpan = angle->start()->starter(angle->end()); |
| 2150 return minSpan->windSum(); | 1658 return minSpan->windSum(); |
| 2151 } | 1659 } |
| OLD | NEW |