1use crate::{DevicePixels, ImageId, Pixels, Result, SharedString, Size, size};
2use smallvec::SmallVec;
3
4use image::{Delay, Frame};
5use std::{
6 borrow::Cow,
7 fmt,
8 sync::atomic::{AtomicUsize, Ordering::SeqCst},
9};
10
11pub trait AssetSource: 'static + Send + Sync {
13 fn load(&self, path: &str) -> Result<Option<Cow<'static, [u8]>>>;
15
16 fn list(&self, path: &str) -> Result<Vec<SharedString>>;
18}
19
20impl AssetSource for () {
21 fn load(&self, _path: &str) -> Result<Option<Cow<'static, [u8]>>> {
22 Ok(None)
23 }
24
25 fn list(&self, _path: &str) -> Result<Vec<SharedString>> {
26 Ok(vec![])
27 }
28}
29
30pub struct RenderImage {
32 pub id: ImageId,
34 pub(crate) scale_factor: f32,
36 data: SmallVec<[Frame; 1]>,
37}
38
39impl PartialEq for RenderImage {
40 fn eq(&self, other: &Self) -> bool {
41 self.id == other.id
42 }
43}
44
45impl Eq for RenderImage {}
46
47impl RenderImage {
48 pub fn new(data: impl Into<SmallVec<[Frame; 1]>>) -> Self {
50 static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
51
52 Self {
53 id: ImageId(NEXT_ID.fetch_add(1, SeqCst)),
54 scale_factor: 1.0,
55 data: data.into(),
56 }
57 }
58
59 pub fn as_bytes(&self, frame_index: usize) -> Option<&[u8]> {
61 self.data
62 .get(frame_index)
63 .map(|frame| frame.buffer().as_raw().as_slice())
64 }
65
66 pub fn size(&self, frame_index: usize) -> Size<DevicePixels> {
68 self.data
69 .get(frame_index)
70 .map(|frame| {
71 let (width, height) = frame.buffer().dimensions();
72 size(width.into(), height.into())
73 })
74 .unwrap_or_default()
75 }
76
77 pub(crate) fn render_size(&self, frame_index: usize) -> Size<Pixels> {
79 self.size(frame_index)
80 .map(|v| (v.0 as f32 / self.scale_factor).into())
81 }
82
83 pub fn delay(&self, frame_index: usize) -> Delay {
85 self.data
86 .get(frame_index)
87 .map(|frame| frame.delay())
88 .unwrap_or(Delay::from_numer_denom_ms(100, 1))
89 }
90
91 pub fn frame_count(&self) -> usize {
93 self.data.len()
94 }
95}
96
97impl fmt::Debug for RenderImage {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 f.debug_struct("ImageData")
100 .field("id", &self.id)
101 .field("size", &self.data.first().map(|f| f.buffer().dimensions()))
102 .finish()
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use smallvec::SmallVec;
110
111 #[test]
112 fn empty_render_image_does_not_panic() {
113 let image = RenderImage::new(SmallVec::new());
114 assert_eq!(image.frame_count(), 0);
115 assert_eq!(image.size(0), Size::default());
116 assert_eq!(image.as_bytes(0), None);
117 assert_eq!(image.render_size(0), Size::default());
118 assert_eq!(image.delay(0), Delay::from_numer_denom_ms(100, 1));
119 let _ = format!("{image:?}");
120 }
121}