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 |