skia_safe/core/
path_builder.rs

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