cairo/font/
scaled_font.rs

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