| 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 |