1use super::animations::{ICompositionAnimation, ICompositionAnimationBase, ImplicitAnimationCollection};
13use super::composition_custom_visual::CustomVisualData;
14use super::composition_draw_list_visual::DrawListData;
15use super::composition_object::ICompositionObjectAnimations;
16use super::drawing::brush_get_server_resource;
17use super::expressions::ExpressionVariant;
18use super::generated::{
19 CompositionContainerVisualHooks, CompositionContainerVisualProps, CompositionSolidColorVisualProps,
20 CompositionSurfaceVisualProps, CompositionVisualHooks, CompositionVisualProps,
21 ServerCompositionContainerVisualProps, ShapeVisualProps, SpriteVisualProps,
22};
23use super::generated::{LayerVisualProps, RedirectVisualProps};
24use super::hit_testing::CompositionHitTestAabbTree;
25use super::server::{
26 CompositionProperty, IServerVisualContent, ReadbackData, ServerCompositionVisual,
27 ServerCompositionVisualCollection, ServerObjectId, VisualReadback,
28};
29use super::transport::{BatchStreamWriter, IRegisterForSerialization};
30use super::{
31 AsCompositionObject, CompositionBitmapCache, CompositionClip, CompositionObject, CompositionTarget,
32 CompositionVisualCollection, Compositor, ICompositionObject, ICompositionObjectHost, ICompositorSerializable,
33 PendingAnimations,
34};
35use crate::media::{BrushExtensions, Geometry, IBrush, IImmutableEffect, IntersectionResult, RenderOptions, TextOptions};
36use crate::numerics::Quaternion;
37use crate::platform::IGeometryImpl;
38use crate::{Matrix, Point, Ref, Vector, Vector3D};
39use std::any::Any;
40use std::cell::{Cell, RefCell};
41use std::rc::{Rc, Weak};
42use std::sync::Arc;
43
44pub(crate) enum CompositionVisualKind {
46 Container(CompositionContainerVisualProps),
47 DrawList(DrawListData),
48 SolidColor(CompositionSolidColorVisualProps),
49 Surface(CompositionSurfaceVisualProps),
50 Custom(CustomVisualData),
51 Sprite(SpriteVisualProps),
53 Shape(ShapeVisualProps),
55 Layer(LayerVisualProps),
57 Redirect(RedirectVisualProps),
59}
60
61pub struct CompositionVisual {
63 pub(super) this: Weak<CompositionVisual>,
64 object: CompositionObject,
65 pub(super) kind: CompositionVisualKind,
66 children: Rc<CompositionVisualCollection>,
67 pub(super) hit_test_children: RefCell<Option<CompositionHitTestAabbTree>>,
68 opacity_mask: RefCell<Option<Rc<dyn IBrush>>>,
69 pub(super) custom_hit_test_count_in_sub_tree: Cell<i32>,
70 tag: RefCell<Option<Rc<dyn Any>>>,
71 readback: Arc<VisualReadback>,
72}
73
74macro_rules! visual_value_properties {
75 ($($(#[$meta:meta])* $get:ident / $set:ident : $ty:ty;)*) => {
76 impl CompositionVisual {$(
77 $(#[$meta])*
78 pub fn $get(&self) -> $ty {
79 self.visual_props().$get()
80 }
81
82 pub fn $set(&self, value: $ty) {
83 self.visual_props().$set(self, value)
84 }
85 )*}
86 };
87}
88
89visual_value_properties! {
90 visible / set_visible: bool;
91 opacity / set_opacity: f32;
92 clip / set_clip: Option<Arc<dyn IGeometryImpl>>;
94 clip_to_bounds / set_clip_to_bounds: bool;
95 offset / set_offset: Vector3D;
96 translation / set_translation: Vector3D;
97 size / set_size: Vector;
98 anchor_point / set_anchor_point: Vector;
99 center_point / set_center_point: Vector3D;
100 rotation_angle / set_rotation_angle: f32;
101 orientation / set_orientation: Quaternion;
102 scale / set_scale: Vector3D;
103 transform_matrix / set_transform_matrix: Matrix;
104 adorner_is_clipped / set_adorner_is_clipped: bool;
107 effect / set_effect: Option<std::sync::Arc<dyn IImmutableEffect>>;
108 render_options / set_render_options: RenderOptions;
109 text_options / set_text_options: TextOptions;
110}
111
112impl CompositionVisual {
113 pub(crate) fn create(
116 compositor: &Rc<Compositor>,
117 kind: CompositionVisualKind,
118 content: impl FnOnce() -> Box<dyn IServerVisualContent> + Send + 'static,
119 ) -> Rc<CompositionVisual> {
120 Self::create_with(compositor, kind, content, |_| {})
121 }
122
123 pub(crate) fn create_with(
126 compositor: &Rc<Compositor>,
127 kind: CompositionVisualKind,
128 content: impl FnOnce() -> Box<dyn IServerVisualContent> + Send + 'static,
129 created: impl FnOnce(&Rc<ServerCompositionVisual>) + Send + 'static,
130 ) -> Rc<CompositionVisual> {
131 let children_server =
132 compositor.create_server_object(|compositor, _| ServerCompositionVisualCollection::new(compositor));
133 let readback = Arc::new(VisualReadback::new());
134 let server_readback = readback.clone();
135 let server = compositor.create_server_object(move |compositor, _| {
136 let visual = ServerCompositionVisual::new(
137 compositor,
138 compositor.get::<ServerCompositionVisualCollection>(children_server),
139 server_readback,
140 content(),
141 );
142 created(&visual);
143 visual
144 });
145 let visual = Rc::new_cyclic(|this: &Weak<CompositionVisual>| CompositionVisual {
146 this: this.clone(),
147 object: CompositionObject::new(compositor, Some(server)),
148 kind,
149 children: CompositionVisualCollection::new(compositor, this.clone(), children_server),
150 hit_test_children: RefCell::new(None),
151 opacity_mask: RefCell::new(None),
152 custom_hit_test_count_in_sub_tree: Cell::new(0),
153 tag: RefCell::new(None),
154 readback,
155 });
156 visual.initialize_defaults();
157 visual
158 }
159
160 fn initialize_defaults(&self) {
161 match &self.kind {
162 CompositionVisualKind::Container(props) => props.initialize_defaults(self),
163 CompositionVisualKind::DrawList(data) => data.initialize_defaults(self),
164 CompositionVisualKind::SolidColor(props) => props.initialize_defaults(self),
165 CompositionVisualKind::Surface(props) => props.initialize_defaults(self),
166 CompositionVisualKind::Custom(data) => data.props().initialize_defaults(self),
167 CompositionVisualKind::Sprite(props) => props.initialize_defaults(self),
168 CompositionVisualKind::Shape(props) => props.initialize_defaults(self),
169 CompositionVisualKind::Layer(props) => props.initialize_defaults(self),
170 CompositionVisualKind::Redirect(props) => props.initialize_defaults(self),
171 }
172 }
173
174 pub(super) fn container_props(&self) -> &CompositionContainerVisualProps {
175 match &self.kind {
176 CompositionVisualKind::Container(props) => props,
177 CompositionVisualKind::DrawList(data) => data.props(),
178 CompositionVisualKind::SolidColor(props) => props.base(),
179 CompositionVisualKind::Surface(props) => props.base(),
180 CompositionVisualKind::Custom(data) => data.props(),
181 CompositionVisualKind::Sprite(props) => props.base(),
182 CompositionVisualKind::Shape(props) => props.base(),
183 CompositionVisualKind::Layer(props) => props.base(),
184 CompositionVisualKind::Redirect(props) => props.base(),
185 }
186 }
187
188 pub fn visual_props(&self) -> &CompositionVisualProps {
190 self.container_props().base()
191 }
192
193 pub fn compositor(&self) -> &Rc<Compositor> {
194 self.object.compositor()
195 }
196
197 pub fn object(&self) -> &CompositionObject {
199 &self.object
200 }
201
202 pub fn implicit_animations(&self) -> Option<Rc<ImplicitAnimationCollection>> {
204 self.object.implicit_animations()
205 }
206
207 pub fn set_implicit_animations(&self, value: Option<Rc<ImplicitAnimationCollection>>) {
208 self.object.set_implicit_animations(value)
209 }
210
211 pub fn server(&self) -> ServerObjectId {
213 self.object.required_server()
214 }
215
216 pub fn is_disposed(&self) -> bool {
217 self.object.is_disposed()
218 }
219
220 pub fn dispose(&self) {
221 self.object.dispose();
222 }
223
224 pub fn children(&self) -> &Rc<CompositionVisualCollection> {
226 &self.children
227 }
228
229 pub fn root(&self) -> Option<Rc<CompositionTarget>> {
233 self.visual_props().root().and_then(|o| o.into_any_rc().downcast::<CompositionTarget>().ok())
234 }
235
236 pub(crate) fn set_root(&self, value: Option<Rc<CompositionTarget>>) {
237 self.visual_props().set_root(self, value.map(|v| v as Rc<dyn ICompositionObject>));
238 }
239
240 pub fn parent(&self) -> Option<Rc<CompositionVisual>> {
241 self.visual_props().parent().and_then(|o| o.into_any_rc().downcast::<CompositionVisual>().ok())
242 }
243
244 pub(crate) fn set_parent(&self, value: Option<Rc<CompositionVisual>>) {
245 self.visual_props().set_parent(self, value.map(|v| v as Rc<dyn ICompositionObject>));
246 }
247
248 pub fn adorned_visual(&self) -> Option<Rc<CompositionVisual>> {
251 self.visual_props().adorned_visual().and_then(|o| o.into_any_rc().downcast::<CompositionVisual>().ok())
252 }
253
254 pub fn set_adorned_visual(&self, value: Option<Rc<CompositionVisual>>) {
255 self.visual_props().set_adorned_visual(self, value.map(|v| v as Rc<dyn ICompositionObject>));
256 }
257
258 pub fn cache_mode(&self) -> Option<Rc<CompositionBitmapCache>> {
259 self.visual_props().cache_mode().and_then(|o| o.into_any_rc().downcast::<CompositionBitmapCache>().ok())
260 }
261
262 pub fn set_cache_mode(&self, value: Option<Rc<CompositionBitmapCache>>) {
263 self.visual_props().set_cache_mode(self, value.map(|v| v as Rc<dyn ICompositionObject>));
264 }
265
266 pub fn composition_clip(&self) -> Option<Rc<CompositionClip>> {
276 self.visual_props().composition_clip().and_then(|o| o.into_any_rc().downcast::<CompositionClip>().ok())
277 }
278
279 pub fn set_composition_clip(&self, value: Option<Rc<CompositionClip>>) {
280 self.visual_props().set_composition_clip(self, value.map(|v| v as Rc<dyn ICompositionObject>));
281 }
282
283 pub fn disable_sub_tree_bounds_hit_test_optimization(&self) -> bool {
286 self.custom_hit_test_count_in_sub_tree.get() != 0
287 }
288
289 pub fn opacity_mask(&self) -> Option<Rc<dyn IBrush>> {
290 self.opacity_mask.borrow().clone()
291 }
292
293 pub fn set_opacity_mask(&self, value: Option<Rc<dyn IBrush>>) {
294 let current = self.opacity_mask.borrow().clone();
295 let same = match (¤t, &value) {
296 (Some(a), Some(b)) => std::ptr::addr_eq(Rc::as_ptr(a), Rc::as_ptr(b)),
297 (None, None) => true,
298 _ => false,
299 };
300 if same {
301 return;
302 }
303
304 let compositor = self.compositor().clone();
305 if let Some(old) = ¤t {
307 if let Some(resource) = old.as_composition_render_resource() {
308 resource.release_on_compositor(&compositor);
309 *self.opacity_mask.borrow_mut() = None;
310 self.visual_props().set_opacity_mask_brush_transport_field(self, None);
311 }
312 }
313
314 match &value {
315 Some(brush) if brush.as_composition_render_resource().is_some() => {
316 if let Some(resource) = brush.as_composition_render_resource() {
317 resource.add_ref_on_compositor(&compositor);
318 }
319 let transport = brush_get_server_resource(Some(brush), Some(&compositor));
320 self.visual_props().set_opacity_mask_brush_transport_field(self, transport);
321 *self.opacity_mask.borrow_mut() = value;
322 }
323 _ => {
324 let immutable = value.as_ref().map(|brush| {
325 let immutable: Rc<dyn IBrush> = BrushExtensions::to_immutable(brush);
326 super::transport::BatchResource::Value(immutable)
327 });
328 *self.opacity_mask.borrow_mut() = value;
329 self.visual_props().set_opacity_mask_brush_transport_field(self, immutable);
330 }
331 }
332 }
333
334 pub fn try_get_valid_readback(&self) -> Option<ReadbackData> {
337 let root = self.root()?;
338
339 let indices = self.compositor().readback().clone();
340 let readback = self.readback.get_readback(indices.read_revision())?;
341
342 if !readback.visible || readback.target_id != root.id() {
344 return None;
345 }
346
347 Some(readback)
348 }
349
350 pub fn tag(&self) -> Option<Rc<dyn Any>> {
351 self.tag.borrow().clone()
352 }
353
354 pub fn set_tag(&self, value: Option<Rc<dyn Any>>) {
355 *self.tag.borrow_mut() = value;
356 }
357
358 pub fn hit_test(&self, point: Point) -> bool {
361 match &self.kind {
362 CompositionVisualKind::DrawList(data) => data.hit_test(point),
363 _ => true,
364 }
365 }
366
367 pub fn hit_test_geometry(&self, geometry: &Ref<Geometry>) -> IntersectionResult {
370 match &self.kind {
371 CompositionVisualKind::DrawList(data) => data.hit_test_geometry(geometry),
372 _ => IntersectionResult::Intersects,
373 }
374 }
375
376 fn serialize_changes_core(&self, writer: &mut BatchStreamWriter<'_>) {
377 match &self.kind {
378 CompositionVisualKind::Container(props) => props.serialize_changes_core(self, writer),
379 CompositionVisualKind::DrawList(data) => data.serialize_changes_core(self, writer),
380 CompositionVisualKind::SolidColor(props) => props.serialize_changes_core(self, writer),
381 CompositionVisualKind::Surface(props) => props.serialize_changes_core(self, writer),
382 CompositionVisualKind::Custom(data) => data.props().serialize_changes_core(self, writer),
383 CompositionVisualKind::Sprite(props) => props.serialize_changes_core(self, writer),
384 CompositionVisualKind::Shape(props) => props.serialize_changes_core(self, writer),
385 CompositionVisualKind::Layer(props) => props.serialize_changes_core(self, writer),
386 CompositionVisualKind::Redirect(props) => props.serialize_changes_core(self, writer),
387 }
388 }
389}
390
391impl CompositionVisualHooks for CompositionVisual {
392 fn on_root_changed(&self) {
393 let root = self.root();
395 let mut index = 0;
398 while index < self.children.count() {
399 self.children.get(index).set_root(root.clone());
400 index += 1;
401 }
402 }
403
404 fn on_parent_changing(&self) {
405 let count = self.custom_hit_test_count_in_sub_tree.get();
407 if count != 0 {
408 let mut parent = self.parent();
409 while let Some(p) = parent {
410 p.custom_hit_test_count_in_sub_tree.set(p.custom_hit_test_count_in_sub_tree.get() - count);
411 parent = p.parent();
412 }
413 }
414 }
415
416 fn on_parent_changed(&self) {
417 self.set_root(self.parent().and_then(|parent| parent.root()));
418
419 let count = self.custom_hit_test_count_in_sub_tree.get();
421 if count != 0 {
422 let mut parent = self.parent();
423 while let Some(p) = parent {
424 p.custom_hit_test_count_in_sub_tree.set(p.custom_hit_test_count_in_sub_tree.get() + count);
425 parent = p.parent();
426 }
427 }
428 }
429}
430
431impl CompositionContainerVisualHooks for CompositionVisual {}
432
433impl IRegisterForSerialization for CompositionVisual {
434 fn register_for_serialization(&self) {
435 self.object
436 .register_for_serialization(|| self.this.upgrade().map(|this| this as Rc<dyn ICompositorSerializable>));
437 }
438}
439
440impl ICompositionObjectHost for CompositionVisual {
441 fn server(&self) -> ServerObjectId {
442 self.object.required_server()
443 }
444
445 fn pending_animations(&self) -> &PendingAnimations {
446 self.object.pending_animations()
447 }
448
449 fn implicit_animation(&self, property_name: &str) -> Option<Rc<dyn ICompositionAnimationBase>> {
450 self.object.implicit_animation(property_name)
451 }
452
453 fn start_animation_group(
454 &self,
455 grp: &Rc<dyn ICompositionAnimationBase>,
456 target: &str,
457 final_value: ExpressionVariant,
458 ) -> bool {
459 self.start_animation_group_for(&**grp, target, final_value)
460 }
461}
462
463impl ICompositionObjectAnimations for CompositionVisual {
464 fn try_start_animation(
465 &self,
466 property_name: &str,
467 animation: &dyn ICompositionAnimation,
468 final_value: Option<ExpressionVariant>,
469 ) -> bool {
470 match &self.kind {
471 CompositionVisualKind::Container(props) => props.start_animation(self, property_name, animation, final_value),
472 CompositionVisualKind::DrawList(data) => {
473 data.props().start_animation(self, property_name, animation, final_value)
474 }
475 CompositionVisualKind::SolidColor(props) => props.start_animation(self, property_name, animation, final_value),
476 CompositionVisualKind::Surface(props) => props.start_animation(self, property_name, animation, final_value),
477 CompositionVisualKind::Custom(data) => {
478 data.props().start_animation(self, property_name, animation, final_value)
479 }
480 CompositionVisualKind::Sprite(props) => props.start_animation(self, property_name, animation, final_value),
481 CompositionVisualKind::Shape(props) => props.start_animation(self, property_name, animation, final_value),
482 CompositionVisualKind::Layer(props) => props.start_animation(self, property_name, animation, final_value),
483 CompositionVisualKind::Redirect(props) => props.start_animation(self, property_name, animation, final_value),
484 }
485 }
486
487 fn get_composition_property(&self, property_name: &str) -> Option<&'static CompositionProperty> {
488 match &self.kind {
489 CompositionVisualKind::SolidColor(_) => {
490 super::generated::ServerCompositionSolidColorVisualProps::get_composition_property(property_name)
491 .or_else(|| ServerCompositionContainerVisualProps::get_composition_property(property_name))
492 }
493 _ => ServerCompositionContainerVisualProps::get_composition_property(property_name),
494 }
495 }
496
497 fn composition_object(&self) -> &CompositionObject {
498 &self.object
499 }
500}
501
502impl AsCompositionObject for CompositionVisual {
503 fn as_composition_object(&self) -> &CompositionObject {
504 &self.object
505 }
506
507 fn composition_type_name(&self) -> &'static str {
508 match &self.kind {
509 CompositionVisualKind::Container(_) => "CompositionContainerVisual",
510 CompositionVisualKind::DrawList(_) => "CompositionDrawListVisual",
511 CompositionVisualKind::SolidColor(_) => "CompositionSolidColorVisual",
512 CompositionVisualKind::Surface(_) => "CompositionSurfaceVisual",
513 CompositionVisualKind::Custom(_) => "CompositionCustomVisual",
514 CompositionVisualKind::Sprite(_) => "SpriteVisual",
515 CompositionVisualKind::Shape(_) => "ShapeVisual",
516 CompositionVisualKind::Layer(_) => "LayerVisual",
517 CompositionVisualKind::Redirect(_) => "RedirectVisual",
518 }
519 }
520}
521
522impl ICompositionObject for CompositionVisual {
523 fn server(&self) -> ServerObjectId {
524 self.object.required_server()
525 }
526
527 fn as_any(&self) -> &dyn Any {
528 self
529 }
530
531 fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
532 self
533 }
534}
535
536impl ICompositorSerializable for CompositionVisual {
537 fn try_get_server(&self, c: &Compositor) -> Option<ServerObjectId> {
538 self.object.try_get_server(c)
539 }
540
541 fn serialize_changes(&self, c: &Compositor, writer: &mut BatchStreamWriter<'_>) {
542 self.object.begin_serialize_changes(c);
543 self.serialize_changes_core(writer);
544 }
545}