ferroui_base/rendering/composition/server/server_composition_visual/
adorners.rs1use super::render::RenderContext;
5use super::ServerCompositionVisual;
6use crate::rendering::composition::MatrixUtils;
7use crate::{Matrix, Rect};
8use std::rc::Rc;
9
10const OP_POP_CLIP: i32 = 0;
11const OP_POP_GEOMETRY_CLIP: i32 = 1;
12const OP_STOP: i32 = 2;
13
14impl ServerCompositionVisual {
15 pub(super) fn adorner_helper_attached_to_root(&self) {
16 if self.adorned_visual().is_some() {
17 self.adorner_helper_enqueue_for_adorner_update();
18 }
19 }
20
21 pub fn adorner_helper_enqueue_for_adorner_update(&self) {
22 if self.att_helper.enqueued_for_adorner_update.get() {
23 return;
24 }
25 if let (Some(compositor), Some(this)) = (self.compositor(), self.rc()) {
26 compositor.enqueue_adorner_update(this);
27 self.att_helper.enqueued_for_adorner_update.set(true);
28 }
29 }
30
31 pub(super) fn on_adorned_visual_changing_core(&self) {
32 if let Some(adorned) = self.adorned_visual() {
33 adorned.att_helper_unsubscribe_from_act_notification(&self.adorned_visual_act_subscription_action());
34 }
35 }
36
37 pub(super) fn on_adorned_visual_changed_core(&self) {
38 if let Some(adorned) = self.adorned_visual() {
39 adorned.att_helper_subscribe_to_act_notification(self.adorned_visual_act_subscription_action());
40 }
41 self.adorner_helper_enqueue_for_adorner_update();
42 }
43
44 fn adorner_layer_get_expected_shared_ancestor(adorner: &ServerCompositionVisual) -> Option<Rc<ServerCompositionVisual>> {
45 adorner.parent()?.parent()
49 }
50
51 pub fn update_adorner(&self) {
52 self.att_helper.enqueued_for_adorner_update.set(false);
53 let adorned = self.adorned_visual();
54 if let (Some(adorned), true) = (&adorned, self.parent().is_some()) {
55 let own_transform = MatrixUtils::compute_transform(
58 self.size(),
59 self.anchor_point(),
60 self.center_point(),
61 Matrix::IDENTITY,
62 self.scale(),
63 self.rotation_angle(),
64 self.orientation(),
65 self.offset() + self.translation(),
66 );
67
68 let adorner_layer_to_adorned_visual = Self::adorner_layer_get_expected_shared_ancestor(self)
69 .and_then(|shared_ancestor| Self::compute_transform_from_ancestor(adorned, &shared_ancestor));
70 match adorner_layer_to_adorned_visual {
71 Some(transform) => {
72 self.own_transform.set(Some(own_transform.unwrap_or(Matrix::IDENTITY) * transform))
73 }
74 None => self.own_transform.set(Some(Matrix::new_3x3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0))),
76 }
77 } else {
78 self.own_transform.set(MatrixUtils::compute_transform(
79 self.size(),
80 self.anchor_point(),
81 self.center_point(),
82 self.transform_matrix(),
83 self.scale(),
84 self.rotation_angle(),
85 self.orientation(),
86 self.offset() + self.translation(),
87 ));
88 }
89
90 self.propagate_flags(true, true, false);
91 }
92}
93
94impl RenderContext<'_> {
95 fn adorner_layer_walk_adorner_parent_clip_recursive(&mut self, visual: Option<Rc<ServerCompositionVisual>>) -> bool {
96 let Some(visual) = visual else { return false };
98 let is_layer = self.current_adorner_layer.as_ref().is_some_and(|layer| Rc::ptr_eq(layer, &visual));
99 if !is_layer && !self.adorner_layer_walk_adorner_parent_clip_recursive(visual.parent()) {
100 return false;
101 }
102
103 if let Some(own_transform) = visual.own_transform.get() {
104 let transform = own_transform * self.canvas.transform();
105 self.canvas.set_transform(transform);
106 }
107
108 if visual.clip_to_bounds() {
109 let size = visual.size();
110 self.canvas.push_clip(Rect::new(0.0, 0.0, size.x, size.y));
111 if let Some(stack) = &mut self.adorner_pushed_clip_stack {
112 stack.push(OP_POP_CLIP);
113 }
114 }
115
116 if let Some(clip) = visual.clip() {
117 self.canvas.push_geometry_clip(&*clip);
118 if let Some(stack) = &mut self.adorner_pushed_clip_stack {
119 stack.push(OP_POP_GEOMETRY_CLIP);
120 }
121 }
122
123 true
124 }
125
126 fn skip_adorner_clip(&self, visual: &Rc<ServerCompositionVisual>) -> bool {
127 !visual.adorner_is_clipped()
128 || Rc::ptr_eq(visual, &self.root_visual)
129 || visual.parent().is_some_and(|parent| Rc::ptr_eq(&parent, &self.root_visual))
131 || ServerCompositionVisual::adorner_layer_get_expected_shared_ancestor(visual).is_none()
132 }
133
134 pub(super) fn adorner_helper_render_pre_graph_push_adorner_clip(&mut self, visual: &Rc<ServerCompositionVisual>) {
135 if self.skip_adorner_clip(visual) {
136 return;
137 }
138
139 let pools = self.pools;
140 self.adorner_pushed_clip_stack.get_or_insert_with(|| pools.int_stack_pool.rent()).push(OP_STOP);
141
142 let original_transform = self.canvas.transform();
143 let mut transform = original_transform;
144 if let Some(own_transform) = visual.own_transform.get() {
145 let Some(transform_to_adorner_layer) = own_transform.try_invert() else { return };
146 transform = transform_to_adorner_layer * transform;
147 }
148
149 self.canvas.set_transform(transform);
150
151 self.current_adorner_layer = ServerCompositionVisual::adorner_layer_get_expected_shared_ancestor(visual);
152 self.adorner_layer_walk_adorner_parent_clip_recursive(visual.adorned_visual());
153
154 self.canvas.set_transform(original_transform);
155 }
156
157 pub(super) fn adorner_helper_render_post_graph_push_adorner_clip(&mut self, visual: &Rc<ServerCompositionVisual>) {
158 if self.skip_adorner_clip(visual) {
159 return;
160 }
161
162 loop {
163 let Some(op) = self.adorner_pushed_clip_stack.as_mut().and_then(Vec::pop) else { break };
164 if op == OP_STOP {
165 break;
166 }
167 if op == OP_POP_GEOMETRY_CLIP {
168 self.canvas.pop_geometry_clip();
169 } else if op == OP_POP_CLIP {
170 self.canvas.pop_clip();
171 }
172 }
173 }
174
175 pub(super) fn adorner_helper_dispose(&mut self) {
176 if let Some(stack) = self.adorner_pushed_clip_stack.take() {
177 self.pools.int_stack_pool.return_stack(stack);
178 }
179 }
180}