| 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 | SkPath::RawIter fIter; |
| 124 | SkPath fPath; |
| 125 | SkScalar fTolerance; |
| 126 | bool fForceClosed; |
| 127 | |
| 128 | // temporary |
| 129 | SkTDArray<SkContourMeasure::Segment> fSegments; |
| 130 | SkTDArray<SkPoint> fPts; // Points used to define the segments |
| 131 | |
| 132 | SkContourMeasure* buildSegments(); |
| 133 | |
| 134 | SkScalar compute_line_seg(SkPoint p0, SkPoint p1, SkScalar distance, unsigned ptIndex); |
| 135 | SkScalar compute_quad_segs(const SkPoint pts[3], SkScalar distance, |
| 136 | int mint, int maxt, unsigned ptIndex); |
| 137 | SkScalar compute_conic_segs(const SkConic& conic, SkScalar distance, |
| 138 | int mint, const SkPoint& minPt, |
| 139 | int maxt, const SkPoint& maxPt, |
| 140 | unsigned ptIndex); |
| 141 | SkScalar compute_cubic_segs(const SkPoint pts[4], SkScalar distance, |
| 142 | int mint, int maxt, unsigned ptIndex); |
| 143 | |
| 144 | SkContourMeasureIter(const SkContourMeasureIter&) = delete; |
| 145 | SkContourMeasureIter& operator=(const SkContourMeasureIter&) = delete; |
| 146 | }; |
| 147 | |
| 148 | #endif |
| 149 | |