Skip to main content

ferroui_vello/
geometry_group_impl.rs

1use crate::geometry_impl::{
2    impl_geometry_impl, register, try_get_geometry_impl, FillPath, GeometryImpl, GeometryImplBase, VelloPath,
3};
4use ferroui_base::media::FillRule;
5use ferroui_base::platform::IGeometryImpl;
6use ferroui_base::Rect;
7use kurbo::BezPath;
8use std::sync::Arc;
9
10/// A kurbo implementation of a geometry group.
11pub struct GeometryGroupImpl {
12    base: GeometryImplBase,
13    bounds: Rect,
14    stroke_path: VelloPath,
15    fill: FillPath,
16}
17
18impl GeometryGroupImpl {
19    /// Creates a geometry from the paths of `children`. Children of another
20    /// backend are skipped.
21    pub fn new(fill_rule: FillRule, children: &[Arc<dyn IGeometryImpl>]) -> Arc<Self> {
22        let children: Vec<&dyn GeometryImpl> =
23            children.iter().filter_map(|child| try_get_geometry_impl(&**child)).collect();
24
25        let mut stroke = BezPath::new();
26        let mut requires_fill_pass = false;
27
28        for geo in &children {
29            if let Some(stroke_path) = geo.stroke_path() {
30                stroke.extend(stroke_path.path().iter());
31            }
32
33            if !geo.is_fill_same_as_stroke() {
34                requires_fill_pass = true;
35            }
36        }
37
38        let stroke_path = VelloPath::new(stroke, fill_rule);
39
40        let fill = if requires_fill_pass {
41            let mut fill = BezPath::new();
42
43            for geo in &children {
44                if let Some(fill_path) = geo.fill_path() {
45                    fill.extend(fill_path.path().iter());
46                }
47            }
48
49            FillPath::Separate(VelloPath::new(fill, fill_rule))
50        } else {
51            FillPath::SameAsStroke
52        };
53
54        let bounds = stroke_path.tight_bounds();
55
56        register(Self { base: GeometryImplBase::new(), bounds, stroke_path, fill })
57    }
58
59    fn geometry_bounds(&self) -> Rect {
60        self.bounds
61    }
62}
63
64impl GeometryImpl for GeometryGroupImpl {
65    fn base(&self) -> &GeometryImplBase {
66        &self.base
67    }
68
69    fn stroke_path(&self) -> Option<VelloPath> {
70        Some(self.stroke_path.clone())
71    }
72
73    fn fill(&self) -> FillPath {
74        self.fill.clone()
75    }
76}
77
78impl_geometry_impl!(GeometryGroupImpl);