cairo/
image_surface.rs
1use std::{
4 ops::{Deref, DerefMut},
5 rc::Rc,
6 slice,
7};
8
9#[cfg(feature = "use_glib")]
10use glib::translate::*;
11
12use crate::{ffi, utils::status_to_result, BorrowError, Error, Format, Surface, SurfaceType};
13
14declare_surface!(ImageSurface, SurfaceType::Image);
15
16impl ImageSurface {
17 #[doc(alias = "cairo_image_surface_create")]
18 pub fn create(format: Format, width: i32, height: i32) -> Result<ImageSurface, Error> {
19 unsafe {
20 Self::from_raw_full(ffi::cairo_image_surface_create(
21 format.into(),
22 width,
23 height,
24 ))
25 }
26 }
27
28 #[doc(alias = "cairo_image_surface_create_for_data")]
35 pub unsafe fn create_for_data_unsafe(
36 data: *mut u8,
37 format: Format,
38 width: i32,
39 height: i32,
40 stride: i32,
41 ) -> Result<ImageSurface, Error> {
42 ImageSurface::from_raw_full(ffi::cairo_image_surface_create_for_data(
43 data,
44 format.into(),
45 width,
46 height,
47 stride,
48 ))
49 }
50
51 #[doc(alias = "cairo_image_surface_create_for_data")]
52 pub fn create_for_data<D: AsMut<[u8]> + 'static>(
53 data: D,
54 format: Format,
55 width: i32,
56 height: i32,
57 stride: i32,
58 ) -> Result<ImageSurface, Error> {
59 let mut data: Box<dyn AsMut<[u8]>> = Box::new(data);
60
61 let (ptr, len) = {
62 let data: &mut [u8] = (*data).as_mut();
63
64 (data.as_mut_ptr(), data.len())
65 };
66
67 assert!(len >= (height * stride) as usize);
68 let result = unsafe {
69 ImageSurface::from_raw_full(ffi::cairo_image_surface_create_for_data(
70 ptr,
71 format.into(),
72 width,
73 height,
74 stride,
75 ))
76 };
77 if let Ok(surface) = &result {
78 static IMAGE_SURFACE_DATA: crate::UserDataKey<Box<dyn AsMut<[u8]>>> =
79 crate::UserDataKey::new();
80 surface.set_user_data(&IMAGE_SURFACE_DATA, Rc::new(data))?;
81 }
82 result
83 }
84
85 #[doc(alias = "cairo_image_surface_get_data")]
86 #[doc(alias = "get_data")]
87 pub fn data(&mut self) -> Result<ImageSurfaceData, BorrowError> {
88 unsafe {
89 if ffi::cairo_surface_get_reference_count(self.to_raw_none()) > 1 {
90 return Err(BorrowError::NonExclusive);
91 }
92
93 self.flush();
94 let status = ffi::cairo_surface_status(self.to_raw_none());
95 if let Some(err) = status_to_result(status).err() {
96 return Err(BorrowError::from(err));
97 }
98 if ffi::cairo_image_surface_get_data(self.to_raw_none()).is_null() || is_finished(self)
99 {
100 return Err(BorrowError::from(Error::SurfaceFinished));
101 }
102 Ok(ImageSurfaceData::new(self))
103 }
104 }
105
106 pub fn take_data(self) -> Result<ImageSurfaceDataOwned, BorrowError> {
107 unsafe {
108 if ffi::cairo_surface_get_reference_count(self.to_raw_none()) > 1 {
109 return Err(BorrowError::NonExclusive);
110 }
111
112 self.flush();
113 let status = ffi::cairo_surface_status(self.to_raw_none());
114 if let Some(err) = status_to_result(status).err() {
115 return Err(BorrowError::from(err));
116 }
117 if ffi::cairo_image_surface_get_data(self.to_raw_none()).is_null() || is_finished(&self)
118 {
119 return Err(BorrowError::from(Error::SurfaceFinished));
120 }
121 Ok(ImageSurfaceDataOwned { surface: self })
122 }
123 }
124
125 pub fn with_data<F: FnOnce(&[u8])>(&self, f: F) -> Result<(), BorrowError> {
126 self.flush();
127 unsafe {
128 let status = ffi::cairo_surface_status(self.to_raw_none());
129 if let Some(err) = status_to_result(status).err() {
130 return Err(BorrowError::from(err));
131 }
132 let ptr = ffi::cairo_image_surface_get_data(self.to_raw_none());
133 if ptr.is_null() || is_finished(self) {
134 return Err(BorrowError::from(Error::SurfaceFinished));
135 }
136 let len = self.height() as usize * self.stride() as usize;
137 let data = if len == 0 {
138 &[]
139 } else {
140 slice::from_raw_parts(ptr, len)
141 };
142 f(data);
143 }
144 Ok(())
145 }
146
147 #[doc(alias = "cairo_image_surface_get_format")]
148 #[doc(alias = "get_format")]
149 pub fn format(&self) -> Format {
150 unsafe { Format::from(ffi::cairo_image_surface_get_format(self.to_raw_none())) }
151 }
152
153 #[doc(alias = "cairo_image_surface_get_height")]
154 #[doc(alias = "get_height")]
155 pub fn height(&self) -> i32 {
156 unsafe { ffi::cairo_image_surface_get_height(self.to_raw_none()) }
157 }
158
159 #[doc(alias = "cairo_image_surface_get_stride")]
160 #[doc(alias = "get_stride")]
161 pub fn stride(&self) -> i32 {
162 unsafe { ffi::cairo_image_surface_get_stride(self.to_raw_none()) }
163 }
164
165 #[doc(alias = "cairo_image_surface_get_width")]
166 #[doc(alias = "get_width")]
167 pub fn width(&self) -> i32 {
168 unsafe { ffi::cairo_image_surface_get_width(self.to_raw_none()) }
169 }
170}
171
172pub struct ImageSurfaceDataOwned {
173 surface: ImageSurface,
174}
175
176unsafe impl Send for ImageSurfaceDataOwned {}
177unsafe impl Sync for ImageSurfaceDataOwned {}
178
179impl ImageSurfaceDataOwned {
180 #[inline]
181 pub fn into_inner(self) -> ImageSurface {
182 self.surface
183 }
184}
185
186impl AsRef<[u8]> for ImageSurfaceDataOwned {
187 #[inline]
188 fn as_ref(&self) -> &[u8] {
189 let len = (self.surface.stride() as usize) * (self.surface.height() as usize);
190 unsafe {
191 let ptr = ffi::cairo_image_surface_get_data(self.surface.to_raw_none());
192 if ptr.is_null() || len == 0 {
193 return &[];
194 }
195 slice::from_raw_parts(ptr, len)
196 }
197 }
198}
199
200impl AsMut<[u8]> for ImageSurfaceDataOwned {
201 #[inline]
202 fn as_mut(&mut self) -> &mut [u8] {
203 let len = (self.surface.stride() as usize) * (self.surface.height() as usize);
204 unsafe {
205 let ptr = ffi::cairo_image_surface_get_data(self.surface.to_raw_none());
206 if ptr.is_null() || len == 0 {
207 return &mut [];
208 }
209 slice::from_raw_parts_mut(ptr, len)
210 }
211 }
212}
213
214impl Deref for ImageSurfaceDataOwned {
215 type Target = [u8];
216
217 #[inline]
218 fn deref(&self) -> &Self::Target {
219 self.as_ref()
220 }
221}
222
223impl DerefMut for ImageSurfaceDataOwned {
224 #[inline]
225 fn deref_mut(&mut self) -> &mut Self::Target {
226 self.as_mut()
227 }
228}
229
230#[derive(Debug)]
231pub struct ImageSurfaceData<'a> {
232 surface: &'a mut ImageSurface,
233 slice: &'a mut [u8],
234 dirty: bool,
235}
236
237unsafe impl Send for ImageSurfaceData<'_> {}
238unsafe impl Sync for ImageSurfaceData<'_> {}
239
240impl<'a> ImageSurfaceData<'a> {
241 fn new(surface: &'a mut ImageSurface) -> ImageSurfaceData<'a> {
242 unsafe {
243 let ptr = ffi::cairo_image_surface_get_data(surface.to_raw_none());
244 let len = (surface.stride() as usize) * (surface.height() as usize);
245 ImageSurfaceData {
246 surface,
247 slice: if ptr.is_null() || len == 0 {
248 &mut []
249 } else {
250 slice::from_raw_parts_mut(ptr, len)
251 },
252 dirty: false,
253 }
254 }
255 }
256}
257
258impl Drop for ImageSurfaceData<'_> {
259 #[inline]
260 fn drop(&mut self) {
261 if self.dirty {
262 self.surface.mark_dirty()
263 }
264 }
265}
266
267impl Deref for ImageSurfaceData<'_> {
268 type Target = [u8];
269
270 #[inline]
271 fn deref(&self) -> &[u8] {
272 self.slice
273 }
274}
275
276impl DerefMut for ImageSurfaceData<'_> {
277 #[inline]
278 fn deref_mut(&mut self) -> &mut [u8] {
279 self.dirty = true;
280 self.slice
281 }
282}
283
284fn is_finished(surface: &ImageSurface) -> bool {
287 use super::Context;
288 Context::new(surface).is_err()
289}
290
291#[cfg(test)]
292mod tests {
293 use super::*;
294
295 #[test]
296 fn create_with_invalid_size_yields_error() {
297 let result = ImageSurface::create(Format::ARgb32, 50000, 50000);
298 assert!(result.is_err());
299 }
300
301 #[test]
302 fn create_for_data_with_invalid_stride_yields_error() {
303 let result = ImageSurface::create_for_data(vec![0u8; 10], Format::ARgb32, 1, 2, 5); assert!(result.is_err());
305 }
306
307 #[test]
308 fn create_with_valid_size() {
309 let result = ImageSurface::create(Format::ARgb32, 10, 10);
310 assert!(result.is_ok());
311
312 let result = ImageSurface::create_for_data(vec![0u8; 40 * 10], Format::ARgb32, 10, 10, 40);
313 assert!(result.is_ok());
314 }
315
316 #[test]
317 fn no_crash_after_finish() {
318 let mut surf = ImageSurface::create(Format::ARgb32, 1024, 1024).unwrap();
319
320 surf.finish();
321
322 assert!(surf.data().is_err());
323 }
324
325 #[test]
326 fn create_from_owned() {
327 let result = ImageSurface::create(Format::ARgb32, 10, 10);
328 assert!(result.is_ok());
329 let image_surface = result.unwrap();
330 let stride = image_surface.stride();
331 let data = image_surface.take_data().unwrap();
332 let second = ImageSurface::create_for_data(data, Format::ARgb32, 10, 10, stride);
333 assert!(second.is_ok())
334 }
335
336 #[cfg(feature = "use_glib")]
337 #[test]
338 fn surface_gvalues() {
339 use glib::prelude::*;
340
341 let surface = ImageSurface::create(Format::ARgb32, 10, 10).unwrap();
342 let value = surface.to_value();
343 assert_eq!(value.get::<ImageSurface>().unwrap().width(), 10);
344 let _ = surface.to_value();
345 let surface = Some(surface);
346 let value = surface.to_value();
347 assert_eq!(
348 value
349 .get::<Option<ImageSurface>>()
350 .unwrap()
351 .map(|s| s.width()),
352 Some(10)
353 );
354 let _ = surface.as_ref().to_value();
355 assert_eq!(
356 value
357 .get::<Option<&ImageSurface>>()
358 .unwrap()
359 .map(|s| s.width()),
360 Some(10)
361 );
362 }
363}