skia_safe/core/
path_builder.rs

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    /* m87: No Implementation.
41    pub fn new_fill_type(fill_type: PathFillType) -> Self {
42        Self::construct(|pb| unsafe { sb::C_SkPathBuilder_Construct2(pb, fill_type) })
43    }
44    */
45
46    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        // m86: default start index changed from 0 to 1
279        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        // m86: default start index changed from 0 to 6 or 7 depending on the path's direction.
295        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}