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