| 1 | /* | 
|---|
| 2 | * Copyright 2018 Google Inc. | 
|---|
| 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 | #ifndef SkContourMeasure_DEFINED | 
|---|
| 9 | #define SkContourMeasure_DEFINED | 
|---|
| 10 |  | 
|---|
| 11 | #include "include/core/SkPath.h" | 
|---|
| 12 | #include "include/core/SkRefCnt.h" | 
|---|
| 13 | #include "include/private/SkTDArray.h" | 
|---|
| 14 |  | 
|---|
| 15 | struct SkConic; | 
|---|
| 16 |  | 
|---|
| 17 | class SK_API SkContourMeasure : public SkRefCnt { | 
|---|
| 18 | public: | 
|---|
| 19 | /** Return the length of the contour. | 
|---|
| 20 | */ | 
|---|
| 21 | SkScalar length() const { return fLength; } | 
|---|
| 22 |  | 
|---|
| 23 | /** Pins distance to 0 <= distance <= length(), and then computes the corresponding | 
|---|
| 24 | *  position and tangent. | 
|---|
| 25 | */ | 
|---|
| 26 | bool SK_WARN_UNUSED_RESULT getPosTan(SkScalar distance, SkPoint* position, | 
|---|
| 27 | SkVector* tangent) const; | 
|---|
| 28 |  | 
|---|
| 29 | enum MatrixFlags { | 
|---|
| 30 | kGetPosition_MatrixFlag     = 0x01, | 
|---|
| 31 | kGetTangent_MatrixFlag      = 0x02, | 
|---|
| 32 | kGetPosAndTan_MatrixFlag    = kGetPosition_MatrixFlag | kGetTangent_MatrixFlag | 
|---|
| 33 | }; | 
|---|
| 34 |  | 
|---|
| 35 | /** Pins distance to 0 <= distance <= getLength(), and then computes | 
|---|
| 36 | the corresponding matrix (by calling getPosTan). | 
|---|
| 37 | Returns false if there is no path, or a zero-length path was specified, in which case | 
|---|
| 38 | matrix is unchanged. | 
|---|
| 39 | */ | 
|---|
| 40 | bool SK_WARN_UNUSED_RESULT getMatrix(SkScalar distance, SkMatrix* matrix, | 
|---|
| 41 | MatrixFlags flags = kGetPosAndTan_MatrixFlag) const; | 
|---|
| 42 |  | 
|---|
| 43 | /** Given a start and stop distance, return in dst the intervening segment(s). | 
|---|
| 44 | If the segment is zero-length, return false, else return true. | 
|---|
| 45 | startD and stopD are pinned to legal values (0..getLength()). If startD > stopD | 
|---|
| 46 | then return false (and leave dst untouched). | 
|---|
| 47 | Begin the segment with a moveTo if startWithMoveTo is true | 
|---|
| 48 | */ | 
|---|
| 49 | bool SK_WARN_UNUSED_RESULT getSegment(SkScalar startD, SkScalar stopD, SkPath* dst, | 
|---|
| 50 | bool startWithMoveTo) const; | 
|---|
| 51 |  | 
|---|
| 52 | /** Return true if the contour is closed() | 
|---|
| 53 | */ | 
|---|
| 54 | bool isClosed() const { return fIsClosed; } | 
|---|
| 55 |  | 
|---|
| 56 | private: | 
|---|
| 57 | struct Segment { | 
|---|
| 58 | SkScalar    fDistance;  // total distance up to this point | 
|---|
| 59 | unsigned    fPtIndex; // index into the fPts array | 
|---|
| 60 | unsigned    fTValue : 30; | 
|---|
| 61 | unsigned    fType : 2;  // actually the enum SkSegType | 
|---|
| 62 | // See SkPathMeasurePriv.h | 
|---|
| 63 |  | 
|---|
| 64 | SkScalar getScalarT() const; | 
|---|
| 65 |  | 
|---|
| 66 | static const Segment* Next(const Segment* seg) { | 
|---|
| 67 | unsigned ptIndex = seg->fPtIndex; | 
|---|
| 68 | do { | 
|---|
| 69 | ++seg; | 
|---|
| 70 | } while (seg->fPtIndex == ptIndex); | 
|---|
| 71 | return seg; | 
|---|
| 72 | } | 
|---|
| 73 |  | 
|---|
| 74 | }; | 
|---|
| 75 |  | 
|---|
| 76 | const SkTDArray<Segment>  fSegments; | 
|---|
| 77 | const SkTDArray<SkPoint>  fPts; // Points used to define the segments | 
|---|
| 78 |  | 
|---|
| 79 | const SkScalar fLength; | 
|---|
| 80 | const bool fIsClosed; | 
|---|
| 81 |  | 
|---|
| 82 | SkContourMeasure(SkTDArray<Segment>&& segs, SkTDArray<SkPoint>&& pts, | 
|---|
| 83 | SkScalar length, bool isClosed); | 
|---|
| 84 | ~SkContourMeasure() override {} | 
|---|
| 85 |  | 
|---|
| 86 | const Segment* distanceToSegment(SkScalar distance, SkScalar* t) const; | 
|---|
| 87 |  | 
|---|
| 88 | friend class SkContourMeasureIter; | 
|---|
| 89 | }; | 
|---|
| 90 |  | 
|---|
| 91 | class SK_API SkContourMeasureIter { | 
|---|
| 92 | public: | 
|---|
| 93 | SkContourMeasureIter(); | 
|---|
| 94 | /** | 
|---|
| 95 | *  Initialize the Iter with a path. | 
|---|
| 96 | *  The parts of the path that are needed are copied, so the client is free to modify/delete | 
|---|
| 97 | *  the path after this call. | 
|---|
| 98 | */ | 
|---|
| 99 | SkContourMeasureIter(const SkPath& path, bool forceClosed, SkScalar resScale = 1); | 
|---|
| 100 | ~SkContourMeasureIter(); | 
|---|
| 101 |  | 
|---|
| 102 | /** | 
|---|
| 103 | *  Reset the Iter with a path. | 
|---|
| 104 | *  The parts of the path that are needed are copied, so the client is free to modify/delete | 
|---|
| 105 | *  the path after this call. | 
|---|
| 106 | */ | 
|---|
| 107 | void reset(const SkPath& path, bool forceClosed, SkScalar resScale = 1); | 
|---|
| 108 |  | 
|---|
| 109 | /** | 
|---|
| 110 | *  Iterates through contours in path, returning a contour-measure object for each contour | 
|---|
| 111 | *  in the path. Returns null when it is done. | 
|---|
| 112 | * | 
|---|
| 113 | *  This only returns non-zero length contours, where a contour is the segments between | 
|---|
| 114 | *  a kMove_Verb and either ... | 
|---|
| 115 | *      - the next kMove_Verb | 
|---|
| 116 | *      - kClose_Verb (1 or more) | 
|---|
| 117 | *      - kDone_Verb | 
|---|
| 118 | *  If it encounters a zero-length contour, it is skipped. | 
|---|
| 119 | */ | 
|---|
| 120 | sk_sp<SkContourMeasure> next(); | 
|---|
| 121 |  | 
|---|
| 122 | private: | 
|---|
| 123 | class Impl; | 
|---|
| 124 |  | 
|---|
| 125 | std::unique_ptr<Impl> fImpl; | 
|---|
| 126 | }; | 
|---|
| 127 |  | 
|---|
| 128 | #endif | 
|---|
| 129 |  | 
|---|