ferroui_base/rendering/composition/
composition_custom_visual_handler.rs1use super::server::ServerCompositionVisual;
2use crate::media::ImmediateDrawingContext;
3use crate::platform::LtrbRect;
4use crate::{Matrix, Point, Rect, Vector};
5use std::any::Any;
6use std::cell::{Cell, RefCell};
7use std::rc::{Rc, Weak};
8use std::time::Duration;
9
10#[derive(Default)]
17pub struct CompositionCustomVisualHandler {
18 host: RefCell<Option<Weak<ServerCompositionVisual>>>,
19 in_render: Cell<bool>,
20 current_transformed_clip: Cell<Rect>,
21 current_transform: Cell<Matrix>,
22}
23
24pub trait ICompositionCustomVisualHandler: 'static {
27 fn handler_base(&self) -> &CompositionCustomVisualHandler;
29
30 fn on_message(&self, _message: std::sync::Arc<dyn Any + Send + Sync>) {}
32
33 fn on_animation_frame_update(&self) {}
34
35 fn on_render(&self, drawing_context: &mut ImmediateDrawingContext<'_>);
36
37 fn get_render_bounds(&self) -> Rect {
40 let size = self.handler_base().effective_size();
41 Rect::new(0.0, 0.0, size.x, size.y)
42 }
43}
44
45impl CompositionCustomVisualHandler {
46 pub fn new() -> Self {
47 Self::default()
48 }
49
50 pub(crate) fn render(
53 handler: &dyn ICompositionCustomVisualHandler,
54 drawing_context: &mut ImmediateDrawingContext<'_>,
55 current_transformed_clip: Rect,
56 ) {
57 let base = handler.handler_base();
58 base.in_render.set(true);
59 base.current_transformed_clip.set(current_transformed_clip);
60 base.current_transform.set(drawing_context.current_transform());
61 struct Reset<'a>(&'a Cell<bool>);
62 impl Drop for Reset<'_> {
63 fn drop(&mut self) {
64 self.0.set(false);
65 }
66 }
67 let _reset = Reset(&base.in_render);
68 handler.on_render(drawing_context);
69 }
70
71 fn host(&self) -> Rc<ServerCompositionVisual> {
72 match self.host.borrow().as_ref().and_then(Weak::upgrade) {
73 Some(host) => host,
74 None => panic!("Object is not yet attached to the compositor"),
75 }
76 }
77
78 fn verify_access(&self) -> (Rc<ServerCompositionVisual>, Rc<super::server::ServerCompositor>) {
81 let host = self.host();
82 let compositor = super::server::ServerCompositor::verify_access_of(host.compositor().as_ref());
83 (host, compositor)
84 }
85
86 fn verify_in_render(&self) {
87 self.verify_access();
88 if !self.in_render.get() {
89 panic!("This API is only available from OnRender");
90 }
91 }
92
93 pub fn effective_size(&self) -> Vector {
95 self.verify_access().0.size()
96 }
97
98 pub fn composition_now(&self) -> Duration {
100 self.verify_access().1.server_now()
101 }
102
103 pub(crate) fn attach(&self, visual: Weak<ServerCompositionVisual>) {
104 *self.host.borrow_mut() = Some(visual);
105 }
106
107 pub fn invalidate(&self) {
109 self.verify_access().0.invalidate_content();
110 }
111
112 pub fn invalidate_rect(&self, rc: Rect) {
114 self.verify_access().0.add_extra_dirty_rect(LtrbRect::from_rect(rc));
115 }
116
117 pub fn register_for_next_animation_frame_update(&self) {
120 let (host, _) = self.verify_access();
121 super::server::ServerCompositionCustomVisual::handler_register_for_next_animation_frame_update(&host);
122 }
123
124 pub fn render_clip_contains(&self, pt: Point) -> bool {
126 self.verify_in_render();
127 let pt = pt.transform(self.current_transform.get());
128 self.current_transformed_clip.get().contains(pt)
129 }
130
131 pub fn render_clip_intersectes(&self, rc: Rect) -> bool {
133 self.verify_in_render();
134 let rc = rc.transform_to_aabb(self.current_transform.get());
135 self.current_transformed_clip.get().intersects(rc)
136 }
137}