use super::shared::*;
use crate::parse_prelude::*;
use crate::var::item::ItemVariationStore;
#[derive(Copy, Clone)]
pub struct Gdef<'a> {
data: Buffer<'a>,
classes: u16,
mark_classes: u16,
mark_sets: u16,
var_store: u32,
}
impl<'a> Gdef<'a> {
pub fn new(gdef: &'a [u8]) -> Option<Self> {
let b = Buffer::new(gdef);
let major = b.read::<u16>(0)?;
let minor = b.read::<u16>(2)?;
let classes = b.read::<u16>(4)?;
let mark_classes = b.read::<u16>(10)?;
let mark_sets = if major > 1 || minor >= 2 {
b.read_or_default::<u16>(12)
} else {
0
};
let var_store = if major > 1 || minor >= 3 {
b.read_or_default::<u32>(14)
} else {
0
};
Some(Self {
data: b,
classes,
mark_classes,
mark_sets,
var_store,
})
}
pub fn has_classes(&self) -> bool {
self.classes != 0
}
pub fn class(&self, glyph_id: u16) -> u16 {
get_class(&self.data, self.classes as u32, glyph_id)
}
pub fn classes(&self) -> Option<ClassDef<'a>> {
if self.classes != 0 {
Some(ClassDef::new(self.data, self.classes as u32))
} else {
None
}
}
pub fn has_mark_classes(&self) -> bool {
self.mark_classes != 0
}
pub fn mark_class(&self, glyph_id: u16) -> u16 {
get_class(&self.data, self.mark_classes as u32, glyph_id)
}
pub fn mark_classes(&self) -> Option<ClassDef<'a>> {
if self.mark_classes != 0 {
Some(ClassDef::new(self.data, self.mark_classes as u32))
} else {
None
}
}
pub fn has_mark_sets(&self) -> bool {
self.mark_sets != 0
}
pub fn num_mark_sets(&self) -> u16 {
if self.mark_sets != 0 {
self.data
.read::<u16>(self.mark_sets as usize + 2)
.unwrap_or(0)
} else {
0
}
}
pub fn mark_set(&self, index: u16) -> Option<Coverage<'a>> {
Some(Coverage::new(self.data, self.mark_set_offset(index)?))
}
pub fn mark_sets(&self) -> impl Iterator<Item = Coverage<'a>> + '_ + Clone {
let len = self.num_mark_sets();
(0..len).map(move |index| {
let offset = self.mark_set_offset(index).unwrap_or(0);
Coverage::new(self.data, offset)
})
}
pub fn supports_variations(&self) -> bool {
self.var_store != 0
}
pub fn ivs(&self) -> Option<ItemVariationStore<'a>> {
if self.var_store != 0 {
ItemVariationStore::new(self.data, self.var_store)
} else {
None
}
}
pub(super) fn _mark_set_coverage(&self, set_offset: u32, glyph_id: u16) -> Option<u16> {
if set_offset == 0 {
return None;
}
unsafe { _get_coverage_unchecked(&self.data, set_offset, glyph_id) }
}
pub(super) fn mark_set_offset(&self, set_index: u16) -> Option<u32> {
if self.mark_sets == 0 {
return None;
}
let set = set_index as usize;
let b = &self.data;
let sets_base = self.mark_sets as usize;
let len = b.read::<u16>(sets_base + 2)? as usize;
if set >= len {
return None;
}
let offset = b.read::<u32>(sets_base + 4 + set * 4)?;
let set_offset = sets_base as u32 + offset;
if offset != 0 && validate_coverage(b, set_offset).is_some() {
return Some(set_offset);
}
None
}
}