1 /* 2 * Copyright 2008 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 9 #include "SkPathMeasure.h" 10 #include "SkPathMeasurePriv.h" 11 #include "SkGeometry.h" 12 #include "SkPath.h" 13 #include "SkTSearch.h" 14 15 #define kMaxTValue 0x3FFFFFFF 16 17 static inline SkScalar tValue2Scalar(int t) { 18 SkASSERT((unsigned)t <= kMaxTValue); 19 const SkScalar kMaxTReciprocal = 1.0f / kMaxTValue; 20 return t * kMaxTReciprocal; 21 } 22 23 SkScalar SkPathMeasure::Segment::getScalarT() const { 24 return tValue2Scalar(fTValue); 25 } 26 27 const SkPathMeasure::Segment* SkPathMeasure::NextSegment(const Segment* seg) { 28 unsigned ptIndex = seg->fPtIndex; 29 30 do { 31 ++seg; 32 } while (seg->fPtIndex == ptIndex); 33 return seg; 34 } 35 36 void SkPathMeasure_segTo(const SkPoint pts[], unsigned segType, 37 SkScalar startT, SkScalar stopT, SkPath* dst) { 38 SkASSERT(startT >= 0 && startT <= SK_Scalar1); 39 SkASSERT(stopT >= 0 && stopT <= SK_Scalar1); 40 SkASSERT(startT <= stopT); 41 42 if (startT == stopT) { 43 /* if the dash as a zero-length on segment, add a corresponding zero-length line. 44 The stroke code will add end caps to zero length lines as appropriate */ 45 SkPoint lastPt; 46 SkAssertResult(dst->getLastPt(&lastPt)); 47 dst->lineTo(lastPt); 48 return; 49 } 50 51 SkPoint tmp0[7], tmp1[7]; 52 53 switch (segType) { 54 case kLine_SegType: 55 if (SK_Scalar1 == stopT) { 56 dst->lineTo(pts[1]); 57 } else { 58 dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT), 59 SkScalarInterp(pts[0].fY, pts[1].fY, stopT)); 60 } 61 break; 62 case kQuad_SegType: 63 if (0 == startT) { 64 if (SK_Scalar1 == stopT) { 65 dst->quadTo(pts[1], pts[2]); 66 } else { 67 SkChopQuadAt(pts, tmp0, stopT); 68 dst->quadTo(tmp0[1], tmp0[2]); 69 } 70 } else { 71 SkChopQuadAt(pts, tmp0, startT); 72 if (SK_Scalar1 == stopT) { 73 dst->quadTo(tmp0[3], tmp0[4]); 74 } else { 75 SkChopQuadAt(&tmp0[2], tmp1, (stopT - startT) / (1 - startT)); 76 dst->quadTo(tmp1[1], tmp1[2]); 77 } 78 } 79 break; 80 case kConic_SegType: { 81 SkConic conic(pts[0], pts[2], pts[3], pts[1].fX); 82 83 if (0 == startT) { 84 if (SK_Scalar1 == stopT) { 85 dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW); 86 } else { 87 SkConic tmp[2]; 88 if (conic.chopAt(stopT, tmp)) { 89 dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW); 90 } 91 } 92 } else { 93 if (SK_Scalar1 == stopT) { 94 SkConic tmp1[2]; 95 if (conic.chopAt(startT, tmp1)) { 96 dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW); 97 } 98 } else { 99 SkConic tmp; 100 conic.chopAt(startT, stopT, &tmp); 101 dst->conicTo(tmp.fPts[1], tmp.fPts[2], tmp.fW); 102 } 103 } 104 } break; 105 case kCubic_SegType: 106 if (0 == startT) { 107 if (SK_Scalar1 == stopT) { 108 dst->cubicTo(pts[1], pts[2], pts[3]); 109 } else { 110 SkChopCubicAt(pts, tmp0, stopT); 111 dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]); 112 } 113 } else { 114 SkChopCubicAt(pts, tmp0, startT); 115 if (SK_Scalar1 == stopT) { 116 dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]); 117 } else { 118 SkChopCubicAt(&tmp0[3], tmp1, (stopT - startT) / (1 - startT)); 119 dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]); 120 } 121 } 122 break; 123 default: 124 SK_ABORT("unknown segType"); 125 } 126 } 127 128 /////////////////////////////////////////////////////////////////////////////// 129 130 static inline int tspan_big_enough(int tspan) { 131 SkASSERT((unsigned)tspan <= kMaxTValue); 132 return tspan >> 10; 133 } 134 135 // can't use tangents, since we need [0..1..................2] to be seen 136 // as definitely not a line (it is when drawn, but not parametrically) 137 // so we compare midpoints 138 #define CHEAP_DIST_LIMIT (SK_Scalar1/2) // just made this value up 139 140 bool SkPathMeasure::quad_too_curvy(const SkPoint pts[3]) { 141 // diff = (a/4 + b/2 + c/4) - (a/2 + c/2) 142 // diff = -a/4 + b/2 - c/4 143 SkScalar dx = SkScalarHalf(pts[1].fX) - 144 SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX)); 145 SkScalar dy = SkScalarHalf(pts[1].fY) - 146 SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY)); 147 148 SkScalar dist = SkMaxScalar(SkScalarAbs(dx), SkScalarAbs(dy)); 149 return dist > fTolerance; 150 } 151 152 bool SkPathMeasure::conic_too_curvy(const SkPoint& firstPt, const SkPoint& midTPt, 153 const SkPoint& lastPt) { 154 SkPoint midEnds = firstPt + lastPt; 155 midEnds *= 0.5f; 156 SkVector dxy = midTPt - midEnds; 157 SkScalar dist = SkMaxScalar(SkScalarAbs(dxy.fX), SkScalarAbs(dxy.fY)); 158 return dist > fTolerance; 159 } 160 161 bool SkPathMeasure::cheap_dist_exceeds_limit(const SkPoint& pt, 162 SkScalar x, SkScalar y) { 163 SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY)); 164 // just made up the 1/2 165 return dist > fTolerance; 166 } 167 168 bool SkPathMeasure::cubic_too_curvy(const SkPoint pts[4]) { 169 return cheap_dist_exceeds_limit(pts[1], 170 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3), 171 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3)) 172 || 173 cheap_dist_exceeds_limit(pts[2], 174 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3), 175 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3)); 176 } 177 178 static SkScalar quad_folded_len(const SkPoint pts[3]) { 179 SkScalar t = SkFindQuadMaxCurvature(pts); 180 SkPoint pt = SkEvalQuadAt(pts, t); 181 SkVector a = pts[2] - pt; 182 SkScalar result = a.length(); 183 if (0 != t) { 184 SkVector b = pts[0] - pt; 185 result += b.length(); 186 } 187 SkASSERT(SkScalarIsFinite(result)); 188 return result; 189 } 190 191 /* from http://www.malczak.linuxpl.com/blog/quadratic-bezier-curve-length/ */ 192 /* This works -- more needs to be done to see if it is performant on all platforms. 193 To use this to measure parts of quads requires recomputing everything -- perhaps 194 a chop-like interface can start from a larger measurement and get two new measurements 195 with one call here. 196 */ 197 static SkScalar compute_quad_len(const SkPoint pts[3]) { 198 SkPoint a,b; 199 a.fX = pts[0].fX - 2 * pts[1].fX + pts[2].fX; 200 a.fY = pts[0].fY - 2 * pts[1].fY + pts[2].fY; 201 SkScalar A = 4 * (a.fX * a.fX + a.fY * a.fY); 202 if (0 == A) { 203 a = pts[2] - pts[0]; 204 return a.length(); 205 } 206 b.fX = 2 * (pts[1].fX - pts[0].fX); 207 b.fY = 2 * (pts[1].fY - pts[0].fY); 208 SkScalar B = 4 * (a.fX * b.fX + a.fY * b.fY); 209 SkScalar C = b.fX * b.fX + b.fY * b.fY; 210 SkScalar Sabc = 2 * SkScalarSqrt(A + B + C); 211 SkScalar A_2 = SkScalarSqrt(A); 212 SkScalar A_32 = 2 * A * A_2; 213 SkScalar C_2 = 2 * SkScalarSqrt(C); 214 SkScalar BA = B / A_2; 215 if (0 == BA + C_2) { 216 return quad_folded_len(pts); 217 } 218 SkScalar J = A_32 * Sabc + A_2 * B * (Sabc - C_2); 219 SkScalar K = 4 * C * A - B * B; 220 SkScalar L = (2 * A_2 + BA + Sabc) / (BA + C_2); 221 if (L <= 0) { 222 return quad_folded_len(pts); 223 } 224 SkScalar M = SkScalarLog(L); 225 SkScalar result = (J + K * M) / (4 * A_32); 226 SkASSERT(SkScalarIsFinite(result)); 227 return result; 228 } 229 230 SkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3], 231 SkScalar distance, int mint, int maxt, int ptIndex) { 232 if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) { 233 SkPoint tmp[5]; 234 int halft = (mint + maxt) >> 1; 235 236 SkChopQuadAtHalf(pts, tmp); 237 distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex); 238 distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptIndex); 239 } else { 240 SkScalar d = SkPoint::Distance(pts[0], pts[2]); 241 SkScalar prevD = distance; 242 distance += d; 243 if (distance > prevD) { 244 Segment* seg = fSegments.append(); 245 seg->fDistance = distance; 246 seg->fPtIndex = ptIndex; 247 seg->fType = kQuad_SegType; 248 seg->fTValue = maxt; 249 } 250 } 251 return distance; 252 } 253 254 SkScalar SkPathMeasure::compute_conic_segs(const SkConic& conic, SkScalar distance, 255 int mint, const SkPoint& minPt, 256 int maxt, const SkPoint& maxPt, int ptIndex) { 257 int halft = (mint + maxt) >> 1; 258 SkPoint halfPt = conic.evalAt(tValue2Scalar(halft)); 259 if (tspan_big_enough(maxt - mint) && conic_too_curvy(minPt, halfPt, maxPt)) { 260 distance = this->compute_conic_segs(conic, distance, mint, minPt, halft, halfPt, ptIndex); 261 distance = this->compute_conic_segs(conic, distance, halft, halfPt, maxt, maxPt, ptIndex); 262 } else { 263 SkScalar d = SkPoint::Distance(minPt, maxPt); 264 SkScalar prevD = distance; 265 distance += d; 266 if (distance > prevD) { 267 Segment* seg = fSegments.append(); 268 seg->fDistance = distance; 269 seg->fPtIndex = ptIndex; 270 seg->fType = kConic_SegType; 271 seg->fTValue = maxt; 272 } 273 } 274 return distance; 275 } 276 277 SkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4], 278 SkScalar distance, int mint, int maxt, int ptIndex) { 279 if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) { 280 SkPoint tmp[7]; 281 int halft = (mint + maxt) >> 1; 282 283 SkChopCubicAtHalf(pts, tmp); 284 distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex); 285 distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIndex); 286 } else { 287 SkScalar d = SkPoint::Distance(pts[0], pts[3]); 288 SkScalar prevD = distance; 289 distance += d; 290 if (distance > prevD) { 291 Segment* seg = fSegments.append(); 292 seg->fDistance = distance; 293 seg->fPtIndex = ptIndex; 294 seg->fType = kCubic_SegType; 295 seg->fTValue = maxt; 296 } 297 } 298 return distance; 299 } 300 301 void SkPathMeasure::buildSegments() { 302 SkPoint pts[4]; 303 int ptIndex = fFirstPtIndex; 304 SkScalar distance = 0; 305 bool isClosed = fForceClosed; 306 bool firstMoveTo = ptIndex < 0; 307 Segment* seg; 308 309 /* Note: 310 * as we accumulate distance, we have to check that the result of += 311 * actually made it larger, since a very small delta might be > 0, but 312 * still have no effect on distance (if distance >>> delta). 313 * 314 * We do this check below, and in compute_quad_segs and compute_cubic_segs 315 */ 316 fSegments.reset(); 317 bool done = false; 318 do { 319 switch (fIter.next(pts)) { 320 case SkPath::kMove_Verb: 321 ptIndex += 1; 322 fPts.append(1, pts); 323 if (!firstMoveTo) { 324 done = true; 325 break; 326 } 327 firstMoveTo = false; 328 break; 329 330 case SkPath::kLine_Verb: { 331 SkScalar d = SkPoint::Distance(pts[0], pts[1]); 332 SkASSERT(d >= 0); 333 SkScalar prevD = distance; 334 distance += d; 335 if (distance > prevD) { 336 seg = fSegments.append(); 337 seg->fDistance = distance; 338 seg->fPtIndex = ptIndex; 339 seg->fType = kLine_SegType; 340 seg->fTValue = kMaxTValue; 341 fPts.append(1, pts + 1); 342 ptIndex++; 343 } 344 } break; 345 346 case SkPath::kQuad_Verb: { 347 SkScalar prevD = distance; 348 if (false) { 349 SkScalar length = compute_quad_len(pts); 350 if (length) { 351 distance += length; 352 Segment* seg = fSegments.append(); 353 seg->fDistance = distance; 354 seg->fPtIndex = ptIndex; 355 seg->fType = kQuad_SegType; 356 seg->fTValue = kMaxTValue; 357 } 358 } else { 359 distance = this->compute_quad_segs(pts, distance, 0, kMaxTValue, ptIndex); 360 } 361 if (distance > prevD) { 362 fPts.append(2, pts + 1); 363 ptIndex += 2; 364 } 365 } break; 366 367 case SkPath::kConic_Verb: { 368 const SkConic conic(pts, fIter.conicWeight()); 369 SkScalar prevD = distance; 370 distance = this->compute_conic_segs(conic, distance, 0, conic.fPts[0], 371 kMaxTValue, conic.fPts[2], ptIndex); 372 if (distance > prevD) { 373 // we store the conic weight in our next point, followed by the last 2 pts 374 // thus to reconstitue a conic, you'd need to say 375 // SkConic(pts[0], pts[2], pts[3], weight = pts[1].fX) 376 fPts.append()->set(conic.fW, 0); 377 fPts.append(2, pts + 1); 378 ptIndex += 3; 379 } 380 } break; 381 382 case SkPath::kCubic_Verb: { 383 SkScalar prevD = distance; 384 distance = this->compute_cubic_segs(pts, distance, 0, kMaxTValue, ptIndex); 385 if (distance > prevD) { 386 fPts.append(3, pts + 1); 387 ptIndex += 3; 388 } 389 } break; 390 391 case SkPath::kClose_Verb: 392 isClosed = true; 393 break; 394 395 case SkPath::kDone_Verb: 396 done = true; 397 break; 398 } 399 } while (!done); 400 401 fLength = distance; 402 fIsClosed = isClosed; 403 fFirstPtIndex = ptIndex; 404 405 #ifdef SK_DEBUG 406 { 407 const Segment* seg = fSegments.begin(); 408 const Segment* stop = fSegments.end(); 409 unsigned ptIndex = 0; 410 SkScalar distance = 0; 411 // limit the loop to a reasonable number; pathological cases can run for minutes 412 int maxChecks = 10000000; // set to INT_MAX to defeat the check 413 while (seg < stop) { 414 SkASSERT(seg->fDistance > distance); 415 SkASSERT(seg->fPtIndex >= ptIndex); 416 SkASSERT(seg->fTValue > 0); 417 418 const Segment* s = seg; 419 while (s < stop - 1 && s[0].fPtIndex == s[1].fPtIndex && --maxChecks > 0) { 420 SkASSERT(s[0].fType == s[1].fType); 421 SkASSERT(s[0].fTValue < s[1].fTValue); 422 s += 1; 423 } 424 425 distance = seg->fDistance; 426 ptIndex = seg->fPtIndex; 427 seg += 1; 428 } 429 // SkDebugf("\n"); 430 } 431 #endif 432 } 433 434 static void compute_pos_tan(const SkPoint pts[], unsigned segType, 435 SkScalar t, SkPoint* pos, SkVector* tangent) { 436 switch (segType) { 437 case kLine_SegType: 438 if (pos) { 439 pos->set(SkScalarInterp(pts[0].fX, pts[1].fX, t), 440 SkScalarInterp(pts[0].fY, pts[1].fY, t)); 441 } 442 if (tangent) { 443 tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY); 444 } 445 break; 446 case kQuad_SegType: 447 SkEvalQuadAt(pts, t, pos, tangent); 448 if (tangent) { 449 tangent->normalize(); 450 } 451 break; 452 case kConic_SegType: { 453 SkConic(pts[0], pts[2], pts[3], pts[1].fX).evalAt(t, pos, tangent); 454 if (tangent) { 455 tangent->normalize(); 456 } 457 } break; 458 case kCubic_SegType: 459 SkEvalCubicAt(pts, t, pos, tangent, nullptr); 460 if (tangent) { 461 tangent->normalize(); 462 } 463 break; 464 default: 465 SkDEBUGFAIL("unknown segType"); 466 } 467 } 468 469 470 //////////////////////////////////////////////////////////////////////////////// 471 //////////////////////////////////////////////////////////////////////////////// 472 473 SkPathMeasure::SkPathMeasure() { 474 fPath = nullptr; 475 fTolerance = CHEAP_DIST_LIMIT; 476 fLength = -1; // signal we need to compute it 477 fForceClosed = false; 478 fFirstPtIndex = -1; 479 } 480 481 SkPathMeasure::SkPathMeasure(const SkPath& path, bool forceClosed, SkScalar resScale) { 482 fPath = &path; 483 fTolerance = CHEAP_DIST_LIMIT * SkScalarInvert(resScale); 484 fLength = -1; // signal we need to compute it 485 fForceClosed = forceClosed; 486 fFirstPtIndex = -1; 487 488 fIter.setPath(path, forceClosed); 489 } 490 491 SkPathMeasure::~SkPathMeasure() {} 492 493 /** Assign a new path, or null to have none. 494 */ 495 void SkPathMeasure::setPath(const SkPath* path, bool forceClosed) { 496 fPath = path; 497 fLength = -1; // signal we need to compute it 498 fForceClosed = forceClosed; 499 fFirstPtIndex = -1; 500 501 if (path) { 502 fIter.setPath(*path, forceClosed); 503 } 504 fSegments.reset(); 505 fPts.reset(); 506 } 507 508 SkScalar SkPathMeasure::getLength() { 509 if (fPath == nullptr) { 510 return 0; 511 } 512 if (fLength < 0) { 513 this->buildSegments(); 514 } 515 if (SkScalarIsNaN(fLength)) { 516 fLength = 0; 517 } 518 SkASSERT(fLength >= 0); 519 return fLength; 520 } 521 522 template <typename T, typename K> 523 int SkTKSearch(const T base[], int count, const K& key) { 524 SkASSERT(count >= 0); 525 if (count <= 0) { 526 return ~0; 527 } 528 529 SkASSERT(base != nullptr); // base may be nullptr if count is zero 530 531 int lo = 0; 532 int hi = count - 1; 533 534 while (lo < hi) { 535 int mid = (hi + lo) >> 1; 536 if (base[mid].fDistance < key) { 537 lo = mid + 1; 538 } else { 539 hi = mid; 540 } 541 } 542 543 if (base[hi].fDistance < key) { 544 hi += 1; 545 hi = ~hi; 546 } else if (key < base[hi].fDistance) { 547 hi = ~hi; 548 } 549 return hi; 550 } 551 552 const SkPathMeasure::Segment* SkPathMeasure::distanceToSegment( 553 SkScalar distance, SkScalar* t) { 554 SkDEBUGCODE(SkScalar length = ) this->getLength(); 555 SkASSERT(distance >= 0 && distance <= length); 556 557 const Segment* seg = fSegments.begin(); 558 int count = fSegments.count(); 559 560 int index = SkTKSearch<Segment, SkScalar>(seg, count, distance); 561 // don't care if we hit an exact match or not, so we xor index if it is negative 562 index ^= (index >> 31); 563 seg = &seg[index]; 564 565 // now interpolate t-values with the prev segment (if possible) 566 SkScalar startT = 0, startD = 0; 567 // check if the prev segment is legal, and references the same set of points 568 if (index > 0) { 569 startD = seg[-1].fDistance; 570 if (seg[-1].fPtIndex == seg->fPtIndex) { 571 SkASSERT(seg[-1].fType == seg->fType); 572 startT = seg[-1].getScalarT(); 573 } 574 } 575 576 SkASSERT(seg->getScalarT() > startT); 577 SkASSERT(distance >= startD); 578 SkASSERT(seg->fDistance > startD); 579 580 *t = startT + (seg->getScalarT() - startT) * (distance - startD) / (seg->fDistance - startD); 581 return seg; 582 } 583 584 bool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos, SkVector* tangent) { 585 if (nullptr == fPath) { 586 return false; 587 } 588 589 SkScalar length = this->getLength(); // call this to force computing it 590 int count = fSegments.count(); 591 592 if (count == 0 || length == 0) { 593 return false; 594 } 595 596 // pin the distance to a legal range 597 if (distance < 0) { 598 distance = 0; 599 } else if (distance > length) { 600 distance = length; 601 } 602 603 SkScalar t; 604 const Segment* seg = this->distanceToSegment(distance, &t); 605 606 compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, t, pos, tangent); 607 return true; 608 } 609 610 bool SkPathMeasure::getMatrix(SkScalar distance, SkMatrix* matrix, 611 MatrixFlags flags) { 612 if (nullptr == fPath) { 613 return false; 614 } 615 616 SkPoint position; 617 SkVector tangent; 618 619 if (this->getPosTan(distance, &position, &tangent)) { 620 if (matrix) { 621 if (flags & kGetTangent_MatrixFlag) { 622 matrix->setSinCos(tangent.fY, tangent.fX, 0, 0); 623 } else { 624 matrix->reset(); 625 } 626 if (flags & kGetPosition_MatrixFlag) { 627 matrix->postTranslate(position.fX, position.fY); 628 } 629 } 630 return true; 631 } 632 return false; 633 } 634 635 bool SkPathMeasure::getSegment(SkScalar startD, SkScalar stopD, SkPath* dst, 636 bool startWithMoveTo) { 637 SkASSERT(dst); 638 639 SkScalar length = this->getLength(); // ensure we have built our segments 640 641 if (startD < 0) { 642 startD = 0; 643 } 644 if (stopD > length) { 645 stopD = length; 646 } 647 if (startD > stopD) { 648 return false; 649 } 650 if (!fSegments.count()) { 651 return false; 652 } 653 654 SkPoint p; 655 SkScalar startT, stopT; 656 const Segment* seg = this->distanceToSegment(startD, &startT); 657 const Segment* stopSeg = this->distanceToSegment(stopD, &stopT); 658 SkASSERT(seg <= stopSeg); 659 660 if (startWithMoveTo) { 661 compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, startT, &p, nullptr); 662 dst->moveTo(p); 663 } 664 665 if (seg->fPtIndex == stopSeg->fPtIndex) { 666 SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, stopT, dst); 667 } else { 668 do { 669 SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, SK_Scalar1, dst); 670 seg = SkPathMeasure::NextSegment(seg); 671 startT = 0; 672 } while (seg->fPtIndex < stopSeg->fPtIndex); 673 SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, 0, stopT, dst); 674 } 675 return true; 676 } 677 678 bool SkPathMeasure::isClosed() { 679 (void)this->getLength(); // make sure we measure the current contour 680 return fIsClosed; 681 } 682 683 /** Move to the next contour in the path. Return true if one exists, or false if 684 we're done with the path. 685 */ 686 bool SkPathMeasure::nextContour() { 687 (void)this->getLength(); // make sure we measure the current contour 688 fLength = -1; // now signal that we should build the next set of segments 689 return this->getLength() > 0; 690 } 691 692 /////////////////////////////////////////////////////////////////////////////// 693 /////////////////////////////////////////////////////////////////////////////// 694 695 #ifdef SK_DEBUG 696 697 void SkPathMeasure::dump() { 698 SkDebugf("pathmeas: length=%g, segs=%d\n", fLength, fSegments.count()); 699 700 for (int i = 0; i < fSegments.count(); i++) { 701 const Segment* seg = &fSegments[i]; 702 SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n", 703 i, seg->fDistance, seg->fPtIndex, seg->getScalarT(), 704 seg->fType); 705 } 706 } 707 708 #endif 709