1use std::convert::TryFrom;
6use std::ops::{Deref, DerefMut};
7use std::rc::Rc;
8use std::slice;
9
10use enums::{Format, SurfaceType};
11use ffi;
12#[cfg(feature = "use_glib")]
13use glib::translate::*;
14
15use std::fmt;
16use surface::Surface;
17use BorrowError;
18use Status;
19
20#[derive(Debug)]
21pub struct ImageSurface(Surface);
22
23impl TryFrom<Surface> for ImageSurface {
24 type Error = Surface;
25
26 fn try_from(surface: Surface) -> Result<ImageSurface, Surface> {
27 if surface.get_type() == SurfaceType::Image {
28 Ok(ImageSurface(surface))
29 } else {
30 Err(surface)
31 }
32 }
33}
34
35impl ImageSurface {
36 pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Result<ImageSurface, Status> {
37 let surface = Self::try_from(Surface::from_raw_full(ptr)).unwrap();
38 let status = surface.status();
39 match status {
40 Status::Success => Ok(surface),
41 _ => Err(status),
42 }
43 }
44
45 pub fn create(format: Format, width: i32, height: i32) -> Result<ImageSurface, Status> {
46 unsafe {
47 Self::from_raw_full(ffi::cairo_image_surface_create(
48 format.into(),
49 width,
50 height,
51 ))
52 }
53 }
54
55 pub fn create_for_data<D: AsMut<[u8]> + 'static>(
56 data: D,
57 format: Format,
58 width: i32,
59 height: i32,
60 stride: i32,
61 ) -> Result<ImageSurface, Status> {
62 let mut data: Box<dyn AsMut<[u8]>> = Box::new(data);
63
64 let (ptr, len) = {
65 let data: &mut [u8] = (*data).as_mut();
66
67 (data.as_mut_ptr(), data.len())
68 };
69
70 assert!(len >= (height * stride) as usize);
71 let result = unsafe {
72 ImageSurface::from_raw_full(ffi::cairo_image_surface_create_for_data(
73 ptr,
74 format.into(),
75 width,
76 height,
77 stride,
78 ))
79 };
80 if let Ok(surface) = &result {
81 static IMAGE_SURFACE_DATA: crate::UserDataKey<Box<dyn AsMut<[u8]>>> =
82 crate::UserDataKey::new();
83 surface.set_user_data(&IMAGE_SURFACE_DATA, Rc::new(data))
84 }
85 result
86 }
87
88 pub fn get_data(&mut self) -> Result<ImageSurfaceData, BorrowError> {
89 unsafe {
90 if ffi::cairo_surface_get_reference_count(self.to_raw_none()) > 1 {
91 return Err(BorrowError::NonExclusive);
92 }
93 self.flush();
94 match self.status() {
95 Status::Success => (),
96 status => return Err(BorrowError::from(status)),
97 }
98 if ffi::cairo_image_surface_get_data(self.to_raw_none()).is_null() {
99 return Err(BorrowError::from(Status::SurfaceFinished));
100 }
101 Ok(ImageSurfaceData::new(self))
102 }
103 }
104
105 pub fn get_format(&self) -> Format {
106 unsafe { Format::from(ffi::cairo_image_surface_get_format(self.to_raw_none())) }
107 }
108
109 pub fn get_height(&self) -> i32 {
110 unsafe { ffi::cairo_image_surface_get_height(self.to_raw_none()) }
111 }
112
113 pub fn get_stride(&self) -> i32 {
114 unsafe { ffi::cairo_image_surface_get_stride(self.to_raw_none()) }
115 }
116
117 pub fn get_width(&self) -> i32 {
118 unsafe { ffi::cairo_image_surface_get_width(self.to_raw_none()) }
119 }
120}
121
122#[cfg(feature = "use_glib")]
123impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for ImageSurface {
124 type Storage = &'a Surface;
125
126 #[inline]
127 fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self> {
128 let stash = self.0.to_glib_none();
129 Stash(stash.0, stash.1)
130 }
131
132 #[inline]
133 fn to_glib_full(&self) -> *mut ffi::cairo_surface_t {
134 unsafe { ffi::cairo_surface_reference(self.0.to_glib_none().0) }
135 }
136}
137
138#[cfg(feature = "use_glib")]
139impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for ImageSurface {
140 #[inline]
141 unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> ImageSurface {
142 Self::try_from(from_glib_none::<_, Surface>(ptr)).unwrap()
143 }
144}
145
146#[cfg(feature = "use_glib")]
147impl FromGlibPtrBorrow<*mut ffi::cairo_surface_t> for ImageSurface {
148 #[inline]
149 unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_surface_t) -> ImageSurface {
150 Self::try_from(from_glib_borrow::<_, Surface>(ptr)).unwrap()
151 }
152}
153
154#[cfg(feature = "use_glib")]
155impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for ImageSurface {
156 #[inline]
157 unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> ImageSurface {
158 Self::from_raw_full(ptr).unwrap()
159 }
160}
161
162#[cfg(feature = "use_glib")]
163gvalue_impl!(
164 ImageSurface,
165 ffi::cairo_surface_t,
166 ffi::gobject::cairo_gobject_surface_get_type
167);
168
169impl Deref for ImageSurface {
170 type Target = Surface;
171
172 fn deref(&self) -> &Surface {
173 &self.0
174 }
175}
176
177impl Clone for ImageSurface {
178 fn clone(&self) -> ImageSurface {
179 ImageSurface(self.0.clone())
180 }
181}
182
183impl fmt::Display for ImageSurface {
184 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185 write!(f, "ImageSurface")
186 }
187}
188
189#[derive(Debug)]
190pub struct ImageSurfaceData<'a> {
191 surface: &'a mut ImageSurface,
192 slice: &'a mut [u8],
193 dirty: bool,
194}
195
196impl<'a> ImageSurfaceData<'a> {
197 fn new(surface: &'a mut ImageSurface) -> ImageSurfaceData<'a> {
198 unsafe {
199 let ptr = ffi::cairo_image_surface_get_data(surface.to_raw_none());
200 debug_assert!(!ptr.is_null());
201 let len = (surface.get_stride() as usize) * (surface.get_height() as usize);
202 ImageSurfaceData {
203 surface,
204 slice: slice::from_raw_parts_mut(ptr, len),
205 dirty: false,
206 }
207 }
208 }
209}
210
211impl<'a> Drop for ImageSurfaceData<'a> {
212 fn drop(&mut self) {
213 if self.dirty {
214 unsafe { ffi::cairo_surface_mark_dirty(self.surface.to_raw_none()) }
215 }
216 }
217}
218
219impl<'a> Deref for ImageSurfaceData<'a> {
220 type Target = [u8];
221
222 fn deref(&self) -> &[u8] {
223 self.slice
224 }
225}
226
227impl<'a> DerefMut for ImageSurfaceData<'a> {
228 fn deref_mut(&mut self) -> &mut [u8] {
229 self.dirty = true;
230 self.slice
231 }
232}
233
234impl<'a> fmt::Display for ImageSurfaceData<'a> {
235 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236 write!(f, "ImageSurfaceData")
237 }
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243
244 #[test]
245 fn create_with_invalid_size_yields_error() {
246 let result = ImageSurface::create(Format::ARgb32, 50000, 50000);
247 assert!(result.is_err());
248 }
249
250 #[test]
251 fn create_for_data_with_invalid_stride_yields_error() {
252 let result = ImageSurface::create_for_data(vec![0u8; 10], Format::ARgb32, 1, 2, 5); assert!(result.is_err());
254 }
255
256 #[test]
257 fn create_with_valid_size() {
258 let result = ImageSurface::create(Format::ARgb32, 10, 10);
259 assert!(result.is_ok());
260
261 let result = ImageSurface::create_for_data(vec![0u8; 40 * 10], Format::ARgb32, 10, 10, 40);
262 assert!(result.is_ok());
263 }
264}