1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use std::convert::TryFrom;
4 use std::ops::{Deref, DerefMut};
5 use std::rc::Rc;
6 use std::slice;
7 
8 use crate::enums::{Format, SurfaceType};
9 use crate::error::Error;
10 #[cfg(feature = "use_glib")]
11 use glib::translate::*;
12 
13 use crate::surface::Surface;
14 use crate::utils::status_to_result;
15 use crate::BorrowError;
16 use std::fmt;
17 
18 declare_surface!(ImageSurface, SurfaceType::Image);
19 
20 impl ImageSurface {
21     #[doc(alias = "cairo_image_surface_create")]
create(format: Format, width: i32, height: i32) -> Result<ImageSurface, Error>22     pub fn create(format: Format, width: i32, height: i32) -> Result<ImageSurface, Error> {
23         unsafe {
24             Self::from_raw_full(ffi::cairo_image_surface_create(
25                 format.into(),
26                 width,
27                 height,
28             ))
29         }
30     }
31 
32     // rustdoc-stripper-ignore-next
33     /// Creates an image surface for the provided pixel data.
34     /// - The pointer `data` is the beginning of the underlying slice,
35     ///   and at least `width * stride` succeeding bytes should be allocated.
36     /// - `data` must live longer than any reference to the returned surface.
37     /// - You have to free `data` by yourself.
38     #[doc(alias = "cairo_image_surface_create_for_data")]
create_for_data_unsafe( data: *mut u8, format: Format, width: i32, height: i32, stride: i32, ) -> Result<ImageSurface, Error>39     pub unsafe fn create_for_data_unsafe(
40         data: *mut u8,
41         format: Format,
42         width: i32,
43         height: i32,
44         stride: i32,
45     ) -> Result<ImageSurface, Error> {
46         ImageSurface::from_raw_full(ffi::cairo_image_surface_create_for_data(
47             data,
48             format.into(),
49             width,
50             height,
51             stride,
52         ))
53     }
54 
55     #[doc(alias = "cairo_image_surface_create_for_data")]
create_for_data<D: AsMut<[u8]> + 'static>( data: D, format: Format, width: i32, height: i32, stride: i32, ) -> Result<ImageSurface, Error>56     pub fn create_for_data<D: AsMut<[u8]> + 'static>(
57         data: D,
58         format: Format,
59         width: i32,
60         height: i32,
61         stride: i32,
62     ) -> Result<ImageSurface, Error> {
63         let mut data: Box<dyn AsMut<[u8]>> = Box::new(data);
64 
65         let (ptr, len) = {
66             let data: &mut [u8] = (*data).as_mut();
67 
68             (data.as_mut_ptr(), data.len())
69         };
70 
71         assert!(len >= (height * stride) as usize);
72         let result = unsafe {
73             ImageSurface::from_raw_full(ffi::cairo_image_surface_create_for_data(
74                 ptr,
75                 format.into(),
76                 width,
77                 height,
78                 stride,
79             ))
80         };
81         if let Ok(surface) = &result {
82             static IMAGE_SURFACE_DATA: crate::UserDataKey<Box<dyn AsMut<[u8]>>> =
83                 crate::UserDataKey::new();
84             surface.set_user_data(&IMAGE_SURFACE_DATA, Rc::new(data))?;
85         }
86         result
87     }
88 
89     #[doc(alias = "cairo_image_surface_get_data")]
90     #[doc(alias = "get_data")]
data(&mut self) -> Result<ImageSurfaceData, BorrowError>91     pub fn data(&mut self) -> Result<ImageSurfaceData, BorrowError> {
92         unsafe {
93             if ffi::cairo_surface_get_reference_count(self.to_raw_none()) > 1 {
94                 return Err(BorrowError::NonExclusive);
95             }
96 
97             self.flush();
98             let status = ffi::cairo_surface_status(self.to_raw_none());
99             if let Some(err) = status_to_result(status).err() {
100                 return Err(BorrowError::from(err));
101             }
102             if ffi::cairo_image_surface_get_data(self.to_raw_none()).is_null() || is_finished(self)
103             {
104                 return Err(BorrowError::from(Error::SurfaceFinished));
105             }
106             Ok(ImageSurfaceData::new(self))
107         }
108     }
109 
take_data(self) -> Result<ImageSurfaceDataOwned, BorrowError>110     pub fn take_data(self) -> Result<ImageSurfaceDataOwned, BorrowError> {
111         unsafe {
112             if ffi::cairo_surface_get_reference_count(self.to_raw_none()) > 1 {
113                 return Err(BorrowError::NonExclusive);
114             }
115 
116             self.flush();
117             let status = ffi::cairo_surface_status(self.to_raw_none());
118             if let Some(err) = status_to_result(status).err() {
119                 return Err(BorrowError::from(err));
120             }
121             if ffi::cairo_image_surface_get_data(self.to_raw_none()).is_null() || is_finished(&self)
122             {
123                 return Err(BorrowError::from(Error::SurfaceFinished));
124             }
125             Ok(ImageSurfaceDataOwned { surface: self })
126         }
127     }
128 
with_data<F: FnOnce(&[u8])>(&self, f: F) -> Result<(), BorrowError>129     pub fn with_data<F: FnOnce(&[u8])>(&self, f: F) -> Result<(), BorrowError> {
130         self.flush();
131         unsafe {
132             let status = ffi::cairo_surface_status(self.to_raw_none());
133             if let Some(err) = status_to_result(status).err() {
134                 return Err(BorrowError::from(err));
135             }
136             let ptr = ffi::cairo_image_surface_get_data(self.to_raw_none());
137             if ptr.is_null() || is_finished(self) {
138                 return Err(BorrowError::from(Error::SurfaceFinished));
139             }
140             let len = self.height() as usize * self.stride() as usize;
141             f(slice::from_raw_parts(ptr, len));
142         }
143         Ok(())
144     }
145 
146     #[doc(alias = "cairo_image_surface_get_format")]
147     #[doc(alias = "get_format")]
format(&self) -> Format148     pub fn format(&self) -> Format {
149         unsafe { Format::from(ffi::cairo_image_surface_get_format(self.to_raw_none())) }
150     }
151 
152     #[doc(alias = "cairo_image_surface_get_height")]
153     #[doc(alias = "get_height")]
height(&self) -> i32154     pub fn height(&self) -> i32 {
155         unsafe { ffi::cairo_image_surface_get_height(self.to_raw_none()) }
156     }
157 
158     #[doc(alias = "cairo_image_surface_get_stride")]
159     #[doc(alias = "get_stride")]
stride(&self) -> i32160     pub fn stride(&self) -> i32 {
161         unsafe { ffi::cairo_image_surface_get_stride(self.to_raw_none()) }
162     }
163 
164     #[doc(alias = "cairo_image_surface_get_width")]
165     #[doc(alias = "get_width")]
width(&self) -> i32166     pub fn width(&self) -> i32 {
167         unsafe { ffi::cairo_image_surface_get_width(self.to_raw_none()) }
168     }
169 }
170 
171 pub struct ImageSurfaceDataOwned {
172     surface: ImageSurface,
173 }
174 
175 impl AsRef<[u8]> for ImageSurfaceDataOwned {
as_ref(&self) -> &[u8]176     fn as_ref(&self) -> &[u8] {
177         let len = (self.surface.stride() as usize) * (self.surface.height() as usize);
178         unsafe {
179             let ptr = ffi::cairo_image_surface_get_data(self.surface.to_raw_none());
180             debug_assert!(!ptr.is_null());
181             slice::from_raw_parts(ptr, len)
182         }
183     }
184 }
185 
186 impl AsMut<[u8]> for ImageSurfaceDataOwned {
as_mut(&mut self) -> &mut [u8]187     fn as_mut(&mut self) -> &mut [u8] {
188         let len = (self.surface.stride() as usize) * (self.surface.height() as usize);
189         unsafe {
190             let ptr = ffi::cairo_image_surface_get_data(self.surface.to_raw_none());
191             debug_assert!(!ptr.is_null());
192             slice::from_raw_parts_mut(ptr, len)
193         }
194     }
195 }
196 
197 impl Deref for ImageSurfaceDataOwned {
198     type Target = [u8];
199 
deref(&self) -> &Self::Target200     fn deref(&self) -> &Self::Target {
201         self.as_ref()
202     }
203 }
204 
205 impl DerefMut for ImageSurfaceDataOwned {
deref_mut(&mut self) -> &mut Self::Target206     fn deref_mut(&mut self) -> &mut Self::Target {
207         self.as_mut()
208     }
209 }
210 
211 #[derive(Debug)]
212 pub struct ImageSurfaceData<'a> {
213     surface: &'a mut ImageSurface,
214     slice: &'a mut [u8],
215     dirty: bool,
216 }
217 
218 impl<'a> ImageSurfaceData<'a> {
new(surface: &'a mut ImageSurface) -> ImageSurfaceData<'a>219     fn new(surface: &'a mut ImageSurface) -> ImageSurfaceData<'a> {
220         unsafe {
221             let ptr = ffi::cairo_image_surface_get_data(surface.to_raw_none());
222             debug_assert!(!ptr.is_null());
223             let len = (surface.stride() as usize) * (surface.height() as usize);
224             ImageSurfaceData {
225                 surface,
226                 slice: slice::from_raw_parts_mut(ptr, len),
227                 dirty: false,
228             }
229         }
230     }
231 }
232 
233 impl<'a> Drop for ImageSurfaceData<'a> {
drop(&mut self)234     fn drop(&mut self) {
235         if self.dirty {
236             self.surface.mark_dirty()
237         }
238     }
239 }
240 
241 impl<'a> Deref for ImageSurfaceData<'a> {
242     type Target = [u8];
243 
deref(&self) -> &[u8]244     fn deref(&self) -> &[u8] {
245         self.slice
246     }
247 }
248 
249 impl<'a> DerefMut for ImageSurfaceData<'a> {
deref_mut(&mut self) -> &mut [u8]250     fn deref_mut(&mut self) -> &mut [u8] {
251         self.dirty = true;
252         self.slice
253     }
254 }
255 
256 impl<'a> fmt::Display for ImageSurfaceData<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result257     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
258         write!(f, "ImageSurfaceData")
259     }
260 }
261 
262 // Workaround for cairo not having a direct way to check if the surface is finished.
263 // See: https://gitlab.freedesktop.org/cairo/cairo/-/issues/406
is_finished(surface: &ImageSurface) -> bool264 fn is_finished(surface: &ImageSurface) -> bool {
265     use super::Context;
266     Context::new(surface).is_err()
267 }
268 
269 #[cfg(test)]
270 mod tests {
271     use super::*;
272 
273     #[test]
create_with_invalid_size_yields_error()274     fn create_with_invalid_size_yields_error() {
275         let result = ImageSurface::create(Format::ARgb32, 50000, 50000);
276         assert!(result.is_err());
277     }
278 
279     #[test]
create_for_data_with_invalid_stride_yields_error()280     fn create_for_data_with_invalid_stride_yields_error() {
281         let result = ImageSurface::create_for_data(vec![0u8; 10], Format::ARgb32, 1, 2, 5); // unaligned stride
282         assert!(result.is_err());
283     }
284 
285     #[test]
create_with_valid_size()286     fn create_with_valid_size() {
287         let result = ImageSurface::create(Format::ARgb32, 10, 10);
288         assert!(result.is_ok());
289 
290         let result = ImageSurface::create_for_data(vec![0u8; 40 * 10], Format::ARgb32, 10, 10, 40);
291         assert!(result.is_ok());
292     }
293 
294     #[test]
no_crash_after_finish()295     fn no_crash_after_finish() {
296         let mut surf = ImageSurface::create(Format::ARgb32, 1024, 1024).unwrap();
297 
298         surf.finish();
299 
300         assert!(surf.data().is_err());
301     }
302 
303     #[test]
create_from_owned()304     fn create_from_owned() {
305         let result = ImageSurface::create(Format::ARgb32, 10, 10);
306         assert!(result.is_ok());
307         let image_surface = result.unwrap();
308         let stride = image_surface.stride();
309         let data = image_surface.take_data().unwrap();
310         let second = ImageSurface::create_for_data(data, Format::ARgb32, 10, 10, stride);
311         assert!(second.is_ok())
312     }
313 }
314