Skip to main content

ferroui_vello/
writeable_bitmap_impl.rs

1use crate::helpers::image_saving_helper;
2use crate::helpers::pixel_format_helper::{self, to_image, to_premul_rgba};
3use crate::i_drawable_bitmap_impl::IDrawableBitmapImpl;
4use crate::immutable_bitmap::{decode_bitmap, decode_bitmap_to_size};
5use crate::vello_platform::VelloPlatform;
6use ferroui_base::media::imaging::{BitmapEncoderOptions, BitmapInterpolationMode};
7use ferroui_base::platform::{
8    AlphaFormat, IBitmapImpl, ILockedFramebuffer, IReadableBitmapImpl, IWriteableBitmapImpl, PixelFormat,
9};
10use ferroui_base::{PixelSize, Vector};
11use peniko::ImageData;
12use std::any::Any;
13use std::cell::RefCell;
14use std::io::{self, Read, Write};
15use std::rc::Rc;
16use std::sync::atomic::{AtomicI32, Ordering};
17use std::sync::{Arc, Mutex, Weak};
18
19/// A writeable bitmap: pixels in memory, in one of the formats of the
20/// contract.
21///
22/// The UI thread writes the pixels and the render thread draws them: the
23/// pixels and the image drawn from them are under one lock.
24pub struct WriteableBitmapImpl {
25    weak_self: Weak<WriteableBitmapImpl>,
26    pixels: Mutex<Pixels>,
27    dpi: Vector,
28    pixel_size: PixelSize,
29    format: PixelFormat,
30    alpha_format: AlphaFormat,
31    version: AtomicI32,
32}
33
34struct Pixels {
35    /// The pixels in the format of the bitmap, rows without padding.
36    data: Option<Vec<u8>>,
37    /// The snapshot the bitmap is drawn from, until the pixels change.
38    image: Option<ImageData>,
39}
40
41impl WriteableBitmapImpl {
42    fn from_data(data: Vec<u8>, pixel_size: PixelSize, dpi: Vector, format: PixelFormat, alpha_format: AlphaFormat) -> Arc<Self> {
43        Arc::new_cyclic(|weak_self| Self {
44            weak_self: weak_self.clone(),
45            pixels: Mutex::new(Pixels { data: Some(data), image: None }),
46            dpi,
47            pixel_size,
48            format,
49            alpha_format,
50            version: AtomicI32::new(1),
51        })
52    }
53
54    fn from_image(image: ImageData, alpha_format: AlphaFormat) -> Arc<Self> {
55        let pixel_size = PixelSize::new(image.width as i32, image.height as i32);
56        let data = image.data.data().to_vec();
57
58        Self::from_data(data, pixel_size, VelloPlatform::default_dpi(), PixelFormat::RGBA8888, alpha_format)
59    }
60
61    /// Creates a writeable bitmap from the given stream. A bitmap of an
62    /// image without alpha is opaque, as the codec of Skia reports it.
63    pub fn from_stream(stream: &mut dyn Read) -> io::Result<Arc<Self>> {
64        let (image, opaque) = decode_bitmap(stream)?;
65
66        Ok(Self::from_image(image, if opaque { AlphaFormat::Opaque } else { AlphaFormat::Premul }))
67    }
68
69    /// Creates a writeable bitmap from a stream, decoded so that its width
70    /// (`horizontal`) or height is `decode_size`.
71    pub fn from_stream_to_size(
72        stream: &mut dyn Read,
73        decode_size: i32,
74        horizontal: bool,
75        interpolation_mode: BitmapInterpolationMode,
76    ) -> io::Result<Arc<Self>> {
77        let image = decode_bitmap_to_size(stream, decode_size, horizontal, interpolation_mode)?;
78
79        Ok(Self::from_image(image, AlphaFormat::Premul))
80    }
81
82    /// Creates a writeable bitmap with the given size, DPI and formats. The
83    /// pixels start out transparent.
84    ///
85    /// # Panics
86    /// Panics when the pixel format is not one the backend reads and writes
87    /// or the size has no pixels.
88    pub fn new(size: PixelSize, dpi: Vector, format: PixelFormat, alpha_format: AlphaFormat) -> Arc<Self> {
89        let pixel_bytes = pixel_format_helper::bytes_per_pixel(format);
90        if size.width < 1 || size.height < 1 {
91            panic!("Unable to allocate a {}x{} bitmap", size.width, size.height);
92        }
93
94        let data = vec![0u8; size.width as usize * size.height as usize * pixel_bytes];
95
96        Self::from_data(data, size, dpi, format, alpha_format)
97    }
98
99    fn with_data<R>(&self, f: impl FnOnce(&mut Vec<u8>) -> R) -> R {
100        let mut pixels = self.pixels.lock().unwrap();
101        f(pixels.data.as_mut().expect("WriteableBitmapImpl has been disposed"))
102    }
103
104    fn row_bytes(&self) -> usize {
105        self.pixel_size.width as usize * pixel_format_helper::bytes_per_pixel(self.format)
106    }
107}
108
109impl IBitmapImpl for WriteableBitmapImpl {
110    fn dpi(&self) -> Vector {
111        self.dpi
112    }
113
114    fn pixel_size(&self) -> PixelSize {
115        self.pixel_size
116    }
117
118    fn version(&self) -> i32 {
119        self.version.load(Ordering::SeqCst)
120    }
121
122    fn save(&self, stream: &mut dyn Write, options: &BitmapEncoderOptions) -> io::Result<()> {
123        let image = self.image().ok_or_else(|| io::Error::other("WriteableBitmapImpl has been disposed"))?;
124        image_saving_helper::save_image(&image, stream, options)
125    }
126
127    fn dispose(&self) {
128        let mut pixels = self.pixels.lock().unwrap();
129        pixels.image.take();
130        pixels.data.take();
131    }
132
133    fn as_any(&self) -> &dyn Any {
134        self
135    }
136
137    fn as_readable_bitmap(&self) -> Option<&dyn IReadableBitmapImpl> {
138        Some(self)
139    }
140}
141
142impl IDrawableBitmapImpl for WriteableBitmapImpl {
143    fn image(&self) -> Option<ImageData> {
144        let mut pixels = self.pixels.lock().unwrap();
145        if pixels.image.is_none() {
146            // NOTE: this does a snapshot of the bitmap, converted to the
147            // format the renderers draw.
148            let data = pixels.data.as_ref()?;
149            let rgba = to_premul_rgba(data, self.row_bytes(), self.pixel_size, self.format, self.alpha_format);
150            pixels.image = Some(to_image(rgba, self.pixel_size));
151        }
152        pixels.image.clone()
153    }
154}
155
156impl IReadableBitmapImpl for WriteableBitmapImpl {
157    fn format(&self) -> Option<PixelFormat> {
158        Some(self.format)
159    }
160
161    fn alpha_format(&self) -> Option<AlphaFormat> {
162        Some(self.alpha_format)
163    }
164
165    fn lock(&self) -> Rc<dyn ILockedFramebuffer> {
166        let parent = self.weak_self.upgrade().expect("WriteableBitmapImpl is alive while it is used");
167        Rc::new(BitmapFramebuffer { parent: RefCell::new(Some(parent)) })
168    }
169}
170
171impl IWriteableBitmapImpl for WriteableBitmapImpl {}
172
173/// Framebuffer for a bitmap.
174struct BitmapFramebuffer {
175    parent: RefCell<Option<Arc<WriteableBitmapImpl>>>,
176}
177
178impl BitmapFramebuffer {
179    fn with_parent<R>(&self, f: impl FnOnce(&WriteableBitmapImpl) -> R) -> R {
180        let parent = self.parent.borrow();
181        f(parent.as_ref().expect("the framebuffer has been unlocked"))
182    }
183}
184
185impl ILockedFramebuffer for BitmapFramebuffer {
186    fn address(&self) -> *mut u8 {
187        // The pixels stay where they are until the bitmap is disposed: the
188        // address outlives the lock it is read under, as the contract of a
189        // framebuffer has it.
190        self.with_parent(|parent| parent.with_data(|data| data.as_mut_ptr()))
191    }
192
193    fn with_data(&self, access: &mut dyn FnMut(&mut [u8])) {
194        self.with_parent(|parent| parent.with_data(|data| access(data)));
195    }
196
197    fn size(&self) -> PixelSize {
198        self.with_parent(|parent| parent.pixel_size)
199    }
200
201    fn row_bytes(&self) -> i32 {
202        self.with_parent(|parent| parent.row_bytes() as i32)
203    }
204
205    fn dpi(&self) -> Vector {
206        self.with_parent(|parent| parent.dpi)
207    }
208
209    fn format(&self) -> PixelFormat {
210        self.with_parent(|parent| parent.format)
211    }
212
213    fn alpha_format(&self) -> AlphaFormat {
214        self.with_parent(|parent| parent.alpha_format)
215    }
216
217    fn dispose(&self) {
218        if let Some(parent) = self.parent.borrow_mut().take() {
219            let mut pixels = parent.pixels.lock().unwrap();
220            parent.version.fetch_add(1, Ordering::SeqCst);
221            // The image is taken again from the new pixels when drawn.
222            pixels.image = None;
223        }
224    }
225}