use super::server::ServerCompositionVisual;
use crate::media::ImmediateDrawingContext;
use crate::platform::LtrbRect;
use crate::{Matrix, Point, Rect, Vector};
use std::any::Any;
use std::cell::{Cell, RefCell};
use std::rc::{Rc, Weak};
use std::time::Duration;
#[derive(Default)]
pub struct CompositionCustomVisualHandler {
host: RefCell<Option<Weak<ServerCompositionVisual>>>,
in_render: Cell<bool>,
current_transformed_clip: Cell<Rect>,
current_transform: Cell<Matrix>,
}
pub trait ICompositionCustomVisualHandler: 'static {
fn handler_base(&self) -> &CompositionCustomVisualHandler;
fn on_message(&self, _message: std::sync::Arc<dyn Any + Send + Sync>) {}
fn on_animation_frame_update(&self) {}
fn on_render(&self, drawing_context: &mut ImmediateDrawingContext<'_>);
fn get_render_bounds(&self) -> Rect {
let size = self.handler_base().effective_size();
Rect::new(0.0, 0.0, size.x, size.y)
}
}
impl CompositionCustomVisualHandler {
pub fn new() -> Self {
Self::default()
}
pub(crate) fn render(
handler: &dyn ICompositionCustomVisualHandler,
drawing_context: &mut ImmediateDrawingContext<'_>,
current_transformed_clip: Rect,
) {
let base = handler.handler_base();
base.in_render.set(true);
base.current_transformed_clip.set(current_transformed_clip);
base.current_transform.set(drawing_context.current_transform());
struct Reset<'a>(&'a Cell<bool>);
impl Drop for Reset<'_> {
fn drop(&mut self) {
self.0.set(false);
}
}
let _reset = Reset(&base.in_render);
handler.on_render(drawing_context);
}
fn host(&self) -> Rc<ServerCompositionVisual> {
match self.host.borrow().as_ref().and_then(Weak::upgrade) {
Some(host) => host,
None => panic!("Object is not yet attached to the compositor"),
}
}
fn verify_access(&self) -> (Rc<ServerCompositionVisual>, Rc<super::server::ServerCompositor>) {
let host = self.host();
let compositor = super::server::ServerCompositor::verify_access_of(host.compositor().as_ref());
(host, compositor)
}
fn verify_in_render(&self) {
self.verify_access();
if !self.in_render.get() {
panic!("This API is only available from OnRender");
}
}
pub fn effective_size(&self) -> Vector {
self.verify_access().0.size()
}
pub fn composition_now(&self) -> Duration {
self.verify_access().1.server_now()
}
pub(crate) fn attach(&self, visual: Weak<ServerCompositionVisual>) {
*self.host.borrow_mut() = Some(visual);
}
pub fn invalidate(&self) {
self.verify_access().0.invalidate_content();
}
pub fn invalidate_rect(&self, rc: Rect) {
self.verify_access().0.add_extra_dirty_rect(LtrbRect::from_rect(rc));
}
pub fn register_for_next_animation_frame_update(&self) {
let (host, _) = self.verify_access();
super::server::ServerCompositionCustomVisual::handler_register_for_next_animation_frame_update(&host);
}
pub fn render_clip_contains(&self, pt: Point) -> bool {
self.verify_in_render();
let pt = pt.transform(self.current_transform.get());
self.current_transformed_clip.get().contains(pt)
}
pub fn render_clip_intersectes(&self, rc: Rect) -> bool {
self.verify_in_render();
let rc = rc.transform_to_aabb(self.current_transform.get());
self.current_transformed_clip.get().intersects(rc)
}
}