OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2008 The Android Open Source Project | 2 * Copyright 2008 The Android Open Source Project |
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 | 7 |
8 #include "SkStrokerPriv.h" | 8 #include "SkStrokerPriv.h" |
9 #include "SkGeometry.h" | 9 #include "SkGeometry.h" |
10 #include "SkPathPriv.h" | 10 #include "SkPathPriv.h" |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 fOuter.close(); | 289 fOuter.close(); |
290 // now add fInner as its own contour | 290 // now add fInner as its own contour |
291 fInner.getLastPt(&pt); | 291 fInner.getLastPt(&pt); |
292 fOuter.moveTo(pt.fX, pt.fY); | 292 fOuter.moveTo(pt.fX, pt.fY); |
293 fOuter.reversePathTo(fInner); | 293 fOuter.reversePathTo(fInner); |
294 fOuter.close(); | 294 fOuter.close(); |
295 } else { // add caps to start and end | 295 } else { // add caps to start and end |
296 // cap the end | 296 // cap the end |
297 fInner.getLastPt(&pt); | 297 fInner.getLastPt(&pt); |
298 fCapper(&fOuter, fPrevPt, fPrevNormal, pt, | 298 fCapper(&fOuter, fPrevPt, fPrevNormal, pt, |
299 currIsLine ? &fInner : NULL); | 299 currIsLine ? &fInner : nullptr); |
300 fOuter.reversePathTo(fInner); | 300 fOuter.reversePathTo(fInner); |
301 // cap the start | 301 // cap the start |
302 fCapper(&fOuter, fFirstPt, -fFirstNormal, fFirstOuterPt, | 302 fCapper(&fOuter, fFirstPt, -fFirstNormal, fFirstOuterPt, |
303 fPrevIsLine ? &fInner : NULL); | 303 fPrevIsLine ? &fInner : nullptr); |
304 fOuter.close(); | 304 fOuter.close(); |
305 } | 305 } |
306 } | 306 } |
307 // since we may re-use fInner, we rewind instead of reset, to save on | 307 // since we may re-use fInner, we rewind instead of reset, to save on |
308 // reallocating its internal storage. | 308 // reallocating its internal storage. |
309 fInner.rewind(); | 309 fInner.rewind(); |
310 fSegmentCount = -1; | 310 fSegmentCount = -1; |
311 } | 311 } |
312 | 312 |
313 /////////////////////////////////////////////////////////////////////////////// | 313 /////////////////////////////////////////////////////////////////////////////// |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 *tangentPtPtr = degenerateAB ? &cubic[2] : &cubic[1]; | 546 *tangentPtPtr = degenerateAB ? &cubic[2] : &cubic[1]; |
547 return kQuad_ReductionType; | 547 return kQuad_ReductionType; |
548 } | 548 } |
549 SkScalar tValues[3]; | 549 SkScalar tValues[3]; |
550 int count = SkFindCubicMaxCurvature(cubic, tValues); | 550 int count = SkFindCubicMaxCurvature(cubic, tValues); |
551 if (count == 0) { | 551 if (count == 0) { |
552 return kLine_ReductionType; | 552 return kLine_ReductionType; |
553 } | 553 } |
554 for (int index = 0; index < count; ++index) { | 554 for (int index = 0; index < count; ++index) { |
555 SkScalar t = tValues[index]; | 555 SkScalar t = tValues[index]; |
556 SkEvalCubicAt(cubic, t, &reduction[index], NULL, NULL); | 556 SkEvalCubicAt(cubic, t, &reduction[index], nullptr, nullptr); |
557 } | 557 } |
558 static_assert(kQuad_ReductionType + 1 == kDegenerate_ReductionType, "enum_ou
t_of_whack"); | 558 static_assert(kQuad_ReductionType + 1 == kDegenerate_ReductionType, "enum_ou
t_of_whack"); |
559 static_assert(kQuad_ReductionType + 2 == kDegenerate2_ReductionType, "enum_o
ut_of_whack"); | 559 static_assert(kQuad_ReductionType + 2 == kDegenerate2_ReductionType, "enum_o
ut_of_whack"); |
560 static_assert(kQuad_ReductionType + 3 == kDegenerate3_ReductionType, "enum_o
ut_of_whack"); | 560 static_assert(kQuad_ReductionType + 3 == kDegenerate3_ReductionType, "enum_o
ut_of_whack"); |
561 | 561 |
562 return (ReductionType) (kQuad_ReductionType + count); | 562 return (ReductionType) (kQuad_ReductionType + count); |
563 } | 563 } |
564 | 564 |
565 SkPathStroker::ReductionType SkPathStroker::CheckConicLinear(const SkConic& coni
c, | 565 SkPathStroker::ReductionType SkPathStroker::CheckConicLinear(const SkConic& coni
c, |
566 SkPoint* reduction) { | 566 SkPoint* reduction) { |
(...skipping 15 matching lines...) Expand all Loading... |
582 } | 582 } |
583 #else // but for now, use extrema instead | 583 #else // but for now, use extrema instead |
584 SkScalar xT = 0, yT = 0; | 584 SkScalar xT = 0, yT = 0; |
585 (void) conic.findXExtrema(&xT); | 585 (void) conic.findXExtrema(&xT); |
586 (void) conic.findYExtrema(&yT); | 586 (void) conic.findYExtrema(&yT); |
587 SkScalar t = SkTMax(xT, yT); | 587 SkScalar t = SkTMax(xT, yT); |
588 if (0 == t) { | 588 if (0 == t) { |
589 return kLine_ReductionType; | 589 return kLine_ReductionType; |
590 } | 590 } |
591 #endif | 591 #endif |
592 conic.evalAt(t, reduction, NULL); | 592 conic.evalAt(t, reduction, nullptr); |
593 return kDegenerate_ReductionType; | 593 return kDegenerate_ReductionType; |
594 } | 594 } |
595 | 595 |
596 SkPathStroker::ReductionType SkPathStroker::CheckQuadLinear(const SkPoint quad[3
], | 596 SkPathStroker::ReductionType SkPathStroker::CheckQuadLinear(const SkPoint quad[3
], |
597 SkPoint* reduction) { | 597 SkPoint* reduction) { |
598 bool degenerateAB = degenerate_vector(quad[1] - quad[0]); | 598 bool degenerateAB = degenerate_vector(quad[1] - quad[0]); |
599 bool degenerateBC = degenerate_vector(quad[2] - quad[1]); | 599 bool degenerateBC = degenerate_vector(quad[2] - quad[1]); |
600 if (degenerateAB & degenerateBC) { | 600 if (degenerateAB & degenerateBC) { |
601 return kPoint_ReductionType; | 601 return kPoint_ReductionType; |
602 } | 602 } |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
731 quadPts->fEndSet = true; | 731 quadPts->fEndSet = true; |
732 } | 732 } |
733 } | 733 } |
734 | 734 |
735 | 735 |
736 // Given a cubic and t, return the point on curve, its perpendicular, and the pe
rpendicular tangent. | 736 // Given a cubic and t, return the point on curve, its perpendicular, and the pe
rpendicular tangent. |
737 // Returns false if the perpendicular could not be computed (because the derivat
ive collapsed to 0) | 737 // Returns false if the perpendicular could not be computed (because the derivat
ive collapsed to 0) |
738 bool SkPathStroker::cubicPerpRay(const SkPoint cubic[4], SkScalar t, SkPoint* tP
t, SkPoint* onPt, | 738 bool SkPathStroker::cubicPerpRay(const SkPoint cubic[4], SkScalar t, SkPoint* tP
t, SkPoint* onPt, |
739 SkPoint* tangent) const { | 739 SkPoint* tangent) const { |
740 SkVector dxy; | 740 SkVector dxy; |
741 SkEvalCubicAt(cubic, t, tPt, &dxy, NULL); | 741 SkEvalCubicAt(cubic, t, tPt, &dxy, nullptr); |
742 if (dxy.fX == 0 && dxy.fY == 0) { | 742 if (dxy.fX == 0 && dxy.fY == 0) { |
743 if (SkScalarNearlyZero(t)) { | 743 if (SkScalarNearlyZero(t)) { |
744 dxy = cubic[2] - cubic[0]; | 744 dxy = cubic[2] - cubic[0]; |
745 } else if (SkScalarNearlyZero(1 - t)) { | 745 } else if (SkScalarNearlyZero(1 - t)) { |
746 dxy = cubic[3] - cubic[1]; | 746 dxy = cubic[3] - cubic[1]; |
747 } else { | 747 } else { |
748 return false; | 748 return false; |
749 } | 749 } |
750 if (dxy.fX == 0 && dxy.fY == 0) { | 750 if (dxy.fX == 0 && dxy.fY == 0) { |
751 dxy = cubic[3] - cubic[0]; | 751 dxy = cubic[3] - cubic[0]; |
(...skipping 20 matching lines...) Expand all Loading... |
772 return false; | 772 return false; |
773 } | 773 } |
774 quadPts->fEndSet = true; | 774 quadPts->fEndSet = true; |
775 } | 775 } |
776 return true; | 776 return true; |
777 } | 777 } |
778 | 778 |
779 bool SkPathStroker::cubicQuadMid(const SkPoint cubic[4], const SkQuadConstruct*
quadPts, | 779 bool SkPathStroker::cubicQuadMid(const SkPoint cubic[4], const SkQuadConstruct*
quadPts, |
780 SkPoint* mid) const { | 780 SkPoint* mid) const { |
781 SkPoint cubicMidPt; | 781 SkPoint cubicMidPt; |
782 return this->cubicPerpRay(cubic, quadPts->fMidT, &cubicMidPt, mid, NULL); | 782 return this->cubicPerpRay(cubic, quadPts->fMidT, &cubicMidPt, mid, nullptr); |
783 } | 783 } |
784 | 784 |
785 // Given a quad and t, return the point on curve, its perpendicular, and the per
pendicular tangent. | 785 // Given a quad and t, return the point on curve, its perpendicular, and the per
pendicular tangent. |
786 void SkPathStroker::quadPerpRay(const SkPoint quad[3], SkScalar t, SkPoint* tPt,
SkPoint* onPt, | 786 void SkPathStroker::quadPerpRay(const SkPoint quad[3], SkScalar t, SkPoint* tPt,
SkPoint* onPt, |
787 SkPoint* tangent) const { | 787 SkPoint* tangent) const { |
788 SkVector dxy; | 788 SkVector dxy; |
789 SkEvalQuadAt(quad, t, tPt, &dxy); | 789 SkEvalQuadAt(quad, t, tPt, &dxy); |
790 if (dxy.fX == 0 && dxy.fY == 0) { | 790 if (dxy.fX == 0 && dxy.fY == 0) { |
791 dxy = quad[2] - quad[0]; | 791 dxy = quad[2] - quad[0]; |
792 } | 792 } |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
969 if (!this->cubicQuadEnds(cubic, quadPts)) { | 969 if (!this->cubicQuadEnds(cubic, quadPts)) { |
970 return kNormalError_ResultType; | 970 return kNormalError_ResultType; |
971 } | 971 } |
972 ResultType resultType = this->intersectRay(quadPts, kCtrlPt_RayType | 972 ResultType resultType = this->intersectRay(quadPts, kCtrlPt_RayType |
973 STROKER_DEBUG_PARAMS(fRecursionDepth) ); | 973 STROKER_DEBUG_PARAMS(fRecursionDepth) ); |
974 if (resultType != kQuad_ResultType) { | 974 if (resultType != kQuad_ResultType) { |
975 return resultType; | 975 return resultType; |
976 } | 976 } |
977 // project a ray from the curve to the stroke | 977 // project a ray from the curve to the stroke |
978 SkPoint ray[2]; // points near midpoint on quad, midpoint on cubic | 978 SkPoint ray[2]; // points near midpoint on quad, midpoint on cubic |
979 if (!this->cubicPerpRay(cubic, quadPts->fMidT, &ray[1], &ray[0], NULL)) { | 979 if (!this->cubicPerpRay(cubic, quadPts->fMidT, &ray[1], &ray[0], nullptr)) { |
980 return kNormalError_ResultType; | 980 return kNormalError_ResultType; |
981 } | 981 } |
982 return this->strokeCloseEnough(quadPts->fQuad, ray, quadPts | 982 return this->strokeCloseEnough(quadPts->fQuad, ray, quadPts |
983 STROKER_DEBUG_PARAMS(fRecursionDepth)); | 983 STROKER_DEBUG_PARAMS(fRecursionDepth)); |
984 } | 984 } |
985 | 985 |
986 SkPathStroker::ResultType SkPathStroker::compareQuadConic(const SkConic& conic, | 986 SkPathStroker::ResultType SkPathStroker::compareQuadConic(const SkConic& conic, |
987 SkQuadConstruct* quadPts) const { | 987 SkQuadConstruct* quadPts) const { |
988 // get the quadratic approximation of the stroke | 988 // get the quadratic approximation of the stroke |
989 this->conicQuadEnds(conic, quadPts); | 989 this->conicQuadEnds(conic, quadPts); |
990 ResultType resultType = this->intersectRay(quadPts, kCtrlPt_RayType | 990 ResultType resultType = this->intersectRay(quadPts, kCtrlPt_RayType |
991 STROKER_DEBUG_PARAMS(fRecursionDepth) ); | 991 STROKER_DEBUG_PARAMS(fRecursionDepth) ); |
992 if (resultType != kQuad_ResultType) { | 992 if (resultType != kQuad_ResultType) { |
993 return resultType; | 993 return resultType; |
994 } | 994 } |
995 // project a ray from the curve to the stroke | 995 // project a ray from the curve to the stroke |
996 SkPoint ray[2]; // points near midpoint on quad, midpoint on conic | 996 SkPoint ray[2]; // points near midpoint on quad, midpoint on conic |
997 this->conicPerpRay(conic, quadPts->fMidT, &ray[1], &ray[0], NULL); | 997 this->conicPerpRay(conic, quadPts->fMidT, &ray[1], &ray[0], nullptr); |
998 return this->strokeCloseEnough(quadPts->fQuad, ray, quadPts | 998 return this->strokeCloseEnough(quadPts->fQuad, ray, quadPts |
999 STROKER_DEBUG_PARAMS(fRecursionDepth)); | 999 STROKER_DEBUG_PARAMS(fRecursionDepth)); |
1000 } | 1000 } |
1001 | 1001 |
1002 SkPathStroker::ResultType SkPathStroker::compareQuadQuad(const SkPoint quad[3], | 1002 SkPathStroker::ResultType SkPathStroker::compareQuadQuad(const SkPoint quad[3], |
1003 SkQuadConstruct* quadPts) { | 1003 SkQuadConstruct* quadPts) { |
1004 // get the quadratic approximation of the stroke | 1004 // get the quadratic approximation of the stroke |
1005 if (!quadPts->fStartSet) { | 1005 if (!quadPts->fStartSet) { |
1006 SkPoint quadStartPt; | 1006 SkPoint quadStartPt; |
1007 this->quadPerpRay(quad, quadPts->fStartT, &quadStartPt, &quadPts->fQuad[
0], | 1007 this->quadPerpRay(quad, quadPts->fStartT, &quadStartPt, &quadPts->fQuad[
0], |
1008 &quadPts->fTangentStart); | 1008 &quadPts->fTangentStart); |
1009 quadPts->fStartSet = true; | 1009 quadPts->fStartSet = true; |
1010 } | 1010 } |
1011 if (!quadPts->fEndSet) { | 1011 if (!quadPts->fEndSet) { |
1012 SkPoint quadEndPt; | 1012 SkPoint quadEndPt; |
1013 this->quadPerpRay(quad, quadPts->fEndT, &quadEndPt, &quadPts->fQuad[2], | 1013 this->quadPerpRay(quad, quadPts->fEndT, &quadEndPt, &quadPts->fQuad[2], |
1014 &quadPts->fTangentEnd); | 1014 &quadPts->fTangentEnd); |
1015 quadPts->fEndSet = true; | 1015 quadPts->fEndSet = true; |
1016 } | 1016 } |
1017 ResultType resultType = this->intersectRay(quadPts, kCtrlPt_RayType | 1017 ResultType resultType = this->intersectRay(quadPts, kCtrlPt_RayType |
1018 STROKER_DEBUG_PARAMS(fRecursionDepth)); | 1018 STROKER_DEBUG_PARAMS(fRecursionDepth)); |
1019 if (resultType != kQuad_ResultType) { | 1019 if (resultType != kQuad_ResultType) { |
1020 return resultType; | 1020 return resultType; |
1021 } | 1021 } |
1022 // project a ray from the curve to the stroke | 1022 // project a ray from the curve to the stroke |
1023 SkPoint ray[2]; | 1023 SkPoint ray[2]; |
1024 this->quadPerpRay(quad, quadPts->fMidT, &ray[1], &ray[0], NULL); | 1024 this->quadPerpRay(quad, quadPts->fMidT, &ray[1], &ray[0], nullptr); |
1025 return this->strokeCloseEnough(quadPts->fQuad, ray, quadPts | 1025 return this->strokeCloseEnough(quadPts->fQuad, ray, quadPts |
1026 STROKER_DEBUG_PARAMS(fRecursionDepth)); | 1026 STROKER_DEBUG_PARAMS(fRecursionDepth)); |
1027 } | 1027 } |
1028 | 1028 |
1029 void SkPathStroker::addDegenerateLine(const SkQuadConstruct* quadPts) { | 1029 void SkPathStroker::addDegenerateLine(const SkQuadConstruct* quadPts) { |
1030 const SkPoint* quad = quadPts->fQuad; | 1030 const SkPoint* quad = quadPts->fQuad; |
1031 SkPath* path = fStrokeType == kOuter_StrokeType ? &fOuter : &fInner; | 1031 SkPath* path = fStrokeType == kOuter_StrokeType ? &fOuter : &fInner; |
1032 path->lineTo(quad[2].fX, quad[2].fY); | 1032 path->lineTo(quad[2].fX, quad[2].fY); |
1033 } | 1033 } |
1034 | 1034 |
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1422 pts[3].set(r.fRight, outer.fBottom); | 1422 pts[3].set(r.fRight, outer.fBottom); |
1423 pts[2].set(r.fLeft, outer.fBottom); | 1423 pts[2].set(r.fLeft, outer.fBottom); |
1424 pts[1].set(outer.fLeft, r.fBottom); | 1424 pts[1].set(outer.fLeft, r.fBottom); |
1425 pts[0].set(outer.fLeft, r.fTop); | 1425 pts[0].set(outer.fLeft, r.fTop); |
1426 } | 1426 } |
1427 path->addPoly(pts, 8, true); | 1427 path->addPoly(pts, 8, true); |
1428 } | 1428 } |
1429 | 1429 |
1430 void SkStroke::strokeRect(const SkRect& origRect, SkPath* dst, | 1430 void SkStroke::strokeRect(const SkRect& origRect, SkPath* dst, |
1431 SkPath::Direction dir) const { | 1431 SkPath::Direction dir) const { |
1432 SkASSERT(dst != NULL); | 1432 SkASSERT(dst != nullptr); |
1433 dst->reset(); | 1433 dst->reset(); |
1434 | 1434 |
1435 SkScalar radius = SkScalarHalf(fWidth); | 1435 SkScalar radius = SkScalarHalf(fWidth); |
1436 if (radius <= 0) { | 1436 if (radius <= 0) { |
1437 return; | 1437 return; |
1438 } | 1438 } |
1439 | 1439 |
1440 SkScalar rw = origRect.width(); | 1440 SkScalar rw = origRect.width(); |
1441 SkScalar rh = origRect.height(); | 1441 SkScalar rh = origRect.height(); |
1442 if ((rw < 0) ^ (rh < 0)) { | 1442 if ((rw < 0) ^ (rh < 0)) { |
(...skipping 26 matching lines...) Expand all Loading... |
1469 default: | 1469 default: |
1470 break; | 1470 break; |
1471 } | 1471 } |
1472 | 1472 |
1473 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { | 1473 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { |
1474 r = rect; | 1474 r = rect; |
1475 r.inset(radius, radius); | 1475 r.inset(radius, radius); |
1476 dst->addRect(r, reverse_direction(dir)); | 1476 dst->addRect(r, reverse_direction(dir)); |
1477 } | 1477 } |
1478 } | 1478 } |
OLD | NEW |