makepad_vector/ttf_parser/
mod.rs

1use crate::font::{TTFFont, Glyph, HorizontalMetrics};
2use crate::geometry::{Point, Rectangle};
3use crate::path::PathCommand;
4use std::result;
5
6pub use ttf_parser::{Face, FaceParsingError};
7
8struct OutlineBuilder(Vec<PathCommand>);
9
10impl ttf_parser::OutlineBuilder for OutlineBuilder {
11    fn move_to(&mut self, x: f32, y: f32) {
12        self.0.push(PathCommand::MoveTo(Point { x: x as f64, y: y as f64 }));
13    }
14    fn line_to(&mut self, x: f32, y: f32) {
15        self.0.push(PathCommand::LineTo(Point { x: x as f64, y: y as f64 }));
16    }
17    fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
18        self.0.push(PathCommand::QuadraticTo(
19            Point { x: x1 as f64, y: y1 as f64 },
20            Point { x: x as f64, y: y as f64 },
21        ));
22    }
23    fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
24        self.0.push(PathCommand::CubicTo(
25            Point { x: x1 as f64, y: y1 as f64 },
26            Point { x: x2 as f64, y: y2 as f64 },
27            Point { x: x as f64, y: y as f64 },
28        ));
29    }
30    fn close(&mut self) {
31        self.0.push(PathCommand::Close);
32    }
33}
34
35pub type Result<T> = result::Result<T, Error>;
36
37#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
38pub struct Error;
39
40pub fn from_ttf_parser_face(face: &Face<'_>) -> TTFFont {
41    TTFFont {
42        units_per_em: face.units_per_em() as f64,
43        ascender: face.ascender() as f64,
44        descender: face.descender() as f64,
45        line_gap: face.line_gap() as f64,
46        bounds: {
47            let ttf_parser::Rect { x_min, y_min, x_max, y_max } = face.global_bounding_box();
48            Rectangle::new(
49                Point::new(x_min as f64, y_min as f64),
50                Point::new(x_max as f64, y_max as f64),
51            )
52        },
53        cached_decoded_glyphs: vec![],
54    }
55}
56
57impl TTFFont {
58    pub fn get_glyph_by_id(&mut self, face: &Face<'_>, id: usize) -> Result<&Glyph> {
59        if self.cached_decoded_glyphs.len() <= id {
60            self.cached_decoded_glyphs.resize(id + 1, None);
61        }
62        let glyph_slot = &mut self.cached_decoded_glyphs[id];
63        if glyph_slot.is_none() {
64            let id = ttf_parser::GlyphId(u16::try_from(id).unwrap());
65            let horizontal_metrics = HorizontalMetrics {
66                advance_width: face.glyph_hor_advance(id).ok_or(Error)? as f64,
67                left_side_bearing: face.glyph_hor_side_bearing(id).ok_or(Error)? as f64,
68            };
69            let mut outline_builder = OutlineBuilder(vec![]);
70            let bounds = face.outline_glyph(id, &mut outline_builder)
71                .map(|ttf_parser::Rect { x_min, y_min, x_max, y_max }| {
72                    Rectangle::new(
73                        Point::new(x_min as f64, y_min as f64),
74                        Point::new(x_max as f64, y_max as f64),
75                    )
76                })
77                .unwrap_or_default();
78            *glyph_slot = Some(Box::new(Glyph {
79                horizontal_metrics,
80                bounds,
81                outline: outline_builder.0,
82            }));
83        }
84        Ok(glyph_slot.as_ref().unwrap())
85    }
86}