| OLD | NEW |
| 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 | 8 |
| 9 #include "SkPathMeasure.h" | 9 #include "SkPathMeasure.h" |
| 10 #include "SkPathMeasurePriv.h" |
| 10 #include "SkGeometry.h" | 11 #include "SkGeometry.h" |
| 11 #include "SkPath.h" | 12 #include "SkPath.h" |
| 12 #include "SkTSearch.h" | 13 #include "SkTSearch.h" |
| 13 | 14 |
| 14 // these must be 0,1,2,3 since they are in our 2-bit field | |
| 15 enum { | |
| 16 kLine_SegType, | |
| 17 kQuad_SegType, | |
| 18 kCubic_SegType, | |
| 19 kConic_SegType, | |
| 20 }; | |
| 21 | |
| 22 #define kMaxTValue 0x3FFFFFFF | 15 #define kMaxTValue 0x3FFFFFFF |
| 23 | 16 |
| 24 static inline SkScalar tValue2Scalar(int t) { | 17 static inline SkScalar tValue2Scalar(int t) { |
| 25 SkASSERT((unsigned)t <= kMaxTValue); | 18 SkASSERT((unsigned)t <= kMaxTValue); |
| 26 const SkScalar kMaxTReciprocal = 1.0f / kMaxTValue; | 19 const SkScalar kMaxTReciprocal = 1.0f / kMaxTValue; |
| 27 return t * kMaxTReciprocal; | 20 return t * kMaxTReciprocal; |
| 28 } | 21 } |
| 29 | 22 |
| 30 SkScalar SkPathMeasure::Segment::getScalarT() const { | 23 SkScalar SkPathMeasure::Segment::getScalarT() const { |
| 31 return tValue2Scalar(fTValue); | 24 return tValue2Scalar(fTValue); |
| 32 } | 25 } |
| 33 | 26 |
| 34 const SkPathMeasure::Segment* SkPathMeasure::NextSegment(const Segment* seg) { | 27 const SkPathMeasure::Segment* SkPathMeasure::NextSegment(const Segment* seg) { |
| 35 unsigned ptIndex = seg->fPtIndex; | 28 unsigned ptIndex = seg->fPtIndex; |
| 36 | 29 |
| 37 do { | 30 do { |
| 38 ++seg; | 31 ++seg; |
| 39 } while (seg->fPtIndex == ptIndex); | 32 } while (seg->fPtIndex == ptIndex); |
| 40 return seg; | 33 return seg; |
| 41 } | 34 } |
| 42 | 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-len
gth 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 conic.chopAt(stopT, tmp); |
| 89 dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW); |
| 90 } |
| 91 } else { |
| 92 if (SK_Scalar1 == stopT) { |
| 93 SkConic tmp1[2]; |
| 94 conic.chopAt(startT, tmp1); |
| 95 dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW); |
| 96 } else { |
| 97 SkConic tmp; |
| 98 conic.chopAt(startT, stopT, &tmp); |
| 99 dst->conicTo(tmp.fPts[1], tmp.fPts[2], tmp.fW); |
| 100 } |
| 101 } |
| 102 } break; |
| 103 case kCubic_SegType: |
| 104 if (0 == startT) { |
| 105 if (SK_Scalar1 == stopT) { |
| 106 dst->cubicTo(pts[1], pts[2], pts[3]); |
| 107 } else { |
| 108 SkChopCubicAt(pts, tmp0, stopT); |
| 109 dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]); |
| 110 } |
| 111 } else { |
| 112 SkChopCubicAt(pts, tmp0, startT); |
| 113 if (SK_Scalar1 == stopT) { |
| 114 dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]); |
| 115 } else { |
| 116 SkChopCubicAt(&tmp0[3], tmp1, (stopT - startT) / (1 - startT
)); |
| 117 dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]); |
| 118 } |
| 119 } |
| 120 break; |
| 121 default: |
| 122 SkDEBUGFAIL("unknown segType"); |
| 123 sk_throw(); |
| 124 } |
| 125 } |
| 126 |
| 43 /////////////////////////////////////////////////////////////////////////////// | 127 /////////////////////////////////////////////////////////////////////////////// |
| 44 | 128 |
| 45 static inline int tspan_big_enough(int tspan) { | 129 static inline int tspan_big_enough(int tspan) { |
| 46 SkASSERT((unsigned)tspan <= kMaxTValue); | 130 SkASSERT((unsigned)tspan <= kMaxTValue); |
| 47 return tspan >> 10; | 131 return tspan >> 10; |
| 48 } | 132 } |
| 49 | 133 |
| 50 // can't use tangents, since we need [0..1..................2] to be seen | 134 // can't use tangents, since we need [0..1..................2] to be seen |
| 51 // as definitely not a line (it is when drawn, but not parametrically) | 135 // as definitely not a line (it is when drawn, but not parametrically) |
| 52 // so we compare midpoints | 136 // so we compare midpoints |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 | 422 |
| 339 distance = seg->fDistance; | 423 distance = seg->fDistance; |
| 340 ptIndex = seg->fPtIndex; | 424 ptIndex = seg->fPtIndex; |
| 341 seg += 1; | 425 seg += 1; |
| 342 } | 426 } |
| 343 // SkDebugf("\n"); | 427 // SkDebugf("\n"); |
| 344 } | 428 } |
| 345 #endif | 429 #endif |
| 346 } | 430 } |
| 347 | 431 |
| 348 static void compute_pos_tan(const SkPoint pts[], int segType, | 432 static void compute_pos_tan(const SkPoint pts[], unsigned segType, |
| 349 SkScalar t, SkPoint* pos, SkVector* tangent) { | 433 SkScalar t, SkPoint* pos, SkVector* tangent) { |
| 350 switch (segType) { | 434 switch (segType) { |
| 351 case kLine_SegType: | 435 case kLine_SegType: |
| 352 if (pos) { | 436 if (pos) { |
| 353 pos->set(SkScalarInterp(pts[0].fX, pts[1].fX, t), | 437 pos->set(SkScalarInterp(pts[0].fX, pts[1].fX, t), |
| 354 SkScalarInterp(pts[0].fY, pts[1].fY, t)); | 438 SkScalarInterp(pts[0].fY, pts[1].fY, t)); |
| 355 } | 439 } |
| 356 if (tangent) { | 440 if (tangent) { |
| 357 tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].
fY); | 441 tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].
fY); |
| 358 } | 442 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 373 SkEvalCubicAt(pts, t, pos, tangent, nullptr); | 457 SkEvalCubicAt(pts, t, pos, tangent, nullptr); |
| 374 if (tangent) { | 458 if (tangent) { |
| 375 tangent->normalize(); | 459 tangent->normalize(); |
| 376 } | 460 } |
| 377 break; | 461 break; |
| 378 default: | 462 default: |
| 379 SkDEBUGFAIL("unknown segType"); | 463 SkDEBUGFAIL("unknown segType"); |
| 380 } | 464 } |
| 381 } | 465 } |
| 382 | 466 |
| 383 static void seg_to(const SkPoint pts[], int segType, | |
| 384 SkScalar startT, SkScalar stopT, SkPath* dst) { | |
| 385 SkASSERT(startT >= 0 && startT <= SK_Scalar1); | |
| 386 SkASSERT(stopT >= 0 && stopT <= SK_Scalar1); | |
| 387 SkASSERT(startT <= stopT); | |
| 388 | |
| 389 if (startT == stopT) { | |
| 390 /* if the dash as a zero-length on segment, add a corresponding zero-len
gth line. | |
| 391 The stroke code will add end caps to zero length lines as appropriate
*/ | |
| 392 SkPoint lastPt; | |
| 393 SkAssertResult(dst->getLastPt(&lastPt)); | |
| 394 dst->lineTo(lastPt); | |
| 395 return; | |
| 396 } | |
| 397 | |
| 398 SkPoint tmp0[7], tmp1[7]; | |
| 399 | |
| 400 switch (segType) { | |
| 401 case kLine_SegType: | |
| 402 if (SK_Scalar1 == stopT) { | |
| 403 dst->lineTo(pts[1]); | |
| 404 } else { | |
| 405 dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT), | |
| 406 SkScalarInterp(pts[0].fY, pts[1].fY, stopT)); | |
| 407 } | |
| 408 break; | |
| 409 case kQuad_SegType: | |
| 410 if (0 == startT) { | |
| 411 if (SK_Scalar1 == stopT) { | |
| 412 dst->quadTo(pts[1], pts[2]); | |
| 413 } else { | |
| 414 SkChopQuadAt(pts, tmp0, stopT); | |
| 415 dst->quadTo(tmp0[1], tmp0[2]); | |
| 416 } | |
| 417 } else { | |
| 418 SkChopQuadAt(pts, tmp0, startT); | |
| 419 if (SK_Scalar1 == stopT) { | |
| 420 dst->quadTo(tmp0[3], tmp0[4]); | |
| 421 } else { | |
| 422 SkChopQuadAt(&tmp0[2], tmp1, (stopT - startT) / (1 - startT)
); | |
| 423 dst->quadTo(tmp1[1], tmp1[2]); | |
| 424 } | |
| 425 } | |
| 426 break; | |
| 427 case kConic_SegType: { | |
| 428 SkConic conic(pts[0], pts[2], pts[3], pts[1].fX); | |
| 429 | |
| 430 if (0 == startT) { | |
| 431 if (SK_Scalar1 == stopT) { | |
| 432 dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW); | |
| 433 } else { | |
| 434 SkConic tmp[2]; | |
| 435 conic.chopAt(stopT, tmp); | |
| 436 dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW); | |
| 437 } | |
| 438 } else { | |
| 439 if (SK_Scalar1 == stopT) { | |
| 440 SkConic tmp1[2]; | |
| 441 conic.chopAt(startT, tmp1); | |
| 442 dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW); | |
| 443 } else { | |
| 444 SkConic tmp; | |
| 445 conic.chopAt(startT, stopT, &tmp); | |
| 446 dst->conicTo(tmp.fPts[1], tmp.fPts[2], tmp.fW); | |
| 447 } | |
| 448 } | |
| 449 } break; | |
| 450 case kCubic_SegType: | |
| 451 if (0 == startT) { | |
| 452 if (SK_Scalar1 == stopT) { | |
| 453 dst->cubicTo(pts[1], pts[2], pts[3]); | |
| 454 } else { | |
| 455 SkChopCubicAt(pts, tmp0, stopT); | |
| 456 dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]); | |
| 457 } | |
| 458 } else { | |
| 459 SkChopCubicAt(pts, tmp0, startT); | |
| 460 if (SK_Scalar1 == stopT) { | |
| 461 dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]); | |
| 462 } else { | |
| 463 SkChopCubicAt(&tmp0[3], tmp1, (stopT - startT) / (1 - startT
)); | |
| 464 dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]); | |
| 465 } | |
| 466 } | |
| 467 break; | |
| 468 default: | |
| 469 SkDEBUGFAIL("unknown segType"); | |
| 470 sk_throw(); | |
| 471 } | |
| 472 } | |
| 473 | 467 |
| 474 //////////////////////////////////////////////////////////////////////////////// | 468 //////////////////////////////////////////////////////////////////////////////// |
| 475 //////////////////////////////////////////////////////////////////////////////// | 469 //////////////////////////////////////////////////////////////////////////////// |
| 476 | 470 |
| 477 SkPathMeasure::SkPathMeasure() { | 471 SkPathMeasure::SkPathMeasure() { |
| 478 fPath = nullptr; | 472 fPath = nullptr; |
| 479 fTolerance = CHEAP_DIST_LIMIT; | 473 fTolerance = CHEAP_DIST_LIMIT; |
| 480 fLength = -1; // signal we need to compute it | 474 fLength = -1; // signal we need to compute it |
| 481 fForceClosed = false; | 475 fForceClosed = false; |
| 482 fFirstPtIndex = -1; | 476 fFirstPtIndex = -1; |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 660 const Segment* seg = this->distanceToSegment(startD, &startT); | 654 const Segment* seg = this->distanceToSegment(startD, &startT); |
| 661 const Segment* stopSeg = this->distanceToSegment(stopD, &stopT); | 655 const Segment* stopSeg = this->distanceToSegment(stopD, &stopT); |
| 662 SkASSERT(seg <= stopSeg); | 656 SkASSERT(seg <= stopSeg); |
| 663 | 657 |
| 664 if (startWithMoveTo) { | 658 if (startWithMoveTo) { |
| 665 compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, startT, &p, nullptr); | 659 compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, startT, &p, nullptr); |
| 666 dst->moveTo(p); | 660 dst->moveTo(p); |
| 667 } | 661 } |
| 668 | 662 |
| 669 if (seg->fPtIndex == stopSeg->fPtIndex) { | 663 if (seg->fPtIndex == stopSeg->fPtIndex) { |
| 670 seg_to(&fPts[seg->fPtIndex], seg->fType, startT, stopT, dst); | 664 SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, stopT, dst
); |
| 671 } else { | 665 } else { |
| 672 do { | 666 do { |
| 673 seg_to(&fPts[seg->fPtIndex], seg->fType, startT, SK_Scalar1, dst); | 667 SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, SK_Sca
lar1, dst); |
| 674 seg = SkPathMeasure::NextSegment(seg); | 668 seg = SkPathMeasure::NextSegment(seg); |
| 675 startT = 0; | 669 startT = 0; |
| 676 } while (seg->fPtIndex < stopSeg->fPtIndex); | 670 } while (seg->fPtIndex < stopSeg->fPtIndex); |
| 677 seg_to(&fPts[seg->fPtIndex], seg->fType, 0, stopT, dst); | 671 SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, 0, stopT, dst); |
| 678 } | 672 } |
| 679 return true; | 673 return true; |
| 680 } | 674 } |
| 681 | 675 |
| 682 bool SkPathMeasure::isClosed() { | 676 bool SkPathMeasure::isClosed() { |
| 683 (void)this->getLength(); | 677 (void)this->getLength(); |
| 684 return fIsClosed; | 678 return fIsClosed; |
| 685 } | 679 } |
| 686 | 680 |
| 687 /** Move to the next contour in the path. Return true if one exists, or false if | 681 /** Move to the next contour in the path. Return true if one exists, or false if |
| (...skipping 14 matching lines...) Expand all Loading... |
| 702 | 696 |
| 703 for (int i = 0; i < fSegments.count(); i++) { | 697 for (int i = 0; i < fSegments.count(); i++) { |
| 704 const Segment* seg = &fSegments[i]; | 698 const Segment* seg = &fSegments[i]; |
| 705 SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n", | 699 SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n", |
| 706 i, seg->fDistance, seg->fPtIndex, seg->getScalarT(), | 700 i, seg->fDistance, seg->fPtIndex, seg->getScalarT(), |
| 707 seg->fType); | 701 seg->fType); |
| 708 } | 702 } |
| 709 } | 703 } |
| 710 | 704 |
| 711 #endif | 705 #endif |
| OLD | NEW |