cairo/
device.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3#[cfg(feature = "script")]
4use std::ffi::CString;
5#[cfg(feature = "use_glib")]
6use std::marker::PhantomData;
7#[cfg(feature = "script")]
8use std::path::Path;
9use std::ptr;
10
11#[cfg(feature = "use_glib")]
12use glib::translate::*;
13
14#[cfg(feature = "script")]
15use crate::{Content, RecordingSurface, ScriptMode, Surface};
16use crate::{DeviceType, Error, ffi, utils::status_to_result};
17
18#[derive(Debug)]
19#[must_use = "if unused the Device will immediately be released"]
20pub struct DeviceAcquireGuard<'a>(&'a Device);
21
22impl Drop for DeviceAcquireGuard<'_> {
23    #[inline]
24    fn drop(&mut self) {
25        self.0.release();
26    }
27}
28
29#[derive(Debug)]
30#[doc(alias = "cairo_device_t")]
31#[repr(transparent)]
32pub struct Device(ptr::NonNull<ffi::cairo_device_t>);
33
34impl Device {
35    #[inline]
36    pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_device_t) -> Device {
37        unsafe {
38            debug_assert!(!ptr.is_null());
39            ffi::cairo_device_reference(ptr);
40            Device(ptr::NonNull::new_unchecked(ptr))
41        }
42    }
43
44    #[inline]
45    pub unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_device_t) -> crate::Borrowed<Device> {
46        unsafe {
47            debug_assert!(!ptr.is_null());
48            crate::Borrowed::new(Device(ptr::NonNull::new_unchecked(ptr)))
49        }
50    }
51
52    #[inline]
53    pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_device_t) -> Device {
54        unsafe {
55            debug_assert!(!ptr.is_null());
56            Device(ptr::NonNull::new_unchecked(ptr))
57        }
58    }
59
60    #[inline]
61    pub fn to_raw_none(&self) -> *mut ffi::cairo_device_t {
62        self.0.as_ptr()
63    }
64
65    #[cfg(feature = "script")]
66    #[cfg_attr(docsrs, doc(cfg(feature = "script")))]
67    #[doc(alias = "cairo_script_create")]
68    pub fn create<P: AsRef<Path>>(filename: P) -> Option<Device> {
69        unsafe {
70            let filename = filename.as_ref().to_string_lossy().into_owned();
71            let filename = CString::new(filename).unwrap();
72            let p = ffi::cairo_script_create(filename.as_ptr());
73            if p.is_null() {
74                None
75            } else {
76                Some(Self::from_raw_full(p))
77            }
78        }
79    }
80
81    #[cfg(feature = "script")]
82    #[cfg_attr(docsrs, doc(cfg(feature = "script")))]
83    #[doc(alias = "cairo_script_from_recording_surface")]
84    pub fn from_recording_surface(&self, surface: &RecordingSurface) -> Result<(), Error> {
85        unsafe {
86            let status =
87                ffi::cairo_script_from_recording_surface(self.to_raw_none(), surface.to_raw_none());
88            status_to_result(status)
89        }
90    }
91
92    #[cfg(feature = "script")]
93    #[cfg_attr(docsrs, doc(cfg(feature = "script")))]
94    #[doc(alias = "cairo_script_get_mode")]
95    #[doc(alias = "get_mode")]
96    pub fn mode(&self) -> ScriptMode {
97        unsafe { ScriptMode::from(ffi::cairo_script_get_mode(self.to_raw_none())) }
98    }
99
100    #[cfg(feature = "script")]
101    #[cfg_attr(docsrs, doc(cfg(feature = "script")))]
102    #[doc(alias = "cairo_script_set_mode")]
103    pub fn set_mode(&self, mode: ScriptMode) {
104        unsafe { ffi::cairo_script_set_mode(self.to_raw_none(), mode.into()) }
105    }
106
107    #[cfg(feature = "script")]
108    #[cfg_attr(docsrs, doc(cfg(feature = "script")))]
109    #[doc(alias = "cairo_script_surface_create")]
110    pub fn surface_create(
111        &self,
112        content: Content,
113        width: f64,
114        height: f64,
115    ) -> Result<Surface, Error> {
116        unsafe {
117            Surface::from_raw_full(ffi::cairo_script_surface_create(
118                self.to_raw_none(),
119                content.into(),
120                width,
121                height,
122            ))
123        }
124    }
125
126    #[cfg(feature = "script")]
127    #[cfg_attr(docsrs, doc(cfg(feature = "script")))]
128    #[doc(alias = "cairo_script_surface_create_for_target")]
129    pub fn surface_create_for_target(&self, target: impl AsRef<Surface>) -> Result<Surface, Error> {
130        let target = target.as_ref();
131        target.status()?;
132        unsafe {
133            Surface::from_raw_full(ffi::cairo_script_surface_create_for_target(
134                self.to_raw_none(),
135                target.to_raw_none(),
136            ))
137        }
138    }
139
140    #[cfg(feature = "script")]
141    #[cfg_attr(docsrs, doc(cfg(feature = "script")))]
142    #[doc(alias = "cairo_script_write_comment")]
143    pub fn write_comment(&self, comment: &str) {
144        unsafe {
145            let len = comment.len();
146            let comment = CString::new(comment).unwrap();
147            ffi::cairo_script_write_comment(self.to_raw_none(), comment.as_ptr(), len as i32)
148        }
149    }
150
151    #[doc(alias = "cairo_device_finish")]
152    pub fn finish(&self) {
153        unsafe { ffi::cairo_device_finish(self.to_raw_none()) }
154    }
155
156    #[doc(alias = "cairo_device_flush")]
157    pub fn flush(&self) {
158        unsafe { ffi::cairo_device_flush(self.to_raw_none()) }
159    }
160
161    #[doc(alias = "cairo_device_get_type")]
162    #[doc(alias = "get_type")]
163    pub fn type_(&self) -> DeviceType {
164        unsafe { DeviceType::from(ffi::cairo_device_get_type(self.to_raw_none())) }
165    }
166
167    #[doc(alias = "cairo_device_acquire")]
168    pub fn acquire(&self) -> Result<DeviceAcquireGuard<'_>, Error> {
169        unsafe {
170            let status = ffi::cairo_device_acquire(self.to_raw_none());
171            status_to_result(status)?;
172        }
173        Ok(DeviceAcquireGuard(self))
174    }
175
176    #[doc(alias = "cairo_device_release")]
177    fn release(&self) {
178        unsafe { ffi::cairo_device_release(self.to_raw_none()) }
179    }
180
181    #[doc(alias = "cairo_device_observer_elapsed")]
182    pub fn observer_elapsed(&self) -> f64 {
183        unsafe { ffi::cairo_device_observer_elapsed(self.to_raw_none()) }
184    }
185
186    #[doc(alias = "cairo_device_observer_fill_elapsed")]
187    pub fn observer_fill_elapsed(&self) -> f64 {
188        unsafe { ffi::cairo_device_observer_fill_elapsed(self.to_raw_none()) }
189    }
190
191    #[doc(alias = "cairo_device_observer_glyphs_elapsed")]
192    pub fn observer_glyphs_elapsed(&self) -> f64 {
193        unsafe { ffi::cairo_device_observer_glyphs_elapsed(self.to_raw_none()) }
194    }
195
196    #[doc(alias = "cairo_device_observer_mask_elapsed")]
197    pub fn observer_mask_elapsed(&self) -> f64 {
198        unsafe { ffi::cairo_device_observer_mask_elapsed(self.to_raw_none()) }
199    }
200
201    #[doc(alias = "cairo_device_observer_paint_elapsed")]
202    pub fn observer_paint_elapsed(&self) -> f64 {
203        unsafe { ffi::cairo_device_observer_paint_elapsed(self.to_raw_none()) }
204    }
205
206    #[doc(alias = "cairo_device_observer_stroke_elapsed")]
207    pub fn observer_stroke_elapsed(&self) -> f64 {
208        unsafe { ffi::cairo_device_observer_stroke_elapsed(self.to_raw_none()) }
209    }
210
211    #[cfg(any(feature = "xlib", feature = "xcb"))]
212    #[cfg_attr(docsrs, doc(cfg(any(feature = "xlib", feature = "xcb"))))]
213    #[doc(alias = "cairo_xlib_device_debug_cap_xrender_version")]
214    #[doc(alias = "cairo_xcb_device_debug_cap_xrender_version")]
215    pub fn debug_cap_xrender_version(&self, _major_version: i32, _minor_version: i32) {
216        match self.type_() {
217            DeviceType::Xlib => {
218                #[cfg(feature = "xlib")]
219                unsafe {
220                    ffi::cairo_xlib_device_debug_cap_xrender_version(
221                        self.to_raw_none(),
222                        _major_version,
223                        _minor_version,
224                    )
225                }
226                #[cfg(not(feature = "xlib"))]
227                {
228                    panic!("you need to enable \"xlib\" feature")
229                }
230            }
231            DeviceType::Xcb => {
232                #[cfg(feature = "xcb")]
233                unsafe {
234                    ffi::cairo_xcb_device_debug_cap_xrender_version(
235                        self.to_raw_none(),
236                        _major_version,
237                        _minor_version,
238                    )
239                }
240                #[cfg(not(feature = "xcb"))]
241                {
242                    panic!("you need to enable \"xcb\" feature")
243                }
244            }
245            d => panic!("invalid device type: {:#?}", d),
246        }
247    }
248
249    #[cfg(any(feature = "xlib", feature = "xcb"))]
250    #[cfg_attr(docsrs, doc(cfg(any(feature = "xlib", feature = "xcb"))))]
251    #[doc(alias = "cairo_xlib_device_debug_get_precision")]
252    #[doc(alias = "cairo_xcb_device_debug_get_precision")]
253    pub fn debug_get_precision(&self) -> i32 {
254        match self.type_() {
255            DeviceType::Xlib => {
256                #[cfg(feature = "xlib")]
257                unsafe {
258                    ffi::cairo_xlib_device_debug_get_precision(self.to_raw_none())
259                }
260                #[cfg(not(feature = "xlib"))]
261                {
262                    panic!("you need to enable \"xlib\" feature")
263                }
264            }
265            DeviceType::Xcb => {
266                #[cfg(feature = "xcb")]
267                unsafe {
268                    ffi::cairo_xcb_device_debug_get_precision(self.to_raw_none())
269                }
270                #[cfg(not(feature = "xcb"))]
271                {
272                    panic!("you need to enable \"xcb\" feature")
273                }
274            }
275            d => panic!("invalid device type: {:#?}", d),
276        }
277    }
278
279    #[cfg(any(feature = "xlib", feature = "xcb"))]
280    #[cfg_attr(docsrs, doc(cfg(any(feature = "xlib", feature = "xcb"))))]
281    #[doc(alias = "cairo_xlib_device_debug_set_precision")]
282    #[doc(alias = "cairo_xcb_device_debug_set_precision")]
283    pub fn debug_set_precision(&self, _precision: i32) {
284        match self.type_() {
285            DeviceType::Xlib => {
286                #[cfg(feature = "xlib")]
287                unsafe {
288                    ffi::cairo_xlib_device_debug_set_precision(self.to_raw_none(), _precision)
289                }
290                #[cfg(not(feature = "xlib"))]
291                {
292                    panic!("you need to enable \"xlib\" feature")
293                }
294            }
295            DeviceType::Xcb => {
296                #[cfg(feature = "xcb")]
297                unsafe {
298                    ffi::cairo_xcb_device_debug_set_precision(self.to_raw_none(), _precision)
299                }
300                #[cfg(not(feature = "xcb"))]
301                {
302                    panic!("you need to enable \"xcb\" feature")
303                }
304            }
305            d => panic!("invalid device type: {:#?}", d),
306        }
307    }
308
309    #[doc(alias = "cairo_device_status")]
310    #[inline]
311    pub fn status(&self) -> Result<(), Error> {
312        let status = unsafe { ffi::cairo_device_status(self.to_raw_none()) };
313        status_to_result(status)
314    }
315
316    user_data_methods! {
317        ffi::cairo_device_get_user_data,
318        ffi::cairo_device_set_user_data,
319    }
320}
321
322#[cfg(feature = "use_glib")]
323#[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))]
324impl IntoGlibPtr<*mut ffi::cairo_device_t> for Device {
325    #[inline]
326    fn into_glib_ptr(self) -> *mut ffi::cairo_device_t {
327        std::mem::ManuallyDrop::new(self).to_glib_none().0
328    }
329}
330
331#[cfg(feature = "use_glib")]
332#[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))]
333impl<'a> ToGlibPtr<'a, *mut ffi::cairo_device_t> for Device {
334    type Storage = PhantomData<&'a Device>;
335
336    #[inline]
337    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_device_t, Self> {
338        Stash(self.to_raw_none(), PhantomData)
339    }
340
341    #[inline]
342    fn to_glib_full(&self) -> *mut ffi::cairo_device_t {
343        unsafe { ffi::cairo_device_reference(self.to_raw_none()) }
344    }
345}
346
347#[cfg(feature = "use_glib")]
348#[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))]
349impl FromGlibPtrNone<*mut ffi::cairo_device_t> for Device {
350    #[inline]
351    unsafe fn from_glib_none(ptr: *mut ffi::cairo_device_t) -> Device {
352        unsafe { Self::from_raw_none(ptr) }
353    }
354}
355
356#[cfg(feature = "use_glib")]
357#[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))]
358impl FromGlibPtrBorrow<*mut ffi::cairo_device_t> for Device {
359    #[inline]
360    unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_device_t) -> crate::Borrowed<Device> {
361        unsafe { Self::from_raw_borrow(ptr) }
362    }
363}
364
365#[cfg(feature = "use_glib")]
366#[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))]
367impl FromGlibPtrFull<*mut ffi::cairo_device_t> for Device {
368    #[inline]
369    unsafe fn from_glib_full(ptr: *mut ffi::cairo_device_t) -> Device {
370        unsafe { Self::from_raw_full(ptr) }
371    }
372}
373
374#[cfg(feature = "use_glib")]
375gvalue_impl!(
376    Device,
377    ffi::cairo_device_t,
378    ffi::gobject::cairo_gobject_device_get_type
379);
380
381impl Clone for Device {
382    #[inline]
383    fn clone(&self) -> Device {
384        unsafe { Self::from_raw_none(ffi::cairo_device_reference(self.0.as_ptr())) }
385    }
386}
387
388impl Drop for Device {
389    #[inline]
390    fn drop(&mut self) {
391        unsafe {
392            ffi::cairo_device_destroy(self.0.as_ptr());
393        }
394    }
395}