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 */ length()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 */ isClosed()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 NextSegment66 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); ~SkContourMeasure()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