ferroui_base/rendering/composition/drawing/
server_composition_render_data.rs1use super::{RenderDataStream, ReplayScope};
2use crate::platform::{IDrawingContextImpl, LtrbRect};
3use crate::rendering::composition::server::{
4 IServerObject, IServerRenderResource, IServerRenderResourceHost, IServerRenderResourceObserver, ServerCompositor,
5 ServerRenderResourceCore,
6};
7use crate::rendering::composition::transport::BatchStreamReader;
8use crate::Rect;
9use std::any::Any;
10use std::cell::{Cell, RefCell};
11use std::rc::{Rc, Weak};
12use std::time::Duration;
13
14pub struct ServerCompositionRenderData {
17 this: Weak<ServerCompositionRenderData>,
18 compositor: Weak<ServerCompositor>,
19 core: ServerRenderResourceCore,
20 stream: RefCell<Option<RenderDataStream>>,
21 referenced_resources: RefCell<Vec<Rc<dyn IServerRenderResource>>>,
22 bounds: Cell<Option<LtrbRect>>,
23 bounds_valid: Cell<bool>,
24 replay_scopes: RefCell<Vec<ReplayScope>>,
25}
26
27impl ServerCompositionRenderData {
28 pub fn new(compositor: &Rc<ServerCompositor>) -> Rc<ServerCompositionRenderData> {
29 Rc::new_cyclic(|this| ServerCompositionRenderData {
30 this: this.clone(),
31 compositor: Rc::downgrade(compositor),
32 core: ServerRenderResourceCore::new(),
33 stream: RefCell::new(None),
34 referenced_resources: RefCell::new(Vec::new()),
35 bounds: Cell::new(None),
36 bounds_valid: Cell::new(false),
37 replay_scopes: RefCell::new(Vec::new()),
38 })
39 }
40
41 pub fn is_disposed(&self) -> bool {
42 self.core.is_disposed()
43 }
44
45 fn as_observer(&self) -> Option<Rc<dyn IServerRenderResourceObserver>> {
46 self.this.upgrade().map(|this| this as Rc<dyn IServerRenderResourceObserver>)
47 }
48
49 pub fn bounds(&self) -> Option<LtrbRect> {
52 if !self.bounds_valid.get() {
53 self.bounds.set(self.calculate_render_bounds());
54 self.bounds_valid.set(true);
55 }
56 self.bounds.get()
57 }
58
59 fn calculate_render_bounds(&self) -> Option<LtrbRect> {
60 let bounds = self.stream.borrow().as_ref().and_then(RenderDataStream::calculate_bounds);
61 Self::apply_render_bounds_rounding(bounds.map(LtrbRect::from_rect))
62 }
63
64 pub fn apply_render_bounds_rounding_rect(rect: Option<Rect>) -> Option<Rect> {
66 Self::apply_render_bounds_rounding(rect.map(LtrbRect::from_rect)).map(|r| r.to_rect())
67 }
68
69 pub fn apply_render_bounds_rounding(rect: Option<LtrbRect>) -> Option<LtrbRect> {
71 rect.map(|r| LtrbRect { left: r.left.floor(), top: r.top.floor(), right: r.right.ceil(), bottom: r.bottom.ceil() })
72 }
73
74 pub fn render(&self, context: &mut dyn IDrawingContextImpl) {
76 if let Some(stream) = self.stream.borrow().as_ref() {
77 stream.replay_with_scopes(context, &mut self.replay_scopes.borrow_mut());
78 }
79 }
80
81 fn reset(&self) {
82 self.bounds.set(None);
83 self.bounds_valid.set(false);
84 let referenced = std::mem::take(&mut *self.referenced_resources.borrow_mut());
85 if let Some(observer) = self.as_observer() {
86 for resource in &referenced {
87 resource.remove_observer(&observer);
88 }
89 }
90 if let Some(mut stream) = self.stream.borrow_mut().take() {
91 stream.dispose_resources();
92 stream.dispose();
93 }
94 }
95}
96
97impl IServerObject for ServerCompositionRenderData {
98 fn deserialize_changes_core(&self, reader: &mut BatchStreamReader<'_>, _committed_at: Duration) {
99 self.reset();
100 let mut stream = RenderDataStream::new();
101 let compositor = self.compositor.upgrade();
102 let server_ids = RefCell::new(Vec::new());
103 stream.deserialize_from(reader, &|id| {
104 server_ids.borrow_mut().push(id);
105 compositor.as_ref().and_then(|c| c.get_object(id))
106 });
107 let server_ids = server_ids.into_inner();
108
109 if let (Some(compositor), Some(observer)) = (&compositor, self.as_observer()) {
112 let mut referenced = self.referenced_resources.borrow_mut();
113 for id in &server_ids {
114 if let Some(resource) = compositor.get_object(*id).and_then(|o| o.as_render_resource()) {
115 resource.add_observer(&observer);
116 referenced.push(resource);
117 }
118 }
119 }
120 *self.stream.borrow_mut() = Some(stream);
121 }
122
123 fn values_invalidated(&self) {
124 self.core.invalidated(self);
125 }
126
127 fn dispose(&self) {
128 self.reset();
129 self.core.dispose();
130 }
131
132 fn as_render_resource(self: Rc<Self>) -> Option<Rc<dyn IServerRenderResource>> {
133 Some(self)
134 }
135
136 fn as_any(&self) -> &dyn Any {
137 self
138 }
139
140 fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
141 self
142 }
143}
144
145impl IServerRenderResourceObserver for ServerCompositionRenderData {
146 fn dependency_queued_invalidate(&self, _sender: &dyn IServerRenderResource) {
147 self.bounds_valid.set(false);
148 self.core.dependency_queued_invalidate(self);
149 }
150}
151
152impl IServerRenderResource for ServerCompositionRenderData {
153 fn add_observer(&self, observer: &Rc<dyn IServerRenderResourceObserver>) {
154 self.core.add_observer(observer);
155 }
156
157 fn remove_observer(&self, observer: &Rc<dyn IServerRenderResourceObserver>) {
158 self.core.remove_observer(observer);
159 }
160
161 fn queued_invalidate(&self) {
162 self.core.queued_invalidate(self);
163 }
164}
165
166impl IServerRenderResourceHost for ServerCompositionRenderData {
167 fn compositor(&self) -> Option<Rc<ServerCompositor>> {
168 self.compositor.upgrade()
169 }
170
171 fn as_render_resource_rc(&self) -> Option<Rc<dyn IServerRenderResource>> {
172 self.this.upgrade().map(|this| this as Rc<dyn IServerRenderResource>)
173 }
174}