skia_safe/utils/
parse_path.rs

1use std::ffi::CString;
2
3use crate::{interop, prelude::*, Path};
4
5use skia_bindings as sb;
6
7pub fn from_svg(svg: impl AsRef<str>) -> Option<Path> {
8    let str = CString::new(svg.as_ref()).unwrap();
9    let mut path = Path::default();
10    unsafe { sb::SkParsePath_FromSVGString(str.as_ptr(), path.native_mut()) }.then_some(path)
11}
12
13pub use skia_bindings::SkParsePath_PathEncoding as PathEncoding;
14variant_name!(PathEncoding::Absolute);
15
16impl Path {
17    pub fn from_svg(svg: impl AsRef<str>) -> Option<Path> {
18        from_svg(svg)
19    }
20
21    pub fn to_svg(&self) -> String {
22        to_svg(self)
23    }
24
25    pub fn to_svg_with_encoding(&self, encoding: PathEncoding) -> String {
26        to_svg_with_encoding(self, encoding)
27    }
28}
29
30pub fn to_svg(path: &Path) -> String {
31    to_svg_with_encoding(path, PathEncoding::Absolute)
32}
33
34pub fn to_svg_with_encoding(path: &Path, encoding: PathEncoding) -> String {
35    interop::String::construct(|svg| {
36        unsafe { sb::C_SkParsePath_ToSVGString(path.native(), svg, encoding) };
37    })
38    .as_str()
39    .into()
40}
41
42#[cfg(test)]
43mod tests {
44    use super::Path;
45
46    #[test]
47    fn simple_path_to_svg_and_back() {
48        let mut path = Path::default();
49        path.move_to((0, 0));
50        path.line_to((100, 100));
51        path.line_to((0, 100));
52        path.close();
53
54        let svg = Path::to_svg(&path);
55        assert_eq!(svg, "M0 0L100 100L0 100L0 0Z");
56        // And back. Someone may find why they are not equal.
57        let _recreated = Path::from_svg(svg).expect("Failed to parse SVG path");
58    }
59}