1use std::{fmt, mem};
2
3use crate::{
4 matrix, prelude::*, scalar, Matrix, Path, PathDirection, PathFillType, Point, RRect, Rect,
5 Vector,
6};
7use skia_bindings::{self as sb, SkPathBuilder};
8
9pub use skia_bindings::SkPathBuilder_ArcSize as ArcSize;
10variant_name!(ArcSize::Large);
11
12pub type PathBuilder = Handle<SkPathBuilder>;
13unsafe_send_sync!(PathBuilder);
14
15impl NativeDrop for SkPathBuilder {
16 fn drop(&mut self) {
17 unsafe { sb::C_SkPathBuilder_destruct(self) }
18 }
19}
20
21impl Clone for PathBuilder {
22 fn clone(&self) -> Self {
23 Self::construct(|pb| unsafe { sb::C_SkPathBuilder_CopyConstruct(pb, self.native()) })
24 }
25}
26
27impl fmt::Debug for PathBuilder {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 f.debug_struct("PathBuilder")
30 .field("fill_type", &self.fill_type())
31 .finish()
32 }
33}
34
35impl PathBuilder {
36 pub fn new() -> Self {
37 Self::construct(|pb| unsafe { sb::C_SkPathBuilder_Construct(pb) })
38 }
39
40 pub fn new_path(path: &Path) -> Self {
47 Self::construct(|pb| unsafe { sb::C_SkPathBuilder_Construct3(pb, path.native()) })
48 }
49
50 pub fn fill_type(&self) -> PathFillType {
51 self.native().fFillType
52 }
53
54 pub fn compute_bounds(&self) -> Rect {
55 Rect::construct(|r| unsafe { sb::C_SkPathBuilder_computeBounds(self.native(), r) })
56 }
57
58 pub fn snapshot(&self) -> Path {
59 let mut path = Path::default();
60 unsafe { sb::C_SkPathBuilder_snapshot(self.native(), path.native_mut()) }
61 path
62 }
63
64 pub fn detach(&mut self) -> Path {
65 let mut path = Path::default();
66 unsafe { sb::C_SkPathBuilder_detach(self.native_mut(), path.native_mut()) }
67 path
68 }
69
70 pub fn set_fill_type(&mut self, ft: PathFillType) -> &mut Self {
71 self.native_mut().fFillType = ft;
72 self
73 }
74
75 pub fn set_is_volatile(&mut self, is_volatile: bool) -> &mut Self {
76 self.native_mut().fIsVolatile = is_volatile;
77 self
78 }
79
80 pub fn reset(&mut self) -> &mut Self {
81 unsafe {
82 self.native_mut().reset();
83 }
84 self
85 }
86
87 pub fn move_to(&mut self, pt: impl Into<Point>) -> &mut Self {
88 unsafe {
89 self.native_mut().moveTo(pt.into().into_native());
90 }
91 self
92 }
93
94 pub fn line_to(&mut self, pt: impl Into<Point>) -> &mut Self {
95 unsafe {
96 self.native_mut().lineTo(pt.into().into_native());
97 }
98 self
99 }
100
101 pub fn quad_to(&mut self, p1: impl Into<Point>, p2: impl Into<Point>) -> &mut Self {
102 unsafe {
103 self.native_mut()
104 .quadTo(p1.into().into_native(), p2.into().into_native());
105 }
106 self
107 }
108
109 pub fn conic_to(&mut self, p1: impl Into<Point>, p2: impl Into<Point>, w: scalar) -> &mut Self {
110 unsafe {
111 self.native_mut()
112 .conicTo(p1.into().into_native(), p2.into().into_native(), w);
113 }
114 self
115 }
116
117 pub fn cubic_to(
118 &mut self,
119 p1: impl Into<Point>,
120 p2: impl Into<Point>,
121 p3: impl Into<Point>,
122 ) -> &mut Self {
123 unsafe {
124 self.native_mut().cubicTo(
125 p1.into().into_native(),
126 p2.into().into_native(),
127 p3.into().into_native(),
128 )
129 };
130 self
131 }
132
133 pub fn close(&mut self) -> &mut Self {
134 unsafe {
135 self.native_mut().close();
136 }
137 self
138 }
139
140 pub fn polyline_to(&mut self, points: &[Point]) -> &mut Self {
141 unsafe {
142 self.native_mut()
143 .polylineTo(points.native().as_ptr(), points.len().try_into().unwrap());
144 }
145 self
146 }
147
148 pub fn r_line_to(&mut self, pt: impl Into<Point>) -> &mut Self {
149 unsafe {
150 self.native_mut().rLineTo(pt.into().into_native());
151 }
152 self
153 }
154
155 pub fn r_quad_to(&mut self, pt1: impl Into<Point>, pt2: impl Into<Point>) -> &mut Self {
156 unsafe {
157 self.native_mut()
158 .rQuadTo(pt1.into().into_native(), pt2.into().into_native());
159 }
160 self
161 }
162
163 pub fn r_conic_to(
164 &mut self,
165 pt1: impl Into<Point>,
166 pt2: impl Into<Point>,
167 w: scalar,
168 ) -> &mut Self {
169 unsafe {
170 self.native_mut()
171 .rConicTo(pt1.into().into_native(), pt2.into().into_native(), w);
172 }
173 self
174 }
175
176 pub fn r_cubic_to(
177 &mut self,
178 pt1: impl Into<Point>,
179 pt2: impl Into<Point>,
180 pt3: impl Into<Point>,
181 ) -> &mut Self {
182 unsafe {
183 self.native_mut().rCubicTo(
184 pt1.into().into_native(),
185 pt2.into().into_native(),
186 pt3.into().into_native(),
187 );
188 }
189 self
190 }
191
192 pub fn arc_to(
193 &mut self,
194 oval: impl AsRef<Rect>,
195 start_angle_deg: scalar,
196 sweep_angle_deg: scalar,
197 force_move_to: bool,
198 ) -> &mut Self {
199 unsafe {
200 self.native_mut().arcTo(
201 oval.as_ref().native(),
202 start_angle_deg,
203 sweep_angle_deg,
204 force_move_to,
205 );
206 }
207 self
208 }
209
210 pub fn arc_to_tangent(
211 &mut self,
212 p1: impl Into<Point>,
213 p2: impl Into<Point>,
214 radius: scalar,
215 ) -> &mut Self {
216 unsafe {
217 self.native_mut()
218 .arcTo1(p1.into().into_native(), p2.into().into_native(), radius);
219 }
220 self
221 }
222
223 pub fn arc_to_radius(
224 &mut self,
225 r: impl Into<Point>,
226 x_axis_rotate: scalar,
227 large_arc: ArcSize,
228 sweep: PathDirection,
229 xy: impl Into<Point>,
230 ) -> &mut Self {
231 unsafe {
232 self.native_mut().arcTo2(
233 r.into().into_native(),
234 x_axis_rotate,
235 large_arc,
236 sweep,
237 xy.into().into_native(),
238 );
239 }
240 self
241 }
242
243 pub fn add_arc(
244 &mut self,
245 oval: impl AsRef<Rect>,
246 start_angle_deg: scalar,
247 sweep_angle_deg: scalar,
248 ) -> &mut Self {
249 unsafe {
250 self.native_mut()
251 .addArc(oval.as_ref().native(), start_angle_deg, sweep_angle_deg);
252 }
253 self
254 }
255
256 pub fn add_rect(
257 &mut self,
258 rect: impl AsRef<Rect>,
259 dir: impl Into<Option<PathDirection>>,
260 start_index: impl Into<Option<usize>>,
261 ) -> &mut Self {
262 let dir = dir.into().unwrap_or(PathDirection::CW);
263 let start_index = start_index.into().unwrap_or(0);
264 unsafe {
265 self.native_mut()
266 .addRect(rect.as_ref().native(), dir, start_index.try_into().unwrap());
267 }
268 self
269 }
270
271 pub fn add_oval(
272 &mut self,
273 rect: impl AsRef<Rect>,
274 dir: impl Into<Option<PathDirection>>,
275 start_index: impl Into<Option<usize>>,
276 ) -> &mut Self {
277 let dir = dir.into().unwrap_or(PathDirection::CW);
278 let start_index = start_index.into().unwrap_or(1);
280 unsafe {
281 self.native_mut()
282 .addOval(rect.as_ref().native(), dir, start_index.try_into().unwrap());
283 }
284 self
285 }
286
287 pub fn add_rrect(
288 &mut self,
289 rect: impl AsRef<RRect>,
290 dir: impl Into<Option<PathDirection>>,
291 start_index: impl Into<Option<usize>>,
292 ) -> &mut Self {
293 let dir = dir.into().unwrap_or(PathDirection::CW);
294 let start_index =
296 start_index
297 .into()
298 .unwrap_or(if dir == PathDirection::CW { 6 } else { 7 });
299 unsafe {
300 self.native_mut().addRRect(
301 rect.as_ref().native(),
302 dir,
303 start_index.try_into().unwrap(),
304 );
305 }
306 self
307 }
308
309 pub fn add_circle(
310 &mut self,
311 center: impl Into<Point>,
312 radius: scalar,
313 dir: impl Into<Option<PathDirection>>,
314 ) -> &mut Self {
315 let center = center.into();
316 let dir = dir.into().unwrap_or(PathDirection::CW);
317 unsafe {
318 self.native_mut().addCircle(center.x, center.y, radius, dir);
319 }
320 self
321 }
322
323 pub fn add_polygon(&mut self, pts: &[Point], close: bool) -> &mut Self {
324 unsafe {
325 self.native_mut().addPolygon(
326 pts.native().as_ptr(),
327 pts.len().try_into().unwrap(),
328 close,
329 );
330 }
331 self
332 }
333
334 pub fn add_path(&mut self, path: &Path) -> &mut Self {
335 unsafe { self.native_mut().addPath(path.native()) };
336 self
337 }
338
339 pub fn inc_reserve(&mut self, extra_pt_count: usize, extra_verb_count: usize) {
340 unsafe {
341 self.native_mut().incReserve(
342 extra_pt_count.try_into().unwrap(),
343 extra_verb_count.try_into().unwrap(),
344 )
345 }
346 }
347
348 pub fn offset(&mut self, d: impl Into<Vector>) -> &mut Self {
349 let d = d.into();
350 unsafe {
351 self.native_mut().offset(d.x, d.y);
352 }
353 self
354 }
355
356 pub fn transform(
357 &mut self,
358 matrix: &Matrix,
359 pc: impl Into<Option<matrix::ApplyPerspectiveClip>>,
360 ) -> &mut Self {
361 let pc = pc.into().unwrap_or(matrix::ApplyPerspectiveClip::Yes);
362 unsafe {
363 self.native_mut().transform(matrix.native(), pc);
364 }
365 self
366 }
367
368 pub fn toggle_inverse_fill_type(&mut self) -> &mut Self {
369 let n = self.native_mut();
370 n.fFillType = unsafe { mem::transmute::<i32, sb::SkPathFillType>(n.fFillType as i32 ^ 2) };
371 self
372 }
373
374 pub fn is_empty(&self) -> bool {
375 unsafe { sb::C_SkPathBuilder_isEmpty(self.native()) }
376 }
377
378 pub fn get_last_pt(&self) -> Option<Point> {
379 let mut p = Point::default();
380 unsafe { sb::C_SkPathBuilder_getLastPt(self.native(), p.native_mut()) }
381 .if_true_then_some(|| p)
382 }
383
384 pub fn set_last_pt(&mut self, p: impl Into<Point>) {
385 let p = p.into();
386 unsafe { self.native_mut().setLastPt(p.x, p.y) };
387 }
388
389 pub fn count_points(&self) -> usize {
390 unsafe { sb::C_SkPathBuilder_countPoints(self.native()) }
391 }
392
393 pub fn is_inverse_fill_type(&self) -> bool {
394 PathFillType::is_inverse(self.fill_type())
395 }
396}
397
398#[cfg(test)]
399mod tests {
400 use super::*;
401
402 #[test]
403 fn test_creation_snapshot_and_detach() {
404 let mut builder = PathBuilder::new();
405 let _path = builder.snapshot();
406 let _path = builder.detach();
407 }
408}