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