1use libc::{c_ulong, c_void};
6use std::ffi::CString;
7use std::fmt;
8use std::ops::Deref;
9use std::ptr;
10use std::slice;
11
12use enums::{Content, Format, Status, SurfaceType};
13use ffi;
14#[cfg(feature = "use_glib")]
15use glib::translate::*;
16
17use image_surface::ImageSurface;
18use rectangle_int::RectangleInt;
19
20#[derive(Debug)]
21pub struct Surface(*mut ffi::cairo_surface_t, bool);
22
23impl Surface {
24 pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_surface_t) -> Surface {
25 assert!(!ptr.is_null());
26 ffi::cairo_surface_reference(ptr);
27 Surface(ptr, false)
28 }
29
30 pub unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_surface_t) -> Surface {
31 assert!(!ptr.is_null());
32 Surface(ptr, true)
33 }
34
35 pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
36 assert!(!ptr.is_null());
37 Surface(ptr, false)
38 }
39
40 pub fn to_raw_none(&self) -> *mut ffi::cairo_surface_t {
41 self.0
42 }
43
44 pub fn create_similar(&self, content: Content, width: i32, height: i32) -> Surface {
45 unsafe {
46 Self::from_raw_full(ffi::cairo_surface_create_similar(
47 self.0,
48 content.into(),
49 width,
50 height,
51 ))
52 }
53 }
54
55 pub fn get_mime_data(&self, mime_type: &str) -> Option<Vec<u8>> {
56 let data_ptr: *mut u8 = ptr::null_mut();
57 let mut length: c_ulong = 0;
58 unsafe {
59 let mime_type = CString::new(mime_type).unwrap();
60 ffi::cairo_surface_get_mime_data(
61 self.to_raw_none(),
62 mime_type.as_ptr(),
63 &data_ptr,
64 &mut length,
65 );
66 if !data_ptr.is_null() && length != 0 {
67 Some(slice::from_raw_parts(data_ptr as *const u8, length as usize).to_vec())
68 } else {
69 None
70 }
71 }
72 }
73
74 pub unsafe fn get_mime_data_raw(&self, mime_type: &str) -> Option<&[u8]> {
75 let data_ptr: *mut u8 = ptr::null_mut();
76 let mut length: c_ulong = 0;
77 let mime_type = CString::new(mime_type).unwrap();
78 ffi::cairo_surface_get_mime_data(
79 self.to_raw_none(),
80 mime_type.as_ptr(),
81 &data_ptr,
82 &mut length,
83 );
84 if !data_ptr.is_null() && length != 0 {
85 Some(slice::from_raw_parts(
86 data_ptr as *const u8,
87 length as usize,
88 ))
89 } else {
90 None
91 }
92 }
93
94 pub fn set_mime_data<T: AsRef<[u8]> + 'static>(
95 &self,
96 mime_type: &str,
97 slice: T,
98 ) -> Result<(), Status> {
99 let b = Box::new(slice);
100 let (size, data) = {
101 let slice = (*b).as_ref();
102 (slice.len(), slice.as_ptr())
103 };
104
105 let user_data = Box::into_raw(b);
106
107 unsafe extern "C" fn unbox<T>(data: *mut c_void) {
108 let data: Box<T> = Box::from_raw(data as *mut T);
109 drop(data);
110 }
111
112 let status = unsafe {
113 let mime_type = CString::new(mime_type).unwrap();
114 ffi::cairo_surface_set_mime_data(
115 self.to_raw_none(),
116 mime_type.as_ptr(),
117 data,
118 size as c_ulong,
119 Some(unbox::<T>),
120 user_data as *mut _,
121 )
122 };
123
124 match Status::from(status) {
125 Status::Success => Ok(()),
126 x => Err(x),
127 }
128 }
129
130 pub fn supports_mime_type(&self, mime_type: &str) -> bool {
131 unsafe {
132 let mime_type = CString::new(mime_type).unwrap();
133 ffi::cairo_surface_supports_mime_type(self.0, mime_type.as_ptr()).as_bool()
134 }
135 }
136
137 pub fn set_device_offset(&self, x_offset: f64, y_offset: f64) {
138 unsafe { ffi::cairo_surface_set_device_offset(self.to_raw_none(), x_offset, y_offset) }
139 }
140
141 pub fn get_device_offset(&self) -> (f64, f64) {
142 let mut x_offset = 0.0f64;
143 let mut y_offset = 0.0f64;
144 unsafe {
145 ffi::cairo_surface_get_device_offset(self.to_raw_none(), &mut x_offset, &mut y_offset);
146 }
147 (x_offset, y_offset)
148 }
149
150 #[cfg(any(feature = "v1_14", feature = "dox"))]
151 pub fn set_device_scale(&self, x_scale: f64, y_scale: f64) {
152 unsafe { ffi::cairo_surface_set_device_scale(self.to_raw_none(), x_scale, y_scale) }
153 }
154
155 #[cfg(any(feature = "v1_14", feature = "dox"))]
156 pub fn get_device_scale(&self) -> (f64, f64) {
157 let mut x_scale = 0.0f64;
158 let mut y_scale = 0.0f64;
159 unsafe {
160 ffi::cairo_surface_get_device_scale(self.to_raw_none(), &mut x_scale, &mut y_scale);
161 }
162 (x_scale, y_scale)
163 }
164
165 pub fn set_fallback_resolution(&self, x_pixels_per_inch: f64, y_pixels_per_inch: f64) {
166 unsafe {
167 ffi::cairo_surface_set_fallback_resolution(
168 self.to_raw_none(),
169 x_pixels_per_inch,
170 y_pixels_per_inch,
171 )
172 }
173 }
174
175 pub fn get_fallback_resolution(&self) -> (f64, f64) {
176 let mut x_pixels_per_inch = 0.0f64;
177 let mut y_pixels_per_inch = 0.0f64;
178 unsafe {
179 ffi::cairo_surface_get_fallback_resolution(
180 self.to_raw_none(),
181 &mut x_pixels_per_inch,
182 &mut y_pixels_per_inch,
183 );
184 }
185 (x_pixels_per_inch, y_pixels_per_inch)
186 }
187
188 pub fn create_similar_image(&self, format: Format, width: i32, height: i32) -> Option<Surface> {
189 unsafe {
190 let p = ffi::cairo_surface_create_similar_image(
191 self.to_raw_none(),
192 format.into(),
193 width,
194 height,
195 );
196 if p.is_null() {
197 None
198 } else {
199 Some(Self::from_raw_full(p))
200 }
201 }
202 }
203
204 pub fn map_to_image(
205 &self,
206 extents: Option<RectangleInt>,
207 ) -> Result<MappedImageSurface, Status> {
208 unsafe {
209 ImageSurface::from_raw_full(match extents {
210 Some(ref e) => ffi::cairo_surface_map_to_image(self.to_raw_none(), e.to_raw_none()),
211 None => ffi::cairo_surface_map_to_image(self.to_raw_none(), 0 as *const _),
212 })
213 .map(|s| MappedImageSurface {
214 original_surface: self.clone(),
215 image_surface: s,
216 })
217 }
218 }
219
220 user_data_methods! {
221 ffi::cairo_surface_get_user_data,
222 ffi::cairo_surface_set_user_data,
223 }
224}
225
226#[cfg(feature = "use_glib")]
227impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for Surface {
228 type Storage = &'a Surface;
229
230 #[inline]
231 fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self> {
232 Stash(self.to_raw_none(), self)
233 }
234
235 #[inline]
236 fn to_glib_full(&self) -> *mut ffi::cairo_surface_t {
237 unsafe { ffi::cairo_surface_reference(self.to_raw_none()) }
238 }
239}
240
241#[cfg(feature = "use_glib")]
242impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for Surface {
243 #[inline]
244 unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> Surface {
245 Self::from_raw_none(ptr)
246 }
247}
248
249#[cfg(feature = "use_glib")]
250impl FromGlibPtrBorrow<*mut ffi::cairo_surface_t> for Surface {
251 #[inline]
252 unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_surface_t) -> Surface {
253 Self::from_raw_borrow(ptr)
254 }
255}
256
257#[cfg(feature = "use_glib")]
258impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for Surface {
259 #[inline]
260 unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
261 Self::from_raw_full(ptr)
262 }
263}
264
265#[cfg(feature = "use_glib")]
266gvalue_impl!(
267 Surface,
268 ffi::cairo_surface_t,
269 ffi::gobject::cairo_gobject_surface_get_type
270);
271
272impl Clone for Surface {
273 fn clone(&self) -> Surface {
274 unsafe { Self::from_raw_none(self.0) }
275 }
276}
277
278impl Drop for Surface {
279 fn drop(&mut self) {
280 if !self.1 {
281 unsafe {
282 ffi::cairo_surface_destroy(self.0);
283 }
284 }
285 }
286}
287
288impl fmt::Display for Surface {
289 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
290 write!(f, "Surface")
291 }
292}
293
294impl Surface {
295 pub fn flush(&self) {
296 unsafe {
297 ffi::cairo_surface_flush(self.0);
298 }
299 }
300
301 pub fn finish(&self) {
302 unsafe {
303 ffi::cairo_surface_finish(self.0);
304 }
305 }
306
307 pub fn get_type(&self) -> SurfaceType {
308 unsafe { SurfaceType::from(ffi::cairo_surface_get_type(self.0)) }
309 }
310
311 pub fn status(&self) -> Status {
312 unsafe { Status::from(ffi::cairo_surface_status(self.0)) }
313 }
314}
315
316#[derive(Debug)]
317pub struct MappedImageSurface {
318 original_surface: Surface,
319 image_surface: ImageSurface,
320}
321
322impl Deref for MappedImageSurface {
323 type Target = ImageSurface;
324
325 fn deref(&self) -> &ImageSurface {
326 &self.image_surface
327 }
328}
329
330impl Drop for MappedImageSurface {
331 fn drop(&mut self) {
332 unsafe {
333 ffi::cairo_surface_unmap_image(
334 self.original_surface.to_raw_none(),
335 self.image_surface.to_raw_none(),
336 );
337 ffi::cairo_surface_reference(self.image_surface.to_raw_none());
338 }
339 }
340}
341
342impl fmt::Display for MappedImageSurface {
343 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
344 write!(f, "MappedImageSurface")
345 }
346}
347
348#[cfg(test)]
349mod tests {
350 use constants::MIME_TYPE_PNG;
351 use Format;
352 use ImageSurface;
353
354 #[test]
355 fn mime_data() {
356 let surface = ImageSurface::create(Format::ARgb32, 500, 500).unwrap();
357 let data = surface.get_mime_data(MIME_TYPE_PNG);
358 assert!(data.is_none());
360
361 assert!(surface.set_mime_data(MIME_TYPE_PNG, &[1u8, 10u8]).is_ok());
362 let data = surface.get_mime_data(MIME_TYPE_PNG).unwrap();
363 assert_eq!(data, &[1u8, 10u8]);
364 }
365}