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