1 // Copyright 2015-2016, The Gtk-rs Project Developers. 2 // See the COPYRIGHT file at the top-level directory of this distribution. 3 // Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT> 4 5 use libc::{c_ulong, c_void}; 6 use std::ffi::CString; 7 use std::fmt; 8 use std::ops::Deref; 9 use std::ptr; 10 use std::slice; 11 12 use enums::{Content, Format, Status, SurfaceType}; 13 use ffi; 14 #[cfg(feature = "use_glib")] 15 use glib::translate::*; 16 17 use image_surface::ImageSurface; 18 use rectangle_int::RectangleInt; 19 20 #[derive(Debug)] 21 pub struct Surface(*mut ffi::cairo_surface_t, bool); 22 23 impl Surface { from_raw_none(ptr: *mut ffi::cairo_surface_t) -> Surface24 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 from_raw_borrow(ptr: *mut ffi::cairo_surface_t) -> Surface30 pub unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_surface_t) -> Surface { 31 assert!(!ptr.is_null()); 32 Surface(ptr, true) 33 } 34 from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Surface35 pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Surface { 36 assert!(!ptr.is_null()); 37 Surface(ptr, false) 38 } 39 to_raw_none(&self) -> *mut ffi::cairo_surface_t40 pub fn to_raw_none(&self) -> *mut ffi::cairo_surface_t { 41 self.0 42 } 43 create_similar(&self, content: Content, width: i32, height: i32) -> Surface44 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 get_mime_data(&self, mime_type: &str) -> Option<Vec<u8>>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 get_mime_data_raw(&self, mime_type: &str) -> Option<&[u8]>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 set_mime_data<T: AsRef<[u8]> + 'static>( &self, mime_type: &str, slice: T, ) -> Result<(), Status>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 supports_mime_type(&self, mime_type: &str) -> bool130 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 set_device_offset(&self, x_offset: f64, y_offset: f64)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 get_device_offset(&self) -> (f64, f64)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"))] set_device_scale(&self, x_scale: f64, y_scale: f64)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"))] get_device_scale(&self) -> (f64, f64)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 set_fallback_resolution(&self, x_pixels_per_inch: f64, y_pixels_per_inch: f64)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 get_fallback_resolution(&self) -> (f64, f64)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 create_similar_image(&self, format: Format, width: i32, height: i32) -> Option<Surface>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 map_to_image( &self, extents: Option<RectangleInt>, ) -> Result<MappedImageSurface, Status>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")] 227 impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for Surface { 228 type Storage = &'a Surface; 229 230 #[inline] to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self>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] to_glib_full(&self) -> *mut ffi::cairo_surface_t236 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")] 242 impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for Surface { 243 #[inline] from_glib_none(ptr: *mut ffi::cairo_surface_t) -> Surface244 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")] 250 impl FromGlibPtrBorrow<*mut ffi::cairo_surface_t> for Surface { 251 #[inline] from_glib_borrow(ptr: *mut ffi::cairo_surface_t) -> Surface252 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")] 258 impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for Surface { 259 #[inline] from_glib_full(ptr: *mut ffi::cairo_surface_t) -> Surface260 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")] 266 gvalue_impl!( 267 Surface, 268 ffi::cairo_surface_t, 269 ffi::gobject::cairo_gobject_surface_get_type 270 ); 271 272 impl Clone for Surface { clone(&self) -> Surface273 fn clone(&self) -> Surface { 274 unsafe { Self::from_raw_none(self.0) } 275 } 276 } 277 278 impl Drop for Surface { drop(&mut self)279 fn drop(&mut self) { 280 if !self.1 { 281 unsafe { 282 ffi::cairo_surface_destroy(self.0); 283 } 284 } 285 } 286 } 287 288 impl fmt::Display for Surface { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result289 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 290 write!(f, "Surface") 291 } 292 } 293 294 impl Surface { flush(&self)295 pub fn flush(&self) { 296 unsafe { 297 ffi::cairo_surface_flush(self.0); 298 } 299 } 300 finish(&self)301 pub fn finish(&self) { 302 unsafe { 303 ffi::cairo_surface_finish(self.0); 304 } 305 } 306 get_type(&self) -> SurfaceType307 pub fn get_type(&self) -> SurfaceType { 308 unsafe { SurfaceType::from(ffi::cairo_surface_get_type(self.0)) } 309 } 310 status(&self) -> Status311 pub fn status(&self) -> Status { 312 unsafe { Status::from(ffi::cairo_surface_status(self.0)) } 313 } 314 } 315 316 #[derive(Debug)] 317 pub struct MappedImageSurface { 318 original_surface: Surface, 319 image_surface: ImageSurface, 320 } 321 322 impl Deref for MappedImageSurface { 323 type Target = ImageSurface; 324 deref(&self) -> &ImageSurface325 fn deref(&self) -> &ImageSurface { 326 &self.image_surface 327 } 328 } 329 330 impl Drop for MappedImageSurface { drop(&mut self)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 342 impl fmt::Display for MappedImageSurface { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result343 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 344 write!(f, "MappedImageSurface") 345 } 346 } 347 348 #[cfg(test)] 349 mod tests { 350 use constants::MIME_TYPE_PNG; 351 use Format; 352 use ImageSurface; 353 354 #[test] mime_data()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 /* Initially the data for any mime type has to be none */ 359 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 } 366