ferroui_base/rendering/composition/
loaded_image_surface.rs1use super::server::{ServerLoadedImageSurface, ServerObjectId};
2use super::{CompositionObject, Compositor, ICompositionObject, ICompositionSurface};
3use crate::media::imaging::Bitmap;
4use crate::Size;
5use std::any::Any;
6use std::io::Read;
7use std::rc::Rc;
8
9#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
12pub enum LoadedImageSourceLoadStatus {
13 #[default]
15 Success,
16 NetworkError,
18 InvalidFormat,
20 Other,
22}
23
24pub struct LoadedImageSurface {
37 object: CompositionObject,
38 bitmap: Option<Bitmap>,
39 load_status: LoadedImageSourceLoadStatus,
40}
41
42impl LoadedImageSurface {
43 fn create(compositor: &Rc<Compositor>, bitmap: Option<Bitmap>, status: LoadedImageSourceLoadStatus) -> Rc<Self> {
44 let server_bitmap = bitmap.as_ref().map(|bitmap| bitmap.platform_impl().clone_ref());
45 let server = compositor.create_server_object(move |_, _| ServerLoadedImageSurface::new(server_bitmap));
46 Rc::new(LoadedImageSurface {
47 object: CompositionObject::new(compositor, Some(server)),
48 bitmap,
49 load_status: status,
50 })
51 }
52
53 pub fn from_bitmap(compositor: &Rc<Compositor>, bitmap: &Bitmap) -> Rc<LoadedImageSurface> {
56 Self::create(compositor, Some(Bitmap::from_ref(bitmap.platform_impl())), LoadedImageSourceLoadStatus::Success)
57 }
58
59 pub fn start_load_from_stream(compositor: &Rc<Compositor>, stream: &mut dyn Read) -> Rc<LoadedImageSurface> {
64 match Bitmap::from_stream(stream) {
65 Ok(bitmap) => Self::create(compositor, Some(bitmap), LoadedImageSourceLoadStatus::Success),
66 Err(error) => {
67 let status = match error.kind() {
68 std::io::ErrorKind::InvalidData | std::io::ErrorKind::Unsupported => {
69 LoadedImageSourceLoadStatus::InvalidFormat
70 }
71 std::io::ErrorKind::NotFound
72 | std::io::ErrorKind::PermissionDenied
73 | std::io::ErrorKind::UnexpectedEof
74 | std::io::ErrorKind::ConnectionReset
75 | std::io::ErrorKind::TimedOut => LoadedImageSourceLoadStatus::NetworkError,
76 _ => LoadedImageSourceLoadStatus::Other,
77 };
78 Self::create(compositor, None, status)
79 }
80 }
81 }
82
83 pub fn compositor(&self) -> &Rc<Compositor> {
84 self.object.compositor()
85 }
86
87 pub fn object(&self) -> &CompositionObject {
89 &self.object
90 }
91
92 pub fn server(&self) -> ServerObjectId {
94 self.object.required_server()
95 }
96
97 pub fn load_status(&self) -> LoadedImageSourceLoadStatus {
99 self.load_status
100 }
101
102 pub fn bitmap(&self) -> Option<&Bitmap> {
105 self.bitmap.as_ref().filter(|bitmap| bitmap.platform_impl().is_alive())
106 }
107
108 pub fn natural_size(&self) -> Size {
111 self.bitmap().map(|bitmap| bitmap.size()).unwrap_or_default()
112 }
113
114 pub fn decoded_size(&self) -> Size {
118 self.natural_size()
119 }
120
121 pub fn decoded_physical_size(&self) -> Size {
123 self.bitmap()
124 .map(|bitmap| {
125 let size = bitmap.pixel_size();
126 Size::new(size.width as f64, size.height as f64)
127 })
128 .unwrap_or_default()
129 }
130
131 pub fn is_disposed(&self) -> bool {
132 self.object.is_disposed()
133 }
134
135 pub fn dispose(&self) {
138 if let Some(bitmap) = &self.bitmap {
139 bitmap.dispose();
140 }
141 self.object.dispose();
142 }
143}
144
145impl ICompositionObject for LoadedImageSurface {
146 fn server(&self) -> ServerObjectId {
147 self.object.required_server()
148 }
149
150 fn as_any(&self) -> &dyn Any {
151 self
152 }
153
154 fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
155 self
156 }
157}
158
159impl ICompositionSurface for LoadedImageSurface {}