Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Side by Side Diff: src/core/SkStroke.cpp

Issue 1862753002: cubic stroke fix (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gm/cubicpaths.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « gm/cubicpaths.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698