verglas/forge/font/
table.rs1use font_types::{Fixed, LongDateTime};
2use write_fonts::{
3 tables::{
4 cmap::Cmap,
5 glyf::{Bbox, GlyfLocaBuilder, Glyph, SimpleGlyph},
6 head::Head,
7 hhea::Hhea,
8 hmtx::{Hmtx, LongMetric},
9 maxp::Maxp,
10 post::Post,
11 },
12 types::GlyphId,
13 FontBuilder,
14};
15
16mod name;
17
18use self::name::name;
19use super::{glyph::BboxMetrics, ADVANCE};
20use crate::Error;
21
22pub fn add_font_tables(
23 font: &mut FontBuilder,
24 font_name: &str,
25 named_glyphs: &[(String, SimpleGlyph)],
26) -> Result<(), Error> {
27 let num_glyphs = (named_glyphs.len() + 1) as u16; let bbox = named_glyphs
29 .iter()
30 .fold(Bbox::default(), |bbox, (_, glyph)| bbox.union(glyph.bbox));
31 let (x_min, y_min, x_max, y_max) = bbox.bounds();
32
33 let name_table = name(font_name);
35 font.add_table(&name_table)?;
36
37 let head_table = head(x_min, y_min, x_max, y_max);
39 font.add_table(&head_table)?;
40
41 let hhea = hhea(num_glyphs);
43 font.add_table(&hhea)?;
44
45 let maxp = maxp(num_glyphs);
47 font.add_table(&maxp)?;
48
49 let mappings = named_glyphs.iter().enumerate().map(|(i, _)| {
51 let unicode = char::from_u32(i as u32 + 0xE000).unwrap();
52 (unicode, GlyphId::new(((i + 1) as u16).into()))
53 });
54 let cmap = Cmap::from_mappings(mappings).unwrap();
55 font.add_table(&cmap)?;
56
57 let mut glyf_builder = GlyfLocaBuilder::new();
59
60 glyf_builder.add_glyph(&Glyph::Empty)?;
62 let mut glyph_order = vec![".notdef"];
63 let mut h_metrics = vec![LongMetric::new(ADVANCE, 1000)];
64 let mut left_side_bearings = vec![0];
65
66 for (name, glyph) in named_glyphs {
68 glyf_builder.add_glyph(glyph)?;
69 let side_bearing = (ADVANCE.saturating_sub(glyph.bbox.width()) / 2) as i16;
70 h_metrics.push(LongMetric::new(ADVANCE, side_bearing));
71 left_side_bearings.push(side_bearing);
72 glyph_order.push(name.as_str());
73 }
74
75 let hmtx = Hmtx::new(h_metrics, left_side_bearings);
77 font.add_table(&hmtx)?;
78
79 let (glyf, loca, _loca_format) = glyf_builder.build();
81 font.add_table(&glyf)?;
82 font.add_table(&loca)?;
83
84 let post = Post::new_v2(glyph_order);
86 font.add_table(&post)?;
87
88 Ok(())
89}
90
91pub fn head(x_min: i16, y_min: i16, x_max: i16, y_max: i16) -> Head {
92 Head {
93 font_revision: Fixed::from_i32(1),
94 created: LongDateTime::new(0),
95 modified: LongDateTime::new(0),
96 units_per_em: 1000,
97 x_min,
98 y_min,
99 x_max,
100 y_max,
101 index_to_loc_format: 0, ..Head::default()
103 }
104}
105
106pub fn hhea(number_of_long_metrics: u16) -> Hhea {
107 Hhea {
108 ascender: (ADVANCE as i16).into(),
109 descender: 0.into(),
110 line_gap: 0.into(),
111 advance_width_max: ADVANCE.into(),
112 number_of_long_metrics,
113 ..Hhea::default()
114 }
115}
116
117pub fn maxp(num_glyphs: u16) -> Maxp {
118 Maxp {
119 num_glyphs,
120 ..Maxp::default()
121 }
122}