Skip to main content

base_ui/text/
font.rs

1use rusttype::{ Font, Scale, point, PositionedGlyph };
2
3pub struct FontRenderer {
4    font: Font<'static>,
5}
6
7impl FontRenderer {
8    pub fn new(font_data: Vec<u8>) -> Self {
9        let font_data = font_data.into_boxed_slice();
10        let font_data: &'static [u8] = Box::leak(font_data);
11        let font = Font::try_from_bytes(font_data).expect("Error constructing Font");
12
13        Self { font }
14    }
15
16    pub fn render_text(&self, text: &str, scale: f32) -> Vec<PositionedGlyph<'static>> {
17        let scale = Scale::uniform(scale * 0.75);
18        let v_metrics = self.font.v_metrics(scale);
19        let offset = point(0.0, v_metrics.ascent);
20
21        self.font.layout(text, scale, offset).collect()
22    }
23
24    pub fn calculate_text_size(&self, text: &str, scale: f32) -> (f32, f32) {
25        let scale = Scale::uniform(scale * 0.75);
26        let v_metrics = self.font.v_metrics(scale);
27        let glyphs: Vec<_> = self.font.layout(text, scale, point(0.0, v_metrics.ascent)).collect();
28
29        if glyphs.is_empty() {
30            return (0.0, 0.0);
31        }
32
33        let min_x = glyphs
34            .first()
35            .and_then(|g| g.pixel_bounding_box())
36            .map(|bb| bb.min.x as f32)
37            .unwrap_or(0.0);
38        let max_x = glyphs
39            .last()
40            .and_then(|g| g.pixel_bounding_box())
41            .map(|bb| bb.max.x as f32)
42            .unwrap_or(0.0);
43
44        let width = max_x - min_x;
45        let height = v_metrics.ascent - v_metrics.descent;
46
47        (width, height.abs())
48    }
49}