1use std::collections::BTreeSet;
2
3use crate::error::{Error, PackingError};
4use crate::graph::{Graph, ObjectId, ObjectStore, OffsetLen};
5use crate::table_type::TableType;
6use crate::validate::Validate;
7use font_types::{FixedSize, Scalar};
8use read_fonts::{FontData, FontRead, FontReadWithArgs, ReadError};
9
10pub trait FontWrite {
15 fn write_into(&self, writer: &mut TableWriter);
17
18 fn table_type(&self) -> TableType {
23 TableType::Unknown
24 }
25}
26
27#[derive(Debug)]
31pub struct TableWriter {
32 tables: ObjectStore,
34 stack: Vec<TableData>,
38 offset_adjustment: u32,
46}
47
48pub fn dump_table<T: FontWrite + Validate>(table: &T) -> Result<Vec<u8>, Error> {
53 log::trace!("writing table '{}'", table.table_type());
54 table.validate()?;
55 let mut graph = TableWriter::make_graph(table);
56
57 if !graph.pack_objects() {
58 return Err(Error::PackingFailed(PackingError {
59 graph: graph.into(),
60 }));
61 }
62 Ok(graph.serialize())
63}
64
65impl TableWriter {
66 pub(crate) fn make_graph(root: &impl FontWrite) -> Graph {
68 let mut writer = TableWriter::default();
69 let root_id = writer.add_table(root);
70 Graph::from_obj_store(writer.tables, root_id)
71 }
72
73 fn add_table(&mut self, table: &dyn FontWrite) -> ObjectId {
74 self.stack.push(TableData::default());
75 table.write_into(self);
76 let mut table_data = self.stack.pop().unwrap();
77 table_data.type_ = table.table_type();
78 self.tables.add(table_data)
79 }
80
81 pub(crate) fn adjust_offsets(&mut self, adjustment: u32, f: impl FnOnce(&mut TableWriter)) {
83 self.offset_adjustment = adjustment;
84 f(self);
85 self.offset_adjustment = 0;
86 }
87
88 #[inline]
92 pub fn write_slice(&mut self, bytes: &[u8]) {
93 self.stack.last_mut().unwrap().write_bytes(bytes)
94 }
95
96 pub fn write_offset(&mut self, obj: &dyn FontWrite, width: usize) {
107 let obj_id = self.add_table(obj);
108 let data = self.stack.last_mut().unwrap();
109 data.add_offset(obj_id, width, self.offset_adjustment);
110 }
111
112 pub fn pad_to_2byte_aligned(&mut self) {
117 if self.stack.last().unwrap().bytes.len() % 2 != 0 {
118 self.write_slice(&[0]);
119 }
120 }
121
122 pub(crate) fn into_data(mut self) -> TableData {
124 assert_eq!(self.stack.len(), 1);
125 let result = self.stack.pop().unwrap();
126 assert!(result.offsets.is_empty());
127 result
128 }
129
130 pub(crate) fn current_data(&self) -> &TableData {
135 self.stack.last().unwrap() }
137}
138
139impl Default for TableWriter {
140 fn default() -> Self {
141 TableWriter {
142 tables: ObjectStore::default(),
143 stack: vec![TableData::default()],
144 offset_adjustment: 0,
145 }
146 }
147}
148
149#[derive(Debug, Default, Clone)] pub(crate) struct TableData {
152 pub(crate) type_: TableType,
153 pub(crate) bytes: Vec<u8>,
154 pub(crate) offsets: Vec<OffsetRecord>,
155}
156
157impl std::hash::Hash for TableData {
158 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
159 self.bytes.hash(state);
160 self.offsets.hash(state);
161 }
162}
163
164impl PartialEq for TableData {
165 fn eq(&self, other: &Self) -> bool {
166 self.bytes == other.bytes && self.offsets == other.offsets
167 }
168}
169
170impl Eq for TableData {}
171
172#[derive(Debug, Clone, Hash, PartialEq, Eq)]
174pub(crate) struct OffsetRecord {
175 pub(crate) pos: u32,
177 pub(crate) len: OffsetLen,
179 pub(crate) object: ObjectId,
181 pub(crate) adjustment: u32,
187}
188
189impl TableData {
190 pub(crate) fn new(type_: TableType) -> Self {
191 TableData {
192 type_,
193 ..Default::default()
194 }
195 }
196
197 pub(crate) fn add_offset(&mut self, object: ObjectId, width: usize, adjustment: u32) {
199 const PLACEHOLDER_BYTES: &[u8] = &[0xff; 4];
200 self.offsets.push(OffsetRecord {
201 pos: self.bytes.len() as u32,
202 len: match width {
203 2 => OffsetLen::Offset16,
204 3 => OffsetLen::Offset24,
205 _ => OffsetLen::Offset32,
206 },
207 object,
208 adjustment,
209 });
210
211 let placeholder = PLACEHOLDER_BYTES.get(..width.min(4)).unwrap();
215 self.write_bytes(placeholder);
216 }
217
218 pub(crate) fn write<T: Scalar>(&mut self, value: T) {
219 self.write_bytes(value.to_raw().as_ref())
220 }
221
222 pub(crate) fn write_over<T: Scalar>(&mut self, value: T, pos: usize) {
227 let raw = value.to_raw();
228 let len = raw.as_ref().len();
229 self.bytes[pos..pos + len].copy_from_slice(raw.as_ref());
230 }
231
232 fn write_bytes(&mut self, bytes: &[u8]) {
233 self.bytes.extend_from_slice(bytes)
234 }
235
236 pub(crate) fn reparse<'a, T: FontRead<'a>>(&'a self) -> Result<T, ReadError> {
241 let data = FontData::new(&self.bytes);
242 T::read(data)
243 }
244
245 pub(crate) fn reparse_with_args<'a, A, T: FontReadWithArgs<'a, Args = A>>(
247 &'a self,
248 args: &A,
249 ) -> Result<T, ReadError> {
250 let data = FontData::new(&self.bytes);
251 T::read_with_args(data, args)
252 }
253
254 pub(crate) fn read_at<T: Scalar>(&self, pos: usize) -> Option<T> {
256 let len = T::RAW_BYTE_LEN;
257 self.bytes.get(pos..pos + len).and_then(T::read)
258 }
259
260 #[cfg(test)]
261 pub fn make_mock(size: usize) -> Self {
262 TableData {
263 bytes: vec![0xca; size], offsets: Vec::new(),
265 type_: TableType::MockTable,
266 }
267 }
268
269 #[cfg(test)]
270 pub fn add_mock_offset(&mut self, object: ObjectId, len: OffsetLen) {
271 let pos = self.offsets.iter().map(|off| off.len as u8 as u32).sum();
272 self.offsets.push(OffsetRecord {
273 pos,
274 len,
275 object,
276 adjustment: 0,
277 });
278 }
279}
280
281macro_rules! write_be_bytes {
282 ($ty:ty) => {
283 impl FontWrite for $ty {
284 #[inline]
285 fn write_into(&self, writer: &mut TableWriter) {
286 writer.write_slice(&self.to_be_bytes())
287 }
288 }
289 };
290}
291
292write_be_bytes!(u8);
294write_be_bytes!(i8);
295write_be_bytes!(u16);
296write_be_bytes!(i16);
297write_be_bytes!(u32);
298write_be_bytes!(i32);
299write_be_bytes!(i64);
300write_be_bytes!(types::Uint24);
301write_be_bytes!(types::Int24);
302write_be_bytes!(types::F2Dot14);
303write_be_bytes!(types::Fixed);
304write_be_bytes!(types::FWord);
305write_be_bytes!(types::UfWord);
306write_be_bytes!(types::LongDateTime);
307write_be_bytes!(types::Tag);
308write_be_bytes!(types::Version16Dot16);
309write_be_bytes!(types::MajorMinor);
310write_be_bytes!(types::GlyphId16);
311write_be_bytes!(types::NameId);
312
313impl<T: FontWrite> FontWrite for [T] {
314 fn write_into(&self, writer: &mut TableWriter) {
315 self.iter().for_each(|item| item.write_into(writer))
316 }
317}
318
319impl<T: FontWrite> FontWrite for BTreeSet<T> {
320 fn write_into(&self, writer: &mut TableWriter) {
321 self.iter().for_each(|item| item.write_into(writer))
322 }
323}
324
325impl<T: FontWrite> FontWrite for Vec<T> {
326 fn write_into(&self, writer: &mut TableWriter) {
327 self.iter().for_each(|item| item.write_into(writer))
328 }
329}
330
331impl<T: FontWrite> FontWrite for Option<T> {
332 fn write_into(&self, writer: &mut TableWriter) {
333 if let Some(obj) = self {
334 obj.write_into(writer)
335 }
336 }
337}