| 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 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 | 78 |
| 79 struct SkQuadConstruct { // The state of the quad stroke under construction. | 79 struct SkQuadConstruct { // The state of the quad stroke under construction. |
| 80 SkPoint fQuad[3]; // the stroked quad parallel to the original curve | 80 SkPoint fQuad[3]; // the stroked quad parallel to the original curve |
| 81 SkPoint fTangentStart; // a point tangent to fQuad[0] | 81 SkPoint fTangentStart; // a point tangent to fQuad[0] |
| 82 SkPoint fTangentEnd; // a point tangent to fQuad[2] | 82 SkPoint fTangentEnd; // a point tangent to fQuad[2] |
| 83 SkScalar fStartT; // a segment of the original curve | 83 SkScalar fStartT; // a segment of the original curve |
| 84 SkScalar fMidT; // " | 84 SkScalar fMidT; // " |
| 85 SkScalar fEndT; // " | 85 SkScalar fEndT; // " |
| 86 bool fStartSet; // state to share common points across structs | 86 bool fStartSet; // state to share common points across structs |
| 87 bool fEndSet; // " | 87 bool fEndSet; // " |
| 88 bool fOppositeTangents; // set if coincident tangents have opposite directio
ns |
| 88 | 89 |
| 89 // return false if start and end are too close to have a unique middle | 90 // return false if start and end are too close to have a unique middle |
| 90 bool init(SkScalar start, SkScalar end) { | 91 bool init(SkScalar start, SkScalar end) { |
| 91 fStartT = start; | 92 fStartT = start; |
| 92 fMidT = (start + end) * SK_ScalarHalf; | 93 fMidT = (start + end) * SK_ScalarHalf; |
| 93 fEndT = end; | 94 fEndT = end; |
| 94 fStartSet = fEndSet = false; | 95 fStartSet = fEndSet = false; |
| 95 return fStartT < fMidT && fMidT < fEndT; | 96 return fStartT < fMidT && fMidT < fEndT; |
| 96 } | 97 } |
| 97 | 98 |
| (...skipping 756 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 854 SkVector aLen = quadPts->fTangentStart - start; | 855 SkVector aLen = quadPts->fTangentStart - start; |
| 855 SkVector bLen = quadPts->fTangentEnd - end; | 856 SkVector bLen = quadPts->fTangentEnd - end; |
| 856 /* Slopes match when denom goes to zero: | 857 /* Slopes match when denom goes to zero: |
| 857 axLen / ayLen == bxLen / byLen | 858 axLen / ayLen == bxLen / byLen |
| 858 (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen | 859 (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen |
| 859 byLen * axLen == ayLen * bxLen | 860 byLen * axLen == ayLen * bxLen |
| 860 byLen * axLen - ayLen * bxLen ( == deno
m ) | 861 byLen * axLen - ayLen * bxLen ( == deno
m ) |
| 861 */ | 862 */ |
| 862 SkScalar denom = aLen.cross(bLen); | 863 SkScalar denom = aLen.cross(bLen); |
| 863 if (denom == 0 || !SkScalarIsFinite(denom)) { | 864 if (denom == 0 || !SkScalarIsFinite(denom)) { |
| 865 quadPts->fOppositeTangents = aLen.dot(bLen) < 0; |
| 864 return STROKER_RESULT(kDegenerate_ResultType, depth, quadPts, "denom ==
0"); | 866 return STROKER_RESULT(kDegenerate_ResultType, depth, quadPts, "denom ==
0"); |
| 865 } | 867 } |
| 868 quadPts->fOppositeTangents = false; |
| 866 SkVector ab0 = start - end; | 869 SkVector ab0 = start - end; |
| 867 SkScalar numerA = bLen.cross(ab0); | 870 SkScalar numerA = bLen.cross(ab0); |
| 868 SkScalar numerB = aLen.cross(ab0); | 871 SkScalar numerB = aLen.cross(ab0); |
| 869 if ((numerA >= 0) == (numerB >= 0)) { // if the control point is outside the
quad ends | 872 if ((numerA >= 0) == (numerB >= 0)) { // if the control point is outside the
quad ends |
| 870 // if the perpendicular distances from the quad points to the opposite t
angent line | 873 // if the perpendicular distances from the quad points to the opposite t
angent line |
| 871 // are small, a straight line is good enough | 874 // are small, a straight line is good enough |
| 872 SkScalar dist1 = pt_to_line(start, end, quadPts->fTangentEnd); | 875 SkScalar dist1 = pt_to_line(start, end, quadPts->fTangentEnd); |
| 873 SkScalar dist2 = pt_to_line(end, start, quadPts->fTangentStart); | 876 SkScalar dist2 = pt_to_line(end, start, quadPts->fTangentStart); |
| 874 if (SkTMax(dist1, dist2) <= fInvResScaleSquared) { | 877 if (SkTMax(dist1, dist2) <= fInvResScaleSquared) { |
| 875 return STROKER_RESULT(kDegenerate_ResultType, depth, quadPts, | 878 return STROKER_RESULT(kDegenerate_ResultType, depth, quadPts, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 886 if (kCtrlPt_RayType == intersectRayType) { | 889 if (kCtrlPt_RayType == intersectRayType) { |
| 887 SkPoint* ctrlPt = &quadPts->fQuad[1]; | 890 SkPoint* ctrlPt = &quadPts->fQuad[1]; |
| 888 // the intersection of the tangents need not be on the tangent segme
nt | 891 // the intersection of the tangents need not be on the tangent segme
nt |
| 889 // so 0 <= numerA <= 1 is not necessarily true | 892 // so 0 <= numerA <= 1 is not necessarily true |
| 890 ctrlPt->fX = start.fX * (1 - numerA) + quadPts->fTangentStart.fX * n
umerA; | 893 ctrlPt->fX = start.fX * (1 - numerA) + quadPts->fTangentStart.fX * n
umerA; |
| 891 ctrlPt->fY = start.fY * (1 - numerA) + quadPts->fTangentStart.fY * n
umerA; | 894 ctrlPt->fY = start.fY * (1 - numerA) + quadPts->fTangentStart.fY * n
umerA; |
| 892 } | 895 } |
| 893 return STROKER_RESULT(kQuad_ResultType, depth, quadPts, | 896 return STROKER_RESULT(kQuad_ResultType, depth, quadPts, |
| 894 "(numerA=%g >= 0) != (numerB=%g >= 0)", numerA, numerB); | 897 "(numerA=%g >= 0) != (numerB=%g >= 0)", numerA, numerB); |
| 895 } | 898 } |
| 899 quadPts->fOppositeTangents = aLen.dot(bLen) < 0; |
| 896 // if the lines are parallel, straight line is good enough | 900 // if the lines are parallel, straight line is good enough |
| 897 return STROKER_RESULT(kDegenerate_ResultType, depth, quadPts, | 901 return STROKER_RESULT(kDegenerate_ResultType, depth, quadPts, |
| 898 "SkScalarNearlyZero(denom=%g)", denom); | 902 "SkScalarNearlyZero(denom=%g)", denom); |
| 899 } | 903 } |
| 900 | 904 |
| 901 // Given a cubic and a t-range, determine if the stroke can be described by a qu
adratic. | 905 // Given a cubic and a t-range, determine if the stroke can be described by a qu
adratic. |
| 902 SkPathStroker::ResultType SkPathStroker::tangentsMeet(const SkPoint cubic[4], | 906 SkPathStroker::ResultType SkPathStroker::tangentsMeet(const SkPoint cubic[4], |
| 903 SkQuadConstruct* quadPts) { | 907 SkQuadConstruct* quadPts) { |
| 904 if (!this->cubicQuadEnds(cubic, quadPts)) { | 908 if (!this->cubicQuadEnds(cubic, quadPts)) { |
| 905 return kNormalError_ResultType; | 909 return kNormalError_ResultType; |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1109 } | 1113 } |
| 1110 if (fFoundTangents) { | 1114 if (fFoundTangents) { |
| 1111 ResultType resultType = this->compareQuadCubic(cubic, quadPts); | 1115 ResultType resultType = this->compareQuadCubic(cubic, quadPts); |
| 1112 if (kQuad_ResultType == resultType) { | 1116 if (kQuad_ResultType == resultType) { |
| 1113 SkPath* path = fStrokeType == kOuter_StrokeType ? &fOuter : &fInner; | 1117 SkPath* path = fStrokeType == kOuter_StrokeType ? &fOuter : &fInner; |
| 1114 const SkPoint* stroke = quadPts->fQuad; | 1118 const SkPoint* stroke = quadPts->fQuad; |
| 1115 path->quadTo(stroke[1].fX, stroke[1].fY, stroke[2].fX, stroke[2].fY)
; | 1119 path->quadTo(stroke[1].fX, stroke[1].fY, stroke[2].fX, stroke[2].fY)
; |
| 1116 return true; | 1120 return true; |
| 1117 } | 1121 } |
| 1118 if (kDegenerate_ResultType == resultType) { | 1122 if (kDegenerate_ResultType == resultType) { |
| 1119 addDegenerateLine(quadPts); | 1123 if (!quadPts->fOppositeTangents) { |
| 1120 return true; | 1124 addDegenerateLine(quadPts); |
| 1125 return true; |
| 1126 } |
| 1121 } | 1127 } |
| 1122 if (kNormalError_ResultType == resultType) { | 1128 if (kNormalError_ResultType == resultType) { |
| 1123 return false; | 1129 return false; |
| 1124 } | 1130 } |
| 1125 } | 1131 } |
| 1126 if (!SkScalarIsFinite(quadPts->fQuad[2].fX) || !SkScalarIsFinite(quadPts->fQ
uad[2].fY)) { | 1132 if (!SkScalarIsFinite(quadPts->fQuad[2].fX) || !SkScalarIsFinite(quadPts->fQ
uad[2].fY)) { |
| 1127 return false; // just abort if projected quad isn't representable | 1133 return false; // just abort if projected quad isn't representable |
| 1128 } | 1134 } |
| 1129 SkDEBUGCODE(gMaxRecursion[fFoundTangents] = SkTMax(gMaxRecursion[fFoundTange
nts], | 1135 SkDEBUGCODE(gMaxRecursion[fFoundTangents] = SkTMax(gMaxRecursion[fFoundTange
nts], |
| 1130 fRecursionDepth + 1)); | 1136 fRecursionDepth + 1)); |
| (...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1531 default: | 1537 default: |
| 1532 break; | 1538 break; |
| 1533 } | 1539 } |
| 1534 | 1540 |
| 1535 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { | 1541 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { |
| 1536 r = rect; | 1542 r = rect; |
| 1537 r.inset(radius, radius); | 1543 r.inset(radius, radius); |
| 1538 dst->addRect(r, reverse_direction(dir)); | 1544 dst->addRect(r, reverse_direction(dir)); |
| 1539 } | 1545 } |
| 1540 } | 1546 } |
| OLD | NEW |