/src/skia/include/core/SkPathBuilder.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2015 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 SkPathBuilder_DEFINED |
9 | | #define SkPathBuilder_DEFINED |
10 | | |
11 | | #include "include/core/SkPath.h" |
12 | | #include "include/core/SkPathTypes.h" |
13 | | #include "include/core/SkPoint.h" |
14 | | #include "include/core/SkRect.h" |
15 | | #include "include/core/SkRefCnt.h" |
16 | | #include "include/core/SkScalar.h" |
17 | | #include "include/core/SkTypes.h" |
18 | | #include "include/private/SkPathRef.h" |
19 | | #include "include/private/base/SkTo.h" |
20 | | |
21 | | #include <initializer_list> |
22 | | |
23 | | class SkRRect; |
24 | | |
25 | | class SK_API SkPathBuilder { |
26 | | public: |
27 | | SkPathBuilder(); |
28 | | SkPathBuilder(SkPathFillType); |
29 | | SkPathBuilder(const SkPath&); |
30 | | SkPathBuilder(const SkPathBuilder&) = default; |
31 | | ~SkPathBuilder(); |
32 | | |
33 | | SkPathBuilder& operator=(const SkPath&); |
34 | | SkPathBuilder& operator=(const SkPathBuilder&) = default; |
35 | | |
36 | 0 | SkPathFillType fillType() const { return fFillType; } |
37 | | SkRect computeBounds() const; |
38 | | |
39 | | SkPath snapshot() const; // the builder is unchanged after returning this path |
40 | | SkPath detach(); // the builder is reset to empty after returning this path |
41 | | |
42 | 61.8k | SkPathBuilder& setFillType(SkPathFillType ft) { fFillType = ft; return *this; } |
43 | 695 | SkPathBuilder& setIsVolatile(bool isVolatile) { fIsVolatile = isVolatile; return *this; } |
44 | | |
45 | | SkPathBuilder& reset(); |
46 | | |
47 | | SkPathBuilder& moveTo(SkPoint pt); |
48 | 126k | SkPathBuilder& moveTo(SkScalar x, SkScalar y) { return this->moveTo(SkPoint::Make(x, y)); } |
49 | | |
50 | | SkPathBuilder& lineTo(SkPoint pt); |
51 | 121k | SkPathBuilder& lineTo(SkScalar x, SkScalar y) { return this->lineTo(SkPoint::Make(x, y)); } |
52 | | |
53 | | SkPathBuilder& quadTo(SkPoint pt1, SkPoint pt2); |
54 | 281k | SkPathBuilder& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { |
55 | 281k | return this->quadTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2)); |
56 | 281k | } |
57 | 0 | SkPathBuilder& quadTo(const SkPoint pts[2]) { return this->quadTo(pts[0], pts[1]); } |
58 | | |
59 | | SkPathBuilder& conicTo(SkPoint pt1, SkPoint pt2, SkScalar w); |
60 | 0 | SkPathBuilder& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w) { |
61 | 0 | return this->conicTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2), w); |
62 | 0 | } |
63 | 0 | SkPathBuilder& conicTo(const SkPoint pts[2], SkScalar w) { |
64 | 0 | return this->conicTo(pts[0], pts[1], w); |
65 | 0 | } |
66 | | |
67 | | SkPathBuilder& cubicTo(SkPoint pt1, SkPoint pt2, SkPoint pt3); |
68 | 11.9k | SkPathBuilder& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3) { |
69 | 11.9k | return this->cubicTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2), SkPoint::Make(x3, y3)); |
70 | 11.9k | } |
71 | 0 | SkPathBuilder& cubicTo(const SkPoint pts[3]) { |
72 | 0 | return this->cubicTo(pts[0], pts[1], pts[2]); |
73 | 0 | } |
74 | | |
75 | | SkPathBuilder& close(); |
76 | | |
77 | | // Append a series of lineTo(...) |
78 | | SkPathBuilder& polylineTo(const SkPoint pts[], int count); |
79 | 0 | SkPathBuilder& polylineTo(const std::initializer_list<SkPoint>& list) { |
80 | 0 | return this->polylineTo(list.begin(), SkToInt(list.size())); |
81 | 0 | } |
82 | | |
83 | | // Relative versions of segments, relative to the previous position. |
84 | | |
85 | | SkPathBuilder& rLineTo(SkPoint pt); |
86 | 0 | SkPathBuilder& rLineTo(SkScalar x, SkScalar y) { return this->rLineTo({x, y}); } |
87 | | SkPathBuilder& rQuadTo(SkPoint pt1, SkPoint pt2); |
88 | 0 | SkPathBuilder& rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { |
89 | 0 | return this->rQuadTo({x1, y1}, {x2, y2}); |
90 | 0 | } |
91 | | SkPathBuilder& rConicTo(SkPoint p1, SkPoint p2, SkScalar w); |
92 | 0 | SkPathBuilder& rConicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w) { |
93 | 0 | return this->rConicTo({x1, y1}, {x2, y2}, w); |
94 | 0 | } |
95 | | SkPathBuilder& rCubicTo(SkPoint pt1, SkPoint pt2, SkPoint pt3); |
96 | 0 | SkPathBuilder& rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3) { |
97 | 0 | return this->rCubicTo({x1, y1}, {x2, y2}, {x3, y3}); |
98 | 0 | } |
99 | | |
100 | | // Arcs |
101 | | |
102 | | /** Appends arc to the builder. Arc added is part of ellipse |
103 | | bounded by oval, from startAngle through sweepAngle. Both startAngle and |
104 | | sweepAngle are measured in degrees, where zero degrees is aligned with the |
105 | | positive x-axis, and positive sweeps extends arc clockwise. |
106 | | |
107 | | arcTo() adds line connecting the builder's last point to initial arc point if forceMoveTo |
108 | | is false and the builder is not empty. Otherwise, added contour begins with first point |
109 | | of arc. Angles greater than -360 and less than 360 are treated modulo 360. |
110 | | |
111 | | @param oval bounds of ellipse containing arc |
112 | | @param startAngleDeg starting angle of arc in degrees |
113 | | @param sweepAngleDeg sweep, in degrees. Positive is clockwise; treated modulo 360 |
114 | | @param forceMoveTo true to start a new contour with arc |
115 | | @return reference to the builder |
116 | | */ |
117 | | SkPathBuilder& arcTo(const SkRect& oval, SkScalar startAngleDeg, SkScalar sweepAngleDeg, |
118 | | bool forceMoveTo); |
119 | | |
120 | | /** Appends arc to SkPath, after appending line if needed. Arc is implemented by conic |
121 | | weighted to describe part of circle. Arc is contained by tangent from |
122 | | last SkPath point to p1, and tangent from p1 to p2. Arc |
123 | | is part of circle sized to radius, positioned so it touches both tangent lines. |
124 | | |
125 | | If last SkPath SkPoint does not start arc, arcTo() appends connecting line to SkPath. |
126 | | The length of vector from p1 to p2 does not affect arc. |
127 | | |
128 | | Arc sweep is always less than 180 degrees. If radius is zero, or if |
129 | | tangents are nearly parallel, arcTo() appends line from last SkPath SkPoint to p1. |
130 | | |
131 | | arcTo() appends at most one line and one conic. |
132 | | arcTo() implements the functionality of PostScript arct and HTML Canvas arcTo. |
133 | | |
134 | | @param p1 SkPoint common to pair of tangents |
135 | | @param p2 end of second tangent |
136 | | @param radius distance from arc to circle center |
137 | | @return reference to SkPath |
138 | | */ |
139 | | SkPathBuilder& arcTo(SkPoint p1, SkPoint p2, SkScalar radius); |
140 | | |
141 | | enum ArcSize { |
142 | | kSmall_ArcSize, //!< smaller of arc pair |
143 | | kLarge_ArcSize, //!< larger of arc pair |
144 | | }; |
145 | | |
146 | | /** Appends arc to SkPath. Arc is implemented by one or more conic weighted to describe |
147 | | part of oval with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves |
148 | | from last SkPath SkPoint to (xy.fX, xy.fY), choosing one of four possible routes: |
149 | | clockwise or counterclockwise, |
150 | | and smaller or larger. |
151 | | |
152 | | Arc sweep is always less than 360 degrees. arcTo() appends line to xy if either |
153 | | radii are zero, or if last SkPath SkPoint equals (xy.fX, xy.fY). arcTo() scales radii r to |
154 | | fit last SkPath SkPoint and xy if both are greater than zero but too small to describe |
155 | | an arc. |
156 | | |
157 | | arcTo() appends up to four conic curves. |
158 | | arcTo() implements the functionality of SVG arc, although SVG sweep-flag value is |
159 | | opposite the integer value of sweep; SVG sweep-flag uses 1 for clockwise, while |
160 | | kCW_Direction cast to int is zero. |
161 | | |
162 | | @param r radii on axes before x-axis rotation |
163 | | @param xAxisRotate x-axis rotation in degrees; positive values are clockwise |
164 | | @param largeArc chooses smaller or larger arc |
165 | | @param sweep chooses clockwise or counterclockwise arc |
166 | | @param xy end of arc |
167 | | @return reference to SkPath |
168 | | */ |
169 | | SkPathBuilder& arcTo(SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, SkPathDirection sweep, |
170 | | SkPoint xy); |
171 | | |
172 | | /** Appends arc to the builder, as the start of new contour. Arc added is part of ellipse |
173 | | bounded by oval, from startAngle through sweepAngle. Both startAngle and |
174 | | sweepAngle are measured in degrees, where zero degrees is aligned with the |
175 | | positive x-axis, and positive sweeps extends arc clockwise. |
176 | | |
177 | | If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly |
178 | | zero, append oval instead of arc. Otherwise, sweepAngle values are treated |
179 | | modulo 360, and arc may or may not draw depending on numeric rounding. |
180 | | |
181 | | @param oval bounds of ellipse containing arc |
182 | | @param startAngleDeg starting angle of arc in degrees |
183 | | @param sweepAngleDeg sweep, in degrees. Positive is clockwise; treated modulo 360 |
184 | | @return reference to this builder |
185 | | */ |
186 | | SkPathBuilder& addArc(const SkRect& oval, SkScalar startAngleDeg, SkScalar sweepAngleDeg); |
187 | | |
188 | | // Add a new contour |
189 | | |
190 | | SkPathBuilder& addRect(const SkRect&, SkPathDirection, unsigned startIndex); |
191 | | SkPathBuilder& addOval(const SkRect&, SkPathDirection, unsigned startIndex); |
192 | | SkPathBuilder& addRRect(const SkRRect&, SkPathDirection, unsigned startIndex); |
193 | | |
194 | 2 | SkPathBuilder& addRect(const SkRect& rect, SkPathDirection dir = SkPathDirection::kCW) { |
195 | 2 | return this->addRect(rect, dir, 0); |
196 | 2 | } |
197 | 1.86k | SkPathBuilder& addOval(const SkRect& rect, SkPathDirection dir = SkPathDirection::kCW) { |
198 | | // legacy start index: 1 |
199 | 1.86k | return this->addOval(rect, dir, 1); |
200 | 1.86k | } |
201 | 2.80k | SkPathBuilder& addRRect(const SkRRect& rrect, SkPathDirection dir = SkPathDirection::kCW) { |
202 | | // legacy start indices: 6 (CW) and 7 (CCW) |
203 | 2.80k | return this->addRRect(rrect, dir, dir == SkPathDirection::kCW ? 6 : 7); |
204 | 2.80k | } |
205 | | |
206 | | SkPathBuilder& addCircle(SkScalar center_x, SkScalar center_y, SkScalar radius, |
207 | | SkPathDirection dir = SkPathDirection::kCW); |
208 | | |
209 | | SkPathBuilder& addPolygon(const SkPoint pts[], int count, bool isClosed); |
210 | 0 | SkPathBuilder& addPolygon(const std::initializer_list<SkPoint>& list, bool isClosed) { |
211 | 0 | return this->addPolygon(list.begin(), SkToInt(list.size()), isClosed); |
212 | 0 | } |
213 | | |
214 | | SkPathBuilder& addPath(const SkPath&); |
215 | | |
216 | | // Performance hint, to reserve extra storage for subsequent calls to lineTo, quadTo, etc. |
217 | | |
218 | | void incReserve(int extraPtCount, int extraVerbCount); |
219 | 93.1k | void incReserve(int extraPtCount) { |
220 | 93.1k | this->incReserve(extraPtCount, extraPtCount); |
221 | 93.1k | } |
222 | | |
223 | | SkPathBuilder& offset(SkScalar dx, SkScalar dy); |
224 | | |
225 | 0 | SkPathBuilder& toggleInverseFillType() { |
226 | 0 | fFillType = (SkPathFillType)((unsigned)fFillType ^ 2); |
227 | 0 | return *this; |
228 | 0 | } |
229 | | |
230 | | private: |
231 | | SkPathRef::PointsArray fPts; |
232 | | SkPathRef::VerbsArray fVerbs; |
233 | | SkPathRef::ConicWeightsArray fConicWeights; |
234 | | |
235 | | SkPathFillType fFillType; |
236 | | bool fIsVolatile; |
237 | | |
238 | | unsigned fSegmentMask; |
239 | | SkPoint fLastMovePoint; |
240 | | int fLastMoveIndex; // only needed until SkPath is immutable |
241 | | bool fNeedsMoveVerb; |
242 | | |
243 | | enum IsA { |
244 | | kIsA_JustMoves, // we only have 0 or more moves |
245 | | kIsA_MoreThanMoves, // we have verbs other than just move |
246 | | kIsA_Oval, // we are 0 or more moves followed by an oval |
247 | | kIsA_RRect, // we are 0 or more moves followed by a rrect |
248 | | }; |
249 | | IsA fIsA = kIsA_JustMoves; |
250 | | int fIsAStart = -1; // tracks direction iff fIsA is not unknown |
251 | | bool fIsACCW = false; // tracks direction iff fIsA is not unknown |
252 | | |
253 | 0 | int countVerbs() const { return fVerbs.size(); } |
254 | | |
255 | | // called right before we add a (non-move) verb |
256 | 6.27M | void ensureMove() { |
257 | 6.27M | fIsA = kIsA_MoreThanMoves; |
258 | 6.27M | if (fNeedsMoveVerb) { |
259 | 12.8k | this->moveTo(fLastMovePoint); |
260 | 12.8k | } |
261 | 6.27M | } |
262 | | |
263 | | SkPath make(sk_sp<SkPathRef>) const; |
264 | | |
265 | | SkPathBuilder& privateReverseAddPath(const SkPath&); |
266 | | |
267 | | friend class SkPathPriv; |
268 | | }; |
269 | | |
270 | | #endif |
271 | | |