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