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      *  resScale controls the precision of the measure. values > 1 increase the
100      *  precision (and possibly slow down the computation).
101      */
102     SkContourMeasureIter(const SkPath& path, bool forceClosed, SkScalar resScale = 1);
103     ~SkContourMeasureIter();
104 
105     /**
106      *  Reset the Iter with a path.
107      *  The parts of the path that are needed are copied, so the client is free to modify/delete
108      *  the path after this call.
109      */
110     void reset(const SkPath& path, bool forceClosed, SkScalar resScale = 1);
111 
112     /**
113      *  Iterates through contours in path, returning a contour-measure object for each contour
114      *  in the path. Returns null when it is done.
115      *
116      *  This only returns non-zero length contours, where a contour is the segments between
117      *  a kMove_Verb and either ...
118      *      - the next kMove_Verb
119      *      - kClose_Verb (1 or more)
120      *      - kDone_Verb
121      *  If it encounters a zero-length contour, it is skipped.
122      */
123     sk_sp<SkContourMeasure> next();
124 
125 private:
126     class Impl;
127 
128     std::unique_ptr<Impl> fImpl;
129 };
130 
131 #endif
132