write_fonts/tables/glyf/
glyf_loca_builder.rs1use crate::{
4 error::Error,
5 tables::loca::{Loca, LocaFormat},
6 validate::Validate,
7 FontWrite, TableWriter,
8};
9
10use super::{CompositeGlyph, Glyf, Glyph, SimpleGlyph};
11
12pub struct GlyfLocaBuilder {
37 glyph_writer: TableWriter,
38 raw_loca: Vec<u32>,
39}
40
41pub trait SomeGlyph: Validate + FontWrite {}
45
46impl GlyfLocaBuilder {
47 pub fn new() -> Self {
49 Self {
50 glyph_writer: TableWriter::default(),
51 raw_loca: vec![0],
52 }
53 }
54
55 pub fn add_glyph(&mut self, glyph: &impl SomeGlyph) -> Result<&mut Self, Error> {
62 glyph.validate()?;
63 glyph.write_into(&mut self.glyph_writer);
64 let pos = self.glyph_writer.current_data().bytes.len();
65 self.raw_loca.push(pos as u32);
66 Ok(self)
67 }
68
69 #[must_use]
76 pub fn build(self) -> (Glyf, Loca, LocaFormat) {
77 let glyph_data = self.glyph_writer.into_data().bytes;
78 let loca = Loca::new(self.raw_loca);
79 let format = loca.format();
80 (Glyf(glyph_data), loca, format)
81 }
82}
83
84impl SomeGlyph for SimpleGlyph {}
85
86impl SomeGlyph for CompositeGlyph {}
87
88impl SomeGlyph for Glyph {}
89
90impl Default for GlyfLocaBuilder {
91 fn default() -> Self {
92 Self::new()
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::super::{Anchor, Component, ComponentFlags, Transform};
99 use crate::from_obj::FromTableRef;
100 use font_types::GlyphId;
101 use kurbo::{BezPath, Shape};
102 use read_fonts::FontRead;
103
104 use super::*;
105
106 #[test]
107 fn build_some_glyphs() {
108 fn make_triangle() -> BezPath {
109 let mut path = BezPath::new();
110 path.move_to((0., 0.));
111 path.line_to((0., 40.));
112 path.line_to((20., 40.));
113 path.line_to((0., 0.));
114 path
115 }
116 let square = kurbo::Rect::from_points((5., 5.), (100., 100.)).into_path(0.1);
117 let triangle = make_triangle();
118
119 let glyph0 = Glyph::Empty;
120 let glyph1 = SimpleGlyph::from_bezpath(&square).unwrap();
121 let glyph2 = SimpleGlyph::from_bezpath(&triangle).unwrap();
122 let gid1 = GlyphId::new(1);
123 let gid2 = GlyphId::new(2);
124
125 let mut glyph3 = CompositeGlyph::new(
126 Component::new(
127 gid1.try_into().unwrap(),
128 Anchor::Offset { x: 0, y: 0 },
129 Transform::default(),
130 ComponentFlags::default(),
131 ),
132 square.bounding_box(),
133 );
134 glyph3.add_component(
135 Component::new(
136 gid2.try_into().unwrap(),
137 Anchor::Offset { x: 0, y: 0 },
138 Transform::default(),
139 ComponentFlags::default(),
140 ),
141 triangle.bounding_box(),
142 );
143
144 let len1 = crate::dump_table(&glyph1).unwrap().len() as u32;
145 let len2 = crate::dump_table(&glyph2).unwrap().len() as u32;
146 let len3 = crate::dump_table(&glyph3).unwrap().len() as u32;
147
148 let mut builder = GlyfLocaBuilder::new();
149 builder
150 .add_glyph(&glyph0)
151 .unwrap()
152 .add_glyph(&glyph1)
153 .unwrap()
154 .add_glyph(&glyph2)
155 .unwrap()
156 .add_glyph(&glyph3)
157 .unwrap();
158
159 let (glyf, loca, format) = builder.build();
160 assert_eq!(loca.offsets.len(), 5);
161 assert_eq!(loca.offsets, &[0, 0, len1, len1 + len2, len1 + len2 + len3]);
162
163 let rglyf = read_fonts::tables::glyf::Glyf::read(glyf.0.as_slice().into()).unwrap();
164 let loca_bytes = crate::dump_table(&loca).unwrap();
165 let rloca = read_fonts::tables::loca::Loca::read(
166 loca_bytes.as_slice().into(),
167 format == LocaFormat::Long,
168 )
169 .unwrap();
170
171 let rglyph1 = Glyph::from_table_ref(&rloca.get_glyf(gid1, &rglyf).unwrap().unwrap());
172 let rglyph2 = Glyph::from_table_ref(&rloca.get_glyf(gid2, &rglyf).unwrap().unwrap());
173 let rglyph3 =
174 Glyph::from_table_ref(&rloca.get_glyf(GlyphId::new(3), &rglyf).unwrap().unwrap());
175 assert_eq!(rglyph1, glyph1.into());
176 assert_eq!(rglyph2, glyph2.into());
177 assert_eq!(rglyph3, glyph3.into());
178 }
179}