• 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 "../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