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