• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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