skia_safe/core/
path_builder.rs

1use std::{fmt, mem};
2
3use crate::{
4    matrix, path, prelude::*, scalar, Matrix, Path, PathDirection, PathFillType, PathVerb, Point,
5    RRect, Rect, Vector,
6};
7use skia_bindings::{self as sb, SkPathBuilder, SkPath_AddPathMode};
8
9pub use skia_bindings::SkPathBuilder_ArcSize as ArcSize;
10variant_name!(ArcSize::Large);
11
12// PathBuilder can't be a Handle<>, because SkPathBuilder contains several STArrays with interior
13// pointers.
14//
15// See <https://github.com/rust-skia/rust-skia/pull/1195>.
16pub type PathBuilder = RefHandle<SkPathBuilder>;
17unsafe_send_sync!(PathBuilder);
18
19impl NativeDrop for SkPathBuilder {
20    fn drop(&mut self) {
21        unsafe { sb::C_SkPathBuilder_delete(self) }
22    }
23}
24
25impl Default for PathBuilder {
26    fn default() -> Self {
27        Self::new()
28    }
29}
30
31impl Clone for PathBuilder {
32    fn clone(&self) -> Self {
33        Self::from_ptr(unsafe { sb::C_SkPathBuilder_clone(self.native()) }).unwrap()
34    }
35}
36
37impl fmt::Debug for PathBuilder {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        f.debug_struct("PathBuilder")
40            .field("fill_type", &self.fill_type())
41            .finish()
42    }
43}
44
45impl From<PathBuilder> for Path {
46    fn from(mut value: PathBuilder) -> Self {
47        value.detach()
48    }
49}
50
51impl PathBuilder {
52    pub fn new() -> Self {
53        Self::from_ptr(unsafe { sb::C_SkPathBuilder_new() }).unwrap()
54    }
55
56    /* m87: No Implementation.
57    pub fn new_fill_type(fill_type: PathFillType) -> Self {
58        Self::construct(|pb| unsafe { sb::C_SkPathBuilder_Construct2(pb, fill_type) })
59    }
60    */
61
62    pub fn new_path(path: &Path) -> Self {
63        Self::from_ptr(unsafe { sb::C_SkPathBuilder_newFromPath(path.native()) }).unwrap()
64    }
65
66    pub fn fill_type(&self) -> PathFillType {
67        self.native().fFillType
68    }
69
70    pub fn compute_bounds(&self) -> Rect {
71        Rect::construct(|r| unsafe { sb::C_SkPathBuilder_computeBounds(self.native(), r) })
72    }
73
74    pub fn snapshot(&self) -> Path {
75        Path::construct(|path| unsafe { sb::C_SkPathBuilder_snapshot(self.native(), path) })
76    }
77
78    pub fn detach(&mut self) -> Path {
79        Path::construct(|path| unsafe { sb::C_SkPathBuilder_detach(self.native_mut(), path) })
80    }
81
82    pub fn set_fill_type(&mut self, ft: PathFillType) -> &mut Self {
83        self.native_mut().fFillType = ft;
84        self
85    }
86
87    pub fn set_is_volatile(&mut self, is_volatile: bool) -> &mut Self {
88        self.native_mut().fIsVolatile = is_volatile;
89        self
90    }
91
92    pub fn reset(&mut self) -> &mut Self {
93        unsafe {
94            self.native_mut().reset();
95        }
96        self
97    }
98
99    pub fn move_to(&mut self, pt: impl Into<Point>) -> &mut Self {
100        unsafe {
101            self.native_mut().moveTo(pt.into().into_native());
102        }
103        self
104    }
105
106    pub fn line_to(&mut self, pt: impl Into<Point>) -> &mut Self {
107        unsafe {
108            self.native_mut().lineTo(pt.into().into_native());
109        }
110        self
111    }
112
113    pub fn quad_to(&mut self, p1: impl Into<Point>, p2: impl Into<Point>) -> &mut Self {
114        unsafe {
115            self.native_mut()
116                .quadTo(p1.into().into_native(), p2.into().into_native());
117        }
118        self
119    }
120
121    pub fn conic_to(&mut self, p1: impl Into<Point>, p2: impl Into<Point>, w: scalar) -> &mut Self {
122        unsafe {
123            self.native_mut()
124                .conicTo(p1.into().into_native(), p2.into().into_native(), w);
125        }
126        self
127    }
128
129    pub fn cubic_to(
130        &mut self,
131        p1: impl Into<Point>,
132        p2: impl Into<Point>,
133        p3: impl Into<Point>,
134    ) -> &mut Self {
135        unsafe {
136            self.native_mut().cubicTo(
137                p1.into().into_native(),
138                p2.into().into_native(),
139                p3.into().into_native(),
140            )
141        };
142        self
143    }
144
145    pub fn close(&mut self) -> &mut Self {
146        unsafe {
147            self.native_mut().close();
148        }
149        self
150    }
151
152    pub fn polyline_to(&mut self, points: &[Point]) -> &mut Self {
153        unsafe {
154            sb::C_SkPathBuilder_polylineTo(
155                self.native_mut(),
156                points.native().as_ptr(),
157                points.len(),
158            );
159        }
160        self
161    }
162
163    pub fn r_move_to(&mut self, pt: impl Into<Point>) -> &mut Self {
164        unsafe {
165            self.native_mut().rMoveTo(pt.into().into_native());
166        }
167        self
168    }
169
170    pub fn r_line_to(&mut self, pt: impl Into<Point>) -> &mut Self {
171        unsafe {
172            self.native_mut().rLineTo(pt.into().into_native());
173        }
174        self
175    }
176
177    pub fn r_quad_to(&mut self, pt1: impl Into<Point>, pt2: impl Into<Point>) -> &mut Self {
178        unsafe {
179            self.native_mut()
180                .rQuadTo(pt1.into().into_native(), pt2.into().into_native());
181        }
182        self
183    }
184
185    pub fn r_conic_to(
186        &mut self,
187        pt1: impl Into<Point>,
188        pt2: impl Into<Point>,
189        w: scalar,
190    ) -> &mut Self {
191        unsafe {
192            self.native_mut()
193                .rConicTo(pt1.into().into_native(), pt2.into().into_native(), w);
194        }
195        self
196    }
197
198    pub fn r_cubic_to(
199        &mut self,
200        pt1: impl Into<Point>,
201        pt2: impl Into<Point>,
202        pt3: impl Into<Point>,
203    ) -> &mut Self {
204        unsafe {
205            self.native_mut().rCubicTo(
206                pt1.into().into_native(),
207                pt2.into().into_native(),
208                pt3.into().into_native(),
209            );
210        }
211        self
212    }
213
214    pub fn r_arc_to(
215        &mut self,
216        r: (scalar, scalar),
217        x_axis_rotate: scalar,
218        large_arc: ArcSize,
219        sweep: PathDirection,
220        d: impl Into<Vector>,
221    ) -> &mut Self {
222        let d = d.into();
223        unsafe {
224            self.native_mut()
225                .rArcTo(r.0, r.1, x_axis_rotate, large_arc, sweep, d.x, d.y);
226        }
227        self
228    }
229
230    pub fn arc_to(
231        &mut self,
232        oval: impl AsRef<Rect>,
233        start_angle_deg: scalar,
234        sweep_angle_deg: scalar,
235        force_move_to: bool,
236    ) -> &mut Self {
237        unsafe {
238            self.native_mut().arcTo(
239                oval.as_ref().native(),
240                start_angle_deg,
241                sweep_angle_deg,
242                force_move_to,
243            );
244        }
245        self
246    }
247
248    pub fn arc_to_tangent(
249        &mut self,
250        p1: impl Into<Point>,
251        p2: impl Into<Point>,
252        radius: scalar,
253    ) -> &mut Self {
254        unsafe {
255            self.native_mut()
256                .arcTo1(p1.into().into_native(), p2.into().into_native(), radius);
257        }
258        self
259    }
260
261    pub fn arc_to_radius(
262        &mut self,
263        r: impl Into<Point>,
264        x_axis_rotate: scalar,
265        large_arc: ArcSize,
266        sweep: PathDirection,
267        xy: impl Into<Point>,
268    ) -> &mut Self {
269        unsafe {
270            self.native_mut().arcTo2(
271                r.into().into_native(),
272                x_axis_rotate,
273                large_arc,
274                sweep,
275                xy.into().into_native(),
276            );
277        }
278        self
279    }
280
281    pub fn add_arc(
282        &mut self,
283        oval: impl AsRef<Rect>,
284        start_angle_deg: scalar,
285        sweep_angle_deg: scalar,
286    ) -> &mut Self {
287        unsafe {
288            self.native_mut()
289                .addArc(oval.as_ref().native(), start_angle_deg, sweep_angle_deg);
290        }
291        self
292    }
293
294    pub fn add_rect(
295        &mut self,
296        rect: impl AsRef<Rect>,
297        dir: impl Into<Option<PathDirection>>,
298        start_index: impl Into<Option<usize>>,
299    ) -> &mut Self {
300        let dir = dir.into().unwrap_or_default();
301        let start_index = start_index.into().unwrap_or(0);
302        unsafe {
303            self.native_mut()
304                .addRect(rect.as_ref().native(), dir, start_index.try_into().unwrap());
305        }
306        self
307    }
308
309    pub fn add_oval(
310        &mut self,
311        rect: impl AsRef<Rect>,
312        dir: impl Into<Option<PathDirection>>,
313        start_index: impl Into<Option<usize>>,
314    ) -> &mut Self {
315        let dir = dir.into().unwrap_or_default();
316        // m86: default start index changed from 0 to 1
317        let start_index = start_index.into().unwrap_or(1);
318        unsafe {
319            self.native_mut()
320                .addOval(rect.as_ref().native(), dir, start_index.try_into().unwrap());
321        }
322        self
323    }
324
325    pub fn add_rrect(
326        &mut self,
327        rect: impl AsRef<RRect>,
328        dir: impl Into<Option<PathDirection>>,
329        start_index: impl Into<Option<usize>>,
330    ) -> &mut Self {
331        let dir = dir.into().unwrap_or_default();
332        // m86: default start index changed from 0 to 6 or 7 depending on the path's direction.
333        let start_index =
334            start_index
335                .into()
336                .unwrap_or(if dir == PathDirection::CW { 6 } else { 7 });
337        unsafe {
338            self.native_mut().addRRect(
339                rect.as_ref().native(),
340                dir,
341                start_index.try_into().unwrap(),
342            );
343        }
344        self
345    }
346
347    pub fn add_circle(
348        &mut self,
349        center: impl Into<Point>,
350        radius: scalar,
351        dir: impl Into<Option<PathDirection>>,
352    ) -> &mut Self {
353        let center = center.into();
354        let dir = dir.into().unwrap_or_default();
355        unsafe {
356            self.native_mut().addCircle(center.x, center.y, radius, dir);
357        }
358        self
359    }
360
361    pub fn add_polygon(&mut self, pts: &[Point], close: bool) -> &mut Self {
362        unsafe {
363            sb::C_SkPathBuilder_addPolygon(
364                self.native_mut(),
365                pts.native().as_ptr(),
366                pts.len(),
367                close,
368            );
369        }
370        self
371    }
372
373    pub fn add_path(&mut self, path: &Path) -> &mut Self {
374        unsafe {
375            self.native_mut()
376                .addPath(path.native(), 0., 0., SkPath_AddPathMode::Append)
377        };
378        self
379    }
380
381    pub fn add_path_with_transform(
382        &mut self,
383        src: &Path,
384        matrix: &Matrix,
385        mode: impl Into<Option<path::AddPathMode>>,
386    ) {
387        unsafe {
388            self.native_mut().addPath1(
389                src.native(),
390                matrix.native(),
391                mode.into().unwrap_or(path::AddPathMode::Append),
392            )
393        };
394    }
395
396    pub fn inc_reserve(&mut self, extra_pt_count: usize, extra_verb_count: usize) {
397        unsafe {
398            self.native_mut().incReserve(
399                extra_pt_count.try_into().unwrap(),
400                extra_verb_count.try_into().unwrap(),
401            )
402        }
403    }
404
405    pub fn offset(&mut self, d: impl Into<Vector>) -> &mut Self {
406        let d = d.into();
407        unsafe {
408            self.native_mut().offset(d.x, d.y);
409        }
410        self
411    }
412
413    pub fn transform(
414        &mut self,
415        matrix: &Matrix,
416        pc: impl Into<Option<matrix::ApplyPerspectiveClip>>,
417    ) -> &mut Self {
418        let pc = pc.into().unwrap_or(matrix::ApplyPerspectiveClip::Yes);
419        unsafe {
420            self.native_mut().transform(matrix.native(), pc);
421        }
422        self
423    }
424
425    pub fn is_finite(&self) -> bool {
426        unsafe { self.native().isFinite() }
427    }
428
429    pub fn toggle_inverse_fill_type(&mut self) -> &mut Self {
430        let n = self.native_mut();
431        n.fFillType = unsafe { mem::transmute::<u8, sb::SkPathFillType>(n.fFillType as u8 ^ 2) };
432        self
433    }
434
435    pub fn is_empty(&self) -> bool {
436        unsafe { sb::C_SkPathBuilder_isEmpty(self.native()) }
437    }
438
439    pub fn get_last_pt(&self) -> Option<Point> {
440        let mut p = Point::default();
441        unsafe { sb::C_SkPathBuilder_getLastPt(self.native(), p.native_mut()) }.then_some(p)
442    }
443
444    pub fn set_last_pt(&mut self, p: impl Into<Point>) {
445        let p = p.into();
446        unsafe { self.native_mut().setLastPt(p.x, p.y) };
447    }
448
449    pub fn count_points(&self) -> usize {
450        unsafe { sb::C_SkPathBuilder_countPoints(self.native()) }
451    }
452
453    pub fn is_inverse_fill_type(&self) -> bool {
454        PathFillType::is_inverse(self.fill_type())
455    }
456
457    pub fn points(&self) -> &[Point] {
458        unsafe {
459            let mut len = 0;
460            let points = sb::C_SkPathBuilder_points(self.native(), &mut len);
461            safer::from_raw_parts(Point::from_native_ptr(points), len)
462        }
463    }
464
465    pub fn verbs(&self) -> &[PathVerb] {
466        unsafe {
467            let mut len = 0;
468            let verbs = sb::C_SkPathBuilder_verbs(self.native(), &mut len);
469            safer::from_raw_parts(verbs, len)
470        }
471    }
472}
473
474#[cfg(test)]
475mod tests {
476    use crate::{paint, surfaces, Paint};
477
478    use super::*;
479
480    #[test]
481    fn test_creation_snapshot_and_detach() {
482        let mut builder = PathBuilder::new();
483        let _path = builder.snapshot();
484        let _path = builder.detach();
485    }
486
487    #[test]
488    fn issue_1195() {
489        let mut surface = surfaces::raster_n32_premul((1000, 1000)).unwrap();
490        let canvas = surface.canvas();
491        let mut paint = Paint::default();
492        paint.set_style(paint::Style::Stroke);
493        let mut path = PathBuilder::new();
494        path.move_to((250., 250.));
495        path.cubic_to((300., 300.), (700., 700.), (750., 750.));
496        let pathsh = path.snapshot();
497        canvas.draw_path(&pathsh, &paint);
498    }
499}