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