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

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

Issue 1602153002: fix circular dashing (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fix test Created 4 years, 11 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 | « src/core/SkGeometry.cpp ('k') | tests/PathMeasureTest.cpp » ('j') | 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 /* 2 /*
3 * Copyright 2008 The Android Open Source Project 3 * Copyright 2008 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #include "SkPathMeasure.h" 10 #include "SkPathMeasure.h"
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 // diff = -a/4 + b/2 - c/4 66 // diff = -a/4 + b/2 - c/4
67 SkScalar dx = SkScalarHalf(pts[1].fX) - 67 SkScalar dx = SkScalarHalf(pts[1].fX) -
68 SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX)); 68 SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX));
69 SkScalar dy = SkScalarHalf(pts[1].fY) - 69 SkScalar dy = SkScalarHalf(pts[1].fY) -
70 SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY)); 70 SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY));
71 71
72 SkScalar dist = SkMaxScalar(SkScalarAbs(dx), SkScalarAbs(dy)); 72 SkScalar dist = SkMaxScalar(SkScalarAbs(dx), SkScalarAbs(dy));
73 return dist > CHEAP_DIST_LIMIT; 73 return dist > CHEAP_DIST_LIMIT;
74 } 74 }
75 75
76 static bool conic_too_curvy(const SkPoint& firstPt, const SkPoint& midTPt,
77 const SkPoint& lastPt) {
78 SkPoint midEnds = firstPt + lastPt;
79 midEnds *= 0.5f;
80 SkVector dxy = midTPt - midEnds;
81 SkScalar dist = SkMaxScalar(SkScalarAbs(dxy.fX), SkScalarAbs(dxy.fY));
82 return dist > CHEAP_DIST_LIMIT;
83 }
84
76 static bool cheap_dist_exceeds_limit(const SkPoint& pt, 85 static bool cheap_dist_exceeds_limit(const SkPoint& pt,
77 SkScalar x, SkScalar y) { 86 SkScalar x, SkScalar y) {
78 SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY)); 87 SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY));
79 // just made up the 1/2 88 // just made up the 1/2
80 return dist > CHEAP_DIST_LIMIT; 89 return dist > CHEAP_DIST_LIMIT;
81 } 90 }
82 91
83 static bool cubic_too_curvy(const SkPoint pts[4]) { 92 static bool cubic_too_curvy(const SkPoint pts[4]) {
84 return cheap_dist_exceeds_limit(pts[1], 93 return cheap_dist_exceeds_limit(pts[1],
85 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3), 94 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3),
86 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3)) 95 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3))
87 || 96 ||
88 cheap_dist_exceeds_limit(pts[2], 97 cheap_dist_exceeds_limit(pts[2],
89 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3), 98 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3),
90 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3)); 99 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3));
91 } 100 }
92 101
93 /* from http://www.malczak.linuxpl.com/blog/quadratic-bezier-curve-length/ */ 102 static SkScalar quad_folded_len(const SkPoint pts[3]) {
94 static SkScalar compute_quad_len(const SkPoint pts[3]) { 103 SkScalar t = SkFindQuadMaxCurvature(pts);
95 SkPoint a,b; 104 SkPoint pt = SkEvalQuadAt(pts, t);
96 a.fX = pts[0].fX - 2 * pts[1].fX + pts[2].fX; 105 SkVector a = pts[2] - pt;
97 a.fY = pts[0].fY - 2 * pts[1].fY + pts[2].fY; 106 SkScalar result = a.length();
98 b.fX = 2 * (pts[1].fX - pts[0].fX); 107 if (0 != t) {
99 b.fY = 2 * (pts[1].fY - pts[0].fY); 108 SkVector b = pts[0] - pt;
100 SkScalar A = 4 * (a.fX * a.fX + a.fY * a.fY); 109 result += b.length();
101 SkScalar B = 4 * (a.fX * b.fX + a.fY * b.fY); 110 }
102 SkScalar C = b.fX * b.fX + b.fY * b.fY; 111 SkASSERT(SkScalarIsFinite(result));
103 112 return result;
104 SkScalar Sabc = 2 * SkScalarSqrt(A + B + C);
105 SkScalar A_2 = SkScalarSqrt(A);
106 SkScalar A_32 = 2 * A * A_2;
107 SkScalar C_2 = 2 * SkScalarSqrt(C);
108 SkScalar BA = B / A_2;
109
110 return (A_32 * Sabc + A_2 * B * (Sabc - C_2) +
111 (4 * C * A - B * B) * SkScalarLog((2 * A_2 + BA + Sabc) / (BA + C_2) )) / (4 * A_32);
112 } 113 }
113 114
115 /* from http://www.malczak.linuxpl.com/blog/quadratic-bezier-curve-length/ */
116 /* This works -- more needs to be done to see if it is performant on all platfor ms.
117 To use this to measure parts of quads requires recomputing everything -- perh aps
118 a chop-like interface can start from a larger measurement and get two new mea surements
119 with one call here.
120 */
121 static SkScalar compute_quad_len(const SkPoint pts[3]) {
122 SkPoint a,b;
123 a.fX = pts[0].fX - 2 * pts[1].fX + pts[2].fX;
124 a.fY = pts[0].fY - 2 * pts[1].fY + pts[2].fY;
125 SkScalar A = 4 * (a.fX * a.fX + a.fY * a.fY);
126 if (0 == A) {
127 a = pts[2] - pts[0];
128 return a.length();
129 }
130 b.fX = 2 * (pts[1].fX - pts[0].fX);
131 b.fY = 2 * (pts[1].fY - pts[0].fY);
132 SkScalar B = 4 * (a.fX * b.fX + a.fY * b.fY);
133 SkScalar C = b.fX * b.fX + b.fY * b.fY;
134 SkScalar Sabc = 2 * SkScalarSqrt(A + B + C);
135 SkScalar A_2 = SkScalarSqrt(A);
136 SkScalar A_32 = 2 * A * A_2;
137 SkScalar C_2 = 2 * SkScalarSqrt(C);
138 SkScalar BA = B / A_2;
139 if (0 == BA + C_2) {
140 return quad_folded_len(pts);
141 }
142 SkScalar J = A_32 * Sabc + A_2 * B * (Sabc - C_2);
143 SkScalar K = 4 * C * A - B * B;
144 SkScalar L = (2 * A_2 + BA + Sabc) / (BA + C_2);
145 if (L <= 0) {
146 return quad_folded_len(pts);
147 }
148 SkScalar M = SkScalarLog(L);
149 SkScalar result = (J + K * M) / (4 * A_32);
150 SkASSERT(SkScalarIsFinite(result));
151 return result;
152 }
114 153
115 SkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3], 154 SkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3],
116 SkScalar distance, int mint, int maxt, int ptIndex) { 155 SkScalar distance, int mint, int maxt, int ptIndex) {
117 if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) { 156 if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) {
118 SkPoint tmp[5]; 157 SkPoint tmp[5];
119 int halft = (mint + maxt) >> 1; 158 int halft = (mint + maxt) >> 1;
120 159
121 SkChopQuadAtHalf(pts, tmp); 160 SkChopQuadAtHalf(pts, tmp);
122 distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex); 161 distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex);
123 distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptInd ex); 162 distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptInd ex);
124 } else { 163 } else {
125 SkScalar d = SkPoint::Distance(pts[0], pts[2]); 164 SkScalar d = SkPoint::Distance(pts[0], pts[2]);
126 SkScalar prevD = distance; 165 SkScalar prevD = distance;
127 distance += d; 166 distance += d;
128 if (distance > prevD) { 167 if (distance > prevD) {
129 Segment* seg = fSegments.append(); 168 Segment* seg = fSegments.append();
130 seg->fDistance = distance; 169 seg->fDistance = distance;
131 seg->fPtIndex = ptIndex; 170 seg->fPtIndex = ptIndex;
132 seg->fType = kQuad_SegType; 171 seg->fType = kQuad_SegType;
133 seg->fTValue = maxt; 172 seg->fTValue = maxt;
134 } 173 }
135 } 174 }
136 return distance; 175 return distance;
137 } 176 }
138 177
178 #ifdef SK_SUPPORT_LEGACY_CONIC_MEASURE
139 SkScalar SkPathMeasure::compute_conic_segs(const SkConic& conic, 179 SkScalar SkPathMeasure::compute_conic_segs(const SkConic& conic,
140 SkScalar distance, int mint, int maxt , int ptIndex) { 180 SkScalar distance, int mint, int maxt , int ptIndex) {
141 if (tspan_big_enough(maxt - mint) && quad_too_curvy(conic.fPts)) { 181 if (tspan_big_enough(maxt - mint) && quad_too_curvy(conic.fPts)) {
142 SkConic tmp[2]; 182 SkConic tmp[2];
143 conic.chop(tmp); 183 conic.chop(tmp);
144 184
145 int halft = (mint + maxt) >> 1; 185 int halft = (mint + maxt) >> 1;
146 distance = this->compute_conic_segs(tmp[0], distance, mint, halft, ptInd ex); 186 distance = this->compute_conic_segs(tmp[0], distance, mint, halft, ptInd ex);
147 distance = this->compute_conic_segs(tmp[1], distance, halft, maxt, ptInd ex); 187 distance = this->compute_conic_segs(tmp[1], distance, halft, maxt, ptInd ex);
148 } else { 188 } else {
149 SkScalar d = SkPoint::Distance(conic.fPts[0], conic.fPts[2]); 189 SkScalar d = SkPoint::Distance(conic.fPts[0], conic.fPts[2]);
150 SkScalar prevD = distance; 190 SkScalar prevD = distance;
151 distance += d; 191 distance += d;
152 if (distance > prevD) { 192 if (distance > prevD) {
153 Segment* seg = fSegments.append(); 193 Segment* seg = fSegments.append();
154 seg->fDistance = distance; 194 seg->fDistance = distance;
155 seg->fPtIndex = ptIndex; 195 seg->fPtIndex = ptIndex;
156 seg->fType = kConic_SegType; 196 seg->fType = kConic_SegType;
157 seg->fTValue = maxt; 197 seg->fTValue = maxt;
158 } 198 }
159 } 199 }
160 return distance; 200 return distance;
161 } 201 }
202 #else
203 SkScalar SkPathMeasure::compute_conic_segs(const SkConic& conic, SkScalar distan ce,
204 int mint, const SkPoint& minPt,
205 int maxt, const SkPoint& maxPt, int p tIndex) {
206 int halft = (mint + maxt) >> 1;
207 SkPoint halfPt = conic.evalAt(tValue2Scalar(halft));
208 if (tspan_big_enough(maxt - mint) && conic_too_curvy(minPt, halfPt, maxPt)) {
209 distance = this->compute_conic_segs(conic, distance, mint, minPt, halft, halfPt, ptIndex);
210 distance = this->compute_conic_segs(conic, distance, halft, halfPt, maxt , maxPt, ptIndex);
211 } else {
212 SkScalar d = SkPoint::Distance(minPt, maxPt);
213 SkScalar prevD = distance;
214 distance += d;
215 if (distance > prevD) {
216 Segment* seg = fSegments.append();
217 seg->fDistance = distance;
218 seg->fPtIndex = ptIndex;
219 seg->fType = kConic_SegType;
220 seg->fTValue = maxt;
221 }
222 }
223 return distance;
224 }
225 #endif
162 226
163 SkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4], 227 SkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4],
164 SkScalar distance, int mint, int maxt, int ptIndex) { 228 SkScalar distance, int mint, int maxt, int ptIndex) {
165 if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) { 229 if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) {
166 SkPoint tmp[7]; 230 SkPoint tmp[7];
167 int halft = (mint + maxt) >> 1; 231 int halft = (mint + maxt) >> 1;
168 232
169 SkChopCubicAtHalf(pts, tmp); 233 SkChopCubicAtHalf(pts, tmp);
170 distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex) ; 234 distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex) ;
171 distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIn dex); 235 distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIn dex);
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 } 310 }
247 if (distance > prevD) { 311 if (distance > prevD) {
248 fPts.append(2, pts + 1); 312 fPts.append(2, pts + 1);
249 ptIndex += 2; 313 ptIndex += 2;
250 } 314 }
251 } break; 315 } break;
252 316
253 case SkPath::kConic_Verb: { 317 case SkPath::kConic_Verb: {
254 const SkConic conic(pts, fIter.conicWeight()); 318 const SkConic conic(pts, fIter.conicWeight());
255 SkScalar prevD = distance; 319 SkScalar prevD = distance;
320 #ifdef SK_SUPPORT_LEGACY_CONIC_MEASURE
256 distance = this->compute_conic_segs(conic, distance, 0, kMaxTVal ue, ptIndex); 321 distance = this->compute_conic_segs(conic, distance, 0, kMaxTVal ue, ptIndex);
322 #else
323 distance = this->compute_conic_segs(conic, distance, 0, conic.fP ts[0],
324 kMaxTValue, conic.fPts[2], p tIndex);
325 #endif
257 if (distance > prevD) { 326 if (distance > prevD) {
258 // we store the conic weight in our next point, followed by the last 2 pts 327 // we store the conic weight in our next point, followed by the last 2 pts
259 // thus to reconstitue a conic, you'd need to say 328 // thus to reconstitue a conic, you'd need to say
260 // SkConic(pts[0], pts[2], pts[3], weight = pts[1].fX) 329 // SkConic(pts[0], pts[2], pts[3], weight = pts[1].fX)
261 fPts.append()->set(conic.fW, 0); 330 fPts.append()->set(conic.fW, 0);
262 fPts.append(2, pts + 1); 331 fPts.append(2, pts + 1);
263 ptIndex += 3; 332 ptIndex += 3;
264 } 333 }
265 } break; 334 } break;
266 335
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 468
400 if (0 == startT) { 469 if (0 == startT) {
401 if (SK_Scalar1 == stopT) { 470 if (SK_Scalar1 == stopT) {
402 dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW); 471 dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW);
403 } else { 472 } else {
404 SkConic tmp[2]; 473 SkConic tmp[2];
405 conic.chopAt(stopT, tmp); 474 conic.chopAt(stopT, tmp);
406 dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW); 475 dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW);
407 } 476 }
408 } else { 477 } else {
409 SkConic tmp1[2]; 478 #ifdef SK_SUPPORT_LEGACY_CONIC_MEASURE
479 SkConic tmp1[2];»
410 conic.chopAt(startT, tmp1); 480 conic.chopAt(startT, tmp1);
411 if (SK_Scalar1 == stopT) { 481 if (SK_Scalar1 == stopT) {
412 dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW); 482 dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW);
413 } else { 483 } else {
414 SkConic tmp2[2]; 484 SkConic tmp2[2];
415 tmp1[1].chopAt((stopT - startT) / (SK_Scalar1 - startT), tmp 2); 485 tmp1[1].chopAt((stopT - startT) / (SK_Scalar1 - startT), tmp 2);
416 dst->conicTo(tmp2[0].fPts[1], tmp2[0].fPts[2], tmp2[0].fW); 486 dst->conicTo(tmp2[0].fPts[1], tmp2[0].fPts[2], tmp2[0].fW);
417 } 487 }
488 #else
489 if (SK_Scalar1 == stopT) {
490 SkConic tmp1[2];
491 conic.chopAt(startT, tmp1);
492 dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW);
493 } else {
494 SkConic tmp;
495 conic.chopAt(startT, stopT, &tmp);
496 dst->conicTo(tmp.fPts[1], tmp.fPts[2], tmp.fW);
497 }
498 #endif
418 } 499 }
419 } break; 500 } break;
420 case kCubic_SegType: 501 case kCubic_SegType:
421 if (0 == startT) { 502 if (0 == startT) {
422 if (SK_Scalar1 == stopT) { 503 if (SK_Scalar1 == stopT) {
423 dst->cubicTo(pts[1], pts[2], pts[3]); 504 dst->cubicTo(pts[1], pts[2], pts[3]);
424 } else { 505 } else {
425 SkChopCubicAt(pts, tmp0, stopT); 506 SkChopCubicAt(pts, tmp0, stopT);
426 dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]); 507 dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]);
427 } 508 }
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
667 748
668 for (int i = 0; i < fSegments.count(); i++) { 749 for (int i = 0; i < fSegments.count(); i++) {
669 const Segment* seg = &fSegments[i]; 750 const Segment* seg = &fSegments[i];
670 SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n", 751 SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n",
671 i, seg->fDistance, seg->fPtIndex, seg->getScalarT(), 752 i, seg->fDistance, seg->fPtIndex, seg->getScalarT(),
672 seg->fType); 753 seg->fType);
673 } 754 }
674 } 755 }
675 756
676 #endif 757 #endif
OLDNEW
« no previous file with comments | « src/core/SkGeometry.cpp ('k') | tests/PathMeasureTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698