OLD | NEW |
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" |
11 #include "SkGeometry.h" | 11 #include "SkGeometry.h" |
12 #include "SkPath.h" | 12 #include "SkPath.h" |
13 #include "SkTSearch.h" | 13 #include "SkTSearch.h" |
14 | 14 |
15 // these must be 0,1,2 since they are in our 2-bit field | 15 // these must be 0,1,2,3 since they are in our 2-bit field |
16 enum { | 16 enum { |
17 kLine_SegType, | 17 kLine_SegType, |
18 kQuad_SegType, | 18 kQuad_SegType, |
19 kCubic_SegType | 19 kCubic_SegType, |
| 20 kConic_SegType, |
20 }; | 21 }; |
21 | 22 |
22 #define kMaxTValue 32767 | 23 #define kMaxTValue 32767 |
23 | 24 |
24 static inline SkScalar tValue2Scalar(int t) { | 25 static inline SkScalar tValue2Scalar(int t) { |
25 SkASSERT((unsigned)t <= kMaxTValue); | 26 SkASSERT((unsigned)t <= kMaxTValue); |
26 return t * 3.05185e-5f; // t / 32767 | 27 return t * 3.05185e-5f; // t / 32767 |
27 } | 28 } |
28 | 29 |
29 SkScalar SkPathMeasure::Segment::getScalarT() const { | 30 SkScalar SkPathMeasure::Segment::getScalarT() const { |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 Segment* seg = fSegments.append(); | 98 Segment* seg = fSegments.append(); |
98 seg->fDistance = distance; | 99 seg->fDistance = distance; |
99 seg->fPtIndex = ptIndex; | 100 seg->fPtIndex = ptIndex; |
100 seg->fType = kQuad_SegType; | 101 seg->fType = kQuad_SegType; |
101 seg->fTValue = maxt; | 102 seg->fTValue = maxt; |
102 } | 103 } |
103 } | 104 } |
104 return distance; | 105 return distance; |
105 } | 106 } |
106 | 107 |
| 108 SkScalar SkPathMeasure::compute_conic_segs(const SkConic& conic, |
| 109 SkScalar distance, int mint, int maxt
, int ptIndex) { |
| 110 if (tspan_big_enough(maxt - mint) && quad_too_curvy(conic.fPts)) { |
| 111 SkConic tmp[2]; |
| 112 conic.chop(tmp); |
| 113 |
| 114 int halft = (mint + maxt) >> 1; |
| 115 distance = this->compute_conic_segs(tmp[0], distance, mint, halft, ptInd
ex); |
| 116 distance = this->compute_conic_segs(tmp[1], distance, halft, maxt, ptInd
ex); |
| 117 } else { |
| 118 SkScalar d = SkPoint::Distance(conic.fPts[0], conic.fPts[2]); |
| 119 SkScalar prevD = distance; |
| 120 distance += d; |
| 121 if (distance > prevD) { |
| 122 Segment* seg = fSegments.append(); |
| 123 seg->fDistance = distance; |
| 124 seg->fPtIndex = ptIndex; |
| 125 seg->fType = kConic_SegType; |
| 126 seg->fTValue = maxt; |
| 127 } |
| 128 } |
| 129 return distance; |
| 130 } |
| 131 |
107 SkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4], | 132 SkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4], |
108 SkScalar distance, int mint, int maxt, int ptIndex) { | 133 SkScalar distance, int mint, int maxt, int ptIndex) { |
109 if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) { | 134 if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) { |
110 SkPoint tmp[7]; | 135 SkPoint tmp[7]; |
111 int halft = (mint + maxt) >> 1; | 136 int halft = (mint + maxt) >> 1; |
112 | 137 |
113 SkChopCubicAtHalf(pts, tmp); | 138 SkChopCubicAtHalf(pts, tmp); |
114 distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex)
; | 139 distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex)
; |
115 distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIn
dex); | 140 distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIn
dex); |
116 } else { | 141 } else { |
(...skipping 23 matching lines...) Expand all Loading... |
140 * as we accumulate distance, we have to check that the result of += | 165 * as we accumulate distance, we have to check that the result of += |
141 * actually made it larger, since a very small delta might be > 0, but | 166 * actually made it larger, since a very small delta might be > 0, but |
142 * still have no effect on distance (if distance >>> delta). | 167 * still have no effect on distance (if distance >>> delta). |
143 * | 168 * |
144 * We do this check below, and in compute_quad_segs and compute_cubic_segs | 169 * We do this check below, and in compute_quad_segs and compute_cubic_segs |
145 */ | 170 */ |
146 fSegments.reset(); | 171 fSegments.reset(); |
147 bool done = false; | 172 bool done = false; |
148 do { | 173 do { |
149 switch (fIter.next(pts)) { | 174 switch (fIter.next(pts)) { |
150 case SkPath::kConic_Verb: | |
151 SkASSERT(0); | |
152 break; | |
153 case SkPath::kMove_Verb: | 175 case SkPath::kMove_Verb: |
154 ptIndex += 1; | 176 ptIndex += 1; |
155 fPts.append(1, pts); | 177 fPts.append(1, pts); |
156 if (!firstMoveTo) { | 178 if (!firstMoveTo) { |
157 done = true; | 179 done = true; |
158 break; | 180 break; |
159 } | 181 } |
160 firstMoveTo = false; | 182 firstMoveTo = false; |
161 break; | 183 break; |
162 | 184 |
163 case SkPath::kLine_Verb: { | 185 case SkPath::kLine_Verb: { |
164 SkScalar d = SkPoint::Distance(pts[0], pts[1]); | 186 SkScalar d = SkPoint::Distance(pts[0], pts[1]); |
165 SkASSERT(d >= 0); | 187 SkASSERT(d >= 0); |
166 SkScalar prevD = distance; | 188 SkScalar prevD = distance; |
167 distance += d; | 189 distance += d; |
168 if (distance > prevD) { | 190 if (distance > prevD) { |
169 seg = fSegments.append(); | 191 seg = fSegments.append(); |
170 seg->fDistance = distance; | 192 seg->fDistance = distance; |
171 seg->fPtIndex = ptIndex; | 193 seg->fPtIndex = ptIndex; |
172 seg->fType = kLine_SegType; | 194 seg->fType = kLine_SegType; |
173 seg->fTValue = kMaxTValue; | 195 seg->fTValue = kMaxTValue; |
174 fPts.append(1, pts + 1); | 196 fPts.append(1, pts + 1); |
175 ptIndex++; | 197 ptIndex++; |
176 } | 198 } |
177 } break; | 199 } break; |
178 | 200 |
179 case SkPath::kQuad_Verb: { | 201 case SkPath::kQuad_Verb: { |
180 SkScalar prevD = distance; | 202 SkScalar prevD = distance; |
181 distance = this->compute_quad_segs(pts, distance, 0, | 203 distance = this->compute_quad_segs(pts, distance, 0, kMaxTValue,
ptIndex); |
182 kMaxTValue, ptIndex); | |
183 if (distance > prevD) { | 204 if (distance > prevD) { |
184 fPts.append(2, pts + 1); | 205 fPts.append(2, pts + 1); |
185 ptIndex += 2; | 206 ptIndex += 2; |
186 } | 207 } |
187 } break; | 208 } break; |
188 | 209 |
| 210 case SkPath::kConic_Verb: { |
| 211 const SkConic conic(pts, fIter.conicWeight()); |
| 212 SkScalar prevD = distance; |
| 213 distance = this->compute_conic_segs(conic, distance, 0, kMaxTVal
ue, ptIndex); |
| 214 if (distance > prevD) { |
| 215 // we store the conic weight in our next point, followed by
the last 2 pts |
| 216 // thus to reconstitue a conic, you'd need to say |
| 217 // SkConic(pts[0], pts[2], pts[3], weight = pts[1].fX) |
| 218 fPts.append()->set(conic.fW, 0); |
| 219 fPts.append(2, pts + 1); |
| 220 ptIndex += 3; |
| 221 } |
| 222 } break; |
| 223 |
189 case SkPath::kCubic_Verb: { | 224 case SkPath::kCubic_Verb: { |
190 SkScalar prevD = distance; | 225 SkScalar prevD = distance; |
191 distance = this->compute_cubic_segs(pts, distance, 0, | 226 distance = this->compute_cubic_segs(pts, distance, 0, kMaxTValue
, ptIndex); |
192 kMaxTValue, ptIndex); | |
193 if (distance > prevD) { | 227 if (distance > prevD) { |
194 fPts.append(3, pts + 1); | 228 fPts.append(3, pts + 1); |
195 ptIndex += 3; | 229 ptIndex += 3; |
196 } | 230 } |
197 } break; | 231 } break; |
198 | 232 |
199 case SkPath::kClose_Verb: | 233 case SkPath::kClose_Verb: |
200 isClosed = true; | 234 isClosed = true; |
201 break; | 235 break; |
202 | 236 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
249 if (tangent) { | 283 if (tangent) { |
250 tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].
fY); | 284 tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].
fY); |
251 } | 285 } |
252 break; | 286 break; |
253 case kQuad_SegType: | 287 case kQuad_SegType: |
254 SkEvalQuadAt(pts, t, pos, tangent); | 288 SkEvalQuadAt(pts, t, pos, tangent); |
255 if (tangent) { | 289 if (tangent) { |
256 tangent->normalize(); | 290 tangent->normalize(); |
257 } | 291 } |
258 break; | 292 break; |
| 293 case kConic_SegType: { |
| 294 SkConic(pts[0], pts[2], pts[3], pts[1].fX).evalAt(t, pos, tangent); |
| 295 if (tangent) { |
| 296 tangent->normalize(); |
| 297 } |
| 298 } break; |
259 case kCubic_SegType: | 299 case kCubic_SegType: |
260 SkEvalCubicAt(pts, t, pos, tangent, NULL); | 300 SkEvalCubicAt(pts, t, pos, tangent, NULL); |
261 if (tangent) { | 301 if (tangent) { |
262 tangent->normalize(); | 302 tangent->normalize(); |
263 } | 303 } |
264 break; | 304 break; |
265 default: | 305 default: |
266 SkDEBUGFAIL("unknown segType"); | 306 SkDEBUGFAIL("unknown segType"); |
267 } | 307 } |
268 } | 308 } |
269 | 309 |
270 static void seg_to(const SkPoint pts[], int segType, | 310 static void seg_to(const SkPoint pts[], int segType, |
271 SkScalar startT, SkScalar stopT, SkPath* dst) { | 311 SkScalar startT, SkScalar stopT, SkPath* dst) { |
272 SkASSERT(startT >= 0 && startT <= SK_Scalar1); | 312 SkASSERT(startT >= 0 && startT <= SK_Scalar1); |
273 SkASSERT(stopT >= 0 && stopT <= SK_Scalar1); | 313 SkASSERT(stopT >= 0 && stopT <= SK_Scalar1); |
274 SkASSERT(startT <= stopT); | 314 SkASSERT(startT <= stopT); |
275 | 315 |
276 if (startT == stopT) { | 316 if (startT == stopT) { |
277 return; // should we report this, to undo a moveTo? | 317 return; // should we report this, to undo a moveTo? |
278 } | 318 } |
279 | 319 |
280 SkPoint tmp0[7], tmp1[7]; | 320 SkPoint tmp0[7], tmp1[7]; |
281 | 321 |
282 switch (segType) { | 322 switch (segType) { |
283 case kLine_SegType: | 323 case kLine_SegType: |
284 if (SK_Scalar1 == stopT) { | 324 if (SK_Scalar1 == stopT) { |
285 dst->lineTo(pts[1]); | 325 dst->lineTo(pts[1]); |
286 } else { | 326 } else { |
287 dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT), | 327 dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT), |
288 SkScalarInterp(pts[0].fY, pts[1].fY, stopT)); | 328 SkScalarInterp(pts[0].fY, pts[1].fY, stopT)); |
289 } | 329 } |
290 break; | 330 break; |
291 case kQuad_SegType: | 331 case kQuad_SegType: |
292 if (0 == startT) { | 332 if (0 == startT) { |
293 if (SK_Scalar1 == stopT) { | 333 if (SK_Scalar1 == stopT) { |
294 dst->quadTo(pts[1], pts[2]); | 334 dst->quadTo(pts[1], pts[2]); |
295 } else { | 335 } else { |
296 SkChopQuadAt(pts, tmp0, stopT); | 336 SkChopQuadAt(pts, tmp0, stopT); |
297 dst->quadTo(tmp0[1], tmp0[2]); | 337 dst->quadTo(tmp0[1], tmp0[2]); |
298 } | 338 } |
299 } else { | 339 } else { |
300 SkChopQuadAt(pts, tmp0, startT); | 340 SkChopQuadAt(pts, tmp0, startT); |
301 if (SK_Scalar1 == stopT) { | 341 if (SK_Scalar1 == stopT) { |
302 dst->quadTo(tmp0[3], tmp0[4]); | 342 dst->quadTo(tmp0[3], tmp0[4]); |
303 } else { | 343 } else { |
304 SkChopQuadAt(&tmp0[2], tmp1, SkScalarDiv(stopT - startT, | 344 SkChopQuadAt(&tmp0[2], tmp1, SkScalarDiv(stopT - startT, |
305 SK_Scalar1 - startT)); | 345 SK_Scalar1 - startT)); |
306 dst->quadTo(tmp1[1], tmp1[2]); | 346 dst->quadTo(tmp1[1], tmp1[2]); |
307 } | 347 } |
308 } | 348 } |
309 break; | 349 break; |
| 350 case kConic_SegType: { |
| 351 SkConic conic(pts[0], pts[2], pts[3], pts[1].fX); |
| 352 |
| 353 if (0 == startT) { |
| 354 if (SK_Scalar1 == stopT) { |
| 355 dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW); |
| 356 } else { |
| 357 SkConic tmp[2]; |
| 358 conic.chopAt(stopT, tmp); |
| 359 dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW); |
| 360 } |
| 361 } else { |
| 362 SkConic tmp1[2]; |
| 363 conic.chopAt(startT, tmp1); |
| 364 if (SK_Scalar1 == stopT) { |
| 365 dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW); |
| 366 } else { |
| 367 SkConic tmp2[2]; |
| 368 tmp1[1].chopAt((stopT - startT) / (SK_Scalar1 - startT), tmp
2); |
| 369 dst->conicTo(tmp2[0].fPts[1], tmp2[0].fPts[2], tmp2[0].fW); |
| 370 } |
| 371 } |
| 372 } break; |
310 case kCubic_SegType: | 373 case kCubic_SegType: |
311 if (0 == startT) { | 374 if (0 == startT) { |
312 if (SK_Scalar1 == stopT) { | 375 if (SK_Scalar1 == stopT) { |
313 dst->cubicTo(pts[1], pts[2], pts[3]); | 376 dst->cubicTo(pts[1], pts[2], pts[3]); |
314 } else { | 377 } else { |
315 SkChopCubicAt(pts, tmp0, stopT); | 378 SkChopCubicAt(pts, tmp0, stopT); |
316 dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]); | 379 dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]); |
317 } | 380 } |
318 } else { | 381 } else { |
319 SkChopCubicAt(pts, tmp0, startT); | 382 SkChopCubicAt(pts, tmp0, startT); |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
528 | 591 |
529 for (int i = 0; i < fSegments.count(); i++) { | 592 for (int i = 0; i < fSegments.count(); i++) { |
530 const Segment* seg = &fSegments[i]; | 593 const Segment* seg = &fSegments[i]; |
531 SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n", | 594 SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n", |
532 i, seg->fDistance, seg->fPtIndex, seg->getScalarT(), | 595 i, seg->fDistance, seg->fPtIndex, seg->getScalarT(), |
533 seg->fType); | 596 seg->fType); |
534 } | 597 } |
535 } | 598 } |
536 | 599 |
537 #endif | 600 #endif |
OLD | NEW |