use super::Tables;
use crate::model::glyph::outline::varc;
use crate::ps::cff::CffFontRef;
use crate::tables::{
cbdt::Cbdt,
cblc::Cblc,
colr::Colr,
cpal::Cpal,
ebdt::Ebdt,
eblc::Eblc,
glyf::Glyf,
gvar::SelectedGvar,
hmtx::GlyphMetricRecords,
hvar::Hvar,
loca::Loca,
sbix::Sbix,
variations::{DeltaSetIndexMap, ItemVariationStore},
vorg::Vorg,
vvar::Vvar,
};
use crate::TableProvider;
use alloc::sync::Arc;
use yoke::{Yoke, Yokeable};
fn units_per_em<'a>(tables: &impl TableProvider<'a>) -> u16 {
crate::model::metrics::units_per_em(tables.head().map_or(0, |head| head.units_per_em()))
}
pub(crate) struct TableCache<Y: for<'a> Yokeable<'a>>(Yoke<Y, Arc<Tables>>);
impl<Y: for<'a> Yokeable<'a>> TableCache<Y> {
pub(crate) fn read<F>(tables: Arc<Tables>, read: F) -> Self
where
F: for<'a> FnOnce(&'a Tables) -> <Y as Yokeable<'a>>::Output,
{
Self(Yoke::attach_to_cart(tables, read))
}
#[inline]
pub(crate) fn get(&self) -> &<Y as Yokeable<'_>>::Output {
self.0.get()
}
}
#[derive(Clone, Default, Yokeable)]
pub(crate) struct GlyfLoca<'a>(pub(crate) Option<(Glyf<'a>, Loca<'a>)>);
impl<'a> GlyfLoca<'a> {
pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
Self(tables.selected_glyf_loca(None).ok())
}
}
#[derive(Clone, Default, Yokeable)]
pub(crate) struct MetricsTable<'a>(pub(crate) GlyphMetricRecords<'a>);
#[derive(Clone, Default, Yokeable)]
pub(crate) struct HvarTable<'a>(pub(crate) Option<Hvar<'a>>);
impl<'a> HvarTable<'a> {
pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
Self(tables.hvar().ok())
}
}
#[derive(Clone, Default, Yokeable)]
pub(crate) struct VvarTable<'a>(pub(crate) Option<Vvar<'a>>);
impl<'a> VvarTable<'a> {
pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
Self(tables.vvar().ok())
}
}
#[derive(Clone, Default, Yokeable)]
pub(crate) struct GvarTable<'a>(pub(crate) Option<SelectedGvar<'a>>);
impl<'a> GvarTable<'a> {
pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
Self(tables.selected_gvar().ok())
}
}
#[derive(Clone, Default, Yokeable)]
pub(crate) struct Cff2Font<'a>(pub(crate) Option<CffFontRef<'a>>);
impl<'a> Cff2Font<'a> {
pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
let upem = Some(units_per_em(tables) as i32);
Self(
tables
.cff2()
.ok()
.and_then(|cff2| CffFontRef::new(cff2.offset_data().as_bytes(), 0, upem).ok()),
)
}
}
#[derive(Clone, Default, Yokeable)]
pub(crate) struct CffFont<'a>(pub(crate) Option<CffFontRef<'a>>);
impl<'a> CffFont<'a> {
pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
let upem = Some(units_per_em(tables) as i32);
Self(
tables
.cff()
.ok()
.and_then(|cff| CffFontRef::new(cff.offset_data().as_bytes(), 0, upem).ok()),
)
}
}
#[derive(Clone, Default, Yokeable)]
pub(crate) struct VorgTable<'a>(pub(crate) Option<Vorg<'a>>);
impl<'a> VorgTable<'a> {
pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
Self(tables.vorg().ok())
}
}
impl<'a> varc::Outlines<'a> {
pub(crate) fn read(tables: &impl TableProvider<'a>) -> Option<Self> {
let varc = tables.varc().ok()?;
let upem = units_per_em(tables);
let mut axis_count = tables
.fvar()
.map(|fvar| fvar.axis_count() as usize)
.unwrap_or_default();
if let Ok(gvar) = tables.gvar() {
axis_count = axis_count.max(gvar.axis_count() as usize);
}
if let Ok(gvar) = tables.gvar_extended() {
axis_count = axis_count.max(gvar.axis_count() as usize);
}
if let Some(count) = tables
.cff2()
.ok()
.and_then(|cff2| CffFontRef::new(cff2.offset_data().as_bytes(), 0, None).ok())
.and_then(|cff| cff.var_store()?.variation_region_list().ok())
.map(|regions| regions.axis_count() as usize)
{
axis_count = axis_count.max(count);
}
varc::Outlines::new(varc, upem, axis_count).ok()
}
}
#[derive(Clone, Yokeable)]
pub(crate) struct ColrTables<'a> {
pub(crate) colr: Colr<'a>,
pub(crate) index_map: Option<DeltaSetIndexMap<'a>>,
pub(crate) var_store: Option<ItemVariationStore<'a>>,
}
impl<'a> ColrTables<'a> {
pub(crate) fn read(tables: &impl TableProvider<'a>) -> Option<Self> {
tables.colr().ok().map(Self::new)
}
pub(crate) fn new(colr: Colr<'a>) -> Self {
Self {
index_map: colr.var_index_map().and_then(|map| map.ok()),
var_store: colr.item_variation_store().and_then(|store| store.ok()),
colr,
}
}
}
#[derive(Clone, Default, Yokeable)]
pub(crate) struct CpalTable<'a>(pub(crate) Option<Cpal<'a>>);
impl<'a> CpalTable<'a> {
pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
Self(tables.cpal().ok())
}
}
#[derive(Clone, Default, Yokeable)]
pub(crate) struct SbixTable<'a>(pub(crate) Option<Sbix<'a>>);
impl<'a> SbixTable<'a> {
pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
Self(tables.sbix().ok())
}
}
#[derive(Clone, Default, Yokeable)]
pub(crate) struct CbdtTables<'a>(pub(crate) Option<(Cblc<'a>, Cbdt<'a>)>);
impl<'a> CbdtTables<'a> {
pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
Self(tables.cblc().ok().zip(tables.cbdt().ok()))
}
}
#[derive(Clone, Default, Yokeable)]
pub(crate) struct EbdtTables<'a>(pub(crate) Option<(Eblc<'a>, Ebdt<'a>)>);
impl<'a> EbdtTables<'a> {
pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
Self(tables.eblc().ok().zip(tables.ebdt().ok()))
}
}