Skip to main content

ferroui_base/rendering/composition/drawing/
render_data_resources.rs

1use super::IRenderDataGeometry;
2use crate::media::{IBrush, IPen};
3use crate::platform::{IGeometryImpl, IGlyphRunImpl};
4use crate::rendering::composition::server::ServerObjectId;
5use crate::rendering::scene_graph::ICustomDrawOperation;
6use std::collections::HashMap;
7use std::rc::Rc;
8use std::sync::Arc;
9
10/// The handle of "no resource".
11pub const NULL_HANDLE: i32 = -1;
12
13/// A resource referenced by render data.
14///
15/// On the UI thread a resource that has a server-side counterpart is kept
16/// as the pair of the counterpart's id and the client object (which is what
17/// hit testing uses). Only the id is sent; the server resolves it to the
18/// server object, so a deserialized table holds no `Server*` entries.
19#[derive(Clone)]
20pub enum RenderDataResource {
21    Brush(Rc<dyn IBrush>),
22    Pen(Rc<dyn IPen>),
23    GeometryImpl(Arc<dyn IGeometryImpl>),
24    Geometry(Rc<dyn IRenderDataGeometry>),
25    /// A recorded glyph run: one counted reference (`IRef<IGlyphRunImpl>`
26    /// upstream), shared by the client render data and the server render
27    /// data it is sent to, so that the glyph run is held once until both
28    /// are released.
29    GlyphRun(Arc<Arc<dyn IGlyphRunImpl>>),
30    /// A recorded bitmap: one counted reference (`IRef<IBitmapImpl>`
31    /// upstream), shared as a glyph run is.
32    Bitmap(Arc<crate::utilities::RefCounted<crate::platform::SharedBitmapImpl>>),
33    CustomDrawOperation(std::sync::Arc<dyn ICustomDrawOperation>),
34    Effect(Arc<dyn crate::media::IImmutableEffect>),
35    ServerBrush { server: ServerObjectId, client: Rc<dyn IBrush> },
36    ServerPen { server: ServerObjectId, client: Rc<dyn IPen> },
37    ServerGeometry { server: ServerObjectId, client: Rc<dyn IRenderDataGeometry> },
38    /// A mutable pen kept on the UI thread for hit testing only; it is not
39    /// sent to the server.
40    ClientPen(Rc<dyn IPen>),
41    /// The slot of a resource that was not sent to the server.
42    NotSent,
43}
44
45#[derive(Clone, Copy, PartialEq, Eq, Hash)]
46enum Kind {
47    Brush,
48    Pen,
49    GeometryImpl,
50    Geometry,
51    GlyphRun,
52    Bitmap,
53    Custom,
54    Effect,
55    Server,
56}
57
58impl RenderDataResource {
59    /// The identity of the resource: resources are deduplicated by
60    /// reference, like upstream.
61    fn key(&self) -> (Kind, usize) {
62        fn address<T: ?Sized>(rc: &Rc<T>) -> usize {
63            Rc::as_ptr(rc) as *const () as usize
64        }
65        match self {
66            RenderDataResource::Brush(v) => (Kind::Brush, address(v)),
67            RenderDataResource::Pen(v) | RenderDataResource::ClientPen(v) => (Kind::Pen, address(v)),
68            RenderDataResource::GeometryImpl(v) => (Kind::GeometryImpl, std::sync::Arc::as_ptr(v) as *const () as usize),
69            RenderDataResource::Geometry(v) => (Kind::Geometry, address(v)),
70            RenderDataResource::GlyphRun(v) => (Kind::GlyphRun, Arc::as_ptr(v) as *const () as usize),
71            RenderDataResource::Bitmap(v) => (Kind::Bitmap, Arc::as_ptr(v) as *const () as usize),
72            RenderDataResource::CustomDrawOperation(v) => (Kind::Custom, Arc::as_ptr(v) as *const () as usize),
73            RenderDataResource::Effect(v) => (Kind::Effect, Arc::as_ptr(v) as *const () as usize),
74            RenderDataResource::ServerBrush { server, .. }
75            | RenderDataResource::ServerPen { server, .. }
76            | RenderDataResource::ServerGeometry { server, .. } => (Kind::Server, server.index()),
77            RenderDataResource::NotSent => (Kind::Server, usize::MAX),
78        }
79    }
80}
81
82/// The resource table of a render data stream: operations refer to
83/// resources by handle.
84#[derive(Default)]
85pub struct RenderDataResources {
86    resources: Vec<RenderDataResource>,
87    intern_map: Option<HashMap<(Kind, usize), i32>>,
88}
89
90impl RenderDataResources {
91    pub fn count(&self) -> usize {
92        self.resources.len()
93    }
94
95    /// Recording path: dedupes by reference equality so a resource reused
96    /// across many draws gets one slot.
97    pub fn intern(&mut self, resource: Option<RenderDataResource>) -> i32 {
98        let Some(resource) = resource else { return NULL_HANDLE };
99        let key = resource.key();
100        let intern_map = self.intern_map.get_or_insert_with(HashMap::new);
101        if let Some(handle) = intern_map.get(&key) {
102            return *handle;
103        }
104        let handle = self.resources.len() as i32;
105        self.resources.push(resource);
106        intern_map.insert(key, handle);
107        handle
108    }
109
110    /// Deserialize path: appends without deduping since the wire format is
111    /// already deduped.
112    pub fn append_deserialized(&mut self, resource: RenderDataResource) -> i32 {
113        let handle = self.resources.len() as i32;
114        self.resources.push(resource);
115        handle
116    }
117
118    /// The resource of a handle; `None` for [`NULL_HANDLE`].
119    pub fn get(&self, handle: i32) -> Option<&RenderDataResource> {
120        if handle == NULL_HANDLE {
121            None
122        } else {
123            Some(&self.resources[handle as usize])
124        }
125    }
126
127    pub fn iter(&self) -> impl Iterator<Item = &RenderDataResource> {
128        self.resources.iter()
129    }
130
131    pub fn brush(&self, handle: i32) -> Option<&dyn IBrush> {
132        match self.get(handle)? {
133            RenderDataResource::Brush(brush) | RenderDataResource::ServerBrush { client: brush, .. } => Some(&**brush),
134            _ => panic!("the render data resource is not a brush"),
135        }
136    }
137
138    pub fn pen(&self, handle: i32) -> Option<&dyn IPen> {
139        match self.get(handle)? {
140            RenderDataResource::Pen(pen)
141            | RenderDataResource::ClientPen(pen)
142            | RenderDataResource::ServerPen { client: pen, .. } => Some(&**pen),
143            RenderDataResource::NotSent => None,
144            _ => panic!("the render data resource is not a pen"),
145        }
146    }
147
148    pub fn geometry_impl(&self, handle: i32) -> Option<Arc<dyn IGeometryImpl>> {
149        match self.get(handle)? {
150            RenderDataResource::GeometryImpl(geometry) => Some(geometry.clone()),
151            RenderDataResource::Geometry(geometry) | RenderDataResource::ServerGeometry { client: geometry, .. } => {
152                geometry.geometry_impl()
153            }
154            _ => panic!("the render data resource is not a geometry"),
155        }
156    }
157
158    pub fn glyph_run(&self, handle: i32) -> Option<&std::sync::Arc<dyn IGlyphRunImpl>> {
159        match self.get(handle)? {
160            RenderDataResource::GlyphRun(glyph_run) => Some(&**glyph_run),
161            _ => panic!("the render data resource is not a glyph run"),
162        }
163    }
164
165    pub fn bitmap(&self, handle: i32) -> Option<std::sync::Arc<crate::platform::SharedBitmapImpl>> {
166        match self.get(handle)? {
167            RenderDataResource::Bitmap(bitmap) => Some(bitmap.item()),
168            _ => panic!("the render data resource is not a bitmap"),
169        }
170    }
171
172    pub fn custom_draw_operation(&self, handle: i32) -> Option<&std::sync::Arc<dyn ICustomDrawOperation>> {
173        match self.get(handle)? {
174            RenderDataResource::CustomDrawOperation(operation) => Some(operation),
175            _ => panic!("the render data resource is not a custom draw operation"),
176        }
177    }
178
179    pub fn effect(&self, handle: i32) -> Option<&Arc<dyn crate::media::IImmutableEffect>> {
180        match self.get(handle)? {
181            RenderDataResource::Effect(effect) => Some(effect),
182            _ => panic!("the render data resource is not an effect"),
183        }
184    }
185
186    /// Releases the table.
187    pub fn dispose(&mut self) {
188        self.resources.clear();
189        self.intern_map = None;
190    }
191}