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 |