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 |