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