1mod act;
11mod adorners;
12mod composition_clip;
13mod computed_properties;
14mod dirty_inputs;
15mod readback;
16mod render;
17mod server_composition_visual_cache;
18mod update;
19mod walker;
20mod winui_members;
21
22pub use readback::{ReadbackData, VisualReadback};
23pub use server_composition_visual_cache::ServerCompositionVisualCache;
24pub use walker::TreeWalkerFrame;
25
26use super::{
27 CompositionProperty, IAnimatedServerObject, IServerAnimatedPropertyHost, IServerObject, IServerPropertyHost,
28 IServerRenderResource, IServerRenderResourceObserver, ServerCompositionBitmapCache, ServerCompositionTarget,
29 ServerCompositionVisualCollection, ServerCompositor, ServerObject, ServerValueChange, ServerVisualRenderContext,
30};
31use crate::media::{IBrush, IImmutableEffect, RenderOptions, TextOptions};
32use crate::numerics::Quaternion;
33use crate::platform::{IDrawingContextImpl, IGeometryImpl, LtrbRect};
34use crate::rendering::composition::animations::IAnimationInstance;
35use crate::rendering::composition::expressions::{ExpressionVariant, IExpressionObject};
36use crate::rendering::composition::generated::{
37 ServerCompositionContainerVisualHooks, ServerCompositionContainerVisualProps, ServerCompositionVisualHooks,
38 ServerCompositionVisualProps,
39};
40use crate::rendering::composition::transport::BatchStreamReader;
41use crate::{Matrix, Rect, Vector, Vector3D};
42use std::any::{Any, TypeId};
43use std::cell::{Cell, RefCell};
44use std::rc::{Rc, Weak};
45use std::sync::Arc;
46use std::time::Duration;
47
48pub trait IServerVisualContent: 'static {
51 fn deserialize_changes_core(
54 &self,
55 visual: &ServerCompositionVisual,
56 reader: &mut BatchStreamReader<'_>,
57 committed_at: Duration,
58 ) {
59 visual.base_deserialize_changes_core(reader, committed_at);
60 }
61
62 fn compute_own_content_bounds(&self, _visual: &ServerCompositionVisual) -> Option<LtrbRect> {
63 None
64 }
65
66 fn render_core(
67 &self,
68 _visual: &ServerCompositionVisual,
69 _context: &mut ServerVisualRenderContext<'_>,
70 _current_transformed_clip: LtrbRect,
71 ) {
72 }
73
74 fn size_changed(&self, _visual: &ServerCompositionVisual) {}
75
76 fn on_attached_to_root(&self, _visual: &ServerCompositionVisual, _target: &Rc<ServerCompositionTarget>) {}
77
78 fn on_detached_from_root(&self, _visual: &ServerCompositionVisual, _target: &Rc<ServerCompositionTarget>) {}
79
80 fn push_clip_to_bounds(&self, visual: &ServerCompositionVisual, canvas: &mut dyn IDrawingContextImpl) {
81 let size = visual.size();
82 canvas.push_clip(Rect::new(0.0, 0.0, size.x, size.y));
83 }
84
85 fn has_effect(&self, visual: &ServerCompositionVisual) -> bool {
86 visual.effect().is_some()
87 }
88
89 fn dependency_queued_invalidate(&self, _visual: &ServerCompositionVisual) {}
91
92 fn render_after_children(&self, _visual: &ServerCompositionVisual, _context: &mut ServerVisualRenderContext<'_>) {}
97
98 fn sub_tree_bounds_padding(&self, _visual: &ServerCompositionVisual) -> Option<crate::Thickness> {
102 None
103 }
104
105 fn has_update_pass_content_bounds(&self) -> bool {
110 false
111 }
112
113 fn find_props(&self, _type_id: TypeId) -> Option<&dyn Any> {
116 None
117 }
118
119 fn get_composition_property(&self, name: &str) -> Option<&'static CompositionProperty> {
120 ServerCompositionContainerVisualProps::get_composition_property(name)
121 }
122
123 fn dispose(&self, _visual: &ServerCompositionVisual) {}
125
126 fn as_any(&self) -> &dyn Any;
127}
128
129pub struct ServerCompositionVisual {
134 this: Weak<ServerCompositionVisual>,
135 object: ServerObject,
136 compositor: Weak<ServerCompositor>,
137 props: ServerCompositionContainerVisualProps,
138 content: Box<dyn IServerVisualContent>,
139 children: Option<Rc<ServerCompositionVisualCollection>>,
140 cache: RefCell<Option<Rc<ServerCompositionVisualCache>>>,
141 disposed: Cell<bool>,
142
143 att_helper: act::AttHelper,
145
146 combined_transform_dirty: Cell<bool>,
148 clip_size_dirty: Cell<bool>,
149 own_bounds_dirty: Cell<bool>,
150 composition_fields_dirty: Cell<bool>,
151 content_changed: Cell<bool>,
152 delay_propagate_needs_bounds_update: Cell<bool>,
153 delay_propagate_is_dirty_for_render: Cell<bool>,
154 delay_propagate_has_extra_dirty_rects: Cell<bool>,
155
156 needs_bounding_box_update: Cell<bool>,
158 is_dirty_for_render: Cell<bool>,
159 is_dirty_for_render_in_subgraph: Cell<bool>,
160
161 own_transform: Cell<Option<Matrix>>,
165 own_content_bounds: Cell<Option<LtrbRect>>,
168 sub_tree_bounds: Cell<Option<LtrbRect>>,
171 transformed_sub_tree_bounds: Cell<Option<LtrbRect>>,
174 own_clip_rect: Cell<Option<LtrbRect>>,
176 needs_to_add_extra_dirty_rect_to_dirty_region: Cell<bool>,
177 extra_dirty_rect: Cell<LtrbRect>,
178 combined_transform_matrix: Cell<Matrix>,
179
180 enqueued_for_own_properties_recompute: Cell<bool>,
182
183 readback: Arc<VisualReadback>,
185 enqueued_for_readback_update: Cell<bool>,
186}
187
188impl ServerCompositionVisual {
189 pub fn new(
194 compositor: &Rc<ServerCompositor>,
195 children: Option<Rc<ServerCompositionVisualCollection>>,
196 readback: Arc<VisualReadback>,
197 content: Box<dyn IServerVisualContent>,
198 ) -> Rc<ServerCompositionVisual> {
199 Rc::new_cyclic(|this: &Weak<ServerCompositionVisual>| {
200 let owner: Weak<dyn IAnimatedServerObject> = this.clone();
201 ServerCompositionVisual {
202 this: this.clone(),
203 object: ServerObject::new(compositor, owner),
204 compositor: Rc::downgrade(compositor),
205 props: ServerCompositionContainerVisualProps::new(),
206 content,
207 children,
208 cache: RefCell::new(None),
209 disposed: Cell::new(false),
210 att_helper: act::AttHelper::default(),
211 combined_transform_dirty: Cell::new(false),
212 clip_size_dirty: Cell::new(false),
213 own_bounds_dirty: Cell::new(false),
214 composition_fields_dirty: Cell::new(false),
215 content_changed: Cell::new(false),
216 delay_propagate_needs_bounds_update: Cell::new(false),
217 delay_propagate_is_dirty_for_render: Cell::new(false),
218 delay_propagate_has_extra_dirty_rects: Cell::new(false),
219 needs_bounding_box_update: Cell::new(false),
220 is_dirty_for_render: Cell::new(false),
221 is_dirty_for_render_in_subgraph: Cell::new(false),
222 own_transform: Cell::new(None),
223 own_content_bounds: Cell::new(None),
224 sub_tree_bounds: Cell::new(None),
225 transformed_sub_tree_bounds: Cell::new(None),
226 own_clip_rect: Cell::new(None),
227 needs_to_add_extra_dirty_rect_to_dirty_region: Cell::new(false),
228 extra_dirty_rect: Cell::new(LtrbRect::default()),
229 combined_transform_matrix: Cell::new(Matrix::IDENTITY),
230 enqueued_for_own_properties_recompute: Cell::new(false),
231 readback,
232 enqueued_for_readback_update: Cell::new(false),
233 }
234 })
235 }
236
237 pub fn weak(&self) -> Weak<ServerCompositionVisual> {
239 self.this.clone()
240 }
241
242 fn rc(&self) -> Option<Rc<ServerCompositionVisual>> {
243 self.this.upgrade()
244 }
245
246 pub fn compositor(&self) -> Option<Rc<ServerCompositor>> {
248 self.compositor.upgrade()
249 }
250
251 pub fn object(&self) -> &ServerObject {
253 &self.object
254 }
255
256 pub fn activate(&self) {
257 self.object.activate();
258 }
259
260 pub fn deactivate(&self) {
261 self.object.deactivate();
262 }
263
264 pub fn content(&self) -> &dyn IServerVisualContent {
266 &*self.content
267 }
268
269 pub fn content_as<T: IServerVisualContent>(&self) -> Option<&T> {
271 self.content.as_any().downcast_ref::<T>()
272 }
273
274 pub fn children(&self) -> Option<&Rc<ServerCompositionVisualCollection>> {
275 self.children.as_ref()
276 }
277
278 pub fn cache(&self) -> Option<Rc<ServerCompositionVisualCache>> {
279 self.cache.borrow().clone()
280 }
281
282 pub fn visual_props(&self) -> &ServerCompositionVisualProps {
284 self.props.base()
285 }
286
287 pub fn root(&self) -> Option<Rc<ServerCompositionTarget>> {
290 self.props.base().root().and_then(|o| o.into_any_rc().downcast::<ServerCompositionTarget>().ok())
291 }
292
293 pub fn parent(&self) -> Option<Rc<ServerCompositionVisual>> {
294 self.props.base().parent().and_then(|o| o.into_any_rc().downcast::<ServerCompositionVisual>().ok())
295 }
296
297 pub fn adorned_visual(&self) -> Option<Rc<ServerCompositionVisual>> {
298 self.props.base().adorned_visual().and_then(|o| o.into_any_rc().downcast::<ServerCompositionVisual>().ok())
299 }
300
301 pub fn cache_mode(&self) -> Option<Rc<ServerCompositionBitmapCache>> {
302 self.props.base().cache_mode().and_then(|o| o.into_any_rc().downcast::<ServerCompositionBitmapCache>().ok())
303 }
304
305 pub fn visible(&self) -> bool {
306 self.props.base().visible()
307 }
308
309 pub fn opacity(&self) -> f32 {
310 self.props.base().opacity()
311 }
312
313 pub fn clip(&self) -> Option<Arc<dyn IGeometryImpl>> {
314 self.props.base().clip()
315 }
316
317 pub fn clip_to_bounds(&self) -> bool {
318 self.props.base().clip_to_bounds()
319 }
320
321 pub fn offset(&self) -> Vector3D {
324 self.effective_offset()
325 }
326
327 pub fn translation(&self) -> Vector3D {
328 self.props.base().translation()
329 }
330
331 pub fn size(&self) -> Vector {
335 self.effective_size()
336 }
337
338 pub fn anchor_point(&self) -> Vector {
339 self.props.base().anchor_point()
340 }
341
342 pub fn center_point(&self) -> Vector3D {
343 self.props.base().center_point()
344 }
345
346 pub fn rotation_angle(&self) -> f32 {
347 self.props.base().rotation_angle()
348 }
349
350 pub fn orientation(&self) -> Quaternion {
351 self.props.base().orientation()
352 }
353
354 pub fn scale(&self) -> Vector3D {
355 self.props.base().scale()
356 }
357
358 pub fn transform_matrix(&self) -> Matrix {
359 self.props.base().transform_matrix()
360 }
361
362 pub fn adorner_is_clipped(&self) -> bool {
363 self.props.base().adorner_is_clipped()
364 }
365
366 pub fn opacity_mask_brush(&self) -> Option<Rc<dyn IBrush>> {
367 self.props.base().opacity_mask_brush().map(|brush| brush.value)
368 }
369
370 pub fn effect(&self) -> Option<std::sync::Arc<dyn IImmutableEffect>> {
371 self.props.base().effect()
372 }
373
374 pub fn render_options(&self) -> RenderOptions {
375 self.props.base().render_options()
376 }
377
378 pub fn text_options(&self) -> TextOptions {
379 self.props.base().text_options()
380 }
381
382 pub fn on_cache_mode_state_changed(&self) {
385 if let Some(cache) = self.cache() {
386 cache.invalidate_properties();
387 }
388 self.invalidate_content();
389 }
390
391 fn render_core(&self, context: &mut ServerVisualRenderContext<'_>, current_transformed_clip: LtrbRect) {
392 self.content.render_core(self, context, current_transformed_clip);
393 }
394
395 pub fn base_deserialize_changes_core(&self, reader: &mut BatchStreamReader<'_>, committed_at: Duration) {
398 self.props.deserialize_changes_core(self, reader, committed_at);
399 }
400}
401
402impl ServerCompositionVisualHooks for ServerCompositionVisual {
403 fn on_fields_deserialized(
404 &self,
405 changed: crate::rendering::composition::generated::CompositionVisualChangedFields,
406 ) {
407 self.on_fields_deserialized_core(changed);
408 }
409
410 fn on_root_changing(&self) {
411 if let (Some(root), Some(this)) = (self.root(), self.rc()) {
412 root.remove_visual(&this);
413 self.content.on_detached_from_root(self, &root);
414 }
415 }
416
417 fn on_root_changed(&self) {
418 if let (Some(root), Some(this)) = (self.root(), self.rc()) {
419 root.add_visual(&this);
420 self.content.on_attached_to_root(self, &root);
421 self.adorner_helper_attached_to_root();
422 }
423 if let Some(cache) = self.cache() {
424 cache.free_resources();
425 }
426 }
427
428 fn on_parent_changing(&self) {
429 self.on_parent_changing_core();
430 }
431
432 fn on_parent_changed(&self) {
433 self.on_parent_changed_core();
434 }
435
436 fn on_adorned_visual_changing(&self) {
437 self.on_adorned_visual_changing_core();
438 }
439
440 fn on_adorned_visual_changed(&self) {
441 self.on_adorned_visual_changed_core();
442 }
443
444 fn on_cache_mode_changing(&self) {
445 if let (Some(cache_mode), Some(this)) = (self.cache_mode(), self.rc()) {
446 cache_mode.unsubscribe(&this);
447 }
448 if let Some(cache) = self.cache.borrow_mut().take() {
449 cache.free_resources();
450 }
451 }
452
453 fn on_composition_clip_changing(&self) {
454 self.observe_composition_clip(false);
455 }
456
457 fn on_composition_clip_changed(&self) {
458 self.observe_composition_clip(true);
459 }
460
461 fn on_parent_for_transform_changing(&self) {
462 self.on_parent_for_transform_changing_core();
463 }
464
465 fn on_parent_for_transform_changed(&self) {
466 self.on_parent_for_transform_changed_core();
467 }
468
469 fn on_cache_mode_changed(&self) {
470 let cache_mode = self.cache_mode();
471 *self.cache.borrow_mut() =
472 cache_mode.as_ref().map(|mode| ServerCompositionVisualCache::new(self.this.clone(), mode.clone()));
473 if let (Some(cache_mode), Some(this)) = (cache_mode, self.rc()) {
474 cache_mode.subscribe(&this);
475 }
476 self.on_cache_mode_state_changed();
477 }
478}
479
480impl ServerCompositionContainerVisualHooks for ServerCompositionVisual {}
481
482impl IServerPropertyHost for ServerCompositionVisual {
483 fn server_compositor(&self) -> Option<Rc<ServerCompositor>> {
484 self.compositor.upgrade()
485 }
486
487 fn set_value(&self, property: &'static CompositionProperty, change: ServerValueChange<'_>) {
488 self.object.set_value(property, change);
489 }
490}
491
492impl IServerAnimatedPropertyHost for ServerCompositionVisual {
493 fn set_animated_value(
494 &self,
495 property: &'static CompositionProperty,
496 current_value: ExpressionVariant,
497 committed_at: Duration,
498 animation: Rc<dyn IAnimationInstance>,
499 ) {
500 self.object.set_animated_value(property, current_value, committed_at, animation);
501 }
502
503 fn remove_animation_for_property(&self, property: &'static CompositionProperty) {
504 self.object.remove_animation_for_property(property);
505 }
506
507 fn notify_animated_value_changed(&self, property: &'static CompositionProperty) {
508 self.notify_animated_value_changed_core(property);
509 }
510}
511
512impl IAnimatedServerObject for ServerCompositionVisual {
513 fn server_object(&self) -> &ServerObject {
514 &self.object
515 }
516
517 fn get_composition_property(&self, field_name: &str) -> Option<&'static CompositionProperty> {
518 self.content.get_composition_property(field_name)
519 }
520
521 fn as_server_object_dyn(&self) -> &dyn IServerObject {
522 self
523 }
524}
525
526impl IExpressionObject for ServerCompositionVisual {
527 fn get_property(&self, name: &str) -> ExpressionVariant {
528 self.object.get_property(name)
529 }
530}
531
532impl IServerRenderResourceObserver for ServerCompositionVisual {
533 fn dependency_queued_invalidate(&self, sender: &dyn IServerRenderResource) {
534 if self.is_composition_clip(sender) {
537 self.composition_clip_changed();
538 return;
539 }
540 self.content.dependency_queued_invalidate(self);
541 }
542}
543
544impl IServerObject for ServerCompositionVisual {
545 fn deserialize_changes_core(&self, reader: &mut BatchStreamReader<'_>, committed_at: Duration) {
546 self.content.deserialize_changes_core(self, reader, committed_at);
547 }
548
549 fn dispose(&self) {
554 if self.disposed.replace(true) {
555 return;
556 }
557 self.content.dispose(self);
558 if let (Some(root), Some(this)) = (self.root(), self.rc()) {
559 root.remove_visual(&this);
560 }
561 if let (Some(cache_mode), Some(this)) = (self.cache_mode(), self.rc()) {
562 cache_mode.unsubscribe(&this);
563 }
564 self.observe_composition_clip(false);
565 self.winui_members_dispose();
566 if let Some(adorned) = self.adorned_visual() {
574 if !adorned.disposed.get() {
575 adorned.att_helper_unsubscribe_from_act_notification(&self.adorned_visual_act_subscription_action());
576 }
577 }
578 if let Some(cache) = self.cache.borrow_mut().take() {
579 cache.free_resources();
580 }
581 if let (Some(parent), Some(bounds)) = (self.parent(), self.transformed_sub_tree_bounds.get()) {
582 if !parent.disposed.get() {
583 parent.add_extra_dirty_rect(bounds);
584 }
585 }
586 ServerCompositionVisualProps::id_of_root_property().set_field(self, None);
587 ServerCompositionVisualProps::id_of_parent_property().set_field(self, None);
588 ServerCompositionVisualProps::id_of_adorned_visual_property().set_field(self, None);
589 ServerCompositionVisualProps::id_of_cache_mode_property().set_field(self, None);
590 ServerCompositionVisualProps::id_of_composition_clip_property().set_field(self, None);
591 }
592
593 fn get_props(&self, type_id: TypeId) -> Option<&dyn Any> {
594 self.props.find_props(type_id).or_else(|| self.content.find_props(type_id))
595 }
596
597 fn as_animated(self: Rc<Self>) -> Option<Rc<dyn IAnimatedServerObject>> {
598 Some(self)
599 }
600
601 fn as_any(&self) -> &dyn Any {
602 self
603 }
604
605 fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
606 self
607 }
608}
609
610pub struct ServerCompositionContainerVisual;
612
613impl IServerVisualContent for ServerCompositionContainerVisual {
614 fn as_any(&self) -> &dyn Any {
615 self
616 }
617}