1use super::{super::once::Once, Blob, Source};
4use crate::{tables, types::Tag, FontRead, ReadError, TableProvider, TopLevelTable};
5use alloc::{boxed::Box, sync::Arc};
6use core::sync::atomic::{AtomicU8, Ordering};
7
8include!("../../../data/generated/generated_tables.rs");
9
10#[derive(Default)]
12struct BlobTableEntry {
13 flag: AtomicU8,
15 start: u32,
16 end: u32,
17}
18
19struct BlobTables {
21 blob: Blob,
22 tables: Box<PerTableData<BlobTableEntry>>,
23}
24
25impl<'a> TableDataProvider<'a> for &'a BlobTables {
26 type Entry = BlobTableEntry;
27
28 fn tables(&self) -> &'a PerTableData<Self::Entry> {
29 &self.tables
30 }
31
32 fn table_state(&self, _tag: Tag, entry: &'a Self::Entry) -> Option<TableState<'a>> {
33 self.blob
34 .get(entry.start as usize..entry.end as usize)
35 .map(|data| TableState {
36 flag: &entry.flag,
37 data,
38 })
39 }
40}
41
42type TableFunctionEntry = Once<Option<(AtomicU8, Blob)>>;
44
45#[derive(Clone)]
47pub struct TableFunction {
48 table_fn: Arc<dyn Fn(Tag) -> Option<Blob> + Send + Sync>,
49 tables: Arc<PerTableData<TableFunctionEntry>>,
50}
51
52impl TableFunction {
53 pub fn new(table_fn: Arc<dyn Fn(Tag) -> Option<Blob> + Send + Sync>) -> Self {
56 Self {
57 table_fn,
58 tables: Arc::new(PerTableData::default()),
59 }
60 }
61}
62
63impl<'a> TableDataProvider<'a> for &'a TableFunction {
64 type Entry = TableFunctionEntry;
65
66 fn tables(&self) -> &'a PerTableData<Self::Entry> {
67 &self.tables
68 }
69
70 fn table_state(&self, tag: Tag, entry: &'a Self::Entry) -> Option<TableState<'a>> {
71 entry
72 .get_or_init(|| (self.table_fn)(tag).map(|blob| (AtomicU8::new(0), blob)))
73 .as_ref()
74 .map(|(flag, data)| TableState {
75 flag,
76 data: data.as_ref(),
77 })
78 }
79}
80
81enum TableSource {
83 None,
84 Blob(BlobTables),
85 Function(TableFunction),
86}
87
88#[derive(Copy, Clone)]
90struct TableState<'a> {
91 flag: &'a AtomicU8,
92 data: &'a [u8],
93}
94
95impl<'a> TableState<'a> {
96 const UNCHECKED: u8 = 0;
97 const VALID: u8 = 1;
98 const INVALID: u8 = 2;
99
100 fn try_load<T>(
101 &self,
102 sanitize_fn: impl Fn(&'a [u8]) -> Result<T, ReadError>,
103 load_fn: impl Fn(&'a [u8]) -> Result<T, ReadError>,
104 ) -> Result<T, ReadError> {
105 match self.flag.load(Ordering::Acquire) {
106 Self::UNCHECKED => {
107 if let Ok(table) = sanitize_fn(self.data) {
108 self.flag.store(Self::VALID, Ordering::Release);
109 Ok(table)
110 } else {
111 self.flag.store(Self::INVALID, Ordering::Release);
112 Err(ReadError::ValidationError)
113 }
114 }
115 Self::VALID => load_fn(self.data),
116 _ => Err(ReadError::ValidationError),
118 }
119 }
120}
121
122pub struct Tables(TableSource);
124
125impl Tables {
126 pub fn new(source: impl Into<Source>, index: u32) -> Option<Self> {
131 let source = source.into();
132 match source {
133 Source::Blob(blob) => {
134 let font_ref = crate::FontRef::from_index(&blob, index).ok()?;
135 let mut tables = PerTableData::default();
136 let directory = font_ref.table_directory();
137 let table_records = directory.table_records();
138 let sorted = directory.is_sorted();
141 tables.init_all(|tag, entry: &mut BlobTableEntry| {
142 entry.start = u32::MAX;
145 let found = if sorted {
146 table_records
147 .binary_search_by_key(&tag, |rec| rec.tag())
148 .ok()
149 } else {
150 table_records.iter().position(|rec| rec.tag() == tag)
151 };
152 let Some(idx) = found else {
153 return;
154 };
155 let record = &table_records[idx];
156 let start = record.offset();
157 let Some(end) = start.checked_add(record.length()) else {
158 return;
159 };
160 if blob.get(start as usize..end as usize).is_none() {
161 return;
162 }
163 *entry = BlobTableEntry {
164 flag: AtomicU8::new(0),
165 start,
166 end,
167 };
168 });
169 Some(Self(TableSource::Blob(BlobTables {
170 blob,
171 tables: Box::new(tables),
172 })))
173 }
174 Source::TableFunction(func) => Some(Self(TableSource::Function(func))),
175 }
176 }
177}
178
179impl Tables {
180 fn load_table<'a, T: TopLevelTable + FontRead<'a, Args = ()>>(
181 &'a self,
182 state: Option<TableState<'a>>,
183 ) -> Result<T, ReadError> {
184 self.load_table_with_tag(state, T::TAG)
185 }
186
187 fn load_table_with_tag<'a, T: FontRead<'a, Args = ()>>(
188 &'a self,
189 state: Option<TableState<'a>>,
190 tag: Tag,
191 ) -> Result<T, ReadError> {
192 let state = state.ok_or(ReadError::TableIsMissing(tag))?;
193 state.try_load(
194 |data| FontRead::read(data.into()),
195 |data| FontRead::read(data.into()),
196 )
197 }
198
199 fn load_table_with_args<'a, T: TopLevelTable + FontRead<'a>>(
200 &'a self,
201 state: Option<TableState<'a>>,
202 args: T::Args,
203 ) -> Result<T, ReadError> {
204 let state = state.ok_or(ReadError::TableIsMissing(T::TAG))?;
205 state.try_load(
206 |data| FontRead::read_with_args(data.into(), args),
207 |data| FontRead::read_with_args(data.into(), args),
208 )
209 }
210}
211
212pub(super) static EMPTY_FONT_TABLES: Tables = Tables(TableSource::None);
213
214impl<'a> TableProvider<'a> for &'a Tables {
215 fn data_for_tag(&self, _tag: Tag) -> Option<crate::FontData<'a>> {
216 None
217 }
218
219 fn head(&self) -> Result<tables::head::Head<'a>, ReadError> {
220 self.load_table(self.head_state())
221 }
222
223 fn name(&self) -> Result<tables::name::Name<'a>, ReadError> {
224 self.load_table(self.name_state())
225 }
226
227 fn hhea(&self) -> Result<tables::hhea::Hhea<'a>, ReadError> {
228 self.load_table(self.hhea_state())
229 }
230
231 fn vhea(&self) -> Result<tables::vhea::Vhea<'a>, ReadError> {
232 self.load_table(self.vhea_state())
233 }
234
235 fn hhea_extended(&self) -> Result<tables::hhea::HheaExtended<'a>, ReadError> {
236 self.load_table(self.hhea_extended_state())
237 }
238
239 fn vhea_extended(&self) -> Result<tables::vhea::VheaExtended<'a>, ReadError> {
240 self.load_table(self.vhea_extended_state())
241 }
242
243 fn hmtx(&self) -> Result<tables::hmtx::Hmtx<'a>, ReadError> {
244 let number_of_h_metrics = self.hhea().map(|hhea| hhea.number_of_h_metrics())?;
246 self.load_table_with_args(self.hmtx_state(), number_of_h_metrics)
247 }
248
249 fn hmtx_extended(&self) -> Result<tables::hmtx::HmtxExtended<'a>, ReadError> {
250 let state = self
251 .hmtx_extended_state()
252 .ok_or(ReadError::TableIsMissing(tables::hmtx::HmtxExtended::TAG))?;
253 let count = self.hhea_extended()?.number_of_h_metrics();
254 self.load_table_with_args(Some(state), count)
255 }
256
257 fn hdmx(&self) -> Result<tables::hdmx::Hdmx<'a>, ReadError> {
258 let num_glyphs = self.selected_maxp()?.num_glyphs();
259 self.load_table_with_args(self.hdmx_state(), num_glyphs)
260 }
261
262 fn vmtx(&self) -> Result<tables::vmtx::Vmtx<'a>, ReadError> {
263 let number_of_v_metrics = self.vhea().map(|vhea| vhea.number_of_long_ver_metrics())?;
265 self.load_table_with_args(self.vmtx_state(), number_of_v_metrics)
266 }
267
268 fn vmtx_extended(&self) -> Result<tables::vmtx::VmtxExtended<'a>, ReadError> {
269 let state = self
270 .vmtx_extended_state()
271 .ok_or(ReadError::TableIsMissing(tables::vmtx::VmtxExtended::TAG))?;
272 let count = self.vhea_extended()?.number_of_long_ver_metrics();
273 self.load_table_with_args(Some(state), count)
274 }
275
276 fn vorg(&self) -> Result<tables::vorg::Vorg<'a>, ReadError> {
277 self.load_table(self.vorg_state())
278 }
279
280 fn fvar(&self) -> Result<tables::fvar::Fvar<'a>, ReadError> {
281 self.load_table(self.fvar_state())
282 }
283
284 fn avar(&self) -> Result<tables::avar::Avar<'a>, ReadError> {
285 self.load_table(self.avar_state())
286 }
287
288 fn hvar(&self) -> Result<tables::hvar::Hvar<'a>, ReadError> {
289 self.load_table(self.hvar_state())
290 }
291
292 fn vvar(&self) -> Result<tables::vvar::Vvar<'a>, ReadError> {
293 self.load_table(self.vvar_state())
294 }
295
296 fn mvar(&self) -> Result<tables::mvar::Mvar<'a>, ReadError> {
297 self.load_table(self.mvar_state())
298 }
299
300 fn maxp(&self) -> Result<tables::maxp::Maxp<'a>, ReadError> {
301 self.load_table(self.maxp_state())
302 }
303
304 fn maxp_extended(&self) -> Result<tables::maxp::MaxpExtended<'a>, ReadError> {
305 self.load_table(self.maxp_extended_state())
306 }
307
308 fn os2(&self) -> Result<tables::os2::Os2<'a>, ReadError> {
309 self.load_table(self.os2_state())
310 }
311
312 fn post(&self) -> Result<tables::post::Post<'a>, ReadError> {
313 self.load_table(self.post_state())
314 }
315
316 fn gasp(&self) -> Result<tables::gasp::Gasp<'a>, ReadError> {
317 self.load_table(self.gasp_state())
318 }
319
320 fn loca(&self, is_long: impl Into<Option<bool>>) -> Result<tables::loca::Loca<'a>, ReadError> {
322 let is_long = match is_long.into() {
323 Some(val) => val,
324 None => self.head()?.index_to_loc_format() == 1,
325 };
326 self.load_table_with_args(self.loca_state(), is_long)
327 }
328
329 fn glyf(&self) -> Result<tables::glyf::Glyf<'a>, ReadError> {
330 self.load_table(self.glyf_state())
331 }
332
333 fn glyf_extended(&self) -> Result<tables::glyf::Glyf<'a>, ReadError> {
334 self.load_table_with_tag(self.glyf_extended_state(), Tag::new(b"GLYF"))
335 }
336
337 fn loca_extended(
338 &self,
339 is_long: impl Into<Option<bool>>,
340 ) -> Result<tables::loca::Loca<'a>, ReadError> {
341 let state = self
342 .loca_extended_state()
343 .ok_or(ReadError::TableIsMissing(Tag::new(b"LOCA")))?;
344 let is_long = match is_long.into() {
345 Some(val) => val,
346 None => self.head()?.index_to_loc_format() == 1,
347 };
348 self.load_table_with_args(Some(state), is_long)
349 }
350
351 fn gvar(&self) -> Result<tables::gvar::Gvar<'a>, ReadError> {
352 self.load_table(self.gvar_state())
353 }
354
355 fn gvar_extended(&self) -> Result<tables::gvar::GvarExtended<'a>, ReadError> {
356 self.load_table(self.gvar_extended_state())
357 }
358
359 fn cvt(&self) -> Result<&'a [types::BigEndian<i16>], ReadError> {
362 let table_data = crate::FontData::new(
363 self.cvt_data()
364 .ok_or(ReadError::TableIsMissing(Tag::new(b"cvt ")))?,
365 );
366 table_data.read_array(0..table_data.len())
367 }
368
369 fn fpgm(&self) -> Result<&'a [u8], ReadError> {
370 self.fpgm_data()
371 .ok_or(ReadError::TableIsMissing(Tag::new(b"fpgm")))
372 }
373
374 fn prep(&self) -> Result<&'a [u8], ReadError> {
375 self.prep_data()
376 .ok_or(ReadError::TableIsMissing(Tag::new(b"prep")))
377 }
378
379 fn cvar(&self) -> Result<tables::cvar::Cvar<'a>, ReadError> {
380 self.load_table(self.cvar_state())
381 }
382
383 fn cff(&self) -> Result<tables::cff::Cff<'a>, ReadError> {
384 self.load_table(self.cff_state())
385 }
386
387 fn cff2(&self) -> Result<tables::cff2::Cff2<'a>, ReadError> {
388 self.load_table(self.cff2_state())
389 }
390
391 fn cmap(&self) -> Result<tables::cmap::Cmap<'a>, ReadError> {
392 self.load_table(self.cmap_state())
393 }
394
395 fn dmap(&self) -> Result<tables::cmap::Dmap<'a>, ReadError> {
396 self.load_table(self.dmap_state())
397 }
398
399 fn gdef(&self) -> Result<tables::gdef::Gdef<'a>, ReadError> {
400 self.load_table(self.gdef_state())
401 }
402
403 fn gpos(&self) -> Result<tables::gpos::Gpos<'a>, ReadError> {
404 self.load_table(self.gpos_state())
405 }
406
407 fn gsub(&self) -> Result<tables::gsub::Gsub<'a>, ReadError> {
408 self.load_table(self.gsub_state())
409 }
410
411 fn feat(&self) -> Result<tables::feat::Feat<'a>, ReadError> {
412 self.load_table(self.feat_state())
413 }
414
415 fn ltag(&self) -> Result<tables::ltag::Ltag<'a>, ReadError> {
416 self.load_table(self.ltag_state())
417 }
418
419 fn ankr(&self) -> Result<tables::ankr::Ankr<'a>, ReadError> {
420 self.load_table(self.ankr_state())
421 }
422
423 fn trak(&self) -> Result<tables::trak::Trak<'a>, ReadError> {
424 self.load_table(self.trak_state())
425 }
426
427 fn morx(&self) -> Result<tables::morx::Morx<'a>, ReadError> {
428 self.load_table(self.morx_state())
429 }
430
431 fn mort(&self) -> Result<tables::mort::Mort<'a>, ReadError> {
432 self.load_table(self.mort_state())
433 }
434
435 fn kerx(&self) -> Result<tables::kerx::Kerx<'a>, ReadError> {
436 self.load_table(self.kerx_state())
437 }
438
439 fn kern(&self) -> Result<tables::kern::Kern<'a>, ReadError> {
440 self.load_table(self.kern_state())
441 }
442
443 fn colr(&self) -> Result<tables::colr::Colr<'a>, ReadError> {
444 self.load_table(self.colr_state())
445 }
446
447 fn cpal(&self) -> Result<tables::cpal::Cpal<'a>, ReadError> {
448 self.load_table(self.cpal_state())
449 }
450
451 fn cblc(&self) -> Result<tables::cblc::Cblc<'a>, ReadError> {
452 self.load_table(self.cblc_state())
453 }
454
455 fn cbdt(&self) -> Result<tables::cbdt::Cbdt<'a>, ReadError> {
456 self.load_table(self.cbdt_state())
457 }
458
459 fn eblc(&self) -> Result<tables::eblc::Eblc<'a>, ReadError> {
460 self.load_table(self.eblc_state())
461 }
462
463 fn ebdt(&self) -> Result<tables::ebdt::Ebdt<'a>, ReadError> {
464 self.load_table(self.ebdt_state())
465 }
466
467 fn sbix(&self) -> Result<tables::sbix::Sbix<'a>, ReadError> {
468 let num_glyphs = self.selected_maxp()?.num_glyphs();
470 self.load_table_with_args(self.sbix_state(), num_glyphs)
471 }
472
473 fn stat(&self) -> Result<tables::stat::Stat<'a>, ReadError> {
474 self.load_table(self.stat_state())
475 }
476
477 fn svg(&self) -> Result<tables::svg::Svg<'a>, ReadError> {
478 self.load_table(self.svg_state())
479 }
480
481 fn varc(&self) -> Result<tables::varc::Varc<'a>, ReadError> {
482 self.load_table(self.varc_state())
483 }
484
485 #[cfg(feature = "ift")]
486 fn ift(&self) -> Result<tables::ift::IftPatchMap<'a>, ReadError> {
487 self.load_table_with_tag(self.ift_state(), Tag::new(b"IFT "))
488 }
489
490 #[cfg(feature = "ift")]
491 fn iftx(&self) -> Result<tables::ift::IftPatchMap<'a>, ReadError> {
492 self.load_table_with_tag(self.iftx_state(), Tag::new(b"IFTX"))
493 }
494
495 fn meta(&self) -> Result<tables::meta::Meta<'a>, ReadError> {
496 self.load_table(self.meta_state())
497 }
498
499 fn base(&self) -> Result<tables::base::Base<'a>, ReadError> {
500 self.load_table(self.base_state())
501 }
502
503 fn dsig(&self) -> Result<tables::dsig::Dsig<'a>, ReadError> {
504 self.load_table(self.dsig_state())
505 }
506
507 fn math(&self) -> Result<tables::math::Math<'a>, ReadError> {
508 self.load_table(self.math_state())
509 }
510}
511
512#[cfg(test)]
513mod tests {
514 use crate::FontRef;
515
516 use super::*;
517
518 #[test]
520 fn unsorted_directory_finds_tables() {
521 let data = font_test_data::TINOS_SUBSET;
522 let count = u16::from_be_bytes([data[4], data[5]]) as usize;
523 let mut unsorted = data[..12].to_vec();
524 for record in data[12..12 + 16 * count].chunks_exact(16).rev() {
525 unsorted.extend_from_slice(record);
526 }
527 unsorted.extend_from_slice(&data[12 + 16 * count..]);
528 let font = FontRef::new(&unsorted).unwrap();
529 assert!(!font.table_directory().is_sorted());
530 let tables = &Tables::new(unsorted.clone(), 0).unwrap();
531 let bytes = |data: Option<crate::FontData>| data.map(|data| data.as_bytes().to_vec());
532 assert_eq!(
533 bytes(tables.head().ok().map(|t| t.offset_data())),
534 bytes(font.head().ok().map(|t| t.offset_data()))
535 );
536 assert!(tables.cmap().is_ok());
537 assert!(tables.hmtx().is_ok());
538 assert!(tables.name().is_ok());
539 assert!(tables.glyf().is_ok());
540 assert!(tables.loca(None).is_ok());
541 }
542
543 #[test]
544 fn missing_tables_are_missing() {
545 let tables = &Tables::new(font_test_data::AHEM, 0).unwrap();
546 assert!(matches!(tables.cbdt(), Err(ReadError::TableIsMissing(_))));
547 assert!(matches!(tables.cff(), Err(ReadError::TableIsMissing(_))));
548 assert!(matches!(tables.dsig(), Err(ReadError::TableIsMissing(_))));
549 }
550
551 #[test]
552 fn table_function_matches_font_ref() {
553 let font = FontRef::new(font_test_data::AHEM).unwrap();
554 let font_copy = font.clone();
555 let table_fn = TableFunction::new(Arc::new(move |tag| {
556 font_copy
557 .data_for_tag(tag)
558 .map(|data| Vec::from(data.as_bytes()).into())
559 }));
560 let tables = &Tables::new(table_fn, 0).unwrap();
561 for (data, tag) in [
562 (tables.gasp_data(), b"gasp"),
563 (tables.glyf_data(), b"glyf"),
564 (tables.hmtx_data(), b"hmtx"),
565 ] {
566 let font_ref_data = font.data_for_tag(Tag::new(tag)).map(|d| d.as_bytes());
567 assert_eq!(data, font_ref_data);
568 }
569 }
570}