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