cairo/font/
scaled_font.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{ffi::CString, mem::MaybeUninit, ptr};
4
5#[cfg(feature = "use_glib")]
6use glib::translate::*;
7
8use crate::{
9    ffi, utils::status_to_result, Error, FontExtents, FontFace, FontOptions, FontType, Glyph,
10    Matrix, TextCluster, TextExtents,
11};
12
13#[cfg(feature = "use_glib")]
14glib::wrapper! {
15    #[derive(Debug)]
16    #[doc(alias = "cairo_scaled_font_t")]
17    pub struct ScaledFont(Shared<ffi::cairo_scaled_font_t>);
18
19    match fn {
20        ref => |ptr| ffi::cairo_scaled_font_reference(ptr),
21        unref => |ptr| ffi::cairo_scaled_font_destroy(ptr),
22        type_ => || ffi::gobject::cairo_gobject_scaled_font_get_type(),
23    }
24}
25
26#[cfg(not(feature = "use_glib"))]
27#[derive(Debug)]
28#[doc(alias = "cairo_scaled_font_t")]
29pub struct ScaledFont(ptr::NonNull<ffi::cairo_scaled_font_t>);
30
31impl ScaledFont {
32    #[doc(alias = "cairo_scaled_font_create")]
33    pub fn new(
34        font_face: &FontFace,
35        font_matrix: &Matrix,
36        ctm: &Matrix,
37        options: &FontOptions,
38    ) -> Result<ScaledFont, Error> {
39        let scaled_font: ScaledFont = unsafe {
40            ScaledFont::from_raw_full(ffi::cairo_scaled_font_create(
41                font_face.to_raw_none(),
42                font_matrix.ptr(),
43                ctm.ptr(),
44                options.to_raw_none(),
45            ))
46        };
47        let status = unsafe { ffi::cairo_scaled_font_status(scaled_font.to_raw_none()) };
48        status_to_result(status)?;
49
50        Ok(scaled_font)
51    }
52
53    #[cfg(feature = "use_glib")]
54    #[inline]
55    pub fn to_raw_none(&self) -> *mut ffi::cairo_scaled_font_t {
56        self.to_glib_none().0
57    }
58
59    #[cfg(not(feature = "use_glib"))]
60    #[inline]
61    pub fn to_raw_none(&self) -> *mut ffi::cairo_scaled_font_t {
62        self.0.as_ptr()
63    }
64
65    #[cfg(not(feature = "use_glib"))]
66    #[inline]
67    pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_scaled_font_t) -> ScaledFont {
68        debug_assert!(!ptr.is_null());
69        ScaledFont(ptr::NonNull::new_unchecked(ptr))
70    }
71
72    #[cfg(feature = "use_glib")]
73    #[inline]
74    pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_scaled_font_t) -> ScaledFont {
75        from_glib_full(ptr)
76    }
77
78    #[cfg(feature = "use_glib")]
79    #[inline]
80    pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_scaled_font_t) -> ScaledFont {
81        from_glib_none(ptr)
82    }
83
84    #[cfg(not(feature = "use_glib"))]
85    #[inline]
86    pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_scaled_font_t) -> ScaledFont {
87        debug_assert!(!ptr.is_null());
88        ffi::cairo_scaled_font_reference(ptr);
89        ScaledFont(ptr::NonNull::new_unchecked(ptr))
90    }
91
92    #[doc(alias = "cairo_scaled_font_get_type")]
93    #[doc(alias = "get_type")]
94    pub fn type_(&self) -> FontType {
95        unsafe { FontType::from(ffi::cairo_scaled_font_get_type(self.to_raw_none())) }
96    }
97
98    #[doc(alias = "cairo_scaled_font_get_reference_count")]
99    #[doc(alias = "get_reference_count")]
100    pub fn reference_count(&self) -> usize {
101        unsafe { ffi::cairo_scaled_font_get_reference_count(self.to_raw_none()) as usize }
102    }
103
104    #[doc(alias = "cairo_scaled_font_extents")]
105    pub fn extents(&self) -> FontExtents {
106        let mut extents = MaybeUninit::<FontExtents>::uninit();
107
108        unsafe {
109            ffi::cairo_scaled_font_extents(self.to_raw_none(), extents.as_mut_ptr() as *mut _);
110            extents.assume_init()
111        }
112    }
113
114    #[doc(alias = "cairo_scaled_font_text_extents")]
115    pub fn text_extents(&self, text: &str) -> TextExtents {
116        let mut extents = MaybeUninit::<TextExtents>::uninit();
117
118        let text = CString::new(text).unwrap();
119        unsafe {
120            ffi::cairo_scaled_font_text_extents(
121                self.to_raw_none(),
122                text.as_ptr(),
123                extents.as_mut_ptr() as *mut _,
124            );
125            extents.assume_init()
126        }
127    }
128
129    #[doc(alias = "cairo_scaled_font_glyph_extents")]
130    pub fn glyph_extents(&self, glyphs: &[Glyph]) -> TextExtents {
131        let mut extents = MaybeUninit::<TextExtents>::uninit();
132
133        unsafe {
134            ffi::cairo_scaled_font_glyph_extents(
135                self.to_raw_none(),
136                glyphs.as_ptr() as *const _,
137                glyphs.len() as _,
138                extents.as_mut_ptr() as *mut _,
139            );
140            extents.assume_init()
141        }
142    }
143
144    #[doc(alias = "cairo_scaled_font_text_to_glyphs")]
145    pub fn text_to_glyphs(
146        &self,
147        x: f64,
148        y: f64,
149        text: &str,
150    ) -> Result<(Vec<Glyph>, Vec<TextCluster>), Error> {
151        // This large unsafe block is due to the FFI function returning two specially allocated
152        // (cairo_{glyph,text_cluster}_allocate) pointers that need to be copied into Vec<T>
153        // types before they're of any use to Rust code.
154
155        unsafe {
156            let mut glyphs_ptr: *mut Glyph = ptr::null_mut();
157            let mut glyph_count = 0i32;
158            let mut clusters_ptr: *mut TextCluster = ptr::null_mut();
159            let mut cluster_count = 0i32;
160            let mut cluster_flags = 0i32;
161            let text_length = text.len() as i32;
162            let text = CString::new(text).unwrap();
163
164            let status = ffi::cairo_scaled_font_text_to_glyphs(
165                self.to_raw_none(),
166                x,
167                y,
168                text.as_ptr(),
169                text_length,
170                &mut glyphs_ptr as *mut *mut Glyph as *mut _,
171                &mut glyph_count,
172                &mut clusters_ptr as *mut *mut TextCluster as *mut _,
173                &mut cluster_count,
174                &mut cluster_flags,
175            );
176            status_to_result(status)?;
177
178            let glyph_count = glyph_count as usize;
179            let glyphs: Vec<Glyph> = {
180                let mut glyphs: Vec<Glyph> = Vec::with_capacity(glyph_count);
181
182                ptr::copy(glyphs_ptr, glyphs.as_mut_ptr(), glyph_count);
183
184                glyphs.set_len(glyph_count);
185
186                glyphs
187            };
188
189            let cluster_count = cluster_count as usize;
190            let clusters: Vec<TextCluster> = {
191                let mut clusters = Vec::with_capacity(cluster_count);
192
193                ptr::copy(clusters_ptr, clusters.as_mut_ptr(), cluster_count);
194
195                clusters.set_len(cluster_count);
196
197                clusters
198            };
199
200            ffi::cairo_glyph_free(glyphs_ptr as _);
201            ffi::cairo_text_cluster_free(clusters_ptr as _);
202
203            Ok((glyphs, clusters))
204        }
205    }
206
207    #[doc(alias = "cairo_scaled_font_get_font_face")]
208    #[doc(alias = "get_font_face")]
209    pub fn font_face(&self) -> FontFace {
210        unsafe { FontFace::from_raw_none(ffi::cairo_scaled_font_get_font_face(self.to_raw_none())) }
211    }
212
213    #[doc(alias = "cairo_scaled_font_get_font_options")]
214    #[doc(alias = "get_font_options")]
215    pub fn font_options(&self) -> Result<FontOptions, Error> {
216        let options = FontOptions::new()?;
217
218        unsafe {
219            ffi::cairo_scaled_font_get_font_options(self.to_raw_none(), options.to_raw_none())
220        }
221
222        Ok(options)
223    }
224
225    #[doc(alias = "cairo_scaled_font_get_font_matrix")]
226    #[doc(alias = "get_font_matrix")]
227    pub fn font_matrix(&self) -> Matrix {
228        let mut matrix = Matrix::null();
229
230        unsafe { ffi::cairo_scaled_font_get_font_matrix(self.to_raw_none(), matrix.mut_ptr()) }
231
232        matrix
233    }
234
235    #[doc(alias = "cairo_scaled_font_get_ctm")]
236    #[doc(alias = "get_ctm")]
237    pub fn ctm(&self) -> Matrix {
238        let mut matrix = Matrix::null();
239
240        unsafe { ffi::cairo_scaled_font_get_ctm(self.to_raw_none(), matrix.mut_ptr()) }
241
242        matrix
243    }
244
245    #[doc(alias = "cairo_scaled_font_get_scale_matrix")]
246    #[doc(alias = "get_scale_matrix")]
247    pub fn scale_matrix(&self) -> Matrix {
248        let mut matrix = Matrix::null();
249
250        unsafe { ffi::cairo_scaled_font_get_scale_matrix(self.to_raw_none(), matrix.mut_ptr()) }
251
252        matrix
253    }
254
255    #[doc(alias = "cairo_scaled_font_status")]
256    pub fn status(&self) -> Result<(), Error> {
257        let status = unsafe { ffi::cairo_scaled_font_status(self.to_raw_none()) };
258        status_to_result(status)
259    }
260
261    user_data_methods! {
262        ffi::cairo_scaled_font_get_user_data,
263        ffi::cairo_scaled_font_set_user_data,
264    }
265}
266
267#[cfg(not(feature = "use_glib"))]
268impl Drop for ScaledFont {
269    #[inline]
270    fn drop(&mut self) {
271        unsafe {
272            ffi::cairo_scaled_font_destroy(self.to_raw_none());
273        }
274    }
275}
276
277#[cfg(not(feature = "use_glib"))]
278impl Clone for ScaledFont {
279    #[inline]
280    fn clone(&self) -> ScaledFont {
281        unsafe { ScaledFont::from_raw_none(self.to_raw_none()) }
282    }
283}