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