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
15struct SkConic;
16
17class SK_API SkContourMeasure : public SkRefCnt {
18public:
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
56private:
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
91class SK_API SkContourMeasureIter {
92public:
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
122private:
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