use core::num::NonZeroU16;
use crate::parser::{FromData, LazyArray32, NumFrom, Offset, Offset32, Stream};
use crate::{aat, GlyphId};
#[derive(Clone, Copy, Debug)]
pub struct Feature {
pub kind: u16,
pub setting: u16,
pub enable_flags: u32,
pub disable_flags: u32,
}
impl FromData for Feature {
const SIZE: usize = 12;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(Feature {
kind: s.read::<u16>()?,
setting: s.read::<u16>()?,
enable_flags: s.read::<u32>()?,
disable_flags: s.read::<u32>()?,
})
}
}
#[derive(Clone, Copy, Debug)]
pub struct ContextualEntryData {
pub mark_index: u16,
pub current_index: u16,
}
impl FromData for ContextualEntryData {
const SIZE: usize = 4;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(ContextualEntryData {
mark_index: s.read::<u16>()?,
current_index: s.read::<u16>()?,
})
}
}
#[derive(Clone)]
pub struct ContextualSubtable<'a> {
pub state: aat::ExtendedStateTable<'a, ContextualEntryData>,
offsets_data: &'a [u8],
offsets: LazyArray32<'a, Offset32>,
number_of_glyphs: NonZeroU16,
}
impl<'a> ContextualSubtable<'a> {
fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let state = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
let offset = s.read::<Offset32>()?.to_usize();
let offsets_data = data.get(offset..)?;
let offsets = LazyArray32::<Offset32>::new(offsets_data);
Some(ContextualSubtable {
state,
offsets_data,
offsets,
number_of_glyphs,
})
}
pub fn lookup(&self, index: u32) -> Option<aat::Lookup<'a>> {
let offset = self.offsets.get(index)?.to_usize();
let lookup_data = self.offsets_data.get(offset..)?;
aat::Lookup::parse(self.number_of_glyphs, lookup_data)
}
}
impl core::fmt::Debug for ContextualSubtable<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "ContextualSubtable {{ ... }}")
}
}
#[derive(Clone, Debug)]
pub struct LigatureSubtable<'a> {
pub state: aat::ExtendedStateTable<'a, u16>,
pub ligature_actions: LazyArray32<'a, u32>,
pub components: LazyArray32<'a, u16>,
pub ligatures: LazyArray32<'a, GlyphId>,
}
impl<'a> LigatureSubtable<'a> {
fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let state = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
let ligature_action_offset = s.read::<Offset32>()?.to_usize();
let component_offset = s.read::<Offset32>()?.to_usize();
let ligature_offset = s.read::<Offset32>()?.to_usize();
let ligature_actions = LazyArray32::<u32>::new(data.get(ligature_action_offset..)?);
let components = LazyArray32::<u16>::new(data.get(component_offset..)?);
let ligatures = LazyArray32::<GlyphId>::new(data.get(ligature_offset..)?);
Some(LigatureSubtable {
state,
ligature_actions,
components,
ligatures,
})
}
}
#[derive(Clone, Copy, Debug)]
pub struct InsertionEntryData {
pub current_insert_index: u16,
pub marked_insert_index: u16,
}
impl FromData for InsertionEntryData {
const SIZE: usize = 4;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(InsertionEntryData {
current_insert_index: s.read::<u16>()?,
marked_insert_index: s.read::<u16>()?,
})
}
}
#[derive(Clone, Debug)]
pub struct InsertionSubtable<'a> {
pub state: aat::ExtendedStateTable<'a, InsertionEntryData>,
pub glyphs: LazyArray32<'a, GlyphId>,
}
impl<'a> InsertionSubtable<'a> {
fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let state = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
let offset = s.read::<Offset32>()?.to_usize();
let glyphs = LazyArray32::<GlyphId>::new(data.get(offset..)?);
Some(InsertionSubtable { state, glyphs })
}
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub enum SubtableKind<'a> {
Rearrangement(aat::ExtendedStateTable<'a, ()>),
Contextual(ContextualSubtable<'a>),
Ligature(LigatureSubtable<'a>),
NonContextual(aat::Lookup<'a>),
Insertion(InsertionSubtable<'a>),
}
#[derive(Clone, Copy, Debug)]
pub struct Coverage(u8);
#[rustfmt::skip]
impl Coverage {
#[inline] pub fn is_logical(self) -> bool { self.0 & 0x10 != 0 }
#[inline] pub fn is_all_directions(self) -> bool { self.0 & 0x20 != 0 }
#[inline] pub fn is_backwards(self) -> bool { self.0 & 0x40 != 0 }
#[inline] pub fn is_vertical(self) -> bool { self.0 & 0x80 != 0 }
}
#[derive(Clone, Debug)]
pub struct Subtable<'a> {
pub kind: SubtableKind<'a>,
pub coverage: Coverage,
pub feature_flags: u32,
}
#[derive(Clone, Copy)]
pub struct Subtables<'a> {
count: u32,
data: &'a [u8],
number_of_glyphs: NonZeroU16,
}
impl<'a> IntoIterator for Subtables<'a> {
type Item = Subtable<'a>;
type IntoIter = SubtablesIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
SubtablesIter {
index: 0,
count: self.count,
stream: Stream::new(self.data),
number_of_glyphs: self.number_of_glyphs,
}
}
}
impl core::fmt::Debug for Subtables<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Subtables {{ ... }}")
}
}
#[allow(missing_debug_implementations)]
#[derive(Clone)]
pub struct SubtablesIter<'a> {
index: u32,
count: u32,
stream: Stream<'a>,
number_of_glyphs: NonZeroU16,
}
impl<'a> Iterator for SubtablesIter<'a> {
type Item = Subtable<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.count {
return None;
}
let s = &mut self.stream;
if s.at_end() {
return None;
}
let len = s.read::<u32>()?;
let coverage = Coverage(s.read::<u8>()?);
s.skip::<u16>(); let kind = s.read::<u8>()?;
let feature_flags = s.read::<u32>()?;
const HEADER_LEN: usize = 12;
let len = usize::num_from(len).checked_sub(HEADER_LEN)?;
let subtables_data = s.read_bytes(len)?;
let kind = match kind {
0 => {
let mut s = Stream::new(subtables_data);
let table = aat::ExtendedStateTable::parse(self.number_of_glyphs, &mut s)?;
SubtableKind::Rearrangement(table)
}
1 => {
let table = ContextualSubtable::parse(self.number_of_glyphs, subtables_data)?;
SubtableKind::Contextual(table)
}
2 => {
let table = LigatureSubtable::parse(self.number_of_glyphs, subtables_data)?;
SubtableKind::Ligature(table)
}
4 => SubtableKind::NonContextual(aat::Lookup::parse(
self.number_of_glyphs,
subtables_data,
)?),
5 => {
let table = InsertionSubtable::parse(self.number_of_glyphs, subtables_data)?;
SubtableKind::Insertion(table)
}
_ => return None,
};
Some(Subtable {
kind,
coverage,
feature_flags,
})
}
}
#[derive(Clone, Copy, Debug)]
pub struct Chain<'a> {
pub default_flags: u32,
pub features: LazyArray32<'a, Feature>,
pub subtables: Subtables<'a>,
}
#[derive(Clone, Copy)]
pub struct Chains<'a> {
data: &'a [u8],
count: u32,
number_of_glyphs: NonZeroU16,
}
impl<'a> Chains<'a> {
fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
s.skip::<u16>(); s.skip::<u16>(); let count = s.read::<u32>()?;
Some(Chains {
count,
data: s.tail()?,
number_of_glyphs,
})
}
}
impl<'a> IntoIterator for Chains<'a> {
type Item = Chain<'a>;
type IntoIter = ChainsIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
ChainsIter {
index: 0,
count: self.count,
stream: Stream::new(self.data),
number_of_glyphs: self.number_of_glyphs,
}
}
}
impl core::fmt::Debug for Chains<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Chains {{ ... }}")
}
}
#[allow(missing_debug_implementations)]
#[derive(Clone)]
pub struct ChainsIter<'a> {
index: u32,
count: u32,
stream: Stream<'a>,
number_of_glyphs: NonZeroU16,
}
impl<'a> Iterator for ChainsIter<'a> {
type Item = Chain<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.count {
return None;
}
if self.stream.at_end() {
return None;
}
let default_flags = self.stream.read::<u32>()?;
let len = self.stream.read::<u32>()?;
let features_count = self.stream.read::<u32>()?;
let subtables_count = self.stream.read::<u32>()?;
let features = self.stream.read_array32::<Feature>(features_count)?;
const HEADER_LEN: usize = 16;
let len = usize::num_from(len)
.checked_sub(HEADER_LEN)?
.checked_sub(Feature::SIZE * usize::num_from(features_count))?;
let subtables_data = self.stream.read_bytes(len)?;
let subtables = Subtables {
data: subtables_data,
count: subtables_count,
number_of_glyphs: self.number_of_glyphs,
};
Some(Chain {
default_flags,
features,
subtables,
})
}
}
#[derive(Clone)]
pub struct Table<'a> {
pub chains: Chains<'a>,
}
impl core::fmt::Debug for Table<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Table {{ ... }}")
}
}
impl<'a> Table<'a> {
pub fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
Chains::parse(number_of_glyphs, data).map(|chains| Self { chains })
}
}