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}