skia_safe/core/
font.rs

1use std::{fmt, ptr};
2
3use skia_bindings::{self as sb, SkFont, SkFont_PrivFlags};
4
5use crate::{
6    interop::VecSink, prelude::*, scalar, EncodedText, FontHinting, FontMetrics, GlyphId, Paint,
7    Path, Point, Rect, Typeface, Unichar,
8};
9
10pub use skia_bindings::SkFont_Edging as Edging;
11variant_name!(Edging::Alias);
12
13pub type Font = Handle<SkFont>;
14unsafe_send_sync!(Font);
15
16impl NativeDrop for SkFont {
17    fn drop(&mut self) {
18        unsafe { sb::C_SkFont_destruct(self) }
19    }
20}
21
22impl NativeClone for SkFont {
23    fn clone(&self) -> Self {
24        construct(|f| unsafe { sb::C_SkFont_CopyConstruct(f, self) })
25    }
26}
27
28impl NativePartialEq for SkFont {
29    fn eq(&self, rhs: &Self) -> bool {
30        unsafe { sb::C_SkFont_Equals(self, rhs) }
31    }
32}
33
34impl Default for Font {
35    fn default() -> Self {
36        Self::from_native_c(unsafe { SkFont::new() })
37    }
38}
39
40impl fmt::Debug for Font {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        f.debug_struct("Font")
43            .field("is_force_auto_hinting", &self.is_force_auto_hinting())
44            .field("is_embedded_bitmaps", &self.is_embedded_bitmaps())
45            .field("is_subpixel", &self.is_subpixel())
46            .field("is_linear_metrics", &self.is_linear_metrics())
47            .field("is_embolden", &self.is_embolden())
48            .field("is_baseline_snap", &self.is_baseline_snap())
49            .field("edging", &self.edging())
50            .field("hinting", &self.hinting())
51            .field("typeface", &self.typeface())
52            .field("size", &self.size())
53            .field("scale_x", &self.scale_x())
54            .field("skew_x", &self.skew_x())
55            .field("metrics", &self.metrics())
56            .field("spacing", &self.spacing())
57            .finish()
58    }
59}
60
61impl Font {
62    pub fn new(typeface: impl Into<Typeface>, size: impl Into<Option<scalar>>) -> Self {
63        Self::from_typeface(typeface, size)
64    }
65
66    pub fn from_typeface(typeface: impl Into<Typeface>, size: impl Into<Option<scalar>>) -> Self {
67        match size.into() {
68            None => Self::construct(|font| unsafe {
69                sb::C_SkFont_ConstructFromTypeface(font, typeface.into().into_ptr())
70            }),
71            Some(size) => Self::construct(|font| unsafe {
72                sb::C_SkFont_ConstructFromTypefaceWithSize(font, typeface.into().into_ptr(), size)
73            }),
74        }
75    }
76
77    pub fn from_typeface_with_params(
78        typeface: impl Into<Typeface>,
79        size: scalar,
80        scale: scalar,
81        skew: scalar,
82    ) -> Self {
83        Self::construct(|font| unsafe {
84            sb::C_SkFont_ConstructFromTypefaceWithSizeScaleAndSkew(
85                font,
86                typeface.into().into_ptr(),
87                size,
88                scale,
89                skew,
90            )
91        })
92    }
93
94    pub fn is_force_auto_hinting(&self) -> bool {
95        self.has_flag(sb::SkFont_PrivFlags_kForceAutoHinting_PrivFlag)
96    }
97
98    pub fn is_embedded_bitmaps(&self) -> bool {
99        self.has_flag(sb::SkFont_PrivFlags_kEmbeddedBitmaps_PrivFlag)
100    }
101
102    pub fn is_subpixel(&self) -> bool {
103        self.has_flag(sb::SkFont_PrivFlags_kSubpixel_PrivFlag)
104    }
105
106    pub fn is_linear_metrics(&self) -> bool {
107        self.has_flag(sb::SkFont_PrivFlags_kLinearMetrics_PrivFlag)
108    }
109
110    pub fn is_embolden(&self) -> bool {
111        self.has_flag(sb::SkFont_PrivFlags_kEmbolden_PrivFlag)
112    }
113
114    pub fn is_baseline_snap(&self) -> bool {
115        self.has_flag(sb::SkFont_PrivFlags_kBaselineSnap_PrivFlag)
116    }
117
118    fn has_flag(&self, flag: SkFont_PrivFlags) -> bool {
119        (SkFont_PrivFlags::from(self.native().fFlags) & flag) != 0
120    }
121
122    pub fn set_force_auto_hinting(&mut self, force_auto_hinting: bool) -> &mut Self {
123        unsafe { self.native_mut().setForceAutoHinting(force_auto_hinting) }
124        self
125    }
126
127    pub fn set_embedded_bitmaps(&mut self, embedded_bitmaps: bool) -> &mut Self {
128        unsafe { self.native_mut().setEmbeddedBitmaps(embedded_bitmaps) }
129        self
130    }
131
132    pub fn set_subpixel(&mut self, subpixel: bool) -> &mut Self {
133        unsafe { self.native_mut().setSubpixel(subpixel) }
134        self
135    }
136
137    pub fn set_linear_metrics(&mut self, linear_metrics: bool) -> &mut Self {
138        unsafe { self.native_mut().setLinearMetrics(linear_metrics) }
139        self
140    }
141
142    pub fn set_embolden(&mut self, embolden: bool) -> &mut Self {
143        unsafe { self.native_mut().setEmbolden(embolden) }
144        self
145    }
146
147    pub fn set_baseline_snap(&mut self, baseline_snap: bool) -> &mut Self {
148        unsafe { self.native_mut().setBaselineSnap(baseline_snap) }
149        self
150    }
151
152    pub fn edging(&self) -> Edging {
153        unsafe { sb::C_SkFont_getEdging(self.native()) }
154    }
155
156    pub fn set_edging(&mut self, edging: Edging) -> &mut Self {
157        unsafe { self.native_mut().setEdging(edging) }
158        self
159    }
160
161    pub fn set_hinting(&mut self, hinting: FontHinting) -> &mut Self {
162        unsafe { self.native_mut().setHinting(hinting) }
163        self
164    }
165
166    pub fn hinting(&self) -> FontHinting {
167        unsafe { sb::C_SkFont_getHinting(self.native()) }
168    }
169
170    #[must_use]
171    pub fn with_size(&self, size: scalar) -> Option<Self> {
172        if size >= 0.0 && !size.is_infinite() && !size.is_nan() {
173            let mut font = unsafe { SkFont::new() };
174            unsafe { sb::C_SkFont_makeWithSize(self.native(), size, &mut font) }
175            Some(Self::from_native_c(font))
176        } else {
177            None
178        }
179    }
180
181    pub fn typeface(&self) -> Typeface {
182        Typeface::from_unshared_ptr(self.native().fTypeface.fPtr)
183            .expect("typeface is expected to be non-null")
184    }
185
186    pub fn size(&self) -> scalar {
187        self.native().fSize
188    }
189
190    pub fn scale_x(&self) -> scalar {
191        self.native().fScaleX
192    }
193
194    pub fn skew_x(&self) -> scalar {
195        self.native().fSkewX
196    }
197
198    pub fn set_typeface(&mut self, tf: impl Into<Typeface>) -> &mut Self {
199        unsafe { sb::C_SkFont_setTypeface(self.native_mut(), tf.into().into_ptr()) }
200        self
201    }
202
203    pub fn set_size(&mut self, size: scalar) -> &mut Self {
204        unsafe { self.native_mut().setSize(size) }
205        self
206    }
207
208    pub fn set_scale_x(&mut self, scale_x: scalar) -> &mut Self {
209        unsafe { self.native_mut().setScaleX(scale_x) }
210        self
211    }
212
213    pub fn set_skew_x(&mut self, skew_x: scalar) -> &mut Self {
214        unsafe { self.native_mut().setSkewX(skew_x) }
215        self
216    }
217
218    pub fn str_to_glyphs(&self, str: impl AsRef<str>, glyphs: &mut [GlyphId]) -> usize {
219        self.text_to_glyphs(str.as_ref(), glyphs)
220    }
221
222    pub fn text_to_glyphs(&self, text: impl EncodedText, glyphs: &mut [GlyphId]) -> usize {
223        let (ptr, size, encoding) = text.as_raw();
224        unsafe {
225            self.native()
226                .textToGlyphs(
227                    ptr,
228                    size,
229                    encoding.into_native(),
230                    glyphs.as_mut_ptr(),
231                    // don't fail if glyphs.len() is too large to fit into an i32.
232                    glyphs
233                        .len()
234                        .min(i32::MAX.try_into().unwrap())
235                        .try_into()
236                        .unwrap(),
237                )
238                .try_into()
239                .unwrap()
240        }
241    }
242
243    pub fn count_str(&self, str: impl AsRef<str>) -> usize {
244        self.count_text(str.as_ref())
245    }
246
247    pub fn count_text(&self, text: impl EncodedText) -> usize {
248        let (ptr, size, encoding) = text.as_raw();
249        unsafe {
250            self.native()
251                .textToGlyphs(ptr, size, encoding.into_native(), ptr::null_mut(), i32::MAX)
252                .try_into()
253                .unwrap()
254        }
255    }
256
257    // convenience function
258    pub fn str_to_glyphs_vec(&self, str: impl AsRef<str>) -> Vec<GlyphId> {
259        self.text_to_glyphs_vec(str.as_ref())
260    }
261
262    // convenience function
263    pub fn text_to_glyphs_vec(&self, text: impl EncodedText) -> Vec<GlyphId> {
264        let count = self.count_text(&text);
265        let mut glyphs: Vec<GlyphId> = vec![Default::default(); count];
266        let resulting_count = self.text_to_glyphs(text, glyphs.as_mut_slice());
267        assert_eq!(count, resulting_count);
268        glyphs
269    }
270
271    pub fn measure_str(&self, str: impl AsRef<str>, paint: Option<&Paint>) -> (scalar, Rect) {
272        self.measure_text(str.as_ref(), paint)
273    }
274
275    pub fn measure_text(&self, text: impl EncodedText, paint: Option<&Paint>) -> (scalar, Rect) {
276        let mut bounds = Rect::default();
277        let (ptr, size, encoding) = text.as_raw();
278        let width = unsafe {
279            self.native().measureText(
280                ptr,
281                size,
282                encoding.into_native(),
283                bounds.native_mut(),
284                paint.native_ptr_or_null(),
285            )
286        };
287
288        (width, bounds)
289    }
290
291    pub fn unichar_to_glyph(&self, uni: Unichar) -> GlyphId {
292        unsafe { self.native().unicharToGlyph(uni) }
293    }
294
295    pub fn unichar_to_glyphs(&self, uni: &[Unichar], glyphs: &mut [GlyphId]) {
296        assert_eq!(uni.len(), glyphs.len());
297        unsafe {
298            self.native().unicharsToGlyphs(
299                uni.as_ptr(),
300                uni.len().try_into().unwrap(),
301                glyphs.as_mut_ptr(),
302            )
303        }
304    }
305
306    pub fn get_widths(&self, glyphs: &[GlyphId], widths: &mut [scalar]) {
307        self.get_widths_bounds(glyphs, Some(widths), None, None)
308    }
309
310    pub fn get_widths_bounds(
311        &self,
312        glyphs: &[GlyphId],
313        mut widths: Option<&mut [scalar]>,
314        mut bounds: Option<&mut [Rect]>,
315        paint: Option<&Paint>,
316    ) {
317        let count = glyphs.len();
318
319        {
320            if let Some(slice) = &widths {
321                assert_eq!(count, slice.len())
322            };
323            if let Some(slice) = &bounds {
324                assert_eq!(count, slice.len())
325            };
326        }
327
328        let bounds_ptr = bounds.native_mut().as_ptr_or_null_mut();
329        let widths_ptr = widths.as_ptr_or_null_mut();
330        let paint_ptr = paint.native_ptr_or_null();
331
332        unsafe {
333            self.native().getWidthsBounds(
334                glyphs.as_ptr(),
335                count.try_into().unwrap(),
336                widths_ptr,
337                bounds_ptr,
338                paint_ptr,
339            )
340        }
341    }
342
343    pub fn get_bounds(&self, glyphs: &[GlyphId], bounds: &mut [Rect], paint: Option<&Paint>) {
344        self.get_widths_bounds(glyphs, None, Some(bounds), paint)
345    }
346
347    pub fn get_pos(&self, glyphs: &[GlyphId], pos: &mut [Point], origin: Option<Point>) {
348        let count = glyphs.len();
349        assert_eq!(count, pos.len());
350
351        let origin = origin.unwrap_or_default();
352
353        unsafe {
354            self.native().getPos(
355                glyphs.as_ptr(),
356                count.try_into().unwrap(),
357                pos.native_mut().as_mut_ptr(),
358                *origin.native(),
359            )
360        }
361    }
362
363    pub fn get_x_pos(&self, glyphs: &[GlyphId], x_pos: &mut [scalar], origin: Option<scalar>) {
364        let count = glyphs.len();
365        assert_eq!(count, x_pos.len());
366        let origin = origin.unwrap_or_default();
367
368        unsafe {
369            self.native().getXPos(
370                glyphs.as_ptr(),
371                count.try_into().unwrap(),
372                x_pos.as_mut_ptr(),
373                origin,
374            )
375        }
376    }
377
378    pub fn get_intercepts<'a>(
379        &self,
380        glyphs: &[GlyphId],
381        pos: &[Point],
382        (top, bottom): (scalar, scalar),
383        paint: impl Into<Option<&'a Paint>>,
384    ) -> Vec<scalar> {
385        assert_eq!(glyphs.len(), pos.len());
386        let count = glyphs.len().try_into().unwrap();
387        let mut r: Vec<scalar> = Vec::new();
388        let mut set = |scalars: &[scalar]| r = scalars.to_vec();
389        unsafe {
390            sb::C_SkFont_getIntercepts(
391                self.native(),
392                glyphs.as_ptr(),
393                count,
394                pos.native().as_ptr(),
395                top,
396                bottom,
397                paint.into().native_ptr_or_null(),
398                VecSink::new(&mut set).native_mut(),
399            );
400        }
401        r
402    }
403
404    pub fn get_path(&self, glyph_id: GlyphId) -> Option<Path> {
405        let mut path = Path::default();
406        unsafe { self.native().getPath(glyph_id, path.native_mut()) }.if_true_some(path)
407    }
408
409    // TODO: getPaths() (needs a function to be passed, but supports a context).
410
411    pub fn metrics(&self) -> (scalar, FontMetrics) {
412        let mut line_spacing = 0.0;
413        let fm =
414            FontMetrics::construct(|fm| line_spacing = unsafe { self.native().getMetrics(fm) });
415        (line_spacing, fm)
416    }
417
418    pub fn spacing(&self) -> scalar {
419        unsafe { self.native().getMetrics(ptr::null_mut()) }
420    }
421}
422
423#[cfg(test)]
424mod tests {
425    use crate::{FontMgr, FontStyle};
426
427    use super::*;
428
429    #[test]
430    fn test_flags() {
431        let font_mgr = FontMgr::new();
432        let typeface = font_mgr
433            .legacy_make_typeface(None, FontStyle::normal())
434            .unwrap();
435        let mut font = Font::new(typeface, 10.0);
436
437        font.set_force_auto_hinting(true);
438        assert!(font.is_force_auto_hinting());
439        font.set_force_auto_hinting(false);
440        assert!(!font.is_force_auto_hinting());
441
442        font.set_embolden(true);
443        assert!(font.is_embolden());
444        font.set_embolden(false);
445        assert!(!font.is_embolden());
446    }
447}