use std::ops::Deref; use std::fmt::{ Debug, Formatter, Result as FmtResult }; use bytemuck::{ Zeroable, Pod }; use super::ReadError; use super::core::*; // Version 0 #[derive(Clone, Copy, Zeroable, Pod)] #[repr(transparent)] pub struct Os2MetricsTable0([u8; 78]); impl<'a> RandomAccess<'a> for &'a Os2MetricsTable0 { fn bytes(&self) -> &'a [u8] { &self.0 } } impl Os2MetricsTable0 { pub fn version(&self) -> u16 { self.uint16(0) } pub fn avg_char_width(&self) -> i16 { self.int16(2) } pub fn weight_class(&self) -> u16 { self.uint16(4) } pub fn width_class(&self) -> u16 { self.uint16(6) } pub fn type_flags(&self) -> u16 { self.uint16(8) } pub fn subscript_size(&self) -> (i16, i16) { (self.int16(10), self.int16(12)) } pub fn subscript_offset(&self) -> (i16, i16) { (self.int16(14), self.int16(16)) } pub fn superscript_size(&self) -> (i16, i16) { (self.int16(18), self.int16(20)) } pub fn superscript_offset(&self) -> (i16, i16) { (self.int16(22), self.int16(24)) } pub fn strikeout_size(&self) -> i16 { self.int16(26) } pub fn strikeout_position(&self) -> i16 { self.int16(28) } pub fn family_class(&self) -> i16 { self.int16(30) } pub fn panose(&self) -> &[u8; 10] { self.item(32) } pub fn unicode_range_1(&self) -> u32 { self.uint32(42) } pub fn unicode_range_2(&self) -> u32 { self.uint32(46) } pub fn unicode_range_3(&self) -> u32 { self.uint32(50) } pub fn unicode_range_4(&self) -> u32 { self.uint32(54) } pub fn vendor_id(&self) -> &Tag { self.item(58) } pub fn selection_flags(&self) -> u16 { self.uint16(62) } pub fn first_char_index(&self) -> u16 { self.uint16(64) } pub fn last_char_index(&self) -> u16 { self.uint16(66) } pub fn typo_ascender(&self) -> i16 { self.int16(68) } pub fn typo_descender(&self) -> i16 { self.int16(70) } pub fn typo_line_gap(&self) -> i16 { self.int16(72) } pub fn win_ascent(&self) -> u16 { self.uint16(74) } pub fn win_descent(&self) -> u16 { self.uint16(76) } } impl Debug for Os2MetricsTable0 { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("Os2MetricsTable0") .field("version", &self.version()) .field("avg_char_width", &self.avg_char_width()) .field("weight_class", &self.weight_class()) .field("width_class", &self.width_class()) .field("type_flags", &self.type_flags()) .field("subscript_size", &self.subscript_size()) .field("subscript_offset", &self.subscript_offset()) .field("superscript_size", &self.superscript_size()) .field("superscript_offset", &self.superscript_offset()) .field("strikeout_size", &self.strikeout_size()) .field("strikeout_position", &self.strikeout_position()) .field("family_class", &self.family_class()) .field("panose", &self.panose()) .field("unicode_range_1", &self.unicode_range_1()) .field("unicode_range_2", &self.unicode_range_2()) .field("unicode_range_3", &self.unicode_range_3()) .field("unicode_range_4", &self.unicode_range_4()) .field("vendor_id", &self.vendor_id()) .field("selection_flags", &self.selection_flags()) .field("first_char_index", &self.first_char_index()) .field("last_char_index", &self.last_char_index()) .field("typo_ascender", &self.typo_ascender()) .field("typo_descender", &self.typo_descender()) .field("typo_line_gap", &self.typo_line_gap()) .field("win_ascent", &self.win_ascent()) .field("win_descent", &self.win_descent()) .finish() } } // Version 1 #[derive(Clone, Copy, Zeroable, Pod)] #[repr(transparent)] pub struct Os2MetricsTable1([u8; 86]); impl<'a> RandomAccess<'a> for &'a Os2MetricsTable1 { fn bytes(&self) -> &'a [u8] { &self.0 } } impl AsRef for Os2MetricsTable1 { fn as_ref(&self) -> &Os2MetricsTable0 { bytemuck::from_bytes(&self.0[0..78]) } } impl Deref for Os2MetricsTable1 { type Target = Os2MetricsTable0; fn deref(&self) -> &Self::Target { self.as_ref() } } impl Os2MetricsTable1 { pub fn code_page_range_1(&self) -> u32 { self.uint32(78) } pub fn code_page_range_2(&self) -> u32 { self.uint32(82) } } impl Debug for Os2MetricsTable1 { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("Os2MetricsTable1") .field("version", &self.version()) .field("avg_char_width", &self.avg_char_width()) .field("weight_class", &self.weight_class()) .field("width_class", &self.width_class()) .field("type_flags", &self.type_flags()) .field("subscript_size", &self.subscript_size()) .field("subscript_offset", &self.subscript_offset()) .field("superscript_size", &self.superscript_size()) .field("superscript_offset", &self.superscript_offset()) .field("strikeout_size", &self.strikeout_size()) .field("strikeout_position", &self.strikeout_position()) .field("family_class", &self.family_class()) .field("panose", &self.panose()) .field("unicode_range_1", &self.unicode_range_1()) .field("unicode_range_2", &self.unicode_range_2()) .field("unicode_range_3", &self.unicode_range_3()) .field("unicode_range_4", &self.unicode_range_4()) .field("vendor_id", &self.vendor_id()) .field("selection_flags", &self.selection_flags()) .field("first_char_index", &self.first_char_index()) .field("last_char_index", &self.last_char_index()) .field("typo_ascender", &self.typo_ascender()) .field("typo_descender", &self.typo_descender()) .field("typo_line_gap", &self.typo_line_gap()) .field("win_ascent", &self.win_ascent()) .field("win_descent", &self.win_descent()) .field("code_page_range_1", &self.code_page_range_1()) .field("code_page_range_2", &self.code_page_range_2()) .finish() } } // Version 2-4 #[derive(Clone, Copy, Zeroable, Pod)] #[repr(transparent)] pub struct Os2MetricsTable2([u8; 96]); impl<'a> RandomAccess<'a> for &'a Os2MetricsTable2 { fn bytes(&self) -> &'a [u8] { &self.0 } } impl AsRef for Os2MetricsTable2 { fn as_ref(&self) -> &Os2MetricsTable0 { bytemuck::from_bytes(&self.0[0..78]) } } impl AsRef for Os2MetricsTable2 { fn as_ref(&self) -> &Os2MetricsTable1 { bytemuck::from_bytes(&self.0[0..86]) } } impl Deref for Os2MetricsTable2 { type Target = Os2MetricsTable1; fn deref(&self) -> &Self::Target { self.as_ref() } } impl Os2MetricsTable2 { pub fn x_height(&self) -> i16 { self.int16(86) } pub fn cap_height(&self) -> i16 { self.int16(88) } pub fn default_char(&self) -> u16 { self.uint16(90) } pub fn break_char(&self) -> u16 { self.uint16(92) } pub fn max_context(&self) -> u16 { self.uint16(94) } } impl Debug for Os2MetricsTable2 { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("Os2MetricsTable2") .field("version", &self.version()) .field("avg_char_width", &self.avg_char_width()) .field("weight_class", &self.weight_class()) .field("width_class", &self.width_class()) .field("type_flags", &self.type_flags()) .field("subscript_size", &self.subscript_size()) .field("subscript_offset", &self.subscript_offset()) .field("superscript_size", &self.superscript_size()) .field("superscript_offset", &self.superscript_offset()) .field("strikeout_size", &self.strikeout_size()) .field("strikeout_position", &self.strikeout_position()) .field("family_class", &self.family_class()) .field("panose", &self.panose()) .field("unicode_range_1", &self.unicode_range_1()) .field("unicode_range_2", &self.unicode_range_2()) .field("unicode_range_3", &self.unicode_range_3()) .field("unicode_range_4", &self.unicode_range_4()) .field("vendor_id", &self.vendor_id()) .field("selection_flags", &self.selection_flags()) .field("first_char_index", &self.first_char_index()) .field("last_char_index", &self.last_char_index()) .field("typo_ascender", &self.typo_ascender()) .field("typo_descender", &self.typo_descender()) .field("typo_line_gap", &self.typo_line_gap()) .field("win_ascent", &self.win_ascent()) .field("win_descent", &self.win_descent()) .field("code_page_range_1", &self.code_page_range_1()) .field("code_page_range_2", &self.code_page_range_2()) .field("x_height", &self.x_height()) .field("cap_height", &self.cap_height()) .field("default_char", &self.default_char()) .field("break_char", &self.break_char()) .field("max_context", &self.max_context()) .finish() } } // Version 5 #[derive(Clone, Copy, Zeroable, Pod)] #[repr(transparent)] pub struct Os2MetricsTable5([u8; 100]); impl<'a> RandomAccess<'a> for &'a Os2MetricsTable5 { fn bytes(&self) -> &'a [u8] { &self.0 } } impl AsRef for Os2MetricsTable5 { fn as_ref(&self) -> &Os2MetricsTable0 { bytemuck::from_bytes(&self.0[0..78]) } } impl AsRef for Os2MetricsTable5 { fn as_ref(&self) -> &Os2MetricsTable1 { bytemuck::from_bytes(&self.0[0..86]) } } impl AsRef for Os2MetricsTable5 { fn as_ref(&self) -> &Os2MetricsTable2 { bytemuck::from_bytes(&self.0[0..96]) } } impl Deref for Os2MetricsTable5 { type Target = Os2MetricsTable2; fn deref(&self) -> &Self::Target { self.as_ref() } } impl Os2MetricsTable5 { pub fn lower_optical_point_size(&self) -> u16 { self.uint16(96) } pub fn upper_optical_point_size(&self) -> u16 { self.uint16(98) } } impl Debug for Os2MetricsTable5 { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("Os2MetricsTable5") .field("version", &self.version()) .field("avg_char_width", &self.avg_char_width()) .field("weight_class", &self.weight_class()) .field("width_class", &self.width_class()) .field("type_flags", &self.type_flags()) .field("subscript_size", &self.subscript_size()) .field("subscript_offset", &self.subscript_offset()) .field("superscript_size", &self.superscript_size()) .field("superscript_offset", &self.superscript_offset()) .field("strikeout_size", &self.strikeout_size()) .field("strikeout_position", &self.strikeout_position()) .field("family_class", &self.family_class()) .field("panose", &self.panose()) .field("unicode_range_1", &self.unicode_range_1()) .field("unicode_range_2", &self.unicode_range_2()) .field("unicode_range_3", &self.unicode_range_3()) .field("unicode_range_4", &self.unicode_range_4()) .field("vendor_id", &self.vendor_id()) .field("selection_flags", &self.selection_flags()) .field("first_char_index", &self.first_char_index()) .field("last_char_index", &self.last_char_index()) .field("typo_ascender", &self.typo_ascender()) .field("typo_descender", &self.typo_descender()) .field("typo_line_gap", &self.typo_line_gap()) .field("win_ascent", &self.win_ascent()) .field("win_descent", &self.win_descent()) .field("code_page_range_1", &self.code_page_range_1()) .field("code_page_range_2", &self.code_page_range_2()) .field("x_height", &self.x_height()) .field("cap_height", &self.cap_height()) .field("default_char", &self.default_char()) .field("break_char", &self.break_char()) .field("max_context", &self.max_context()) .field("lower_optical_point_size", &self.lower_optical_point_size()) .field("upper_optical_point_size", &self.upper_optical_point_size()) .finish() } } // Generic #[derive(Clone, Copy)] pub enum Os2MetricsTable<'a> { Version0(&'a Os2MetricsTable0), Version1(&'a Os2MetricsTable1), Version2(&'a Os2MetricsTable2), Version3(&'a Os2MetricsTable2), Version4(&'a Os2MetricsTable2), Version5(&'a Os2MetricsTable5), } impl<'a> RandomAccess<'a> for Os2MetricsTable<'a> { fn bytes(&self) -> &'a [u8] { match self { Self::Version0(x) => x.bytes(), Self::Version1(x) => x.bytes(), Self::Version2(x) => x.bytes(), Self::Version3(x) => x.bytes(), Self::Version4(x) => x.bytes(), Self::Version5(x) => x.bytes(), } } } impl<'a> Deref for Os2MetricsTable<'a> { type Target = Os2MetricsTable0; fn deref(&self) -> &Self::Target { match self { Self::Version0(x) => x, Self::Version1(x) => x, Self::Version2(x) => x, Self::Version3(x) => x, Self::Version4(x) => x, Self::Version5(x) => x, } } } impl<'a> Debug for Os2MetricsTable<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { match self { Self::Version0(x) => x.fmt(f), Self::Version1(x) => x.fmt(f), Self::Version2(x) => x.fmt(f), Self::Version3(x) => x.fmt(f), Self::Version4(x) => x.fmt(f), Self::Version5(x) => x.fmt(f), } } } impl<'a> TryFrom<&'a [u8]> for Os2MetricsTable<'a> { type Error = ReadError; fn try_from(value: &'a [u8]) -> Result { if value.len() < 2 { return Err(ReadError::UnexpectedEof); } match value.uint16(0) { 0 => { if value.len() < 78 { return Err(ReadError::UnexpectedEof); } Ok(Os2MetricsTable::Version0(bytemuck::from_bytes(&value[0..78]))) }, 1 => { if value.len() < 86 { return Err(ReadError::UnexpectedEof); } Ok(Os2MetricsTable::Version1(bytemuck::from_bytes(&value[0..86]))) }, 2 => { if value.len() < 96 { return Err(ReadError::UnexpectedEof); } Ok(Os2MetricsTable::Version2(bytemuck::from_bytes(&value[0..96]))) }, 3 => { if value.len() < 96 { return Err(ReadError::UnexpectedEof); } Ok(Os2MetricsTable::Version3(bytemuck::from_bytes(&value[0..96]))) }, 4 => { if value.len() < 96 { return Err(ReadError::UnexpectedEof); } Ok(Os2MetricsTable::Version4(bytemuck::from_bytes(&value[0..96]))) }, 5 => { if value.len() < 100 { return Err(ReadError::UnexpectedEof); } Ok(Os2MetricsTable::Version5(bytemuck::from_bytes(&value[0..100]))) }, x => Err(ReadError::UnsupportedTableVersionSingle(x)) } } }