skia_safe/utils/
parse_path.rs

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