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 | |