//! A [Font Header Table]( //! https://docs.microsoft.com/en-us/typography/opentype/spec/head) implementation. use crate::parser::{Fixed, Stream}; use crate::Rect; /// An index format used by the [Index to Location Table]( /// https://docs.microsoft.com/en-us/typography/opentype/spec/loca). #[allow(missing_docs)] #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum IndexToLocationFormat { Short, Long, } /// A [Font Header Table](https://docs.microsoft.com/en-us/typography/opentype/spec/head). #[derive(Clone, Copy, Debug)] pub struct Table { /// Units per EM. /// /// Guarantee to be in a 16..=16384 range. pub units_per_em: u16, /// A bounding box that large enough to enclose any glyph from the face. pub global_bbox: Rect, /// An index format used by the [Index to Location Table]( /// https://docs.microsoft.com/en-us/typography/opentype/spec/loca). pub index_to_location_format: IndexToLocationFormat, } impl Table { /// Parses a table from raw data. pub fn parse(data: &[u8]) -> Option { // Do not check the exact length, because some fonts include // padding in table's length in table records, which is incorrect. if data.len() < 54 { return None; } let mut s = Stream::new(data); s.skip::(); // version s.skip::(); // font revision s.skip::(); // checksum adjustment s.skip::(); // magic number s.skip::(); // flags let units_per_em = s.read::()?; s.skip::(); // created time s.skip::(); // modified time let x_min = s.read::()?; let y_min = s.read::()?; let x_max = s.read::()?; let y_max = s.read::()?; s.skip::(); // mac style s.skip::(); // lowest PPEM s.skip::(); // font direction hint let index_to_location_format = s.read::()?; if !(16..=16384).contains(&units_per_em) { return None; } let index_to_location_format = match index_to_location_format { 0 => IndexToLocationFormat::Short, 1 => IndexToLocationFormat::Long, _ => return None, }; Some(Table { units_per_em, global_bbox: Rect { x_min, y_min, x_max, y_max, }, index_to_location_format, }) } }