use super::render::RenderContext;
use super::ServerCompositionVisual;
use crate::rendering::composition::MatrixUtils;
use crate::{Matrix, Rect};
use std::rc::Rc;
const OP_POP_CLIP: i32 = 0;
const OP_POP_GEOMETRY_CLIP: i32 = 1;
const OP_STOP: i32 = 2;
impl ServerCompositionVisual {
pub(super) fn adorner_helper_attached_to_root(&self) {
if self.adorned_visual().is_some() {
self.adorner_helper_enqueue_for_adorner_update();
}
}
pub fn adorner_helper_enqueue_for_adorner_update(&self) {
if self.att_helper.enqueued_for_adorner_update.get() {
return;
}
if let (Some(compositor), Some(this)) = (self.compositor(), self.rc()) {
compositor.enqueue_adorner_update(this);
self.att_helper.enqueued_for_adorner_update.set(true);
}
}
pub(super) fn on_adorned_visual_changing_core(&self) {
if let Some(adorned) = self.adorned_visual() {
adorned.att_helper_unsubscribe_from_act_notification(&self.adorned_visual_act_subscription_action());
}
}
pub(super) fn on_adorned_visual_changed_core(&self) {
if let Some(adorned) = self.adorned_visual() {
adorned.att_helper_subscribe_to_act_notification(self.adorned_visual_act_subscription_action());
}
self.adorner_helper_enqueue_for_adorner_update();
}
fn adorner_layer_get_expected_shared_ancestor(adorner: &ServerCompositionVisual) -> Option<Rc<ServerCompositionVisual>> {
adorner.parent()?.parent()
}
pub fn update_adorner(&self) {
self.att_helper.enqueued_for_adorner_update.set(false);
let adorned = self.adorned_visual();
if let (Some(adorned), true) = (&adorned, self.parent().is_some()) {
let own_transform = MatrixUtils::compute_transform(
self.size(),
self.anchor_point(),
self.center_point(),
Matrix::IDENTITY,
self.scale(),
self.rotation_angle(),
self.orientation(),
self.offset() + self.translation(),
);
let adorner_layer_to_adorned_visual = Self::adorner_layer_get_expected_shared_ancestor(self)
.and_then(|shared_ancestor| Self::compute_transform_from_ancestor(adorned, &shared_ancestor));
match adorner_layer_to_adorned_visual {
Some(transform) => {
self.own_transform.set(Some(own_transform.unwrap_or(Matrix::IDENTITY) * transform))
}
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))),
}
} else {
self.own_transform.set(MatrixUtils::compute_transform(
self.size(),
self.anchor_point(),
self.center_point(),
self.transform_matrix(),
self.scale(),
self.rotation_angle(),
self.orientation(),
self.offset() + self.translation(),
));
}
self.propagate_flags(true, true, false);
}
}
impl RenderContext<'_> {
fn adorner_layer_walk_adorner_parent_clip_recursive(&mut self, visual: Option<Rc<ServerCompositionVisual>>) -> bool {
let Some(visual) = visual else { return false };
let is_layer = self.current_adorner_layer.as_ref().is_some_and(|layer| Rc::ptr_eq(layer, &visual));
if !is_layer && !self.adorner_layer_walk_adorner_parent_clip_recursive(visual.parent()) {
return false;
}
if let Some(own_transform) = visual.own_transform.get() {
let transform = own_transform * self.canvas.transform();
self.canvas.set_transform(transform);
}
if visual.clip_to_bounds() {
let size = visual.size();
self.canvas.push_clip(Rect::new(0.0, 0.0, size.x, size.y));
if let Some(stack) = &mut self.adorner_pushed_clip_stack {
stack.push(OP_POP_CLIP);
}
}
if let Some(clip) = visual.clip() {
self.canvas.push_geometry_clip(&*clip);
if let Some(stack) = &mut self.adorner_pushed_clip_stack {
stack.push(OP_POP_GEOMETRY_CLIP);
}
}
true
}
fn skip_adorner_clip(&self, visual: &Rc<ServerCompositionVisual>) -> bool {
!visual.adorner_is_clipped()
|| Rc::ptr_eq(visual, &self.root_visual)
|| visual.parent().is_some_and(|parent| Rc::ptr_eq(&parent, &self.root_visual))
|| ServerCompositionVisual::adorner_layer_get_expected_shared_ancestor(visual).is_none()
}
pub(super) fn adorner_helper_render_pre_graph_push_adorner_clip(&mut self, visual: &Rc<ServerCompositionVisual>) {
if self.skip_adorner_clip(visual) {
return;
}
let pools = self.pools;
self.adorner_pushed_clip_stack.get_or_insert_with(|| pools.int_stack_pool.rent()).push(OP_STOP);
let original_transform = self.canvas.transform();
let mut transform = original_transform;
if let Some(own_transform) = visual.own_transform.get() {
let Some(transform_to_adorner_layer) = own_transform.try_invert() else { return };
transform = transform_to_adorner_layer * transform;
}
self.canvas.set_transform(transform);
self.current_adorner_layer = ServerCompositionVisual::adorner_layer_get_expected_shared_ancestor(visual);
self.adorner_layer_walk_adorner_parent_clip_recursive(visual.adorned_visual());
self.canvas.set_transform(original_transform);
}
pub(super) fn adorner_helper_render_post_graph_push_adorner_clip(&mut self, visual: &Rc<ServerCompositionVisual>) {
if self.skip_adorner_clip(visual) {
return;
}
loop {
let Some(op) = self.adorner_pushed_clip_stack.as_mut().and_then(Vec::pop) else { break };
if op == OP_STOP {
break;
}
if op == OP_POP_GEOMETRY_CLIP {
self.canvas.pop_geometry_clip();
} else if op == OP_POP_CLIP {
self.canvas.pop_clip();
}
}
}
pub(super) fn adorner_helper_dispose(&mut self) {
if let Some(stack) = self.adorner_pushed_clip_stack.take() {
self.pools.int_stack_pool.return_stack(stack);
}
}
}