ferroui_base/rendering/composition/server/server_composition_visual/
walker.rs1use super::ServerCompositionVisual;
2use crate::platform::LtrbRect;
3use crate::rendering::composition::server::CompositorPools;
4use crate::Matrix;
5use std::rc::Rc;
6
7pub(super) trait IServerTreeVisitor {
8 fn pre_subgraph(&mut self, visual: &Rc<ServerCompositionVisual>) -> bool;
10 fn post_subgraph(&mut self, visual: &Rc<ServerCompositionVisual>);
11}
12
13pub struct TreeWalkerFrame {
16 visual: Rc<ServerCompositionVisual>,
17 children: Rc<Vec<Rc<ServerCompositionVisual>>>,
18 current_index: usize,
19}
20
21fn children_of(visual: &ServerCompositionVisual) -> Option<Rc<Vec<Rc<ServerCompositionVisual>>>> {
25 visual.children().map(|children| children.list())
26}
27
28pub(super) fn walk<V: IServerTreeVisitor>(visitor: &mut V, root: &Rc<ServerCompositionVisual>, pools: &CompositorPools) {
29 let mut frames = pools.tree_walker_frame_stack_pool.rent();
30
31 let visit_children = visitor.pre_subgraph(root);
32 let mut container = root.clone();
33 let mut children = match children_of(&container) {
34 Some(children) if visit_children && !children.is_empty() => children,
35 _ => {
36 visitor.post_subgraph(root);
37 pools.tree_walker_frame_stack_pool.return_stack(frames);
38 return;
39 }
40 };
41
42 let mut current_index = 0usize;
43
44 loop {
45 if current_index >= children.len() {
46 visitor.post_subgraph(&container);
48 let Some(frame) = frames.pop() else { break };
49 container = frame.visual;
50 children = frame.children;
51 current_index = frame.current_index;
52 continue;
53 }
54
55 let child = children[current_index].clone();
56 let visit_children = visitor.pre_subgraph(&child);
57 if visit_children {
58 if let Some(child_children) = children_of(&child).filter(|children| !children.is_empty()) {
59 frames.push(TreeWalkerFrame { visual: container, children, current_index: current_index + 1 });
61 container = child;
62 children = child_children;
63 current_index = 0;
64 continue; }
66 }
67
68 visitor.post_subgraph(&child);
70 current_index += 1;
71 }
72
73 pools.tree_walker_frame_stack_pool.return_stack(frames);
74}
75
76pub(super) struct TreeWalkContext {
77 pub(super) transform: Matrix,
78 pub(super) clip: LtrbRect,
79 transform_stack: Vec<Matrix>,
80 clip_stack: Vec<LtrbRect>,
81}
82
83impl TreeWalkContext {
84 pub(super) fn new(pools: &CompositorPools, transform: Matrix, clip: LtrbRect) -> Self {
85 Self {
86 transform,
87 clip,
88 transform_stack: pools.matrix_stack_pool.rent(),
89 clip_stack: pools.ltrb_rect_stack_pool.rent(),
90 }
91 }
92
93 pub(super) fn push_transform(&mut self, m: Matrix) {
94 self.transform_stack.push(self.transform);
95 self.transform = m * self.transform;
96 }
97
98 pub(super) fn push_set_transform(&mut self, m: Matrix) {
99 self.transform_stack.push(self.transform);
100 self.transform = m;
101 }
102
103 pub(super) fn push_clip(&mut self, rect: LtrbRect) {
104 self.clip_stack.push(self.clip);
105 self.clip = self.clip.intersect_or_empty(rect);
106 }
107
108 pub(super) fn reset_clip(&mut self, rect: LtrbRect) {
109 self.clip_stack.push(self.clip);
110 self.clip = rect;
111 }
112
113 pub(super) fn pop_transform(&mut self) {
114 self.transform = self.transform_stack.pop().expect("a transform was pushed");
115 }
116
117 pub(super) fn pop_clip(&mut self) {
118 self.clip = self.clip_stack.pop().expect("a clip was pushed");
119 }
120
121 pub(super) fn dispose(self, pools: &CompositorPools) {
122 pools.matrix_stack_pool.return_stack(self.transform_stack);
123 pools.ltrb_rect_stack_pool.return_stack(self.clip_stack);
124 }
125}