1use crate::error::Result;
25use crate::font::Font;
26use crate::stream::FontWriter;
27use crate::tables::name::NameTable;
28use crate::tables::head::HeadTable;
29use crate::tables::hhea::HheaTable;
30use crate::tables::os2::Os2Table;
31use crate::tables::hmtx::HmtxTable;
32use crate::tables::TtfTableWrite;
33use std::collections::HashMap;
34
35pub struct FontModifier {
47 font: Font,
48 modified_tables: HashMap<[u8; 4], Vec<u8>>,
49}
50
51impl FontModifier {
52 pub fn new(font: Font) -> Self {
53 Self {
54 font,
55 modified_tables: HashMap::new(),
56 }
57 }
58
59 pub fn set_font_name(&mut self, name: &str) -> Result<&mut Self> {
77 let mut name_table = self.font.name_table()?;
78
79 let platform_id = 3u16;
80 let encoding_id = 1u16;
81 let language_id = 0x0409u16;
82 let name_id = 1u16;
83
84 name_table.set_name(name, platform_id, encoding_id, language_id, name_id);
85 self.serialize_name_table(name_table)?;
86 Ok(self)
87 }
88
89 pub fn set_full_font_name(&mut self, name: &str) -> Result<&mut Self> {
97 let mut name_table = self.font.name_table()?;
98
99 let platform_id = 3u16;
100 let encoding_id = 1u16;
101 let language_id = 0x0409u16;
102 let name_id = 4u16;
103
104 name_table.set_name(name, platform_id, encoding_id, language_id, name_id);
105 self.serialize_name_table(name_table)?;
106 Ok(self)
107 }
108
109 pub fn set_version(&mut self, major: u16, minor: u16) -> Result<&mut Self> {
128 let version_string = format!("Version {}.{}", major, minor);
129
130 let mut name_table = self.font.name_table()?;
131
132 let platform_id = 3u16;
133 let encoding_id = 1u16;
134 let language_id = 0x0409u16;
135 let name_id = 5u16;
136
137 name_table.set_name(&version_string, platform_id, encoding_id, language_id, name_id);
138 self.serialize_name_table(name_table)?;
139
140 let mut head_table = self.font.head_table()?;
142 head_table.font_revision = (major as f32) + (minor as f32) / 100.0;
143 self.serialize_head_table(head_table)?;
144
145 Ok(self)
146 }
147
148 pub fn set_copyright(&mut self, copyright: &str) -> Result<&mut Self> {
156 let mut name_table = self.font.name_table()?;
157
158 let platform_id = 3u16;
159 let encoding_id = 1u16;
160 let language_id = 0x0409u16;
161 let name_id = 0u16;
162
163 name_table.set_name(copyright, platform_id, encoding_id, language_id, name_id);
164 self.serialize_name_table(name_table)?;
165 Ok(self)
166 }
167
168 pub fn set_trademark(&mut self, trademark: &str) -> Result<&mut Self> {
176 let mut name_table = self.font.name_table()?;
177
178 let platform_id = 3u16;
179 let encoding_id = 1u16;
180 let language_id = 0x0409u16;
181 let name_id = 7u16;
182
183 name_table.set_name(trademark, platform_id, encoding_id, language_id, name_id);
184 self.serialize_name_table(name_table)?;
185 Ok(self)
186 }
187
188 pub fn set_font_revision(&mut self, major: u16, minor: u16) -> Result<&mut Self> {
197 let mut head_table = self.font.head_table()?;
198 head_table.font_revision = (major as f32) + (minor as f32) / 100.0;
199 self.serialize_head_table(head_table)?;
200 Ok(self)
201 }
202
203 pub fn set_embedding_type(&mut self, embedding_type: u16) -> Result<&mut Self> {
205 let mut os2_table = self.font.os2_table()?;
206 os2_table.fs_type = embedding_type;
207 self.serialize_os2_table(os2_table)?;
208 Ok(self)
209 }
210
211 pub fn set_localized_font_name(&mut self, name: &str, language_id: u16) -> Result<&mut Self> {
213 let mut name_table = self.font.name_table()?;
214
215 let platform_id = 3u16;
216 let encoding_id = 1u16;
217 let name_id = 1u16;
218
219 name_table.set_name(name, platform_id, encoding_id, language_id, name_id);
220 self.serialize_name_table(name_table)?;
221 Ok(self)
222 }
223
224 pub fn set_font_metrics(&mut self, units_per_em: u16, ascender: i16, descender: i16, line_gap: i16) -> Result<&mut Self> {
226 let mut head_table = self.font.head_table()?;
228 head_table.units_per_em = units_per_em;
229 self.serialize_head_table(head_table)?;
230
231 let mut hhea_table = self.font.hhea_table()?;
233 hhea_table.ascent = ascender;
234 hhea_table.descent = descender;
235 hhea_table.line_gap = line_gap;
236 self.serialize_hhea_table(hhea_table)?;
237
238 Ok(self)
239 }
240
241 pub fn set_glyph_advance(&mut self, glyph_index: usize, advance_width: u16) -> Result<&mut Self> {
243 let mut hmtx_table = self.font.hmtx_table()?;
244 let hhea_table = self.font.hhea_table()?;
245
246 if glyph_index < hmtx_table.h_metrics.len() {
247 if glyph_index < hhea_table.number_of_h_metrics as usize {
248 hmtx_table.h_metrics[glyph_index].advance_width = advance_width;
249 }
250 self.serialize_hmtx_table(hmtx_table)?;
251 }
252
253 Ok(self)
254 }
255
256 fn serialize_name_table(&mut self, table: NameTable) -> Result<()> {
258 let mut writer = FontWriter::new();
259 table.write(&mut writer)?;
260 self.modified_tables.insert(*b"name", writer.into_inner());
261 Ok(())
262 }
263
264 fn serialize_head_table(&mut self, table: HeadTable) -> Result<()> {
266 let mut writer = FontWriter::new();
267 table.write(&mut writer)?;
268 self.modified_tables.insert(*b"head", writer.into_inner());
269 Ok(())
270 }
271
272 fn serialize_hhea_table(&mut self, table: HheaTable) -> Result<()> {
274 let mut writer = FontWriter::new();
275 table.write(&mut writer)?;
276 self.modified_tables.insert(*b"hhea", writer.into_inner());
277 Ok(())
278 }
279
280 fn serialize_os2_table(&mut self, table: Os2Table) -> Result<()> {
282 let mut writer = FontWriter::new();
283 table.write(&mut writer)?;
284 self.modified_tables.insert(*b"OS/2", writer.into_inner());
285 Ok(())
286 }
287
288 fn serialize_hmtx_table(&mut self, table: HmtxTable) -> Result<()> {
290 let mut writer = FontWriter::new();
291 table.write(&mut writer)?;
292 self.modified_tables.insert(*b"hmtx", writer.into_inner());
293 Ok(())
294 }
295
296 pub fn commit(mut self) -> Result<Font> {
298 for (tag, data) in &self.modified_tables {
300 if let Some(record) = self.font.table_records.iter_mut().find(|r| r.table_tag == *tag) {
302 record.length = data.len() as u32;
303 }
305 }
306
307 let mut new_data = self.font.data.clone();
309
310 for (tag, data) in &self.modified_tables {
312 if let Some(record) = self.font.get_table_record(tag) {
313 let offset = record.offset as usize;
314 if offset + data.len() <= new_data.len() {
316 new_data[offset..offset + data.len()].copy_from_slice(data);
317 }
318 }
319 }
320
321 self.font.data = new_data;
322 Ok(self.font)
323 }
324}
325
326impl Font {
327 pub fn modify(self) -> FontModifier {
328 FontModifier::new(self)
329 }
330}